From b3036eb10b5d5ec1820ff9b5e619a1081e629197 Mon Sep 17 00:00:00 2001 From: Youngjae Cho Date: Tue, 4 Jan 2022 18:34:49 +0900 Subject: [PATCH] device-notifier: add callback that can receive user_data typedef int (*notify_cb_udata)(void *data, void *user_data) >> The callback has an additional parameter, user_data, for receiving user data. typedef void (*destroy_cb_udata)(void *user_data) >> The callback is invoked on removing notifier with parameter user_data. int __register_notifier_udata(enum device_notifier_type type, notify_cb_udata func, void *user_data, destroy_cb_udata func_destroy, const char *caller) >> Returns negative errno on error occured. Otherwise positive integer that denotes notifier id, which can be used for unregistering the notifier. >> There are two additional parameters compared to the original register_notifier(). One is user_data, which is passed as the second parameter to callback and the other is func_destroy, which is invoked on removing notifier. >> It is allowed to register multiple notifier with same callback on a same type, because a user_data might differ even though they have same callback on a same type. int __unregister_notifier_udata(int id, const char *caller) >> Receives notifier id and unregisters matching notifier. Change-Id: I46d1fec98eae19dbd9aaed60dfd84f760d152b9e Signed-off-by: Youngjae Cho --- src/shared/device-notifier.c | 64 +++++++- src/shared/device-notifier.h | 10 ++ .../test-device-notifier.c | 170 ++++++++++++++++++--- 3 files changed, 226 insertions(+), 18 deletions(-) diff --git a/src/shared/device-notifier.c b/src/shared/device-notifier.c index 08044f1..6eacafe 100644 --- a/src/shared/device-notifier.c +++ b/src/shared/device-notifier.c @@ -27,9 +27,15 @@ #define __stringify(x...) __stringify_1(x) struct device_notifier { + int id; + bool deleted; enum device_notifier_type type; int (*func)(void *data); + + int (*func_udata)(void *data, void *user_data); + void (*destroyer)(void *user_data); + void *user_data; }; static GList *device_notifier_list; @@ -110,6 +116,39 @@ int __register_notifier(enum device_notifier_type type, notify_cb func, const ch return 0; } +int __register_notifier_udata(enum device_notifier_type type, + notify_cb_udata func_udata, void *user_data, + destroy_cb_udata func_destroy_udata, const char *caller) +{ + struct device_notifier *notifier; + static int id = 1; + + _I("%s, %p by %s", device_notifier_type_str[type], func_udata, caller); + + if (!func_udata) { + _E("invalid func address! by %s", caller); + return -EINVAL; + } + + notifier = calloc(1, sizeof(struct device_notifier)); + if (!notifier) { + _E("Fail to malloc for %s notifier! by %s", device_notifier_type_str[type], caller); + return -ENOMEM; + } + + notifier->id = id; + notifier->type = type; + notifier->func_udata = func_udata; + notifier->user_data = user_data; + notifier->destroyer = func_destroy_udata; + + SYS_G_LIST_APPEND(device_notifier_list, notifier); + + ++id; + + return notifier->id; +} + int __unregister_notifier(enum device_notifier_type type, notify_cb func, const char *caller) { GList *n; @@ -128,6 +167,22 @@ int __unregister_notifier(enum device_notifier_type type, notify_cb func, const return 0; } +int __unregister_notifier_udata(int id, const char *caller) +{ + GList *n; + struct device_notifier *notifier; + + SYS_G_LIST_FOREACH(device_notifier_list, n, notifier) { + if (notifier->id == id) { + if (notifier->destroyer) + notifier->destroyer(notifier->user_data); + notifier->deleted = true; + } + } + + return 0; +} + static gboolean delete_unused_notifier_cb(void *data) { GList *n; @@ -154,6 +209,8 @@ void device_notify(enum device_notifier_type type, void *data) if (!notifier->deleted && type == notifier->type) { if (notifier->func) notifier->func(data); + else if (notifier->func_udata) + notifier->func_udata(data, notifier->user_data); } } @@ -168,8 +225,13 @@ void device_notify_once(enum device_notifier_type type, void *data) SYS_G_LIST_FOREACH(device_notifier_list, n, notifier) { if (!notifier->deleted && type == notifier->type) { - if (notifier->func) + if (notifier->func) { notifier->func(data); + } else if (notifier->func_udata) { + notifier->func_udata(data, notifier->user_data); + if (notifier->destroyer) + notifier->destroyer(notifier->user_data); + } notifier->deleted = true; } diff --git a/src/shared/device-notifier.h b/src/shared/device-notifier.h index c917049..ec7cfd3 100644 --- a/src/shared/device-notifier.h +++ b/src/shared/device-notifier.h @@ -86,6 +86,8 @@ typedef enum _device_notifier_state { } device_notifier_state_e; typedef int (*notify_cb)(void *data); +typedef int (*notify_cb_udata)(void *data, void *user_data); +typedef void (*destroy_cb_udata)(void *user_data); /* * This is for internal callback method. */ @@ -93,6 +95,14 @@ int __register_notifier(enum device_notifier_type type, notify_cb func, const ch #define register_notifier(type, func) __register_notifier(type, func, __func__) int __unregister_notifier(enum device_notifier_type type, notify_cb func, const char *caller); #define unregister_notifier(type, func) __unregister_notifier(type, func, __func__) + +int __register_notifier_udata(enum device_notifier_type type, notify_cb_udata func, void *user_data, + destroy_cb_udata func_destroy, const char *caller); +#define register_notifier_udata(type, func, user_data, func_destroy) \ + __register_notifier_udata(type, func, user_data, func_destroy, __func__) +int __unregister_notifier_udata(int id, const char *caller); +#define unregister_notifier_udata(id) __unregister_notifier_udata(id, __func__) + void device_notify(enum device_notifier_type type, void *value); void device_notify_once(enum device_notifier_type status, void *data); diff --git a/tests/deviced-common-private-test/test-device-notifier.c b/tests/deviced-common-private-test/test-device-notifier.c index bc86513..b654887 100644 --- a/tests/deviced-common-private-test/test-device-notifier.c +++ b/tests/deviced-common-private-test/test-device-notifier.c @@ -1,64 +1,200 @@ +#include #include #include #include #include "test-main.h" -static int notified; +#define INT_MAX ((~0) >> 1) static int notify_callback(void *data) { - notified = (int)(intptr_t) data; + check_expected(data); return 0; } +static int notify_callback_udata(void *data, void *udata) +{ + check_expected(data); + check_expected(udata); + + return 0; +} + +static void destroy_callback_udata(void *udata) +{ + check_expected(udata); +} + static void test_device_notify_n(void **state) { int retval; retval = register_notifier(DEVICE_NOTIFIER_MAX, NULL); assert_int_equal(retval, -EINVAL); + + retval = register_notifier_udata(DEVICE_NOTIFIER_MAX, NULL, NULL, NULL); + assert_int_equal(retval, -EINVAL); } -static void test_device_notify_p(void **state) +static void test_device_notify_p1(void **state) { int retval; - notified = 999; - retval = register_notifier(DEVICE_NOTIFIER_LCD, notify_callback); assert_int_equal(retval, 0); + expect_value(notify_callback, data, 0x3f3f3f3f); - for (int i = 3; i < 8; ++i) { - device_notify(DEVICE_NOTIFIER_LCD, (void *)(intptr_t) i); - assert_int_equal(notified, i); - } + device_notify(DEVICE_NOTIFIER_LCD, (void *)(intptr_t) 0x3f3f3f3f); } -static void test_device_notify_once_p(void **state) +static void test_device_notify_p2(void **state) { int retval; - int value = 721; + int notify_data; + const int udata2 = 0xaeaeaeae; + const int udata3 = 0x99997777; + + notify_data = 0x12456321; + + /* 1st notifier */ + retval = register_notifier(DEVICE_NOTIFIER_PMQOS, notify_callback); + assert_int_equal(retval, 0); + + /* 2nd notifier */ + retval = register_notifier_udata(DEVICE_NOTIFIER_PMQOS, notify_callback_udata, (void *)(intptr_t) udata2, NULL); + assert_in_range(retval, 1, INT_MAX); + + /* expect invocation of 1st callback and check parameter */ + expect_value(notify_callback, data, notify_data); + /* expect invocation of 2nd callback and check parameter */ + expect_value(notify_callback_udata, data, notify_data); + expect_value(notify_callback_udata, udata, udata2); + + device_notify(DEVICE_NOTIFIER_PMQOS, (void *)(intptr_t) notify_data); + + notify_data = 0x888899dd; + + /* 3rd notifier */ + retval = register_notifier_udata(DEVICE_NOTIFIER_PMQOS, notify_callback_udata, (void *)(intptr_t) udata3, NULL); + assert_in_range(retval, 1, INT_MAX); + + /* expect invocation of 1st callback and check parameter */ + expect_value(notify_callback, data, notify_data); + /* expect invocation of 2nd callback and check parameter */ + expect_value(notify_callback_udata, data, notify_data); + expect_value(notify_callback_udata, udata, udata2); + /* expect invocation of 3rd callback and check parameter */ + expect_value(notify_callback_udata, data, notify_data); + expect_value(notify_callback_udata, udata, udata3); + + device_notify(DEVICE_NOTIFIER_PMQOS, (void *)(intptr_t) notify_data); +} + +static void test_device_notify_p3(void **state) +{ + int notify_data; + int id1, id2; + const int udata1 = 0x41a41a41; + const int udata2 = 0x77777777; + + /* first run */ + notify_data = 0x8575ddff; + + /* 1st notifier */ + id1 = register_notifier_udata(DEVICE_NOTIFIER_POWEROFF, notify_callback_udata, (void *)(intptr_t) udata1, NULL); + assert_in_range(id1, 1, INT_MAX); - notified = 999; + /* 2nd notifier */ + id2 = register_notifier_udata(DEVICE_NOTIFIER_POWEROFF, notify_callback_udata, (void *)(intptr_t) udata2, NULL); + assert_in_range(id2, 1, INT_MAX); + + /* expect invocation of 1st callback and check parameter */ + expect_value(notify_callback_udata, data, notify_data); + expect_value(notify_callback_udata, udata, udata1); + /* expect invocation of 2nd callback and check parameter */ + expect_value(notify_callback_udata, data, notify_data); + expect_value(notify_callback_udata, udata, udata2); + + device_notify(DEVICE_NOTIFIER_POWEROFF, (void *)(intptr_t) notify_data); + + /* second run. at this time device_notify() after unregistering 1st notifier */ + notify_data = 0x345; + + unregister_notifier_udata(id1); + + /* only expect invocation of 2nd callback and check parameter */ + expect_value(notify_callback_udata, data, notify_data); + expect_value(notify_callback_udata, udata, udata2); + + device_notify(DEVICE_NOTIFIER_POWEROFF, (void *)(intptr_t) notify_data); +} + +static void test_device_notify_once_p(void **state) +{ + int retval; retval = register_notifier(DEVICE_NOTIFIER_LCD_OFF, notify_callback); assert_int_equal(retval, 0); - device_notify_once(DEVICE_NOTIFIER_LCD_OFF, (void *)(intptr_t) value); - assert_int_equal(notified, value); + expect_value(notify_callback, data, 0xabcdabcd); + device_notify_once(DEVICE_NOTIFIER_LCD_OFF, (void *)(intptr_t) 0xabcdabcd); + + /* Don't add expect_value() for callback at this time. + * Therefore if the callback is invoked, check_expected() returns error */ + device_notify(DEVICE_NOTIFIER_LCD_OFF, (void *)(intptr_t) 0xabcdabcd); + + retval = register_notifier_udata(DEVICE_NOTIFIER_BATTERY_CHARGING, notify_callback_udata, (void *)(intptr_t) 0xfefefefe, NULL); + assert_in_range(retval, 1, INT_MAX); + + expect_value(notify_callback_udata, data, 0x34343434); + expect_value(notify_callback_udata, udata, 0xfefefefe); + device_notify_once(DEVICE_NOTIFIER_BATTERY_CHARGING, (void *)(intptr_t) 0x34343434); + + /* Don't add expect_value() for callback at this time. + * Therefore if the callback is invoked, check_expected() returns error */ + device_notify(DEVICE_NOTIFIER_BATTERY_CHARGING, (void *)(intptr_t) 0x34343434); +} + +static void test_destroy_callback_p1(void **state) +{ + int id; + + id = register_notifier_udata(DEVICE_NOTIFIER_LOWBAT, notify_callback_udata, + (void *)(intptr_t) 0x4848, destroy_callback_udata); + assert_in_range(id, 1, INT_MAX); + + expect_value(destroy_callback_udata, udata, 0x4848); + + unregister_notifier_udata(id); +} + +static void test_destroy_callback_p2(void **state) +{ + int id; + + id = register_notifier_udata(DEVICE_NOTIFIER_LOWBAT, notify_callback_udata, + (void *)(intptr_t) 0x1177, destroy_callback_udata); + assert_in_range(id, 1, INT_MAX); + + expect_value(notify_callback_udata, data, 0x9a9a9a9a); + expect_value(notify_callback_udata, udata, 0x1177); + expect_value(destroy_callback_udata, udata, 0x1177); - device_notify(DEVICE_NOTIFIER_LCD_OFF, (void *)(intptr_t) (value - 1)); - assert_int_equal(notified, value); + device_notify_once(DEVICE_NOTIFIER_LOWBAT, (void *)(intptr_t) 0x9a9a9a9a); } static int run_device_notifier_test(void) { static const struct CMUnitTest testsuite[] = { cmocka_unit_test(test_device_notify_n), - cmocka_unit_test(test_device_notify_p), + cmocka_unit_test(test_device_notify_p1), + cmocka_unit_test(test_device_notify_p2), + cmocka_unit_test(test_device_notify_p3), cmocka_unit_test(test_device_notify_once_p), + cmocka_unit_test(test_destroy_callback_p1), + cmocka_unit_test(test_destroy_callback_p2), }; return cmocka_run_group_tests(testsuite, NULL, NULL); -- 2.7.4