resource-manager: Add API for event handling 68/298768/4
authorYoungjae Cho <y0.cho@samsung.com>
Wed, 13 Sep 2023 07:38:04 +0000 (16:38 +0900)
committerYoungjae Cho <y0.cho@samsung.com>
Mon, 16 Oct 2023 07:43:37 +0000 (16:43 +0900)
On setting a value onto an attribute using resource-manager set API,
that setting event is broadcasted to listeners.

- typedef (*syscommon_resman_resource_event_cb) (int resource_type,
int resource_id, int attr_id, const void *data, int count)
  : It receives information about attribute value that has been set
    by resource-manager set API.

- syscommon_resman_subscribe_resource_event()
  : It registers callback function and receives associated 'id' that
    represents callback object. The callback function will be called
    on calling set API to the attribute.

- syscommon_resman_unsubscribe_resource_event()
  : It unregisters callback from listening. The 'id' is one that has
    received from the syscommon_resman_subscribe_resource_event().

Change-Id: I38765498521968e5db0c11a5e5d9285b4a4951f2
Signed-off-by: Youngjae Cho <y0.cho@samsung.com>
include/libsyscommon/resource-manager.h
src/resource-manager/resource-manager.c
tests/resource-manager/test.c

index 17d9d72..d6d3264 100644 (file)
@@ -248,8 +248,14 @@ int syscommon_resman_set_resource_attr_ptr(int resource_id, u_int64_t attr_id, v
 int syscommon_resman_set_resource_attr_interest(int resource_id, u_int64_t interest_mask);
 int syscommon_resman_unset_resource_attr_interest(int resource_id, u_int64_t interest_mask);
 bool syscommon_resman_is_resource_attr_interested(int resource_id, u_int64_t interest_mask);
-const char *syscommon_resman_get_resource_attr_name(int resource_id, u_int64_t attr_id);
 
+typedef void (*syscommon_resman_resource_event_cb) (int resource_type,
+       int resource_id, int attr_id, const void *data, int count);
+
+int syscommon_resman_subscribe_resource_event(syscommon_resman_resource_event_cb callback, int *id);
+void syscommon_resman_unsubscribe_resource_event(int id);
+
+const char *syscommon_resman_get_resource_attr_name(int resource_id, u_int64_t attr_id);
 const char *syscommon_resman_get_resource_name(int resource_id);
 void *syscommon_resman_get_resource_privdata(int resource_id);
 int syscommon_resman_get_resource_type(int resource_id);
index 72171d8..61fbe59 100644 (file)
@@ -70,11 +70,19 @@ struct attribute_is_supported_ops {
                   void *data);
 };
 
+struct resource_event_data {
+       int id;
+       syscommon_resman_resource_event_cb callback;
+};
+
 static int set_resource_attr_interest(struct syscommon_resman_resource *resource, u_int64_t interest_mask);
 static int unset_resource_attr_interest(struct syscommon_resman_resource *resource, u_int64_t interest_mask);
 static bool is_resource_attr_interested(struct syscommon_resman_resource *resource, u_int64_t interest_mask);
+static void
+notify_resource_event(int resource_type, int resource_id, int attr_id, const void *data, int count);
 
 static GList *g_resource_driver_head;
