From: Youngjae Cho Date: Wed, 13 Sep 2023 07:38:04 +0000 (+0900) Subject: resource-manager: Add API for event handling X-Git-Tag: accepted/tizen/unified/20231115.024827~6 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d91ade14e1b885621f084a30a81bee3f7e8adfae;p=platform%2Fcore%2Fsystem%2Flibsyscommon.git resource-manager: Add API for event handling 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 --- diff --git a/include/libsyscommon/resource-manager.h b/include/libsyscommon/resource-manager.h index 17d9d72..d6d3264 100644 --- a/include/libsyscommon/resource-manager.h +++ b/include/libsyscommon/resource-manager.h @@ -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); diff --git a/src/resource-manager/resource-manager.c b/src/resource-manager/resource-manager.c index 72171d8..61fbe59 100644 --- a/src/resource-manager/resource-manager.c +++ b/src/resource-manager/resource-manager.c @@ -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) { diff --git a/tests/resource-manager/test.c b/tests/resource-manager/test.c index ccf35e4..a6b3cfe 100644 --- a/tests/resource-manager/test.c +++ b/tests/resource-manager/test.c @@ -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);