2 * Copyright (C) 2015-2018 "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;
86 /* fullname of the event */
91 * Structure for associating events and listeners
93 struct afb_evt_watch {
96 struct afb_evtid *evtid;
98 /* link to the next watcher for the same evtid */
99 struct afb_evt_watch *next_by_evtid;
102 struct afb_evt_listener *listener;
104 /* link to the next watcher for the same listener */
105 struct afb_evt_watch *next_by_listener;
111 /* the interface for events */
112 static struct afb_event_x2_itf afb_evt_event_x2_itf = {
113 .broadcast = (void*)afb_evt_evtid_broadcast,
114 .push = (void*)afb_evt_evtid_push,
115 .unref = (void*)afb_evt_evtid_unref,
116 .name = (void*)afb_evt_evtid_name,
117 .addref = (void*)afb_evt_evtid_addref
120 /* the interface for events */
121 static struct afb_event_x2_itf afb_evt_hooked_eventid_itf = {
122 .broadcast = (void*)afb_evt_evtid_hooked_broadcast,
123 .push = (void*)afb_evt_evtid_hooked_push,
124 .unref = (void*)afb_evt_evtid_hooked_unref,
125 .name = (void*)afb_evt_evtid_hooked_name,
126 .addref = (void*)afb_evt_evtid_hooked_addref
129 /* head of the list of listeners */
130 static pthread_rwlock_t listeners_rwlock = PTHREAD_RWLOCK_INITIALIZER;
131 static struct afb_evt_listener *listeners = NULL;
133 /* handling id of events */
134 static pthread_rwlock_t events_rwlock = PTHREAD_RWLOCK_INITIALIZER;
135 static struct afb_evtid *evtids = NULL;
136 static int event_id_counter = 0;
137 static int event_id_wrapped = 0;
140 * Broadcasts the 'event' of 'id' with its 'obj'
141 * 'obj' is released (like json_object_put)
142 * Returns the count of listener having receive the event.
144 static int broadcast(const char *event, struct json_object *obj, int id)
147 struct afb_evt_listener *listener;
151 pthread_rwlock_rdlock(&listeners_rwlock);
152 listener = listeners;
154 if (listener->itf->broadcast != NULL) {
155 listener->itf->broadcast(listener->closure, event, id, json_object_get(obj));
158 listener = listener->next;
160 pthread_rwlock_unlock(&listeners_rwlock);
161 json_object_put(obj);
166 * Broadcasts the 'event' of 'id' with its 'obj'
167 * 'obj' is released (like json_object_put)
168 * calls hooks if hookflags isn't 0
169 * Returns the count of listener having receive the event.
171 static int hooked_broadcast(const char *event, struct json_object *obj, int id, int hookflags)
175 json_object_get(obj);
177 if (hookflags & afb_hook_flag_evt_broadcast_before)
178 afb_hook_evt_broadcast_before(event, id, obj);
180 result = broadcast(event, obj, id);
182 if (hookflags & afb_hook_flag_evt_broadcast_after)
183 afb_hook_evt_broadcast_after(event, id, obj, result);
185 json_object_put(obj);
191 * Broadcasts the event 'evtid' with its 'object'
192 * 'object' is released (like json_object_put)
193 * Returns the count of listener that received the event.
195 int afb_evt_evtid_broadcast(struct afb_evtid *evtid, struct json_object *object)
197 return broadcast(evtid->fullname, object, evtid->id);
201 * Broadcasts the event 'evtid' with its 'object'
202 * 'object' is released (like json_object_put)
203 * Returns the count of listener that received the event.
205 int afb_evt_evtid_hooked_broadcast(struct afb_evtid *evtid, struct json_object *object)
207 return hooked_broadcast(evtid->fullname, object, evtid->id, evtid->hookflags);
211 * Broadcasts the 'event' with its 'object'
212 * 'object' is released (like json_object_put)
213 * Returns the count of listener having receive the event.
215 int afb_evt_broadcast(const char *event, struct json_object *object)
217 return hooked_broadcast(event, object, 0, -1);
221 * Pushes the event 'evtid' with 'obj' to its listeners
222 * 'obj' is released (like json_object_put)
223 * Returns the count of listener that received the event.
225 int afb_evt_evtid_push(struct afb_evtid *evtid, struct json_object *obj)
228 struct afb_evt_watch *watch;
229 struct afb_evt_listener *listener;
232 pthread_rwlock_rdlock(&evtid->rwlock);
233 watch = evtid->watchs;
235 listener = watch->listener;
236 assert(listener->itf->push != NULL);
237 if (watch->activity != 0) {
238 listener->itf->push(listener->closure, evtid->fullname, evtid->id, json_object_get(obj));
241 watch = watch->next_by_evtid;
243 pthread_rwlock_unlock(&evtid->rwlock);
244 json_object_put(obj);
249 * Pushes the event 'evtid' with 'obj' to its listeners
250 * 'obj' is released (like json_object_put)
251 * Emits calls to hooks.
252 * Returns the count of listener taht received the event.
254 int afb_evt_evtid_hooked_push(struct afb_evtid *evtid, struct json_object *obj)
259 /* lease the object */
260 json_object_get(obj);
262 /* hook before push */
263 if (evtid->hookflags & afb_hook_flag_evt_push_before)
264 afb_hook_evt_push_before(evtid->fullname, evtid->id, obj);
267 result = afb_evt_evtid_push(evtid, obj);
269 /* hook after push */
270 if (evtid->hookflags & afb_hook_flag_evt_push_after)
271 afb_hook_evt_push_after(evtid->fullname, evtid->id, obj, result);
273 /* release the object */
274 json_object_put(obj);
281 static void remove_watch(struct afb_evt_watch *watch)
283 struct afb_evt_watch **prv;
284 struct afb_evtid *evtid;
285 struct afb_evt_listener *listener;
287 /* notify listener if needed */
288 evtid = watch->evtid;
289 listener = watch->listener;
290 if (watch->activity != 0 && listener->itf->remove != NULL)
291 listener->itf->remove(listener->closure, evtid->fullname, evtid->id);
293 /* unlink the watch for its event */
294 prv = &evtid->watchs;
296 prv = &(*prv)->next_by_evtid;
297 *prv = watch->next_by_evtid;
299 /* unlink the watch for its listener */
300 prv = &listener->watchs;
302 prv = &(*prv)->next_by_listener;
303 *prv = watch->next_by_listener;
310 * Creates an event of name 'fullname' and returns it or NULL on error.
312 struct afb_evtid *afb_evt_evtid_create(const char *fullname)
315 struct afb_evtid *evtid, *oevt;
317 /* allocates the event */
318 len = strlen(fullname);
319 evtid = malloc(len + sizeof * evtid);
323 /* allocates the id */
324 pthread_rwlock_wrlock(&events_rwlock);
326 if (++event_id_counter < 0) {
327 event_id_wrapped = 1;
328 event_id_counter = 1024; /* heuristic: small numbers are not destroyed */
330 if (!event_id_wrapped)
333 while(oevt != NULL && oevt->id != event_id_counter)
335 } while (oevt != NULL);
337 /* initialize the event */
338 memcpy(evtid->fullname, fullname, len + 1);
339 evtid->next = evtids;
341 evtid->watchs = NULL;
342 evtid->id = event_id_counter;
343 pthread_rwlock_init(&evtid->rwlock, NULL);
345 evtid->hookflags = afb_hook_flags_evt(evtid->fullname);
346 evtid->eventid.itf = evtid->hookflags ? &afb_evt_hooked_eventid_itf : &afb_evt_event_x2_itf;
347 if (evtid->hookflags & afb_hook_flag_evt_create)
348 afb_hook_evt_create(evtid->fullname, evtid->id);
349 pthread_rwlock_unlock(&events_rwlock);
351 /* returns the event */
358 * Creates an event of name 'prefix'/'name' and returns it or NULL on error.
360 struct afb_evtid *afb_evt_evtid_create2(const char *prefix, const char *name)
362 size_t prelen, postlen;
365 /* makes the event fullname */
366 prelen = strlen(prefix);
367 postlen = strlen(name);
368 fullname = alloca(prelen + postlen + 2);
369 memcpy(fullname, prefix, prelen);
370 fullname[prelen] = '/';
371 memcpy(fullname + prelen + 1, name, postlen + 1);
373 /* create the event */
374 return afb_evt_evtid_create(fullname);
378 * increment the reference count of the event 'evtid'
380 struct afb_evtid *afb_evt_evtid_addref(struct afb_evtid *evtid)
382 __atomic_add_fetch(&evtid->refcount, 1, __ATOMIC_RELAXED);
387 * increment the reference count of the event 'evtid'
389 struct afb_evtid *afb_evt_evtid_hooked_addref(struct afb_evtid *evtid)
391 if (evtid->hookflags & afb_hook_flag_evt_addref)
392 afb_hook_evt_addref(evtid->fullname, evtid->id);
393 return afb_evt_evtid_addref(evtid);
397 * decrement the reference count of the event 'evtid'
398 * and destroy it when the count reachs zero
400 void afb_evt_evtid_unref(struct afb_evtid *evtid)
403 struct afb_evtid **prv;
404 struct afb_evt_listener *listener;
406 if (!__atomic_sub_fetch(&evtid->refcount, 1, __ATOMIC_RELAXED)) {
407 /* unlinks the event if valid! */
408 pthread_rwlock_wrlock(&events_rwlock);
411 while (*prv && !(found = (*prv == evtid)))
415 pthread_rwlock_unlock(&events_rwlock);
417 /* destroys the event */
419 ERROR("event not found");
421 /* removes all watchers */
422 while(evtid->watchs != NULL) {
423 listener = evtid->watchs->listener;
424 pthread_rwlock_wrlock(&listener->rwlock);
425 pthread_rwlock_wrlock(&evtid->rwlock);
426 remove_watch(evtid->watchs);
427 pthread_rwlock_unlock(&evtid->rwlock);
428 pthread_rwlock_unlock(&listener->rwlock);
432 pthread_rwlock_destroy(&evtid->rwlock);
439 * decrement the reference count of the event 'evtid'
440 * and destroy it when the count reachs zero
442 void afb_evt_evtid_hooked_unref(struct afb_evtid *evtid)
444 if (evtid->hookflags & afb_hook_flag_evt_unref)
445 afb_hook_evt_unref(evtid->fullname, evtid->id);
446 afb_evt_evtid_unref(evtid);
450 * Returns the true name of the 'event'
452 const char *afb_evt_evtid_fullname(struct afb_evtid *evtid)
454 return evtid->fullname;
458 * Returns the name of the 'event'
460 const char *afb_evt_evtid_name(struct afb_evtid *evtid)
462 const char *name = strchr(evtid->fullname, '/');
463 return name ? name + 1 : evtid->fullname;
467 * Returns the name associated to the event 'evtid'.
469 const char *afb_evt_evtid_hooked_name(struct afb_evtid *evtid)
471 const char *result = afb_evt_evtid_name(evtid);
472 if (evtid->hookflags & afb_hook_flag_evt_name)
473 afb_hook_evt_name(evtid->fullname, evtid->id, result);
478 * Returns the id of the 'event'
480 int afb_evt_evtid_id(struct afb_evtid *evtid)
486 * Returns an instance of the listener defined by the 'send' callback
488 * Returns NULL in case of memory depletion.
490 struct afb_evt_listener *afb_evt_listener_create(const struct afb_evt_itf *itf, void *closure)
492 struct afb_evt_listener *listener;
494 /* search if an instance already exists */
495 pthread_rwlock_wrlock(&listeners_rwlock);
496 listener = listeners;
497 while (listener != NULL) {
498 if (listener->itf == itf && listener->closure == closure) {
499 listener = afb_evt_listener_addref(listener);
502 listener = listener->next;
506 listener = calloc(1, sizeof *listener);
507 if (listener != NULL) {
510 listener->closure = closure;
511 listener->watchs = NULL;
512 listener->refcount = 1;
513 pthread_rwlock_init(&listener->rwlock, NULL);
514 listener->next = listeners;
515 listeners = listener;
518 pthread_rwlock_unlock(&listeners_rwlock);
523 * Increases the reference count of 'listener' and returns it
525 struct afb_evt_listener *afb_evt_listener_addref(struct afb_evt_listener *listener)
527 __atomic_add_fetch(&listener->refcount, 1, __ATOMIC_RELAXED);
532 * Decreases the reference count of the 'listener' and destroys it
535 void afb_evt_listener_unref(struct afb_evt_listener *listener)
537 struct afb_evt_listener **prv;
538 struct afb_evtid *evtid;
540 if (listener && !__atomic_sub_fetch(&listener->refcount, 1, __ATOMIC_RELAXED)) {
542 /* unlink the listener */
543 pthread_rwlock_wrlock(&listeners_rwlock);
545 while (*prv != listener)
547 *prv = listener->next;
548 pthread_rwlock_unlock(&listeners_rwlock);
550 /* remove the watchers */
551 pthread_rwlock_wrlock(&listener->rwlock);
552 while (listener->watchs != NULL) {
553 evtid = listener->watchs->evtid;
554 pthread_rwlock_wrlock(&evtid->rwlock);
555 remove_watch(listener->watchs);
556 pthread_rwlock_unlock(&evtid->rwlock);
558 pthread_rwlock_unlock(&listener->rwlock);
560 /* free the listener */
561 pthread_rwlock_destroy(&listener->rwlock);
567 * Makes the 'listener' watching 'evtid'
568 * Returns 0 in case of success or else -1.
570 int afb_evt_watch_add_evtid(struct afb_evt_listener *listener, struct afb_evtid *evtid)
572 struct afb_evt_watch *watch;
574 /* check parameter */
575 if (listener->itf->push == NULL) {
580 /* search the existing watch for the listener */
581 pthread_rwlock_wrlock(&listener->rwlock);
582 watch = listener->watchs;
583 while(watch != NULL) {
584 if (watch->evtid == evtid)
586 watch = watch->next_by_listener;
589 /* not found, allocate a new */
590 watch = malloc(sizeof *watch);
592 pthread_rwlock_unlock(&listener->rwlock);
597 /* initialise and link */
598 watch->evtid = evtid;
600 watch->listener = listener;
601 watch->next_by_listener = listener->watchs;
602 listener->watchs = watch;
603 pthread_rwlock_wrlock(&evtid->rwlock);
604 watch->next_by_evtid = evtid->watchs;
605 evtid->watchs = watch;
606 pthread_rwlock_unlock(&evtid->rwlock);
609 if (watch->activity == 0 && listener->itf->add != NULL)
610 listener->itf->add(listener->closure, evtid->fullname, evtid->id);
612 pthread_rwlock_unlock(&listener->rwlock);
618 * Avoids the 'listener' to watch 'evtid'
619 * Returns 0 in case of success or else -1.
621 int afb_evt_watch_sub_evtid(struct afb_evt_listener *listener, struct afb_evtid *evtid)
623 struct afb_evt_watch *watch;
625 /* search the existing watch */
626 pthread_rwlock_wrlock(&listener->rwlock);
627 watch = listener->watchs;
628 while(watch != NULL) {
629 if (watch->evtid == evtid) {
630 if (watch->activity != 0) {
632 if (watch->activity == 0 && listener->itf->remove != NULL)
633 listener->itf->remove(listener->closure, evtid->fullname, evtid->id);
635 pthread_rwlock_unlock(&listener->rwlock);
638 watch = watch->next_by_listener;
640 pthread_rwlock_unlock(&listener->rwlock);
646 * update the hooks for events
648 void afb_evt_update_hooks()
650 struct afb_evtid *evtid;
652 pthread_rwlock_rdlock(&events_rwlock);
653 for (evtid = evtids ; evtid ; evtid = evtid->next) {
654 evtid->hookflags = afb_hook_flags_evt(evtid->fullname);
655 evtid->eventid.itf = evtid->hookflags ? &afb_evt_hooked_eventid_itf : &afb_evt_event_x2_itf;
657 pthread_rwlock_unlock(&events_rwlock);
660 inline struct afb_evtid *afb_evt_event_x2_to_evtid(struct afb_event_x2 *eventid)
662 return (struct afb_evtid*)eventid;
665 inline struct afb_event_x2 *afb_evt_event_x2_from_evtid(struct afb_evtid *evtid)
667 return &evtid->eventid;
671 * Creates an event of 'fullname' and returns it.
672 * Returns an event with closure==NULL in case of error.
674 struct afb_event_x2 *afb_evt_event_x2_create(const char *fullname)
676 return afb_evt_event_x2_from_evtid(afb_evt_evtid_create(fullname));
680 * Creates an event of name 'prefix'/'name' and returns it.
681 * Returns an event with closure==NULL in case of error.
683 struct afb_event_x2 *afb_evt_event_x2_create2(const char *prefix, const char *name)
685 return afb_evt_event_x2_from_evtid(afb_evt_evtid_create2(prefix, name));
689 * Returns the fullname of the 'eventid'
691 const char *afb_evt_event_x2_fullname(struct afb_event_x2 *eventid)
693 struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
694 return evtid ? evtid->fullname : NULL;
698 * Returns the id of the 'eventid'
700 int afb_evt_event_x2_id(struct afb_event_x2 *eventid)
702 struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
703 return evtid ? evtid->id : 0;
707 * Makes the 'listener' watching 'eventid'
708 * Returns 0 in case of success or else -1.
710 int afb_evt_event_x2_add_watch(struct afb_evt_listener *listener, struct afb_event_x2 *eventid)
712 struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
714 /* check parameter */
720 /* search the existing watch for the listener */
721 return afb_evt_watch_add_evtid(listener, evtid);
725 * Avoids the 'listener' to watch 'eventid'
726 * Returns 0 in case of success or else -1.
728 int afb_evt_event_x2_remove_watch(struct afb_evt_listener *listener, struct afb_event_x2 *eventid)
730 struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
732 /* check parameter */
738 /* search the existing watch */
739 return afb_evt_watch_sub_evtid(listener, evtid);
742 int afb_evt_event_x2_push(struct afb_event_x2 *eventid, struct json_object *object)
744 struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
746 return afb_evt_evtid_hooked_push(evtid, object);
747 json_object_put(object);
751 int afb_evt_event_x2_unhooked_push(struct afb_event_x2 *eventid, struct json_object *object)
753 struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
755 return afb_evt_evtid_push(evtid, object);
756 json_object_put(object);
760 struct afb_event_x1 afb_evt_event_from_evtid(struct afb_evtid *evtid)
763 ? (struct afb_event_x1){ .itf = &afb_evt_hooked_eventid_itf, .closure = &evtid->eventid }
764 : (struct afb_event_x1){ .itf = NULL, .closure = NULL };
767 void afb_evt_event_x2_unref(struct afb_event_x2 *eventid)
769 struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
771 afb_evt_evtid_unref(evtid);
774 struct afb_event_x2 *afb_evt_event_x2_addref(struct afb_event_x2 *eventid)
776 struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
778 afb_evt_evtid_addref(evtid);