evt: improves comments
[src/app-framework-binder.git] / src / afb-evt.c
1 /*
2  * Copyright (C) 2015, 2016 "IoT.bzh"
3  * Author "Fulup Ar Foll"
4  * Author José Bollo <jose.bollo@iot.bzh>
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #define _GNU_SOURCE
20
21 #include <stdlib.h>
22 #include <string.h>
23 #include <assert.h>
24 #include <errno.h>
25
26 #include <json-c/json.h>
27 #include <afb/afb-event-itf.h>
28
29 #include "afb-evt.h"
30
31 struct afb_evt_watch;
32
33 /*
34  * Structure for event listeners
35  */
36 struct afb_evt_listener {
37
38         /* chaining listeners */
39         struct afb_evt_listener *next;
40
41         /* callback on event */
42         void (*send)(void *closure, const char *event, struct json_object *object);
43
44         /* closure for the callback */
45         void *closure;
46
47         /* head of the list of events listened */
48         struct afb_evt_watch *watchs;
49
50         /* count of reference to the listener */
51         int refcount;
52 };
53
54 /*
55  * Structure for describing events
56  */
57 struct afb_evt_event {
58
59         /* head of the list of listeners watching the event */
60         struct afb_evt_watch *watchs;
61
62         /* name of the event */
63         char name[1];
64 };
65
66 /*
67  * Structure for associating events and listeners
68  */
69 struct afb_evt_watch {
70
71         /* the event */
72         struct afb_evt_event *event;
73
74         /* link to the next listener for the same event */
75         struct afb_evt_watch *next_by_event;
76
77         /* the listener */
78         struct afb_evt_listener *listener;
79
80         /* link to the next event for the same listener */
81         struct afb_evt_watch *next_by_listener;
82 };
83
84 /* declare functions */
85 static int evt_broadcast(struct afb_evt_event *evt, struct json_object *obj);
86 static int evt_push(struct afb_evt_event *evt, struct json_object *obj);
87 static void evt_destroy(struct afb_evt_event *evt);
88
89 /* the interface for events */
90 static struct afb_event_itf afb_evt_event_itf = {
91         .broadcast = (void*)evt_broadcast,
92         .push = (void*)evt_push,
93         .drop = (void*)evt_destroy
94 };
95
96 /* head of the list of listeners */
97 static struct afb_evt_listener *listeners = NULL;
98
99 /*
100  * Broadcasts the event 'evt' with its 'object'
101  * 'object' is released (like json_object_put)
102  * Returns the count of listener that received the event.
103  */
104 static int evt_broadcast(struct afb_evt_event *evt, struct json_object *object)
105 {
106         return afb_evt_broadcast(evt->name, object);
107 }
108
109 /*
110  * Broadcasts the 'event' with its 'object'
111  * 'object' is released (like json_object_put)
112  * Returns the count of listener having receive the event.
113  */
114 int afb_evt_broadcast(const char *event, struct json_object *object)
115 {
116         int result;
117         struct afb_evt_listener *listener;
118
119         result = 0;
120         listener = listeners;
121         while(listener) {
122                 listener->send(listener->closure, event, json_object_get(object));
123                 listener = listener->next;
124                 result++;
125         }
126         json_object_put(object);
127         return result;
128 }
129
130 /*
131  * Broadcasts the event 'evt' with its 'object'
132  * 'object' is released (like json_object_put)
133  * Returns the count of listener taht received the event.
134  */
135 static int evt_push(struct afb_evt_event *evt, struct json_object *obj)
136 {
137         int result;
138         struct afb_evt_watch *watch;
139         struct afb_evt_listener *listener;
140
141         result = 0;
142         watch = evt->watchs;
143         while(listener) {
144                 listener = watch->listener;
145                 listener->send(listener->closure, evt->name, json_object_get(obj));
146                 watch = watch->next_by_event;
147                 result++;
148         }
149         json_object_put(obj);
150         return result;
151 }
152
153 /*
154  * remove the 'watch'
155  */
156 static void remove_watch(struct afb_evt_watch *watch)
157 {
158         struct afb_evt_watch **prv;
159
160         /* unlink the watch for its event */
161         prv = &watch->event->watchs;
162         while(*prv != watch)
163                 prv = &(*prv)->next_by_event;
164         *prv = watch->next_by_event;
165
166         /* unlink the watch for its listener */
167         prv = &watch->listener->watchs;
168         while(*prv != watch)
169                 prv = &(*prv)->next_by_listener;
170         *prv = watch->next_by_listener;
171
172         /* recycle memory */
173         free(watch);
174 }
175
176 /*
177  * Destroys the event 'evt'
178  */
179 static void evt_destroy(struct afb_evt_event *evt)
180 {
181         if (evt != NULL) {
182                 /* removes all watchers */
183                 while(evt->watchs != NULL)
184                         remove_watch(evt->watchs);
185                 free(evt);
186         }
187 }
188
189 /*
190  * Creates an event of 'name' and returns it.
191  * Returns an event with closure==NULL in case of error.
192  */
193 struct afb_event afb_evt_create_event(const char *name)
194 {
195         size_t len;
196         struct afb_evt_event *evt;
197
198         len = strlen(name);
199         evt = malloc(len + sizeof * evt);
200         if (evt != NULL) {
201                 evt->watchs = NULL;
202                 memcpy(evt->name, name, len + 1);
203         }
204         return (struct afb_event){ .itf = &afb_evt_event_itf, .closure = evt };
205 }
206
207 /*
208  * Returns an instance of the listener defined by the 'send' callback
209  * and the 'closure'.
210  * Returns NULL in case of memory depletion.
211  */
212 struct afb_evt_listener *afb_evt_listener_create(void (*send)(void *closure, const char *event, struct json_object *object), void *closure)
213 {
214         struct afb_evt_listener *listener;
215
216         /* search if an instance already exists */
217         listener = listeners;
218         while (listener != NULL) {
219                 if (listener->send == send && listener->closure == closure)
220                         return afb_evt_listener_addref(listener);
221                 listener = listener->next;
222         }
223
224         /* allocates */
225         listener = calloc(1, sizeof *listener);
226         if (listener != NULL) {
227                 /* init */
228                 listener->next = listeners;
229                 listener->send = send;
230                 listener->closure = closure;
231                 listener->watchs = NULL;
232                 listener->refcount = 1;
233                 listeners = listener;
234         }
235         return listener;
236 }
237
238 /*
239  * Increases the reference count of 'listener' and returns it
240  */
241 struct afb_evt_listener *afb_evt_listener_addref(struct afb_evt_listener *listener)
242 {
243         listener->refcount++;
244         return listener;
245 }
246
247 /*
248  * Decreases the reference count of the 'listener' and destroys it
249  * when no more used.
250  */
251 void afb_evt_listener_unref(struct afb_evt_listener *listener)
252 {
253         if (0 == --listener->refcount) {
254                 struct afb_evt_listener **prv;
255
256                 /* remove the watchers */
257                 while (listener->watchs != NULL)
258                         remove_watch(listener->watchs);
259
260                 /* unlink the listener */
261                 prv = &listeners;
262                 while (*prv != listener)
263                         prv = &(*prv)->next;
264                 *prv = listener->next;
265
266                 /* free the listener */
267                 free(listener);
268         }
269 }
270
271 /*
272  * Makes the 'listener' watching 'event'
273  * Returns 0 in case of success or else -1.
274  */
275 int afb_evt_add_watch(struct afb_evt_listener *listener, struct afb_event event)
276 {
277         struct afb_evt_watch *watch;
278         struct afb_evt_event *evt;
279
280         /* check parameter */
281         if (event.itf != &afb_evt_event_itf) {
282                 errno = EINVAL;
283                 return -1;
284         }
285
286         /* search the existing watch */
287         watch = listener->watchs;
288         while(watch != NULL) {
289                 if (watch->event == event.closure)
290                         return 0;
291                 watch = watch->next_by_listener;
292         }
293
294         /* not found, allocate a new */
295         watch = malloc(sizeof *watch);
296         if (watch == NULL) {
297                 errno = ENOMEM;
298                 return -1;
299         }
300
301         /* initialise and link */
302         evt = event.closure;
303         watch->event = evt;
304         watch->next_by_event = evt->watchs;
305         watch->listener = listener;
306         watch->next_by_listener = listener->watchs;
307         evt->watchs = watch;
308         listener->watchs = watch;
309         
310         return 0;
311 }
312
313 /*
314  * Avoids the 'listener' to watch 'event'
315  * Returns 0 in case of success or else -1.
316  */
317 int afb_evt_remove_watch(struct afb_evt_listener *listener, struct afb_event event)
318 {
319         struct afb_evt_watch *watch;
320
321         /* check parameter */
322         if (event.itf != &afb_evt_event_itf) {
323                 errno = EINVAL;
324                 return -1;
325         }
326
327         /* search the existing watch */
328         watch = listener->watchs;
329         while(watch != NULL) {
330                 if (watch->event == event.closure) {
331                         /* found: remove it */
332                         remove_watch(watch);
333                         break;
334                 }
335                 watch = watch->next_by_listener;
336         }
337         return 0;
338 }
339
340