+static GList *g_resource_event_data_list;
 
 /**
  * key: resource_id, value: struct syscommon_resman_resource
@@ -1467,6 +1475,8 @@ set_resource_attr_value_data(struct syscommon_resman_resource *resource,
                return -EINVAL;
        }
 
+       notify_resource_event(resource->resource_type, resource->id, attr_id, attr_value->data, count);
+
        return 0;
 }
 
@@ -1939,6 +1949,67 @@ syscommon_resman_is_resource_attr_interested(int resource_id, u_int64_t interest
        return is_resource_attr_interested(resource, interest_mask);
 }
 
+static void
+notify_resource_event(int resource_type, int resource_id, int attr_id, const void *data, int count)
+{
+       GList *elem;
+       struct resource_event_data *event_data;
+
+       for (elem = g_resource_event_data_list; elem; elem = elem->next) {
+               event_data = (struct resource_event_data *) elem->data;
+
+               assert(event_data);
+               event_data->callback(resource_type, resource_id, attr_id, data, count);
+       }
+}
+
+static gboolean find_resource_event_data(gconstpointer data, gconstpointer id)
+{
+       const struct resource_event_data *_event_data = (const struct resource_event_data *) data;
+       const int _id = *(const int *) id;
+
+       return (_event_data->id - _id);
+}
+
+int
+syscommon_resman_subscribe_resource_event(syscommon_resman_resource_event_cb callback, int *id)
+{
+       struct resource_event_data *event_data = NULL;
+
+       if (!callback || !id)
+               return -EINVAL;
+
+       event_data = calloc(1, sizeof(*event_data));
+       if (!event_data)
+               return -ENOMEM;
+
+       *event_data = (struct resource_event_data) {
+               .id = alloc_resource_id(),
+               .callback = callback
+       };
+
+       g_resource_event_data_list = g_list_append(g_resource_event_data_list, event_data);
+
+       *id = event_data->id;
+
+       return 0;
+}
+
+void syscommon_resman_unsubscribe_resource_event(int id)
+{
+       GList *list;
+
+       list = g_list_find_custom(g_resource_event_data_list, &id, find_resource_event_data);
+       if (!list)
+               return;
+
+       g_resource_event_data_list = g_list_remove_link(g_resource_event_data_list, list);
+
+       free(list->data);
+       list->data = NULL;
+       g_list_free(list);
+}
+
 const char *
 syscommon_resman_get_resource_attr_name(int resource_id, u_int64_t attr_id)
 {
index ccf35e4..a6b3cfe 100644 (file)
@@ -395,6 +395,154 @@ static void test_set_resource_attr_int_fail_invalid_parameter_1(void **state)
        cleanup_normal_resource(resource_id);
 }
 
+static void test_event_callback1(int resource_type, int resource_id, int attr_id, const void *data, int count)
+{
+       check_expected(resource_type);
+       check_expected(resource_id);
+       check_expected(attr_id);
+       check_expected_ptr(data);
+       check_expected(count);
+}
+
+static void test_event_callback2(int resource_type, int resource_id, int attr_id, const void *data, int count)
+{
+       check_expected(resource_type);
+       check_expected(resource_id);
+       check_expected(attr_id);
+       check_expected_ptr(data);
+       check_expected(count);
+}
+
+static void test_subscribe_event_pass(void **state)
+{
+       int resource_id1;
+       int resource_id2;
+       int callback_id1;
+       int callback_id2;
+       int int_value = 393939;
+       double double_value = 12.1212;
+       int ret;
+
+       resource_id1 = setup_normal_resource();
+       resource_id2 = setup_normal_resource();
+
+       ret = syscommon_resman_subscribe_resource_event(test_event_callback1, &callback_id1);
+       assert_int_equal(ret, 0);
+
+       /* configure mock setter, success */
+       expect_memory(test_set, data, &int_value, sizeof(int));
+       will_return(test_set, 0);
+       /* configure mock callback1 */
+       expect_value(test_event_callback1, resource_type, TEST_RESOURCE_TYPE_NORMAL_SINGLETON);
+       expect_value(test_event_callback1, resource_id, resource_id1);
+       expect_value(test_event_callback1, attr_id, TEST_ATTR_INT);
+       expect_memory(test_event_callback1, data, &int_value, sizeof(int));
+       expect_value(test_event_callback1, count, 1);
+
+       ret = syscommon_resman_set_resource_attr_int(resource_id1, TEST_ATTR_INT, int_value);
+       assert_int_equal(ret, 0);
+
+       /* register additional callback2 */
+       ret = syscommon_resman_subscribe_resource_event(test_event_callback2, &callback_id2);
+       assert_int_equal(ret, 0);
+
+       /* second try, configure mock setter, success */
+       expect_memory(test_set, data, &double_value, sizeof(double));
+       will_return(test_set, 0);
+       /* configure mock callback1 */
+       expect_value(test_event_callback1, resource_type, TEST_RESOURCE_TYPE_NORMAL_SINGLETON);
+       expect_value(test_event_callback1, resource_id, resource_id2);
+       expect_value(test_event_callback1, attr_id, TEST_ATTR_DOUBLE);
+       expect_memory(test_event_callback1, data, &double_value, sizeof(double));
+       expect_value(test_event_callback1, count, 1);
+       /* configure mock callback2 */
+       expect_value(test_event_callback2, resource_type, TEST_RESOURCE_TYPE_NORMAL_SINGLETON);
+       expect_value(test_event_callback2, resource_id, resource_id2);
+       expect_value(test_event_callback2, attr_id, TEST_ATTR_DOUBLE);
+       expect_memory(test_event_callback2, data, &double_value, sizeof(double));
+       expect_value(test_event_callback2, count, 1);
+
+       /* set another resource(2), and another attribute(double) */
+       ret = syscommon_resman_set_resource_attr_double(resource_id2, TEST_ATTR_DOUBLE, double_value);
+       assert_int_equal(ret, 0);
+
+       /* unregister the callback1 */
+       syscommon_resman_unsubscribe_resource_event(callback_id1);
+
+       /* third try, configure mock setter, success */
+       int_value = 10101;
+       expect_memory(test_set, data, &int_value, sizeof(int));
+       will_return(test_set, 0);
+       /* configure only mock callback2 */
+       expect_value(test_event_callback2, resource_type, TEST_RESOURCE_TYPE_NORMAL_SINGLETON);
+       expect_value(test_event_callback2, resource_id, resource_id2);
+       expect_value(test_event_callback2, attr_id, TEST_ATTR_INT);
+       expect_memory(test_event_callback2, data, &int_value, sizeof(int));
+       expect_value(test_event_callback2, count, 1);
+
+       ret = syscommon_resman_set_resource_attr_int(resource_id2, TEST_ATTR_INT, int_value);
+       assert_int_equal(ret, 0);
+
+       /* unregister the callback2 */
+       syscommon_resman_unsubscribe_resource_event(callback_id2);
+
+       /* the last try, configure mock setter, success */
+       double_value = 5959.95;
+       expect_memory(test_set, data, &double_value, sizeof(double));
+       will_return(test_set, 0);
+       /* neither configure callback1 nor callback2 */
+
+       ret = syscommon_resman_set_resource_attr_double(resource_id1, TEST_ATTR_DOUBLE, double_value);
+       assert_int_equal(ret, 0);
+
+       cleanup_normal_resource(resource_id1);
+       cleanup_normal_resource(resource_id2);
+}
+
+static void test_subscribe_event_fail_invalid_parameter_1(void **state)
+{
+       int callback_id;
+       int ret;
+
+       ret = syscommon_resman_subscribe_resource_event(NULL, &callback_id);
+       assert_int_equal(ret, -EINVAL);
+}
+
+static void test_subscribe_event_fail_invalid_parameter_2(void **state)
+{
+       int ret;
+
+       ret = syscommon_resman_subscribe_resource_event(test_event_callback1, NULL);
+       assert_int_equal(ret, -EINVAL);
+}
+
+static void test_subscribe_event_fail_setter(void **state)
+{
+       int resource_id;
+       int callback_id;
+       int ret;
+       int value = 890890;
+
+       resource_id = setup_normal_resource();
+
+       ret = syscommon_resman_subscribe_resource_event(test_event_callback1, &callback_id);
+       assert_int_equal(ret, 0);
+
+       /* configure mock setter, fail */
+       expect_memory(test_set, data, &value, sizeof(int));
+       will_return(test_set, -ENOENT /* An error occured */);
+       /* do not configure mock callback. it must not be invoked if setter has failed */
+
+       ret = syscommon_resman_set_resource_attr_int(resource_id, TEST_ATTR_INT, value);
+       assert_int_equal(ret, -ENOENT);
+
+       syscommon_resman_unsubscribe_resource_event(callback_id);
+
+       cleanup_normal_resource(resource_id);
+}
+
+extern int setup_resource_test_driver(void **state);
+
 static const struct CMUnitTest resource_manager_testsuite[] = {
        cmocka_unit_test(test_create_resource_pass),
        cmocka_unit_test(test_create_resource_fail_driver_ops_create),
@@ -420,5 +568,10 @@ static const struct CMUnitTest resource_manager_testsuite[] = {
        cmocka_unit_test(test_set_resource_attr_int_fail_no_setter),
        cmocka_unit_test(test_set_resource_attr_int_fail_unmatched_type),
        cmocka_unit_test(test_set_resource_attr_int_fail_invalid_parameter_1),
+
+       cmocka_unit_test(test_subscribe_event_pass),
+       cmocka_unit_test(test_subscribe_event_fail_invalid_parameter_1),
+       cmocka_unit_test(test_subscribe_event_fail_invalid_parameter_2),
+       cmocka_unit_test(test_subscribe_event_fail_setter),
 };
 TESTSUITE_FIXTURE(resource_manager_testsuite, resource_driver_test_setup, NULL);