X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fafb-evt.c;h=4924b8cb2b642bee647cc99b786176405463bf85;hb=bca90021828565bddb8624e8f6370bf4959cbfbf;hp=ad5695f140ef6355b6082d973fdab24541ef7baf;hpb=769cec6b4fed063de7f8f54e5fb4283bdb14ecf9;p=src%2Fapp-framework-binder.git diff --git a/src/afb-evt.c b/src/afb-evt.c index ad5695f1..4924b8cb 100644 --- a/src/afb-evt.c +++ b/src/afb-evt.c @@ -28,46 +28,103 @@ #include "afb-evt.h" - struct afb_evt_watch; +/* + * Structure for event listeners + */ struct afb_evt_listener { + + /* chaining listeners */ struct afb_evt_listener *next; - void (*send)(void *closure, const char *event, struct json_object *object); + + /* interface for callbacks */ + const struct afb_evt_itf *itf; + + /* closure for the callback */ void *closure; + + /* head of the list of events listened */ struct afb_evt_watch *watchs; + + /* count of reference to the listener */ int refcount; }; +/* + * Structure for describing events + */ struct afb_evt_event { + + /* next event */ + struct afb_evt_event *next; + + /* head of the list of listeners watching the event */ struct afb_evt_watch *watchs; + + /* id of the event */ + int id; + + /* name of the event */ char name[1]; }; +/* + * Structure for associating events and listeners + */ struct afb_evt_watch { + + /* the event */ struct afb_evt_event *event; + + /* link to the next listener for the same event */ struct afb_evt_watch *next_by_event; + + /* the listener */ struct afb_evt_listener *listener; + + /* link to the next event for the same listener */ struct afb_evt_watch *next_by_listener; + + /* activity */ + unsigned activity; }; +/* declare functions */ static int evt_broadcast(struct afb_evt_event *evt, struct json_object *obj); static int evt_push(struct afb_evt_event *evt, struct json_object *obj); -static void evt_drop(struct afb_evt_event *evt); +static void evt_destroy(struct afb_evt_event *evt); +/* the interface for events */ static struct afb_event_itf afb_evt_event_itf = { .broadcast = (void*)evt_broadcast, .push = (void*)evt_push, - .drop = (void*)evt_drop + .drop = (void*)evt_destroy }; +/* head of the list of listeners */ static struct afb_evt_listener *listeners = NULL; +/* handling id of events */ +static struct afb_evt_event *events = NULL; +static int event_id_counter = 0; +static int event_id_wrapped = 0; + +/* + * Broadcasts the event 'evt' with its 'object' + * 'object' is released (like json_object_put) + * Returns the count of listener that received the event. + */ static int evt_broadcast(struct afb_evt_event *evt, struct json_object *object) { return afb_evt_broadcast(evt->name, object); } +/* + * Broadcasts the 'event' with its 'object' + * 'object' is released (like json_object_put) + * Returns the count of listener having receive the event. + */ int afb_evt_broadcast(const char *event, struct json_object *object) { int result; @@ -76,13 +133,21 @@ int afb_evt_broadcast(const char *event, struct json_object *object) result = 0; listener = listeners; while(listener) { - listener->send(listener->closure, event, json_object_get(object)); + if (listener->itf->broadcast != NULL) { + listener->itf->broadcast(listener->closure, event, 0, json_object_get(object)); + result++; + } listener = listener->next; } json_object_put(object); return result; } +/* + * Broadcasts the event 'evt' with its 'object' + * 'object' is released (like json_object_put) + * Returns the count of listener taht received the event. + */ static int evt_push(struct afb_evt_event *evt, struct json_object *obj) { int result; @@ -91,63 +156,148 @@ static int evt_push(struct afb_evt_event *evt, struct json_object *obj) result = 0; watch = evt->watchs; - while(listener) { + while(watch) { listener = watch->listener; - listener->send(listener->closure, evt->name, json_object_get(obj)); + assert(listener->itf->push != NULL); + if (watch->activity != 0) + listener->itf->push(listener->closure, evt->name, evt->id, json_object_get(obj)); watch = watch->next_by_event; + result++; } json_object_put(obj); return result; } +/* + * remove the 'watch' + */ static void remove_watch(struct afb_evt_watch *watch) { struct afb_evt_watch **prv; + struct afb_evt_event *evt; + struct afb_evt_listener *listener; + + /* notify listener if needed */ + evt = watch->event; + listener = watch->listener; + if (watch->activity != 0 && listener->itf->remove != NULL) + listener->itf->remove(listener->closure, evt->name, evt->id); - prv = &watch->event->watchs; + /* unlink the watch for its event */ + prv = &evt->watchs; while(*prv != watch) prv = &(*prv)->next_by_event; *prv = watch->next_by_event; - prv = &watch->listener->watchs; + /* unlink the watch for its listener */ + prv = &listener->watchs; while(*prv != watch) prv = &(*prv)->next_by_listener; *prv = watch->next_by_listener; + /* recycle memory */ free(watch); } -static void evt_drop(struct afb_evt_event *evt) +/* + * Destroys the event 'evt' + */ +static void evt_destroy(struct afb_evt_event *evt) { + struct afb_evt_event **prv; if (evt != NULL) { - while(evt->watchs != NULL) - remove_watch(evt->watchs); - free(evt); + /* removes the event if valid! */ + prv = &events; + while (*prv != NULL) { + if (*prv != evt) + prv = &(*prv)->next; + else { + /* valid, unlink */ + *prv = evt->next; + + /* removes all watchers */ + while(evt->watchs != NULL) + remove_watch(evt->watchs); + + /* free */ + free(evt); + break; + } + } } } +/* + * Creates an event of 'name' and returns it. + * Returns an event with closure==NULL in case of error. + */ struct afb_event afb_evt_create_event(const char *name) { size_t len; struct afb_evt_event *evt; + /* allocates the id */ + do { + if (++event_id_counter < 0) { + event_id_wrapped = 1; + event_id_counter = 1024; /* heuristic: small numbers are not destroyed */ + } + if (!event_id_wrapped) + break; + evt = events; + while(evt != NULL && evt->id != event_id_counter) + evt = evt->next; + } while (evt != NULL); + + /* allocates the event */ len = strlen(name); evt = malloc(len + sizeof * evt); - if (evt != NULL) { - evt->watchs = NULL; - memcpy(evt->name, name, len + 1); - } + if (evt == NULL) + goto error; + + /* initialize the event */ + evt->next = events; + evt->watchs = NULL; + evt->id = event_id_counter; + assert(evt->id > 0); + memcpy(evt->name, name, len + 1); + events = evt; + + /* returns the event */ return (struct afb_event){ .itf = &afb_evt_event_itf, .closure = evt }; +error: + return (struct afb_event){ .itf = NULL, .closure = NULL }; +} + +/* + * Returns the name of the 'event' + */ +const char *afb_evt_event_name(struct afb_event event) +{ + return (event.itf != &afb_evt_event_itf) ? NULL : ((struct afb_evt_event *)event.closure)->name; +} + +/* + * Returns the id of the 'event' + */ +int afb_evt_event_id(struct afb_event event) +{ + return (event.itf != &afb_evt_event_itf) ? 0 : ((struct afb_evt_event *)event.closure)->id; } -struct afb_evt_listener *afb_evt_listener_create(void (*send)(void *closure, const char *event, struct json_object *object), void *closure) +/* + * Returns an instance of the listener defined by the 'send' callback + * and the 'closure'. + * Returns NULL in case of memory depletion. + */ +struct afb_evt_listener *afb_evt_listener_create(const struct afb_evt_itf *itf, void *closure) { struct afb_evt_listener *listener; /* search if an instance already exists */ listener = listeners; while (listener != NULL) { - if (listener->send == send && listener->closure == closure) + if (listener->itf == itf && listener->closure == closure) return afb_evt_listener_addref(listener); listener = listener->next; } @@ -157,7 +307,7 @@ struct afb_evt_listener *afb_evt_listener_create(void (*send)(void *closure, con if (listener != NULL) { /* init */ listener->next = listeners; - listener->send = send; + listener->itf = itf; listener->closure = closure; listener->watchs = NULL; listener->refcount = 1; @@ -166,12 +316,19 @@ struct afb_evt_listener *afb_evt_listener_create(void (*send)(void *closure, con return listener; } +/* + * Increases the reference count of 'listener' and returns it + */ struct afb_evt_listener *afb_evt_listener_addref(struct afb_evt_listener *listener) { listener->refcount++; return listener; } +/* + * Decreases the reference count of the 'listener' and destroys it + * when no more used. + */ void afb_evt_listener_unref(struct afb_evt_listener *listener) { if (0 == --listener->refcount) { @@ -192,22 +349,27 @@ void afb_evt_listener_unref(struct afb_evt_listener *listener) } } +/* + * Makes the 'listener' watching 'event' + * Returns 0 in case of success or else -1. + */ int afb_evt_add_watch(struct afb_evt_listener *listener, struct afb_event event) { struct afb_evt_watch *watch; struct afb_evt_event *evt; /* check parameter */ - if (event.itf != &afb_evt_event_itf) { + if (event.itf != &afb_evt_event_itf || listener->itf->push == NULL) { errno = EINVAL; return -1; } - /* search the existing watch */ + /* search the existing watch for the listener */ + evt = event.closure; watch = listener->watchs; while(watch != NULL) { - if (watch->event == event.closure) - return 0; + if (watch->event == evt) + goto found; watch = watch->next_by_listener; } @@ -219,20 +381,30 @@ int afb_evt_add_watch(struct afb_evt_listener *listener, struct afb_event event) } /* initialise and link */ - evt = event.closure; watch->event = evt; watch->next_by_event = evt->watchs; watch->listener = listener; watch->next_by_listener = listener->watchs; + watch->activity = 0; evt->watchs = watch; listener->watchs = watch; - + +found: + if (watch->activity == 0 && listener->itf->add != NULL) + listener->itf->add(listener->closure, evt->name, evt->id); + watch->activity++; + return 0; } +/* + * Avoids the 'listener' to watch 'event' + * Returns 0 in case of success or else -1. + */ int afb_evt_remove_watch(struct afb_evt_listener *listener, struct afb_event event) { struct afb_evt_watch *watch; + struct afb_evt_event *evt; /* check parameter */ if (event.itf != &afb_evt_event_itf) { @@ -241,16 +413,21 @@ int afb_evt_remove_watch(struct afb_evt_listener *listener, struct afb_event eve } /* search the existing watch */ + evt = event.closure; watch = listener->watchs; while(watch != NULL) { - if (watch->event == event.closure) { + if (watch->event == evt) { /* found: remove it */ - remove_watch(watch); - break; + if (watch->activity != 0) { + watch->activity--; + if (watch->activity == 0 && listener->itf->remove != NULL) + listener->itf->remove(listener->closure, evt->name, evt->id); + } + return 0; } watch = watch->next_by_listener; } - return 0; + errno = ENOENT; + return -1; } -