3 #include "dwc_notifier.h"
6 typedef struct dwc_observer
{
8 dwc_notifier_callback_t callback
;
11 DWC_CIRCLEQ_ENTRY(dwc_observer
) list_entry
;
14 DWC_CIRCLEQ_HEAD(observer_queue
, dwc_observer
);
16 typedef struct dwc_notifier
{
19 struct observer_queue observers
;
20 DWC_CIRCLEQ_ENTRY(dwc_notifier
) list_entry
;
23 DWC_CIRCLEQ_HEAD(notifier_queue
, dwc_notifier
);
25 typedef struct manager
{
29 // dwc_mutex_t *mutex;
30 struct notifier_queue notifiers
;
33 static manager_t
*manager
= NULL
;
35 static int create_manager(void *mem_ctx
, void *wkq_ctx
)
37 manager
= dwc_alloc(mem_ctx
, sizeof(manager_t
));
39 return -DWC_E_NO_MEMORY
;
42 DWC_CIRCLEQ_INIT(&manager
->notifiers
);
44 manager
->wq
= dwc_workq_alloc(wkq_ctx
, "DWC Notification WorkQ");
46 return -DWC_E_NO_MEMORY
;
52 static void free_manager(void)
54 dwc_workq_free(manager
->wq
);
56 /* All notifiers must have unregistered themselves before this module
57 * can be removed. Hitting this assertion indicates a programmer
59 DWC_ASSERT(DWC_CIRCLEQ_EMPTY(&manager
->notifiers
),
60 "Notification manager being freed before all notifiers have been removed");
61 dwc_free(manager
->mem_ctx
, manager
);
65 static void dump_manager(void)
70 DWC_ASSERT(manager
, "Notification manager not found");
72 DWC_DEBUG("List of all notifiers and observers:\n");
73 DWC_CIRCLEQ_FOREACH(n
, &manager
->notifiers
, list_entry
) {
74 DWC_DEBUG("Notifier %p has observers:\n", n
->object
);
75 DWC_CIRCLEQ_FOREACH(o
, &n
->observers
, list_entry
) {
76 DWC_DEBUG(" %p watching %s\n", o
->observer
, o
->notification
);
81 #define dump_manager(...)
84 static observer_t
*alloc_observer(void *mem_ctx
, void *observer
, char *notification
,
85 dwc_notifier_callback_t callback
, void *data
)
87 observer_t
*new_observer
= dwc_alloc(mem_ctx
, sizeof(observer_t
));
93 DWC_CIRCLEQ_INIT_ENTRY(new_observer
, list_entry
);
94 new_observer
->observer
= observer
;
95 new_observer
->notification
= notification
;
96 new_observer
->callback
= callback
;
97 new_observer
->data
= data
;
101 static void free_observer(void *mem_ctx
, observer_t
*observer
)
103 dwc_free(mem_ctx
, observer
);
106 static notifier_t
*alloc_notifier(void *mem_ctx
, void *object
)
108 notifier_t
*notifier
;
114 notifier
= dwc_alloc(mem_ctx
, sizeof(notifier_t
));
119 DWC_CIRCLEQ_INIT(¬ifier
->observers
);
120 DWC_CIRCLEQ_INIT_ENTRY(notifier
, list_entry
);
122 notifier
->mem_ctx
= mem_ctx
;
123 notifier
->object
= object
;
127 static void free_notifier(notifier_t
*notifier
)
129 observer_t
*observer
;
131 DWC_CIRCLEQ_FOREACH(observer
, ¬ifier
->observers
, list_entry
) {
132 free_observer(notifier
->mem_ctx
, observer
);
135 dwc_free(notifier
->mem_ctx
, notifier
);
138 static notifier_t
*find_notifier(void *object
)
140 notifier_t
*notifier
;
142 DWC_ASSERT(manager
, "Notification manager not found");
148 DWC_CIRCLEQ_FOREACH(notifier
, &manager
->notifiers
, list_entry
) {
149 if (notifier
->object
== object
) {
157 int dwc_alloc_notification_manager(void *mem_ctx
, void *wkq_ctx
)
159 return create_manager(mem_ctx
, wkq_ctx
);
162 void dwc_free_notification_manager(void)
167 dwc_notifier_t
*dwc_register_notifier(void *mem_ctx
, void *object
)
169 notifier_t
*notifier
;
171 DWC_ASSERT(manager
, "Notification manager not found");
173 notifier
= find_notifier(object
);
175 DWC_ERROR("Notifier %p is already registered\n", object
);
179 notifier
= alloc_notifier(mem_ctx
, object
);
184 DWC_CIRCLEQ_INSERT_TAIL(&manager
->notifiers
, notifier
, list_entry
);
186 DWC_INFO("Notifier %p registered", object
);
192 void dwc_unregister_notifier(dwc_notifier_t
*notifier
)
194 DWC_ASSERT(manager
, "Notification manager not found");
196 if (!DWC_CIRCLEQ_EMPTY(¬ifier
->observers
)) {
199 DWC_ERROR("Notifier %p has active observers when removing\n", notifier
->object
);
200 DWC_CIRCLEQ_FOREACH(o
, ¬ifier
->observers
, list_entry
) {
201 DWC_DEBUGC(" %p watching %s\n", o
->observer
, o
->notification
);
204 DWC_ASSERT(DWC_CIRCLEQ_EMPTY(¬ifier
->observers
),
205 "Notifier %p has active observers when removing", notifier
);
208 DWC_CIRCLEQ_REMOVE_INIT(&manager
->notifiers
, notifier
, list_entry
);
209 free_notifier(notifier
);
211 DWC_INFO("Notifier unregistered");
215 /* Add an observer to observe the notifier for a particular state, event, or notification. */
216 int dwc_add_observer(void *observer
, void *object
, char *notification
,
217 dwc_notifier_callback_t callback
, void *data
)
219 notifier_t
*notifier
= find_notifier(object
);
220 observer_t
*new_observer
;
223 DWC_ERROR("Notifier %p is not found when adding observer\n", object
);
224 return -DWC_E_INVALID
;
227 new_observer
= alloc_observer(notifier
->mem_ctx
, observer
, notification
, callback
, data
);
229 return -DWC_E_NO_MEMORY
;
232 DWC_CIRCLEQ_INSERT_TAIL(¬ifier
->observers
, new_observer
, list_entry
);
234 DWC_INFO("Added observer %p to notifier %p observing notification %s, callback=%p, data=%p",
235 observer
, object
, notification
, callback
, data
);
241 int dwc_remove_observer(void *observer
)
245 DWC_ASSERT(manager
, "Notification manager not found");
247 DWC_CIRCLEQ_FOREACH(n
, &manager
->notifiers
, list_entry
) {
251 DWC_CIRCLEQ_FOREACH_SAFE(o
, o2
, &n
->observers
, list_entry
) {
252 if (o
->observer
== observer
) {
253 DWC_CIRCLEQ_REMOVE_INIT(&n
->observers
, o
, list_entry
);
254 DWC_INFO("Removing observer %p from notifier %p watching notification %s:",
255 o
->observer
, n
->object
, o
->notification
);
256 free_observer(n
->mem_ctx
, o
);
265 typedef struct callback_data
{
267 dwc_notifier_callback_t cb
;
272 void *notification_data
;
275 static void cb_task(void *data
)
277 cb_data_t
*cb
= (cb_data_t
*)data
;
279 cb
->cb(cb
->object
, cb
->notification
, cb
->observer
, cb
->notification_data
, cb
->data
);
280 dwc_free(cb
->mem_ctx
, cb
);
283 void dwc_notify(dwc_notifier_t
*notifier
, char *notification
, void *notification_data
)
287 DWC_ASSERT(manager
, "Notification manager not found");
289 DWC_CIRCLEQ_FOREACH(o
, ¬ifier
->observers
, list_entry
) {
290 int len
= DWC_STRLEN(notification
);
292 if (DWC_STRLEN(o
->notification
) != len
) {
296 if (DWC_STRNCMP(o
->notification
, notification
, len
) == 0) {
297 cb_data_t
*cb_data
= dwc_alloc(notifier
->mem_ctx
, sizeof(cb_data_t
));
300 DWC_ERROR("Failed to allocate callback data\n");
304 cb_data
->mem_ctx
= notifier
->mem_ctx
;
305 cb_data
->cb
= o
->callback
;
306 cb_data
->observer
= o
->observer
;
307 cb_data
->data
= o
->data
;
308 cb_data
->object
= notifier
->object
;
309 cb_data
->notification
= notification
;
310 cb_data
->notification_data
= notification_data
;
311 DWC_DEBUGC("Observer found %p for notification %s\n", o
->observer
, notification
);
312 DWC_WORKQ_SCHEDULE(manager
->wq
, cb_task
, cb_data
,
313 "Notify callback from %p for Notification %s, to observer %p",
314 cb_data
->object
, notification
, cb_data
->observer
);
319 #endif /* DWC_NOTIFYLIB */