device-notifier: add callback that can receive user_data 95/268895/5
authorYoungjae Cho <y0.cho@samsung.com>
Tue, 4 Jan 2022 09:34:49 +0000 (18:34 +0900)
committerYoungjae Cho <y0.cho@samsung.com>
Wed, 5 Jan 2022 05:17:42 +0000 (14:17 +0900)
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 <y0.cho@samsung.com>
src/shared/device-notifier.c
src/shared/device-notifier.h
tests/deviced-common-private-test/test-device-notifier.c

index 08044f1..6eacafe 100644 (file)
 #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;
                }
index c917049..ec7cfd3 100644 (file)
@@ -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);
 
index bc86513..b654887 100644 (file)
+#include <stdio.h>
 #include <stdint.h>
 #include <errno.h>
 #include <shared/device-notifier.h>
 
 #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);