libcommon: Introduce notifier 59/296359/2
authorYoungjae Cho <y0.cho@samsung.com>
Tue, 25 Jul 2023 11:21:10 +0000 (20:21 +0900)
committerYoungjae Cho <y0.cho@samsung.com>
Thu, 27 Jul 2023 05:08:56 +0000 (14:08 +0900)
 The libsyscommon notifer provides mean that communicate between
different modules. And it works based on publish-subscribe pattern.

 If someone wants to listen to an event, it subscribes to notify id
that is defined by event publisher, using subscribe function such as
 - syscommon_notifier_subscribe_notify_priority()
 - syscommon_notifier_subscribe_notify()
 - syscommon_notifier_subscribe_notify_udata_priority()
 - syscommon_notifier_subscribe_notify_udata()
Obviously, it is possible to unsubscribe notify via
 - syscommon_notifier_unsubscribe_notify()
 - syscommon_notifier_unsubscribe_notify_udata()

 If someone want publish a notify, it can be done by the functions
such as
 - syscommon_notifier_emit_notify()
 - syscommon_notifier_emit_notify_once()
See below for a detailed description about libsyscommon notifier.

 int syscommon_notifier_subscribe_notify_priority()
  - Subscribe notify without user_data callback.
  - Higher number of priority will be notified first.

 int syscommon_notifier_subscribe_notify()
  - Subscribe notify without user_data callback
  - Automatically assign default priority of 0.

 int syscommon_notifier_unsubscribe_notify()
  - Unsubscribe notify callback without user_data.

 int syscommon_notifier_subscribe_notify_udata_priority()
  - Subscribe notify with user_data callback.
  - Provide destroy callback to free user_data on unsubscribing.
  - Higher number of priority will be notified first.
  - Return notify id and can be used for unsubscribing.

 int syscommon_notifier_unsubscribe_notify_udata()
  - Subscribe notify with user_data callback
  - Provide destroy callback to free user_data on unsubscribing
  - Automatically assign default priority of 0.
  - Return notify id and can be used for unsubscribing.

 int syscommon_notifier_subscribe_notify_udata()
  - Unsubscribe notify callback with user_data.
  - Invoke destroy function with user_data.

 void syscommon_notifier_emit_notify()
  - Emit notify.

 void syscommon_notifier_emit_notify_once()
  - Emit notify only once.
  - Notification after the first one is ignored.

Change-Id: I1853f5a51e999c1f20b34c9281becb9cfbdb8a8b
Signed-off-by: Youngjae Cho <y0.cho@samsung.com>
Change-Id: Iff113c8869e27a90f11156181b500d25893387a8

CMakeLists.txt
include/libsyscommon/notifier.h [new file with mode: 0644]
src/libcommon/notifier.c [new file with mode: 0644]
tests/libcommon/test-common.c

