gam-resource-manager: adjust to updated proxied call callback signature.
[profile/ivi/murphy.git] / src / core / event.c
1 /*
2  * Copyright (c) 2012, Intel Corporation
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *   * Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *   * Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  *   * Neither the name of Intel Corporation nor the names of its contributors
14  *     may be used to endorse or promote products derived from this software
15  *     without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <stdarg.h>
31
32 #include <murphy/common/debug.h>
33 #include <murphy/common/mm.h>
34 #include <murphy/common/list.h>
35 #include <murphy/common/msg.h>
36
37 #include <murphy/core/event.h>
38
39
40 /*
41  * an event definition
42  */
43
44 typedef struct {
45     char            *name;                    /* event name */
46     int              id;                      /* associated event id */
47     mrp_list_hook_t  watches;                 /* single-event watches */
48 } event_def_t;
49
50
51 /*
52  * an event watch
53  */
54
55 struct mrp_event_watch_s {
56     mrp_list_hook_t   hook;                   /* hook to event watch list */
57     mrp_list_hook_t   purge;                  /* hook to deleted event list */
58     mrp_event_cb_t    cb;                     /* notification callback */
59     mrp_event_mask_t  events;                 /* events to watch */
60     void             *user_data;              /* opaque callback data */
61 };
62
63
64 static event_def_t     events[MRP_EVENT_MAX]; /* event table */
65 static int             nevent;                /* number of events */
66 static int             nemit;                 /* events being emitted */
67 static mrp_list_hook_t watches;               /* multi-event watches */
68 static mrp_list_hook_t deleted;               /* events deleted during emit */
69
70
71 static int single_event(mrp_event_mask_t *mask);
72
73
74 MRP_INIT static void init_watch_lists(void)
75 {
76     int i;
77
78     for (i = 0; i < MRP_EVENT_MAX; i++)
79         mrp_list_init(&events[i].watches);
80
81     mrp_list_init(&watches);
82     mrp_list_init(&deleted);
83 }
84
85
86 mrp_event_watch_t *mrp_add_event_watch(mrp_event_mask_t *mask,
87                                        mrp_event_cb_t cb, void *user_data)
88 {
89     mrp_event_watch_t *w;
90     event_def_t       *def;
91     int                id;
92
93     if (cb != NULL) {
94         w = mrp_allocz(sizeof(*w));
95
96         if (w != NULL) {
97             mrp_list_init(&w->hook);
98             mrp_list_init(&w->purge);
99             w->cb        = cb;
100             w->user_data = user_data;
101             w->events    = *mask;
102
103             id = single_event(mask);
104
105             if (id != MRP_EVENT_UNKNOWN) {
106                 if (MRP_EVENT_UNKNOWN < id && id <= nevent) {
107                     def = events + id;
108
109                     if (def->name != NULL)
110                         mrp_list_append(&def->watches, &w->hook);
111                     else {
112                         mrp_free(w);
113                         w = NULL;
114                     }
115                 }
116                 else {
117                     mrp_free(w);
118                     w = NULL;
119                 }
120             }
121             else
122                 mrp_list_append(&watches, &w->hook);
123         }
124     }
125     else
126         w = NULL;
127
128     return w;
129
130 #if 0
131     if (MRP_EVENT_UNKNOWN < id && id <= nevent) {
132         def = events + id;
133
134         if (def->name != NULL && cb != NULL) {
135             w = mrp_allocz(sizeof(*w));
136
137             if (w != NULL) {
138                 mrp_list_init(&w->hook);
139                 mrp_list_init(&w->purge);
140                 w->cb        = cb;
141                 w->user_data = user_data;
142
143                 if (single_event(mask)) {
144                     id = single_event(mask);
145
146                 mrp_list_append(&def->watches, &w->hook);
147
148                 return w;
149             }
150         }
151     }
152
153     return NULL;
154 #endif
155 }
156
157
158 static void delete_watch(mrp_event_watch_t *w)
159 {
160     mrp_list_delete(&w->hook);
161     mrp_list_delete(&w->purge);
162     mrp_free(w);
163 }
164
165
166 static void purge_deleted(void)
167 {
168     mrp_event_watch_t *w;
169     mrp_list_hook_t   *p, *n;
170
171     mrp_list_foreach(&deleted, p, n) {
172         w = mrp_list_entry(p, typeof(*w), purge);
173         delete_watch(w);
174     }
175 }
176
177
178 void mrp_del_event_watch(mrp_event_watch_t *w)
179 {
180     if (w != NULL) {
181         if (nemit > 0)
182             mrp_list_append(&deleted, &w->purge);
183         else
184             delete_watch(w);
185     }
186 }
187
188
189 int mrp_get_event_id(const char *name, int create)
190 {
191     event_def_t *def;
192     int          i;
193
194     for (i = MRP_EVENT_UNKNOWN + 1, def = events + i; i <= nevent; i++, def++) {
195         if (!strcmp(name, def->name))
196             return i;
197     }
198
199     if (create) {
200         if (nevent < MRP_EVENT_MAX - 1) {
201             def       = events + 1 + nevent;
202             def->name = mrp_strdup(name);
203
204             if (def->name != NULL) {
205                 mrp_list_init(&def->watches);
206                 def->id = 1 + nevent++;
207
208                 return def->id;
209             }
210         }
211     }
212
213     return MRP_EVENT_UNKNOWN;
214 }
215
216
217 const char *mrp_get_event_name(int id)
218 {
219     event_def_t *def;
220
221     if (MRP_EVENT_UNKNOWN < id && id <= nevent) {
222         def = events + id;
223
224         return def->name;
225     }
226
227     return "<unknown event>";
228 }
229
230
231 int mrp_emit_event_msg(int id, mrp_msg_t *event_data)
232 {
233     event_def_t       *def;
234     mrp_list_hook_t   *p, *n;
235     mrp_event_watch_t *w;
236
237     if (MRP_EVENT_UNKNOWN < id && id <= nevent) {
238         def = events + id;
239
240         if (def->name != NULL) {
241             nemit++;
242             mrp_msg_ref(event_data);
243
244             mrp_debug("emitting event 0x%x (%s)", def->id, def->name);
245 #if 0
246             mrp_msg_dump(event_data, stdout);
247 #endif
248
249             mrp_list_foreach(&def->watches, p, n) {
250                 w = mrp_list_entry(p, typeof(*w), hook);
251                 w->cb(w, def->id, event_data, w->user_data);
252             }
253
254             mrp_list_foreach(&watches, p, n) {
255                 w = mrp_list_entry(p, typeof(*w), hook);
256                 if (mrp_test_event(&w->events, id))
257                     w->cb(w, def->id, event_data, w->user_data);
258             }
259
260             nemit--;
261             mrp_msg_unref(event_data);
262         }
263
264         if (nemit <= 0)
265             purge_deleted();
266
267         return TRUE;
268     }
269
270     return FALSE;
271 }
272
273
274 int mrp_emit_event(int id, ...)
275 {
276     mrp_msg_t *msg;
277     uint16_t   tag;
278     va_list    ap;
279     int        success;
280
281     va_start(ap, id);
282     tag = va_arg(ap, unsigned int);
283     if (tag != MRP_MSG_FIELD_INVALID)
284         msg = mrp_msg_createv(tag, ap);
285     else
286         msg = NULL;
287     va_end(ap);
288
289     success = mrp_emit_event_msg(id, msg);
290     mrp_msg_unref(msg);
291
292     return success;
293 }
294
295
296 mrp_event_mask_t *mrp_set_events(mrp_event_mask_t *mask, ...)
297 {
298     va_list ap;
299     int     id;
300
301     mrp_reset_event_mask(mask);
302
303     va_start(ap, mask);
304     while ((id = va_arg(ap, int)) != MRP_EVENT_UNKNOWN) {
305         mrp_add_event(mask, id);
306     }
307     va_end(ap);
308
309     return mask;
310 }
311
312
313 mrp_event_mask_t *mrp_set_named_events(mrp_event_mask_t *mask, ...)
314 {
315     va_list     ap;
316     const char *name;
317     int         id;
318
319     mrp_reset_event_mask(mask);
320
321     va_start(ap, mask);
322     while ((name = va_arg(ap, const char *)) != NULL) {
323         id = mrp_lookup_event(name);
324
325         if (id != MRP_EVENT_UNKNOWN)
326             mrp_add_event(mask, id);
327     }
328     va_end(ap);
329
330     return mask;
331 }
332
333
334 static int event_count(mrp_event_mask_t *mask)
335 {
336     uint64_t bits = *mask;
337
338     return __builtin_popcountll(bits);
339 }
340
341
342 static int lowest_bit(mrp_event_mask_t *mask)
343 {
344     uint64_t bits = *mask;
345
346     return __builtin_ffs(bits);
347 }
348
349
350 static int single_event(mrp_event_mask_t *mask)
351 {
352     if (event_count(mask) == 1)
353         return lowest_bit(mask);
354     else
355         return MRP_EVENT_UNKNOWN;
356 }