Add conditionnal support of bindings version 2
[src/app-framework-binder.git] / src / afb-evt.c
1 /*
2  * Copyright (C) 2015-2019 "IoT.bzh"
3  * Author José Bollo <jose.bollo@iot.bzh>
4  *
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
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17
18 #define _GNU_SOURCE
19
20 #include <stdlib.h>
21 #include <string.h>
22 #include <assert.h>
23 #include <errno.h>
24 #include <pthread.h>
25
26 #include <json-c/json.h>
27 #include <afb/afb-event-x2-itf.h>
28 #include <afb/afb-event-x1.h>
29
30 #include "afb-evt.h"
31 #include "afb-hook.h"
32 #include "verbose.h"
33
34 struct afb_evt_watch;
35
36 /*
37  * Structure for event listeners
38  */
39 struct afb_evt_listener {
40
41         /* chaining listeners */
42         struct afb_evt_listener *next;
43
44         /* interface for callbacks */
45         const struct afb_evt_itf *itf;
46
47         /* closure for the callback */
48         void *closure;
49
50         /* head of the list of events listened */
51         struct afb_evt_watch *watchs;
52
53         /* rwlock of the listener */
54         pthread_rwlock_t rwlock;
55
56         /* count of reference to the listener */
57         int refcount;
58 };
59
60 /*
61  * Structure for describing events
62  */
63 struct afb_evtid {
64
65         /* interface */
66         struct afb_event_x2 eventid;
67
68         /* next event */
69         struct afb_evtid *next;
70
71         /* head of the list of listeners watching the event */
72         struct afb_evt_watch *watchs;
73
74         /* rwlock of the event */
75         pthread_rwlock_t rwlock;
76
77 #if WITH_AFB_HOOK
78         /* hooking */
79         int hookflags;
80 #endif
81
82         /* refcount */
83         int refcount;
84
85         /* id of the event */
86         int id;
87
88         /* fullname of the event */
89         char fullname[1];
90 };
91
92 /*
93  * Structure for associating events and listeners
94  */
95 struct afb_evt_watch {
96
97         /* the evtid */
98         struct afb_evtid *evtid;
99
100         /* link to the next watcher for the same evtid */
101         struct afb_evt_watch *next_by_evtid;
102
103         /* the listener */
104         struct afb_evt_listener *listener;
105
106         /* link to the next watcher for the same listener */
107         struct afb_evt_watch *next_by_listener;
108
109         /* activity */
110         unsigned activity;
111 };
112
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
120 };
121
122 #if WITH_AFB_HOOK
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
130 };
131 #endif
132
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;
136
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;
142
143 /*
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.
147  */
148 static int broadcast(const char *event, struct json_object *obj, int id)
149 {
150         int result;
151         struct afb_evt_listener *listener;
152
153         result = 0;
154
155         pthread_rwlock_rdlock(&listeners_rwlock);
156         listener = listeners;
157         while(listener) {
158                 if (listener->itf->broadcast != NULL) {
159                         listener->itf->broadcast(listener->closure, event, id, json_object_get(obj));
160                         result++;
161                 }
162                 listener = listener->next;
163         }
164         pthread_rwlock_unlock(&listeners_rwlock);
165         json_object_put(obj);
166         return result;
167 }
168
169 /*
170  * Broadcasts the event 'evtid' with its 'object'
171  * 'object' is released (like json_object_put)
172  * Returns the count of listener that received the event.
173  */
174 int afb_evt_evtid_broadcast(struct afb_evtid *evtid, struct json_object *object)
175 {
176         return broadcast(evtid->fullname, object, evtid->id);
177 }
178
179 #if WITH_AFB_HOOK
180 /*
181  * Broadcasts the 'event' of 'id' with its 'obj'
182  * 'obj' is released (like json_object_put)
183  * calls hooks if hookflags isn't 0
184  * Returns the count of listener having receive the event.
185  */
186 static int hooked_broadcast(const char *event, struct json_object *obj, int id, int hookflags)
187 {
188         int result;
189
190         json_object_get(obj);
191
192         if (hookflags & afb_hook_flag_evt_broadcast_before)
193                 afb_hook_evt_broadcast_before(event, id, obj);
194
195         result = broadcast(event, obj, id);
196
197         if (hookflags & afb_hook_flag_evt_broadcast_after)
198                 afb_hook_evt_broadcast_after(event, id, obj, result);
199
200         json_object_put(obj);
201
202         return result;
203 }
204
205 /*
206  * Broadcasts the event 'evtid' with its 'object'
207  * 'object' is released (like json_object_put)
208  * Returns the count of listener that received the event.
209  */
210 int afb_evt_evtid_hooked_broadcast(struct afb_evtid *evtid, struct json_object *object)
211 {
212         return hooked_broadcast(evtid->fullname, object, evtid->id, evtid->hookflags);
213 }
214 #endif
215
216 /*
217  * Broadcasts the 'event' with its 'object'
218  * 'object' is released (like json_object_put)
219  * Returns the count of listener having receive the event.
220  */
221 int afb_evt_broadcast(const char *event, struct json_object *object)
222 {
223 #if WITH_AFB_HOOK
224         return hooked_broadcast(event, object, 0, -1);
225 #else
226         return broadcast(event, object, 0);
227 #endif
228 }
229
230 /*
231  * Pushes the event 'evtid' with 'obj' to its listeners
232  * 'obj' is released (like json_object_put)
233  * Returns the count of listener that received the event.
234  */
235 int afb_evt_evtid_push(struct afb_evtid *evtid, struct json_object *obj)
236 {
237         int result;
238         struct afb_evt_watch *watch;
239         struct afb_evt_listener *listener;
240
241         result = 0;
242         pthread_rwlock_rdlock(&evtid->rwlock);
243         watch = evtid->watchs;
244         while(watch) {
245                 listener = watch->listener;
246                 assert(listener->itf->push != NULL);
247                 if (watch->activity != 0) {
248                         listener->itf->push(listener->closure, evtid->fullname, evtid->id, json_object_get(obj));
249                         result++;
250                 }
251                 watch = watch->next_by_evtid;
252         }
253         pthread_rwlock_unlock(&evtid->rwlock);
254         json_object_put(obj);
255         return result;
256 }
257
258 /*
259  * remove the 'watch'
260  */
261 static void remove_watch(struct afb_evt_watch *watch)
262 {
263         struct afb_evt_watch **prv;
264         struct afb_evtid *evtid;
265         struct afb_evt_listener *listener;
266
267         /* notify listener if needed */
268         evtid = watch->evtid;
269         listener = watch->listener;
270         if (watch->activity != 0 && listener->itf->remove != NULL)
271                 listener->itf->remove(listener->closure, evtid->fullname, evtid->id);
272
273         /* unlink the watch for its event */
274         prv = &evtid->watchs;
275         while(*prv != watch)
276                 prv = &(*prv)->next_by_evtid;
277         *prv = watch->next_by_evtid;
278
279         /* unlink the watch for its listener */
280         prv = &listener->watchs;
281         while(*prv != watch)
282                 prv = &(*prv)->next_by_listener;
283         *prv = watch->next_by_listener;
284
285         /* recycle memory */
286         free(watch);
287 }
288
289 /*
290  * Creates an event of name 'fullname' and returns it or NULL on error.
291  */
292 struct afb_evtid *afb_evt_evtid_create(const char *fullname)
293 {
294         size_t len;
295         struct afb_evtid *evtid, *oevt;
296
297         /* allocates the event */
298         len = strlen(fullname);
299         evtid = malloc(len + sizeof * evtid);
300         if (evtid == NULL)
301                 goto error;
302
303         /* allocates the id */
304         pthread_rwlock_wrlock(&events_rwlock);
305         do {
306                 if (++event_id_counter < 0) {
307                         event_id_wrapped = 1;
308                         event_id_counter = 1024; /* heuristic: small numbers are not destroyed */
309                 }
310                 if (!event_id_wrapped)
311                         break;
312                 oevt = evtids;
313                 while(oevt != NULL && oevt->id != event_id_counter)
314                         oevt = oevt->next;
315         } while (oevt != NULL);
316
317         /* initialize the event */
318         memcpy(evtid->fullname, fullname, len + 1);
319         evtid->next = evtids;
320         evtid->refcount = 1;
321         evtid->watchs = NULL;
322         evtid->id = event_id_counter;
323         pthread_rwlock_init(&evtid->rwlock, NULL);
324         evtids = evtid;
325 #if WITH_AFB_HOOK
326         evtid->hookflags = afb_hook_flags_evt(evtid->fullname);
327         evtid->eventid.itf = evtid->hookflags ? &afb_evt_hooked_event_x2_itf : &afb_evt_event_x2_itf;
328         if (evtid->hookflags & afb_hook_flag_evt_create)
329                 afb_hook_evt_create(evtid->fullname, evtid->id);
330 #else
331         evtid->eventid.itf = &afb_evt_event_x2_itf;
332 #endif
333         pthread_rwlock_unlock(&events_rwlock);
334
335         /* returns the event */
336         return evtid;
337 error:
338         return NULL;
339 }
340
341 /*
342  * Creates an event of name 'prefix'/'name' and returns it or NULL on error.
343  */
344 struct afb_evtid *afb_evt_evtid_create2(const char *prefix, const char *name)
345 {
346         size_t prelen, postlen;
347         char *fullname;
348
349         /* makes the event fullname */
350         prelen = strlen(prefix);
351         postlen = strlen(name);
352         fullname = alloca(prelen + postlen + 2);
353         memcpy(fullname, prefix, prelen);
354         fullname[prelen] = '/';
355         memcpy(fullname + prelen + 1, name, postlen + 1);
356
357         /* create the event */
358         return afb_evt_evtid_create(fullname);
359 }
360
361 /*
362  * increment the reference count of the event 'evtid'
363  */
364 struct afb_evtid *afb_evt_evtid_addref(struct afb_evtid *evtid)
365 {
366         __atomic_add_fetch(&evtid->refcount, 1, __ATOMIC_RELAXED);
367         return evtid;
368 }
369
370 /*
371  * decrement the reference count of the event 'evtid'
372  * and destroy it when the count reachs zero
373  */
374 void afb_evt_evtid_unref(struct afb_evtid *evtid)
375 {
376         int found;
377         struct afb_evtid **prv;
378         struct afb_evt_listener *listener;
379
380         if (!__atomic_sub_fetch(&evtid->refcount, 1, __ATOMIC_RELAXED)) {
381                 /* unlinks the event if valid! */
382                 pthread_rwlock_wrlock(&events_rwlock);
383                 found = 0;
384                 prv = &evtids;
385                 while (*prv && !(found = (*prv == evtid)))
386                         prv = &(*prv)->next;
387                 if (found)
388                         *prv = evtid->next;
389                 pthread_rwlock_unlock(&events_rwlock);
390
391                 /* destroys the event */
392                 if (!found)
393                         ERROR("event not found");
394                 else {
395                         /* removes all watchers */
396                         while(evtid->watchs != NULL) {
397                                 listener = evtid->watchs->listener;
398                                 pthread_rwlock_wrlock(&listener->rwlock);
399                                 pthread_rwlock_wrlock(&evtid->rwlock);
400                                 remove_watch(evtid->watchs);
401                                 pthread_rwlock_unlock(&evtid->rwlock);
402                                 pthread_rwlock_unlock(&listener->rwlock);
403                         }
404
405                         /* free */
406                         pthread_rwlock_destroy(&evtid->rwlock);
407                         free(evtid);
408                 }
409         }
410 }
411
412 /*
413  * Returns the true name of the 'event'
414  */
415 const char *afb_evt_evtid_fullname(struct afb_evtid *evtid)
416 {
417         return evtid->fullname;
418 }
419
420 /*
421  * Returns the name of the 'event'
422  */
423 const char *afb_evt_evtid_name(struct afb_evtid *evtid)
424 {
425         const char *name = strchr(evtid->fullname, '/');
426         return name ? name + 1 : evtid->fullname;
427 }
428
429 /*
430  * Returns the id of the 'event'
431  */
432 int afb_evt_evtid_id(struct afb_evtid *evtid)
433 {
434         return evtid->id;
435 }
436
437 /*
438  * Returns an instance of the listener defined by the 'send' callback
439  * and the 'closure'.
440  * Returns NULL in case of memory depletion.
441  */
442 struct afb_evt_listener *afb_evt_listener_create(const struct afb_evt_itf *itf, void *closure)
443 {
444         struct afb_evt_listener *listener;
445
446         /* search if an instance already exists */
447         pthread_rwlock_wrlock(&listeners_rwlock);
448         listener = listeners;
449         while (listener != NULL) {
450                 if (listener->itf == itf && listener->closure == closure) {
451                         listener = afb_evt_listener_addref(listener);
452                         goto found;
453                 }
454                 listener = listener->next;
455         }
456
457         /* allocates */
458         listener = calloc(1, sizeof *listener);
459         if (listener != NULL) {
460                 /* init */
461                 listener->itf = itf;
462                 listener->closure = closure;
463                 listener->watchs = NULL;
464                 listener->refcount = 1;
465                 pthread_rwlock_init(&listener->rwlock, NULL);
466                 listener->next = listeners;
467                 listeners = listener;
468         }
469  found:
470         pthread_rwlock_unlock(&listeners_rwlock);
471         return listener;
472 }
473
474 /*
475  * Increases the reference count of 'listener' and returns it
476  */
477 struct afb_evt_listener *afb_evt_listener_addref(struct afb_evt_listener *listener)
478 {
479         __atomic_add_fetch(&listener->refcount, 1, __ATOMIC_RELAXED);
480         return listener;
481 }
482
483 /*
484  * Decreases the reference count of the 'listener' and destroys it
485  * when no more used.
486  */
487 void afb_evt_listener_unref(struct afb_evt_listener *listener)
488 {
489         struct afb_evt_listener **prv;
490         struct afb_evtid *evtid;
491
492         if (listener && !__atomic_sub_fetch(&listener->refcount, 1, __ATOMIC_RELAXED)) {
493
494                 /* unlink the listener */
495                 pthread_rwlock_wrlock(&listeners_rwlock);
496                 prv = &listeners;
497                 while (*prv != listener)
498                         prv = &(*prv)->next;
499                 *prv = listener->next;
500                 pthread_rwlock_unlock(&listeners_rwlock);
501
502                 /* remove the watchers */
503                 pthread_rwlock_wrlock(&listener->rwlock);
504                 while (listener->watchs != NULL) {
505                         evtid = listener->watchs->evtid;
506                         pthread_rwlock_wrlock(&evtid->rwlock);
507                         remove_watch(listener->watchs);
508                         pthread_rwlock_unlock(&evtid->rwlock);
509                 }
510                 pthread_rwlock_unlock(&listener->rwlock);
511
512                 /* free the listener */
513                 pthread_rwlock_destroy(&listener->rwlock);
514                 free(listener);
515         }
516 }
517
518 /*
519  * Makes the 'listener' watching 'evtid'
520  * Returns 0 in case of success or else -1.
521  */
522 int afb_evt_watch_add_evtid(struct afb_evt_listener *listener, struct afb_evtid *evtid)
523 {
524         struct afb_evt_watch *watch;
525
526         /* check parameter */
527         if (listener->itf->push == NULL) {
528                 errno = EINVAL;
529                 return -1;
530         }
531
532         /* search the existing watch for the listener */
533         pthread_rwlock_wrlock(&listener->rwlock);
534         watch = listener->watchs;
535         while(watch != NULL) {
536                 if (watch->evtid == evtid)
537                         goto found;
538                 watch = watch->next_by_listener;
539         }
540
541         /* not found, allocate a new */
542         watch = malloc(sizeof *watch);
543         if (watch == NULL) {
544                 pthread_rwlock_unlock(&listener->rwlock);
545                 errno = ENOMEM;
546                 return -1;
547         }
548
549         /* initialise and link */
550         watch->evtid = evtid;
551         watch->activity = 0;
552         watch->listener = listener;
553         watch->next_by_listener = listener->watchs;
554         listener->watchs = watch;
555         pthread_rwlock_wrlock(&evtid->rwlock);
556         watch->next_by_evtid = evtid->watchs;
557         evtid->watchs = watch;
558         pthread_rwlock_unlock(&evtid->rwlock);
559
560 found:
561         if (watch->activity == 0 && listener->itf->add != NULL)
562                 listener->itf->add(listener->closure, evtid->fullname, evtid->id);
563         watch->activity++;
564         pthread_rwlock_unlock(&listener->rwlock);
565
566         return 0;
567 }
568
569 /*
570  * Avoids the 'listener' to watch 'evtid'
571  * Returns 0 in case of success or else -1.
572  */
573 int afb_evt_watch_sub_evtid(struct afb_evt_listener *listener, struct afb_evtid *evtid)
574 {
575         struct afb_evt_watch *watch;
576
577         /* search the existing watch */
578         pthread_rwlock_wrlock(&listener->rwlock);
579         watch = listener->watchs;
580         while(watch != NULL) {
581                 if (watch->evtid == evtid) {
582                         if (watch->activity != 0) {
583                                 watch->activity--;
584                                 if (watch->activity == 0 && listener->itf->remove != NULL)
585                                         listener->itf->remove(listener->closure, evtid->fullname, evtid->id);
586                         }
587                         pthread_rwlock_unlock(&listener->rwlock);
588                         return 0;
589                 }
590                 watch = watch->next_by_listener;
591         }
592         pthread_rwlock_unlock(&listener->rwlock);
593         errno = ENOENT;
594         return -1;
595 }
596
597 inline struct afb_evtid *afb_evt_event_x2_to_evtid(struct afb_event_x2 *eventid)
598 {
599         return (struct afb_evtid*)eventid;
600 }
601
602 inline struct afb_event_x2 *afb_evt_event_x2_from_evtid(struct afb_evtid *evtid)
603 {
604         return &evtid->eventid;
605 }
606
607 /*
608  * Creates an event of 'fullname' and returns it.
609  * Returns an event with closure==NULL in case of error.
610  */
611 struct afb_event_x2 *afb_evt_event_x2_create(const char *fullname)
612 {
613         return afb_evt_event_x2_from_evtid(afb_evt_evtid_create(fullname));
614 }
615
616 /*
617  * Creates an event of name 'prefix'/'name' and returns it.
618  * Returns an event with closure==NULL in case of error.
619  */
620 struct afb_event_x2 *afb_evt_event_x2_create2(const char *prefix, const char *name)
621 {
622         return afb_evt_event_x2_from_evtid(afb_evt_evtid_create2(prefix, name));
623 }
624
625 /*
626  * Returns the fullname of the 'eventid'
627  */
628 const char *afb_evt_event_x2_fullname(struct afb_event_x2 *eventid)
629 {
630         struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
631         return evtid ? evtid->fullname : NULL;
632 }
633
634 /*
635  * Returns the id of the 'eventid'
636  */
637 int afb_evt_event_x2_id(struct afb_event_x2 *eventid)
638 {
639         struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
640         return evtid ? evtid->id : 0;
641 }
642
643 /*
644  * Makes the 'listener' watching 'eventid'
645  * Returns 0 in case of success or else -1.
646  */
647 int afb_evt_event_x2_add_watch(struct afb_evt_listener *listener, struct afb_event_x2 *eventid)
648 {
649         struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
650
651         /* check parameter */
652         if (!evtid) {
653                 errno = EINVAL;
654                 return -1;
655         }
656
657         /* search the existing watch for the listener */
658         return afb_evt_watch_add_evtid(listener, evtid);
659 }
660
661 /*
662  * Avoids the 'listener' to watch 'eventid'
663  * Returns 0 in case of success or else -1.
664  */
665 int afb_evt_event_x2_remove_watch(struct afb_evt_listener *listener, struct afb_event_x2 *eventid)
666 {
667         struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
668
669         /* check parameter */
670         if (!evtid) {
671                 errno = EINVAL;
672                 return -1;
673         }
674
675         /* search the existing watch */
676         return afb_evt_watch_sub_evtid(listener, evtid);
677 }
678
679 int afb_evt_event_x2_push(struct afb_event_x2 *eventid, struct json_object *object)
680 #if WITH_AFB_HOOK
681 {
682         struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
683         if (evtid)
684                 return afb_evt_evtid_hooked_push(evtid, object);
685         json_object_put(object);
686         return 0;
687 }
688 #else
689         __attribute__((alias("afb_evt_event_x2_unhooked_push")));
690 #endif
691
692 int afb_evt_event_x2_unhooked_push(struct afb_event_x2 *eventid, struct json_object *object)
693 {
694         struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
695         if (evtid)
696                 return afb_evt_evtid_push(evtid, object);
697         json_object_put(object);
698         return 0;
699 }
700
701 #if WITH_LEGACY_BINDING_V1 || WITH_LEGACY_BINDING_V2
702 struct afb_event_x1 afb_evt_event_from_evtid(struct afb_evtid *evtid)
703 {
704         return evtid
705 #if WITH_AFB_HOOK
706                 ? (struct afb_event_x1){ .itf = &afb_evt_hooked_event_x2_itf, .closure = &evtid->eventid }
707 #else
708                 ? (struct afb_event_x1){ .itf = &afb_evt_event_x2_itf, .closure = &evtid->eventid }
709 #endif
710                 : (struct afb_event_x1){ .itf = NULL, .closure = NULL };
711 }
712 #endif
713
714 void afb_evt_event_x2_unref(struct afb_event_x2 *eventid)
715 {
716         struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
717         if (evtid)
718                 afb_evt_evtid_unref(evtid);
719 }
720
721 struct afb_event_x2 *afb_evt_event_x2_addref(struct afb_event_x2 *eventid)
722 {
723         struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
724         if (evtid)
725                 afb_evt_evtid_addref(evtid);
726         return eventid;
727 }
728
729 #if WITH_AFB_HOOK
730 /*
731  * Pushes the event 'evtid' with 'obj' to its listeners
732  * 'obj' is released (like json_object_put)
733  * Emits calls to hooks.
734  * Returns the count of listener taht received the event.
735  */
736 int afb_evt_evtid_hooked_push(struct afb_evtid *evtid, struct json_object *obj)
737 {
738
739         int result;
740
741         /* lease the object */
742         json_object_get(obj);
743
744         /* hook before push */
745         if (evtid->hookflags & afb_hook_flag_evt_push_before)
746                 afb_hook_evt_push_before(evtid->fullname, evtid->id, obj);
747
748         /* push */
749         result = afb_evt_evtid_push(evtid, obj);
750
751         /* hook after push */
752         if (evtid->hookflags & afb_hook_flag_evt_push_after)
753                 afb_hook_evt_push_after(evtid->fullname, evtid->id, obj, result);
754
755         /* release the object */
756         json_object_put(obj);
757         return result;
758 }
759
760 /*
761  * increment the reference count of the event 'evtid'
762  */
763 struct afb_evtid *afb_evt_evtid_hooked_addref(struct afb_evtid *evtid)
764 {
765         if (evtid->hookflags & afb_hook_flag_evt_addref)
766                 afb_hook_evt_addref(evtid->fullname, evtid->id);
767         return afb_evt_evtid_addref(evtid);
768 }
769
770 /*
771  * decrement the reference count of the event 'evtid'
772  * and destroy it when the count reachs zero
773  */
774 void afb_evt_evtid_hooked_unref(struct afb_evtid *evtid)
775 {
776         if (evtid->hookflags & afb_hook_flag_evt_unref)
777                 afb_hook_evt_unref(evtid->fullname, evtid->id);
778         afb_evt_evtid_unref(evtid);
779 }
780
781 /*
782  * Returns the name associated to the event 'evtid'.
783  */
784 const char *afb_evt_evtid_hooked_name(struct afb_evtid *evtid)
785 {
786         const char *result = afb_evt_evtid_name(evtid);
787         if (evtid->hookflags & afb_hook_flag_evt_name)
788                 afb_hook_evt_name(evtid->fullname, evtid->id, result);
789         return result;
790 }
791
792 /*
793  * update the hooks for events
794  */
795 void afb_evt_update_hooks()
796 {
797         struct afb_evtid *evtid;
798
799         pthread_rwlock_rdlock(&events_rwlock);
800         for (evtid = evtids ; evtid ; evtid = evtid->next) {
801                 evtid->hookflags = afb_hook_flags_evt(evtid->fullname);
802                 evtid->eventid.itf = evtid->hookflags ? &afb_evt_hooked_event_x2_itf : &afb_evt_event_x2_itf;
803         }
804         pthread_rwlock_unlock(&events_rwlock);
805 }
806 #endif
807