index 9094e74..f708755 100644 (file)
@@ -23,6 +23,7 @@ SET(libsyscommon_SRCS
        src/libcommon/common.c
        src/libcommon/bitmap.c
        src/libcommon/proc.c
+       src/libcommon/notifier.c
        src/resource-manager/resource-manager.c
        src/resource-manager/resource-device.c
        src/resource-manager/resource-listener-epoll.c
diff --git a/include/libsyscommon/notifier.h b/include/libsyscommon/notifier.h
new file mode 100644 (file)
index 0000000..f88d22f
--- /dev/null
@@ -0,0 +1,77 @@
+/* MIT License
+ *
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is furnished
+ * to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE. */
+
+#ifndef __SYSCOMMON_NOTIFIER_H__
+#define __SYSCOMMON_NOTIFIER_H__
+
+typedef int (*syscommon_notifier_cb) (void *notify_data);
+typedef int (*syscommon_notifier_udata_cb) (void *notify_data, void *user_data);
+typedef void (*syscommon_notifier_destroy_cb) (void *user_data);
+
+/**
+ * Subscribe notify without user_data callback.
+ * Higher number of priority will be notified first.
+ */
+int syscommon_notifier_subscribe_notify_priority(int type, syscommon_notifier_cb func, int priority);
+
+/* Subscribe notify without user_data callback, default priority 0 */
+static inline int syscommon_notifier_subscribe_notify(int type, syscommon_notifier_cb func)
+{
+       return syscommon_notifier_subscribe_notify_priority(type, func, 0);
+}
+
+/* Unsubscribe notify callback without user_data */
+int syscommon_notifier_unsubscribe_notify(int type, syscommon_notifier_cb func);
+
+/**
+ * Subscribe notify with user_data callback, destroy function, and priority.
+ * Higher number of priority will be notified first.
+ * Return notify id and can it be used for unsubscribing.
+ */
+int syscommon_notifier_subscribe_notify_udata_priority(int type,
+       syscommon_notifier_udata_cb func_udata, void *user_data,
+       syscommon_notifier_destroy_cb func_destroy_udata, int priority);
+
+/**
+ * Subscribe notify with user_data callback, and default priority 0.
+ * Return notify id and it can be used for unsubscribing.
+ */
+static inline int syscommon_notifier_subscribe_notify_udata(int type,
+       syscommon_notifier_udata_cb func_udata, void *user_data, syscommon_notifier_destroy_cb func_destroy)
+{
+       return syscommon_notifier_subscribe_notify_udata_priority(type, func_udata, user_data, func_destroy, 0);
+}
+
+/**
+ * Unsubscribe notify callback with user_data.
+ * Invoke destroy function with user_data.
+ */
+int syscommon_notifier_unsubscribe_notify_udata(int id);
+
+/* Emit notify. */
+void syscommon_notifier_emit_notify(int type, void *notify_data);
+
+/* Emit notify only once.
+ * Notification after the first one is ignored. */
+void syscommon_notifier_emit_notify_once(int type, void *notify_data);
+
+#endif /* __SYSCOMMON_NOTIFIER_H__ */
diff --git a/src/libcommon/notifier.c b/src/libcommon/notifier.c
new file mode 100644 (file)
index 0000000..073bfd3
--- /dev/null
@@ -0,0 +1,215 @@
+/* MIT License
+ *
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is furnished
+ * to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <glib.h>
+
+#include "libsyscommon/notifier.h"
+#include "libsyscommon/list.h"
+#include "shared/log.h"
+
+struct syscommon_notifier {
+       int id;
+       int priority; /* descending order */
+       bool deleted;
+
+       int type;
+       int (*func)(void *data);
+
+       int (*func_udata)(void *data, void *user_data);
+       void (*destroyer)(void *user_data);
+       void *user_data;
+};
+
+static GList *syscommon_notifier_list;
+static guint idl;
+
+#define FIND_NOTIFIER(a, b, d, e, f) \
+       SYS_G_LIST_FOREACH(a, b, d) \
+               if (e == d->e && f == (d->f) && !d->deleted)
+
+static gint compare_priority(gconstpointer a, gconstpointer b)
+{
+       /* descending order */
+       return ((const struct syscommon_notifier *)b)->priority - ((const struct syscommon_notifier *)a)->priority + 1;
+}
+
+int syscommon_notifier_subscribe_notify_priority(int type, syscommon_notifier_cb func, int priority)
+{
+       GList *n;
+       struct syscommon_notifier *notifier;
+
+       _I("notifier type=%d, func=%p", type, func);
+
+       if (!func) {
+               _E("Invalid func address.");
+               return -EINVAL;
+       }
+
+       FIND_NOTIFIER(syscommon_notifier_list, n, notifier, type, func) {
+               _E("Function has already been registered, [%d, %p]", type, func);
+               return -EINVAL;
+       }
+
+       notifier = calloc(1, sizeof(struct syscommon_notifier));
+       if (!notifier) {
+               _E("Fail to malloc for %d notifier.", type);
+               return -ENOMEM;
+       }
+
+       notifier->type = type;
+       notifier->priority = priority;
+       notifier->func = func;
+
+       syscommon_notifier_list = g_list_insert_sorted(syscommon_notifier_list, notifier, compare_priority);
+
+       return 0;
+}
+
+
+int syscommon_notifier_subscribe_notify_udata_priority(int type,
+       syscommon_notifier_udata_cb func_udata, void *user_data,
+       syscommon_notifier_destroy_cb func_destroy_udata, int priority)
+{
+       struct syscommon_notifier *notifier;
+       static int id = 1;
+
+       _I("notifier type=%d, func=%p", type, func_udata);
+
+       if (!func_udata) {
+               _E("Invalid func address.");
+               return -EINVAL;
+       }
+
+       notifier = calloc(1, sizeof(struct syscommon_notifier));
+       if (!notifier) {
+               _E("Fail to malloc for %d notifier.", type);
+               return -ENOMEM;
+       }
+
+       notifier->id = id;
+       notifier->priority = priority;
+       notifier->type = type;
+       notifier->func_udata = func_udata;
+       notifier->user_data = user_data;
+       notifier->destroyer = func_destroy_udata;
+
+       syscommon_notifier_list = g_list_insert_sorted(syscommon_notifier_list, notifier, compare_priority);
+
+       ++id;
+
+       return notifier->id;
+}
+
+int syscommon_notifier_unsubscribe_notify(int type, syscommon_notifier_cb func)
+{
+       GList *n;
+       struct syscommon_notifier *notifier;
+
+       if (!func) {
+               _E("Invalid func address.");
+               return -EINVAL;
+       }
+
+       FIND_NOTIFIER(syscommon_notifier_list, n, notifier, type, func) {
+               _I("notifier type=%d, func=%p", type, func);
+               notifier->deleted = true;
+       }
+
+       return 0;
+}
+
+int syscommon_notifier_unsubscribe_notify_udata(int id)
+{
+       GList *n;
+       struct syscommon_notifier *notifier;
+
+       SYS_G_LIST_FOREACH(syscommon_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;
+       GList *next;
+       struct syscommon_notifier *notifier;
+
+       SYS_G_LIST_FOREACH_SAFE(syscommon_notifier_list, n, next, notifier) {
+               if (notifier->deleted) {
+                       SYS_G_LIST_REMOVE_LIST(syscommon_notifier_list, n);
+                       free(notifier);
+               }
+       }
+
+       idl = 0;
+       return G_SOURCE_REMOVE;
+}
+
+void syscommon_notifier_emit_notify(int type, void *data)
+{
+       GList *n;
+       struct syscommon_notifier *notifier;
+
+       SYS_G_LIST_FOREACH(syscommon_notifier_list, n, notifier) {
+               if (!notifier->deleted && type == notifier->type) {
+                       if (notifier->func)
+                               notifier->func(data);
+                       else if (notifier->func_udata)
+                               notifier->func_udata(data, notifier->user_data);
+               }
+       }
+
+       if (!idl)
+               idl = g_idle_add(delete_unused_notifier_cb, NULL);
+}
+
+void syscommon_notifier_emit_notify_once(int type, void *data)
+{
+       GList *n;
+       struct syscommon_notifier *notifier;
+
+       SYS_G_LIST_FOREACH(syscommon_notifier_list, n, notifier) {
+               if (!notifier->deleted && type == notifier->type) {
+                       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;
+               }
+       }
+
+       if (!idl)
+               idl = g_idle_add(delete_unused_notifier_cb, NULL);
+}
index 9df8e61..f34ce27 100644 (file)
 #include "libsyscommon/list.h"
 #include "libsyscommon/ini-parser.h"
 #include "libsyscommon/bitmap.h"
+#include "libsyscommon/notifier.h"
 #include "../test-main.h"
 #include "../test-mock.h"
 
 #define MOCK_FILE_PATH    "testfile"
 #define MOCK_FILE_LENGTH  100
 
+#define SYSCOMMON_NOTIFIER_1   (1)
+#define SYSCOMMON_NOTIFIER_2   (2)
+#define SYSCOMMON_NOTIFIER_3   (3)
+#define SYSCOMMON_NOTIFIER_4   (4)
+#define SYSCOMMON_NOTIFIER_5   (5)
+#define SYSCOMMON_NOTIFIER_6   (6)
+#define SYSCOMMON_NOTIFIER_7   (7)
+#define SYSCOMMON_NOTIFIER_8   (8)
+
 static int setup(void **state)
 {
        FILE *fp;
@@ -273,6 +283,224 @@ static void test_all_bit(void **state)
        syscommon_bitmap_deinit_bitmap(bm);
 }
 
+static int notify_callback(void *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_syscommon_notifier_emit_notify_p1(void **state)
+{
+       int retval;
+
+       retval = syscommon_notifier_subscribe_notify(SYSCOMMON_NOTIFIER_1, notify_callback);
+       assert_int_equal(retval, 0);
+       expect_value(notify_callback, data, (void *)(intptr_t) 0x3f3f3f3f);
+
+       syscommon_notifier_emit_notify(SYSCOMMON_NOTIFIER_1, (void *)(intptr_t) 0x3f3f3f3f);
+}
+
+static void test_syscommon_notifier_emit_notify_p2(void **state)
+{
+       int retval;
+       int notify_data;
+       const int udata2 = 0xaeaeaeae;
+       const int udata3 = 0x99997777;
+
+       notify_data = 0x12456321;
+
+       /* 1st notifier */
+       retval = syscommon_notifier_subscribe_notify(SYSCOMMON_NOTIFIER_2, notify_callback);
+       assert_int_equal(retval, 0);
+
+       /* 2nd notifier */
+       retval = syscommon_notifier_subscribe_notify_udata(SYSCOMMON_NOTIFIER_2, 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, (void *)(intptr_t) notify_data);
+       /* expect invocation of 2nd callback and check parameter */
+       expect_value(notify_callback_udata, data, (void *)(intptr_t) notify_data);
+       expect_value(notify_callback_udata, udata,(void *)(intptr_t) udata2);
+
+       syscommon_notifier_emit_notify(SYSCOMMON_NOTIFIER_2, (void *)(intptr_t) notify_data);
+
+       notify_data = 0x888899dd;
+
+       /* 3rd notifier */
+       retval = syscommon_notifier_subscribe_notify_udata(SYSCOMMON_NOTIFIER_2, 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, (void *)(intptr_t) notify_data);
+       /* expect invocation of 2nd callback and check parameter */
+       expect_value(notify_callback_udata, data, (void *)(intptr_t) notify_data);
+       expect_value(notify_callback_udata, udata, (void *)(intptr_t) udata2);
+       /* expect invocation of 3rd callback and check parameter */
+       expect_value(notify_callback_udata, data, (void *)(intptr_t) notify_data);
+       expect_value(notify_callback_udata, udata, (void *)(intptr_t) udata3);
+
+       syscommon_notifier_emit_notify(SYSCOMMON_NOTIFIER_2, (void *)(intptr_t) notify_data);
+}
+
+static void test_syscommon_notifier_emit_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 = syscommon_notifier_subscribe_notify_udata(SYSCOMMON_NOTIFIER_3, notify_callback_udata, (void *)(intptr_t) udata1, NULL);
+       assert_in_range(id1, 1, INT_MAX);
+
+       /* 2nd notifier */
+       id2 = syscommon_notifier_subscribe_notify_udata(SYSCOMMON_NOTIFIER_3, 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, (void *)(intptr_t) notify_data);
+       expect_value(notify_callback_udata, udata, (void *)(intptr_t) udata1);
+       /* expect invocation of 2nd callback and check parameter */
+       expect_value(notify_callback_udata, data, (void *)(intptr_t) notify_data);
+       expect_value(notify_callback_udata, udata, (void *)(intptr_t) udata2);
+
+       syscommon_notifier_emit_notify(SYSCOMMON_NOTIFIER_3, (void *)(intptr_t) notify_data);
+
+       /* second run. at this time syscommon_notifier_emit_notify() after unregistering 1st notifier */
+       notify_data = 0x345;
+
+       syscommon_notifier_unsubscribe_notify_udata(id1);
+
+       /* only expect invocation of 2nd callback and check parameter */
+       expect_value(notify_callback_udata, data, (void *)(intptr_t) notify_data);
+       expect_value(notify_callback_udata, udata, (void *)(intptr_t) udata2);
+
+       syscommon_notifier_emit_notify(SYSCOMMON_NOTIFIER_3, (void *)(intptr_t) notify_data);
+}
+
+static void test_syscommon_notifier_emit_notify_once_p(void **state)
+{
+       int retval;
+
+       retval = syscommon_notifier_subscribe_notify(SYSCOMMON_NOTIFIER_4, notify_callback);
+       assert_int_equal(retval, 0);
+
+       expect_value(notify_callback, data, (void *)(intptr_t) 0xabcdabcd);
+       syscommon_notifier_emit_notify_once(SYSCOMMON_NOTIFIER_4, (void *)(intptr_t) 0xabcdabcd);
+
+       /* Don't add expect_value() for callback at this time.
+        * Therefore if the callback is invoked, check_expected() returns error */
+       syscommon_notifier_emit_notify(SYSCOMMON_NOTIFIER_4, (void *)(intptr_t) 0xabcdabcd);
+
+       retval = syscommon_notifier_subscribe_notify_udata(SYSCOMMON_NOTIFIER_5, notify_callback_udata, (void *)(intptr_t) 0xfefefefe, NULL);
+       assert_in_range(retval, 1, INT_MAX);
+
+       expect_value(notify_callback_udata, data, (void *)(intptr_t) 0x34343434);
+       expect_value(notify_callback_udata, udata, (void *)(intptr_t) 0xfefefefe);
+       syscommon_notifier_emit_notify_once(SYSCOMMON_NOTIFIER_5, (void *)(intptr_t) 0x34343434);
+
+       /* Don't add expect_value() for callback at this time.
+        * Therefore if the callback is invoked, check_expected() returns error */
+       syscommon_notifier_emit_notify(SYSCOMMON_NOTIFIER_5, (void *)(intptr_t) 0x34343434);
+}
+
+static void test_destroy_callback_p1(void **state)
+{
+       int id;
+
+       id = syscommon_notifier_subscribe_notify_udata(SYSCOMMON_NOTIFIER_6, notify_callback_udata,
+               (void *)(intptr_t) 0x4848, destroy_callback_udata);
+       assert_in_range(id, 1, INT_MAX);
+
+       expect_value(destroy_callback_udata, udata, (void *)(intptr_t) 0x4848);
+
+       syscommon_notifier_unsubscribe_notify_udata(id);
+}
+
+static void test_destroy_callback_p2(void **state)
+{
+       int id;
+
+       id = syscommon_notifier_subscribe_notify_udata(SYSCOMMON_NOTIFIER_6, notify_callback_udata,
+               (void *)(intptr_t) 0x1177, destroy_callback_udata);
+       assert_in_range(id, 1, INT_MAX);
+
+       expect_value(notify_callback_udata, data, (void *)(intptr_t) 0x9a9a9a9a);
+       expect_value(notify_callback_udata, udata, (void *)(intptr_t) 0x1177);
+       expect_value(destroy_callback_udata, udata, (void *)(intptr_t) 0x1177);
+
+       syscommon_notifier_emit_notify_once(SYSCOMMON_NOTIFIER_6, (void *)(intptr_t) 0x9a9a9a9a);
+}
+
+static void test_destroy_callback_p3(void **state)
+{
+       int retval;
+
+       retval = syscommon_notifier_subscribe_notify(SYSCOMMON_NOTIFIER_7, notify_callback);
+       assert_int_equal(retval, 0);
+       expect_value(notify_callback, data, (void *)(intptr_t) 0x3f3f3f3f);
+       syscommon_notifier_emit_notify(SYSCOMMON_NOTIFIER_7, (void *)(intptr_t) 0x3f3f3f3f);
+
+       /* notify_callback() should not be invoked */
+       syscommon_notifier_unsubscribe_notify(SYSCOMMON_NOTIFIER_7, notify_callback);
+       syscommon_notifier_emit_notify(SYSCOMMON_NOTIFIER_7, (void *)(intptr_t) 0x34ab34ab);
+
+       /* if a notifier have successfully been deleted,
+        * re-registering the notifier must be successful */
+       retval = syscommon_notifier_subscribe_notify(SYSCOMMON_NOTIFIER_7, notify_callback);
+       assert_int_equal(retval, 0);
+
+       expect_value(notify_callback, data, (void *)(intptr_t) 0x7878444);
+       syscommon_notifier_emit_notify(SYSCOMMON_NOTIFIER_7, (void *)(intptr_t) 0x7878444);
+}
+
+static void test_syscommon_notifier_emit_notify_priority_p1(void **state)
+{
+       int id1, id2, id3;
+
+       id1 = syscommon_notifier_subscribe_notify_udata_priority(SYSCOMMON_NOTIFIER_8, notify_callback_udata,
+               (void *)(intptr_t) 0x11111111, NULL, -300);
+       assert_in_range(id1, 1, INT_MAX);
+
+       id2 = syscommon_notifier_subscribe_notify_udata_priority(SYSCOMMON_NOTIFIER_8, notify_callback_udata,
+               (void *)(intptr_t) 0x22222222, NULL, 500);
+       assert_in_range(id2, 1, INT_MAX);
+
+       id3 = syscommon_notifier_subscribe_notify_udata_priority(SYSCOMMON_NOTIFIER_8, notify_callback_udata,
+               (void *)(intptr_t) 0x33333333, NULL, -300);
+       assert_in_range(id3, 1, INT_MAX);
+
+       /* id2 will be invoked first */
+       expect_value(notify_callback_udata, data, (void *)(intptr_t) 0x1234);
+       expect_value(notify_callback_udata, udata, (void *)(intptr_t) 0x22222222);
+       /* id1, id3 invocation follows it,
+        * and those are invoked in the order in which they were registered */
+       expect_value(notify_callback_udata, data, (void *)(intptr_t) 0x1234);
+       expect_value(notify_callback_udata, udata, (void *)(intptr_t) 0x11111111);
+       expect_value(notify_callback_udata, data, (void *)(intptr_t) 0x1234);
+       expect_value(notify_callback_udata, udata, (void *)(intptr_t) 0x33333333);
+
+       syscommon_notifier_emit_notify(SYSCOMMON_NOTIFIER_8, (void *)(intptr_t)0x1234);
+}
+
 int run_test_suite(void)
 {
        const struct CMUnitTest testsuite[] = {
@@ -286,6 +514,14 @@ int run_test_suite(void)
                cmocka_unit_test(test_init_bitmap_n),
                cmocka_unit_test(test_test_bit),
                cmocka_unit_test(test_all_bit),
+               cmocka_unit_test(test_syscommon_notifier_emit_notify_p1),
+               cmocka_unit_test(test_syscommon_notifier_emit_notify_p2),
+               cmocka_unit_test(test_syscommon_notifier_emit_notify_p3),
+               cmocka_unit_test(test_syscommon_notifier_emit_notify_once_p),
+               cmocka_unit_test(test_destroy_callback_p1),
+               cmocka_unit_test(test_destroy_callback_p2),
+               cmocka_unit_test(test_destroy_callback_p3),
+               cmocka_unit_test(test_syscommon_notifier_emit_notify_priority_p1),
        };
 
        return cmocka_run_group_tests(testsuite, NULL, NULL);