2 * Copyright (C) 2015-2019 "IoT.bzh"
3 * Author José Bollo <jose.bollo@iot.bzh>
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
26 #include <json-c/json.h>
27 #include <afb/afb-event-x2-itf.h>
28 #include <afb/afb-event-x1.h>
37 * Structure for event listeners
39 struct afb_evt_listener {
41 /* chaining listeners */
42 struct afb_evt_listener *next;
44 /* interface for callbacks */
45 const struct afb_evt_itf *itf;
47 /* closure for the callback */
50 /* head of the list of events listened */
51 struct afb_evt_watch *watchs;
53 /* rwlock of the listener */
54 pthread_rwlock_t rwlock;
56 /* count of reference to the listener */
61 * Structure for describing events
66 struct afb_event_x2 eventid;
69 struct afb_evtid *next;
71 /* head of the list of listeners watching the event */
72 struct afb_evt_watch *watchs;
74 /* rwlock of the event */
75 pthread_rwlock_t rwlock;
88 /* fullname of the event */
93 * Structure for associating events and listeners
95 struct afb_evt_watch {
98 struct afb_evtid *evtid;
100 /* link to the next watcher for the same evtid */
101 struct afb_evt_watch *next_by_evtid;
104 struct afb_evt_listener *listener;
106 /* link to the next watcher for the same listener */
107 struct afb_evt_watch *next_by_listener;
113 /* the interface for events */
114 static struct afb_event_x2_itf afb_evt_event_x2_itf = {
115 .broadcast = (void*)afb_evt_evtid_broadcast,
116 .push = (void*)afb_evt_evtid_push,
117 .unref = (void*)afb_evt_evtid_unref,
118 .name = (void*)afb_evt_evtid_name,
119 .addref = (void*)afb_evt_evtid_addref
123 /* the interface for events */
124 static struct afb_event_x2_itf afb_evt_hooked_event_x2_itf = {
125 .broadcast = (void*)afb_evt_evtid_hooked_broadcast,
126 .push = (void*)afb_evt_evtid_hooked_push,
127 .unref = (void*)afb_evt_evtid_hooked_unref,
128 .name = (void*)afb_evt_evtid_hooked_name,
129 .addref = (void*)afb_evt_evtid_hooked_addref
133 /* head of the list of listeners */
134 static pthread_rwlock_t listeners_rwlock = PTHREAD_RWLOCK_INITIALIZER;
135 static struct afb_evt_listener *listeners = NULL;
137 /* handling id of events */
138 static pthread_rwlock_t events_rwlock = PTHREAD_RWLOCK_INITIALIZER;
139 static struct afb_evtid *evtids = NULL;
140 static int event_id_counter = 0;
141 static int event_id_wrapped = 0;
144 * Broadcasts the 'event' of 'id' with its 'obj'
145 * 'obj' is released (like json_object_put)
146 * Returns the count of listener having receive the event.
148 static int broadcast(const char *event, struct json_object *obj, int id)
151 struct afb_evt_listener *listener;
155 pthread_rwlock_rdlock(&listeners_rwlock);
156 listener = listeners;
158 if (listener->itf->broadcast != NULL) {
159 listener->itf->broadcast(listener->closure, event, id, json_object_get(obj));
162 listener = listener->next;
164 pthread_rwlock_unlock(&listeners_rwlock);
165 json_object_put(obj);
171 * Broadcasts the 'event' of 'id' with its 'obj'
172 * 'obj' is released (like json_object_put)
173 * calls hooks if hookflags isn't 0
174 * Returns the count of listener having receive the event.
176 static int hooked_broadcast(const char *event, struct json_object *obj, int id, int hookflags)
180 json_object_get(obj);
182 if (hookflags & afb_hook_flag_evt_broadcast_before)
183 afb_hook_evt_broadcast_before(event, id, obj);
185 result = broadcast(event, obj, id);
187 if (hookflags & afb_hook_flag_evt_broadcast_after)
188 afb_hook_evt_broadcast_after(event, id, obj, result);
190 json_object_put(obj);
197 * Broadcasts the event 'evtid' with its 'object'
198 * 'object' is released (like json_object_put)
199 * Returns the count of listener that received the event.
201 int afb_evt_evtid_broadcast(struct afb_evtid *evtid, struct json_object *object)
203 return broadcast(evtid->fullname, object, evtid->id);
208 * Broadcasts the event 'evtid' with its 'object'
209 * 'object' is released (like json_object_put)
210 * Returns the count of listener that received the event.
212 int afb_evt_evtid_hooked_broadcast(struct afb_evtid *evtid, struct json_object *object)
214 return hooked_broadcast(evtid->fullname, object, evtid->id, evtid->hookflags);
219 * Broadcasts the 'event' with its 'object'
220 * 'object' is released (like json_object_put)
221 * Returns the count of listener having receive the event.
223 int afb_evt_broadcast(const char *event, struct json_object *object)
226 return hooked_broadcast(event, object, 0, -1);
228 return broadcast(event, object, 0);
233 * Pushes the event 'evtid' with 'obj' to its listeners
234 * 'obj' is released (like json_object_put)
235 * Returns the count of listener that received the event.
237 int afb_evt_evtid_push(struct afb_evtid *evtid, struct json_object *obj)
240 struct afb_evt_watch *watch;
241 struct afb_evt_listener *listener;
244 pthread_rwlock_rdlock(&evtid->rwlock);
245 watch = evtid->watchs;
247 listener = watch->listener;
248 assert(listener->itf->push != NULL);
249 if (watch->activity != 0) {
250 listener->itf->push(listener->closure, evtid->fullname, evtid->id, json_object_get(obj));
253 watch = watch->next_by_evtid;
255 pthread_rwlock_unlock(&evtid->rwlock);
256 json_object_put(obj);
262 * Pushes the event 'evtid' with 'obj' to its listeners
263 * 'obj' is released (like json_object_put)
264 * Emits calls to hooks.
265 * Returns the count of listener taht received the event.
267 int afb_evt_evtid_hooked_push(struct afb_evtid *evtid, struct json_object *obj)
272 /* lease the object */
273 json_object_get(obj);
275 /* hook before push */
276 if (evtid->hookflags & afb_hook_flag_evt_push_before)
277 afb_hook_evt_push_before(evtid->fullname, evtid->id, obj);
280 result = afb_evt_evtid_push(evtid, obj);
282 /* hook after push */
283 if (evtid->hookflags & afb_hook_flag_evt_push_after)
284 afb_hook_evt_push_after(evtid->fullname, evtid->id, obj, result);
286 /* release the object */
287 json_object_put(obj);
295 static void remove_watch(struct afb_evt_watch *watch)
297 struct afb_evt_watch **prv;
298 struct afb_evtid *evtid;
299 struct afb_evt_listener *listener;
301 /* notify listener if needed */
302 evtid = watch->evtid;
303 listener = watch->listener;
304 if (watch->activity != 0 && listener->itf->remove != NULL)
305 listener->itf->remove(listener->closure, evtid->fullname, evtid->id);
307 /* unlink the watch for its event */
308 prv = &evtid->watchs;
310 prv = &(*prv)->next_by_evtid;
311 *prv = watch->next_by_evtid;
313 /* unlink the watch for its listener */
314 prv = &listener->watchs;
316 prv = &(*prv)->next_by_listener;
317 *prv = watch->next_by_listener;
324 * Creates an event of name 'fullname' and returns it or NULL on error.
326 struct afb_evtid *afb_evt_evtid_create(const char *fullname)
329 struct afb_evtid *evtid, *oevt;
331 /* allocates the event */
332 len = strlen(fullname);
333 evtid = malloc(len + 1 + sizeof * evtid);
337 /* allocates the id */
338 pthread_rwlock_wrlock(&events_rwlock);
340 if (++event_id_counter < 0) {
341 event_id_wrapped = 1;
342 event_id_counter = 1024; /* heuristic: small numbers are not destroyed */
344 if (!event_id_wrapped)
347 while(oevt != NULL && oevt->id != event_id_counter)
349 } while (oevt != NULL);
351 /* initialize the event */
352 memcpy(evtid->fullname, fullname, len + 1);
353 evtid->next = evtids;
355 evtid->watchs = NULL;
356 evtid->id = event_id_counter;
357 pthread_rwlock_init(&evtid->rwlock, NULL);
360 evtid->hookflags = afb_hook_flags_evt(evtid->fullname);
361 evtid->eventid.itf = evtid->hookflags ? &afb_evt_hooked_event_x2_itf : &afb_evt_event_x2_itf;
362 if (evtid->hookflags & afb_hook_flag_evt_create)
363 afb_hook_evt_create(evtid->fullname, evtid->id);
365 evtid->eventid.itf = &afb_evt_event_x2_itf;
367 pthread_rwlock_unlock(&events_rwlock);
369 /* returns the event */
376 * Creates an event of name 'prefix'/'name' and returns it or NULL on error.
378 struct afb_evtid *afb_evt_evtid_create2(const char *prefix, const char *name)
380 size_t prelen, postlen;
383 /* makes the event fullname */
384 prelen = strlen(prefix);
385 postlen = strlen(name);
386 fullname = alloca(prelen + postlen + 2);
387 memcpy(fullname, prefix, prelen);
388 fullname[prelen] = '/';
389 memcpy(fullname + prelen + 1, name, postlen + 1);
391 /* create the event */
392 return afb_evt_evtid_create(fullname);
396 * increment the reference count of the event 'evtid'
398 struct afb_evtid *afb_evt_evtid_addref(struct afb_evtid *evtid)
400 __atomic_add_fetch(&evtid->refcount, 1, __ATOMIC_RELAXED);
406 * increment the reference count of the event 'evtid'
408 struct afb_evtid *afb_evt_evtid_hooked_addref(struct afb_evtid *evtid)
410 if (evtid->hookflags & afb_hook_flag_evt_addref)
411 afb_hook_evt_addref(evtid->fullname, evtid->id);
412 return afb_evt_evtid_addref(evtid);
417 * decrement the reference count of the event 'evtid'
418 * and destroy it when the count reachs zero
420 void afb_evt_evtid_unref(struct afb_evtid *evtid)
423 struct afb_evtid **prv;
424 struct afb_evt_listener *listener;
426 if (!__atomic_sub_fetch(&evtid->refcount, 1, __ATOMIC_RELAXED)) {
427 /* unlinks the event if valid! */
428 pthread_rwlock_wrlock(&events_rwlock);
431 while (*prv && !(found = (*prv == evtid)))
435 pthread_rwlock_unlock(&events_rwlock);
437 /* destroys the event */
439 ERROR("event not found");
441 /* removes all watchers */
442 while(evtid->watchs != NULL) {
443 listener = evtid->watchs->listener;
444 pthread_rwlock_wrlock(&listener->rwlock);
445 pthread_rwlock_wrlock(&evtid->rwlock);
446 remove_watch(evtid->watchs);
447 pthread_rwlock_unlock(&evtid->rwlock);
448 pthread_rwlock_unlock(&listener->rwlock);
452 pthread_rwlock_destroy(&evtid->rwlock);
460 * decrement the reference count of the event 'evtid'
461 * and destroy it when the count reachs zero
463 void afb_evt_evtid_hooked_unref(struct afb_evtid *evtid)
465 if (evtid->hookflags & afb_hook_flag_evt_unref)
466 afb_hook_evt_unref(evtid->fullname, evtid->id);
467 afb_evt_evtid_unref(evtid);
472 * Returns the true name of the 'event'
474 const char *afb_evt_evtid_fullname(struct afb_evtid *evtid)
476 return evtid->fullname;
480 * Returns the name of the 'event'
482 const char *afb_evt_evtid_name(struct afb_evtid *evtid)
484 const char *name = strchr(evtid->fullname, '/');
485 return name ? name + 1 : evtid->fullname;
490 * Returns the name associated to the event 'evtid'.
492 const char *afb_evt_evtid_hooked_name(struct afb_evtid *evtid)
494 const char *result = afb_evt_evtid_name(evtid);
495 if (evtid->hookflags & afb_hook_flag_evt_name)
496 afb_hook_evt_name(evtid->fullname, evtid->id, result);
502 * Returns the id of the 'event'
504 int afb_evt_evtid_id(struct afb_evtid *evtid)
510 * Returns an instance of the listener defined by the 'send' callback
512 * Returns NULL in case of memory depletion.
514 struct afb_evt_listener *afb_evt_listener_create(const struct afb_evt_itf *itf, void *closure)
516 struct afb_evt_listener *listener;
518 /* search if an instance already exists */
519 pthread_rwlock_wrlock(&listeners_rwlock);
520 listener = listeners;
521 while (listener != NULL) {
522 if (listener->itf == itf && listener->closure == closure) {
523 listener = afb_evt_listener_addref(listener);
526 listener = listener->next;
530 listener = calloc(1, sizeof *listener);
531 if (listener != NULL) {
534 listener->closure = closure;
535 listener->watchs = NULL;
536 listener->refcount = 1;
537 pthread_rwlock_init(&listener->rwlock, NULL);
538 listener->next = listeners;
539 listeners = listener;
542 pthread_rwlock_unlock(&listeners_rwlock);
547 * Increases the reference count of 'listener' and returns it
549 struct afb_evt_listener *afb_evt_listener_addref(struct afb_evt_listener *listener)
551 __atomic_add_fetch(&listener->refcount, 1, __ATOMIC_RELAXED);
556 * Decreases the reference count of the 'listener' and destroys it
559 void afb_evt_listener_unref(struct afb_evt_listener *listener)
561 struct afb_evt_listener **prv;
562 struct afb_evtid *evtid;
564 if (listener && !__atomic_sub_fetch(&listener->refcount, 1, __ATOMIC_RELAXED)) {
566 /* unlink the listener */
567 pthread_rwlock_wrlock(&listeners_rwlock);
569 while (*prv != listener)
571 *prv = listener->next;
572 pthread_rwlock_unlock(&listeners_rwlock);
574 /* remove the watchers */
575 pthread_rwlock_wrlock(&listener->rwlock);
576 while (listener->watchs != NULL) {
577 evtid = listener->watchs->evtid;
578 pthread_rwlock_wrlock(&evtid->rwlock);
579 remove_watch(listener->watchs);
580 pthread_rwlock_unlock(&evtid->rwlock);
582 pthread_rwlock_unlock(&listener->rwlock);
584 /* free the listener */
585 pthread_rwlock_destroy(&listener->rwlock);
591 * Makes the 'listener' watching 'evtid'
592 * Returns 0 in case of success or else -1.
594 int afb_evt_watch_add_evtid(struct afb_evt_listener *listener, struct afb_evtid *evtid)
596 struct afb_evt_watch *watch;
598 /* check parameter */
599 if (listener->itf->push == NULL) {
604 /* search the existing watch for the listener */
605 pthread_rwlock_wrlock(&listener->rwlock);
606 watch = listener->watchs;
607 while(watch != NULL) {
608 if (watch->evtid == evtid)
610 watch = watch->next_by_listener;
613 /* not found, allocate a new */
614 watch = malloc(sizeof *watch);
616 pthread_rwlock_unlock(&listener->rwlock);
621 /* initialise and link */
622 watch->evtid = evtid;
624 watch->listener = listener;
625 watch->next_by_listener = listener->watchs;
626 listener->watchs = watch;
627 pthread_rwlock_wrlock(&evtid->rwlock);
628 watch->next_by_evtid = evtid->watchs;
629 evtid->watchs = watch;
630 pthread_rwlock_unlock(&evtid->rwlock);
633 if (watch->activity == 0 && listener->itf->add != NULL)
634 listener->itf->add(listener->closure, evtid->fullname, evtid->id);
636 pthread_rwlock_unlock(&listener->rwlock);
642 * Avoids the 'listener' to watch 'evtid'
643 * Returns 0 in case of success or else -1.
645 int afb_evt_watch_sub_evtid(struct afb_evt_listener *listener, struct afb_evtid *evtid)
647 struct afb_evt_watch *watch;
649 /* search the existing watch */
650 pthread_rwlock_wrlock(&listener->rwlock);
651 watch = listener->watchs;
652 while(watch != NULL) {
653 if (watch->evtid == evtid) {
654 if (watch->activity != 0) {
656 if (watch->activity == 0 && listener->itf->remove != NULL)
657 listener->itf->remove(listener->closure, evtid->fullname, evtid->id);
659 pthread_rwlock_unlock(&listener->rwlock);
662 watch = watch->next_by_listener;
664 pthread_rwlock_unlock(&listener->rwlock);
671 * update the hooks for events
673 void afb_evt_update_hooks()
675 struct afb_evtid *evtid;
677 pthread_rwlock_rdlock(&events_rwlock);
678 for (evtid = evtids ; evtid ; evtid = evtid->next) {
679 evtid->hookflags = afb_hook_flags_evt(evtid->fullname);
680 evtid->eventid.itf = evtid->hookflags ? &afb_evt_hooked_event_x2_itf : &afb_evt_event_x2_itf;
682 pthread_rwlock_unlock(&events_rwlock);
686 inline struct afb_evtid *afb_evt_event_x2_to_evtid(struct afb_event_x2 *eventid)
688 return (struct afb_evtid*)eventid;
691 inline struct afb_event_x2 *afb_evt_event_x2_from_evtid(struct afb_evtid *evtid)
693 return &evtid->eventid;
697 * Creates an event of 'fullname' and returns it.
698 * Returns an event with closure==NULL in case of error.
700 struct afb_event_x2 *afb_evt_event_x2_create(const char *fullname)
702 return afb_evt_event_x2_from_evtid(afb_evt_evtid_create(fullname));
706 * Creates an event of name 'prefix'/'name' and returns it.
707 * Returns an event with closure==NULL in case of error.
709 struct afb_event_x2 *afb_evt_event_x2_create2(const char *prefix, const char *name)
711 return afb_evt_event_x2_from_evtid(afb_evt_evtid_create2(prefix, name));
715 * Returns the fullname of the 'eventid'
717 const char *afb_evt_event_x2_fullname(struct afb_event_x2 *eventid)
719 struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
720 return evtid ? evtid->fullname : NULL;
724 * Returns the id of the 'eventid'
726 int afb_evt_event_x2_id(struct afb_event_x2 *eventid)
728 struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
729 return evtid ? evtid->id : 0;
733 * Makes the 'listener' watching 'eventid'
734 * Returns 0 in case of success or else -1.
736 int afb_evt_event_x2_add_watch(struct afb_evt_listener *listener, struct afb_event_x2 *eventid)
738 struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
740 /* check parameter */
746 /* search the existing watch for the listener */
747 return afb_evt_watch_add_evtid(listener, evtid);
751 * Avoids the 'listener' to watch 'eventid'
752 * Returns 0 in case of success or else -1.
754 int afb_evt_event_x2_remove_watch(struct afb_evt_listener *listener, struct afb_event_x2 *eventid)
756 struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
758 /* check parameter */
764 /* search the existing watch */
765 return afb_evt_watch_sub_evtid(listener, evtid);
768 int afb_evt_event_x2_push(struct afb_event_x2 *eventid, struct json_object *object)
771 struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
773 return afb_evt_evtid_hooked_push(evtid, object);
774 json_object_put(object);
778 __attribute__((alias("afb_evt_event_x2_unhooked_push")));
781 int afb_evt_event_x2_unhooked_push(struct afb_event_x2 *eventid, struct json_object *object)
783 struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
785 return afb_evt_evtid_push(evtid, object);
786 json_object_put(object);
790 #if WITH_LEGACY_BINDING_V1 || WITH_LEGACY_BINDING_V2
791 struct afb_event_x1 afb_evt_event_from_evtid(struct afb_evtid *evtid)
795 ? (struct afb_event_x1){ .itf = &afb_evt_hooked_event_x2_itf, .closure = &evtid->eventid }
797 ? (struct afb_event_x1){ .itf = &afb_evt_event_x2_itf, .closure = &evtid->eventid }
799 : (struct afb_event_x1){ .itf = NULL, .closure = NULL };
803 void afb_evt_event_x2_unref(struct afb_event_x2 *eventid)
805 struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
807 afb_evt_evtid_unref(evtid);
810 struct afb_event_x2 *afb_evt_event_x2_addref(struct afb_event_x2 *eventid)
812 struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
814 afb_evt_evtid_addref(evtid);