gam-resource-manager: adjust to updated proxied call callback signature.
[profile/ivi/murphy.git] / src / common / pulse-subloop.c
1 /*
2  * Copyright (c) 2014, 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 <stdbool.h>
31 #include <sys/time.h>
32
33 #include <murphy/common/debug.h>
34 #include <murphy/common/mm.h>
35 #include <murphy/common/list.h>
36 #include <murphy/common/pulse-subloop.h>
37
38
39 struct pa_murphy_mainloop {
40     mrp_mainloop_t  *ml;
41     pa_mainloop_api  api;
42     mrp_list_hook_t  io_events;
43     mrp_list_hook_t  time_events;
44     mrp_list_hook_t  defer_events;
45     mrp_list_hook_t  io_dead;
46     mrp_list_hook_t  time_dead;
47     mrp_list_hook_t  defer_dead;
48 };
49
50
51 struct pa_io_event {
52     pa_murphy_mainloop       *m;
53     int                       fd;
54     mrp_io_watch_t           *w;
55     pa_io_event_cb_t          cb;
56     pa_io_event_destroy_cb_t  destroy;
57     void                     *userdata;
58     mrp_list_hook_t           hook;
59     int                       busy : 1;
60     int                       dead : 1;
61 };
62
63
64 struct pa_time_event {
65     pa_murphy_mainloop         *m;
66     mrp_timer_t                *t;
67     struct timeval              tv;
68     pa_time_event_cb_t          cb;
69     pa_time_event_destroy_cb_t  destroy;
70     void                       *userdata;
71     mrp_list_hook_t             hook;
72     int                         busy : 1;
73     int                         dead : 1;
74 };
75
76
77 struct pa_defer_event {
78     pa_murphy_mainloop          *m;
79     mrp_deferred_t              *d;
80     pa_defer_event_cb_t          cb;
81     pa_defer_event_destroy_cb_t  destroy;
82     void                        *userdata;
83     mrp_list_hook_t              hook;
84     int                          busy : 1;
85     int                          dead : 1;
86 };
87
88
89 pa_murphy_mainloop *pa_murphy_mainloop_new(mrp_mainloop_t *ml)
90 {
91     pa_murphy_mainloop *m;
92
93     if (ml == NULL)
94         return NULL;
95
96     m = mrp_allocz(sizeof(*m));
97
98     if (m == NULL)
99         return NULL;
100
101     m->ml = ml;
102     mrp_list_init(&m->io_events);
103     mrp_list_init(&m->time_events);
104     mrp_list_init(&m->defer_events);
105     mrp_list_init(&m->io_dead);
106     mrp_list_init(&m->time_dead);
107     mrp_list_init(&m->defer_dead);
108
109     return m;
110 }
111
112
113 static void cleanup_io_events(pa_murphy_mainloop *m)
114 {
115     mrp_list_hook_t *p, *n;
116     pa_io_event     *io;
117
118     mrp_list_foreach(&m->io_events, p, n) {
119         io = mrp_list_entry(p, typeof(*io), hook);
120
121         mrp_list_delete(&io->hook);
122         mrp_del_io_watch(io->w);
123         io->w = NULL;
124
125         if (io->destroy != NULL) {
126             io->dead = true;
127             io->destroy(&io->m->api, io, io->userdata);
128         }
129
130         mrp_free(io);
131     }
132
133     mrp_list_foreach(&m->io_dead, p, n) {
134         io = mrp_list_entry(p, typeof(*io), hook);
135         mrp_list_delete(&io->hook);
136         mrp_free(io);
137     }
138 }
139
140
141 static void cleanup_time_events(pa_murphy_mainloop *m)
142 {
143     mrp_list_hook_t *p, *n;
144     pa_time_event   *t;
145
146     mrp_list_foreach(&m->time_events, p, n) {
147         t = mrp_list_entry(p, typeof(*t), hook);
148
149         mrp_list_delete(&t->hook);
150         mrp_del_timer(t->t);
151         t->t = NULL;
152
153         if (t->destroy != NULL) {
154             t->dead = true;
155             t->destroy(&t->m->api, t, t->userdata);
156         }
157
158         mrp_free(t);
159     }
160
161     mrp_list_foreach(&m->time_dead, p, n) {
162         t = mrp_list_entry(p, typeof(*t), hook);
163         mrp_list_delete(&t->hook);
164         mrp_free(t);
165     }
166 }
167
168
169 static void cleanup_defer_events(pa_murphy_mainloop *m)
170 {
171     mrp_list_hook_t *p, *n;
172     pa_defer_event  *d;
173
174     mrp_list_foreach(&m->defer_events, p, n) {
175         d = mrp_list_entry(p, typeof(*d), hook);
176
177         mrp_list_delete(&d->hook);
178         mrp_del_deferred(d->d);
179         d->d = NULL;
180
181         if (d->destroy != NULL) {
182             d->dead = true;
183             d->destroy(&d->m->api, d, d->userdata);
184         }
185
186         mrp_free(d);
187     }
188
189     mrp_list_foreach(&m->defer_dead, p, n) {
190         d = mrp_list_entry(p, typeof(*d), hook);
191         mrp_list_delete(&d->hook);
192         mrp_free(d);
193     }
194 }
195
196
197 void pa_murphy_mainloop_free(pa_murphy_mainloop *m)
198 {
199     if (m == NULL)
200         return;
201
202     cleanup_io_events(m);
203     cleanup_time_events(m);
204     cleanup_defer_events(m);
205 }
206
207
208 static void io_event_cb(mrp_io_watch_t *w, int fd, mrp_io_event_t events,
209                         void *userdata)
210 {
211     pa_io_event         *io    = (pa_io_event *)userdata;
212     pa_io_event_flags_t  flags = 0;
213
214     MRP_UNUSED(w);
215
216     mrp_debug("PA I/O event 0x%x for watch %p (fd %d)", events, io, fd);
217
218     if (events & MRP_IO_EVENT_IN)  flags |= PA_IO_EVENT_INPUT;
219     if (events & MRP_IO_EVENT_OUT) flags |= PA_IO_EVENT_OUTPUT;
220     if (events & MRP_IO_EVENT_HUP) flags |= PA_IO_EVENT_HANGUP;
221     if (events & MRP_IO_EVENT_ERR) flags |= PA_IO_EVENT_ERROR;
222
223     io->busy = true;
224     io->cb(&io->m->api, io, fd, flags, io->userdata);
225     io->busy = false;
226
227     if (io->dead) {
228         mrp_list_delete(&io->hook);
229         mrp_free(io);
230     }
231 }
232
233
234 static pa_io_event *io_new(pa_mainloop_api *api, int fd, pa_io_event_flags_t e,
235                            pa_io_event_cb_t cb, void *userdata)
236 {
237     pa_murphy_mainloop *m      = (pa_murphy_mainloop *)api->userdata;
238     mrp_io_event_t      events = 0;
239     pa_io_event        *io;
240
241     mrp_debug("PA create I/O watch for fd %d, events 0x%x", fd, e);
242
243     io = mrp_allocz(sizeof(*io));
244
245     if (io == NULL)
246         return NULL;
247
248     mrp_list_init(&io->hook);
249
250     if (e & PA_IO_EVENT_INPUT)  events |= MRP_IO_EVENT_IN;
251     if (e & PA_IO_EVENT_OUTPUT) events |= MRP_IO_EVENT_OUT;
252     if (e & PA_IO_EVENT_HANGUP) events |= MRP_IO_EVENT_HUP; /* RDHUP ? */
253     if (e & PA_IO_EVENT_ERROR)  events |= MRP_IO_EVENT_ERR;
254
255     io->m        = m;
256     io->fd       = fd;
257     io->cb       = cb;
258     io->userdata = userdata;
259     io->w        = mrp_add_io_watch(m->ml, fd, events, io_event_cb, io);
260
261     if (io->w != NULL)
262         mrp_list_append(&m->io_events, &io->hook);
263     else {
264         mrp_free(io);
265         io = NULL;
266     }
267
268     return io;
269 }
270
271
272 static void io_enable(pa_io_event *io, pa_io_event_flags_t e)
273 {
274     pa_murphy_mainloop *m      = io->m;
275     mrp_io_event_t      events = 0;
276
277     mrp_debug("PA enable events 0x%x for I/O watch %p (fd %d)", e, io, io->fd);
278
279     mrp_del_io_watch(io->w);
280     io->w = NULL;
281
282     if (e & PA_IO_EVENT_INPUT)  events |= MRP_IO_EVENT_IN;
283     if (e & PA_IO_EVENT_OUTPUT) events |= MRP_IO_EVENT_OUT;
284     if (e & PA_IO_EVENT_HANGUP) events |= MRP_IO_EVENT_HUP; /* RDHUP ? */
285     if (e & PA_IO_EVENT_ERROR)  events |= MRP_IO_EVENT_ERR;
286
287     io->w = mrp_add_io_watch(m->ml, io->fd, events, io_event_cb, io);
288 }
289
290
291 static void io_free(pa_io_event *io)
292 {
293     pa_murphy_mainloop *m = io->m;
294
295     mrp_debug("PA free I/O watch %p (fd %d)", io, io->fd);
296
297     mrp_list_delete(&io->hook);
298     mrp_del_io_watch(io->w);
299     io->w = NULL;
300
301     io->dead = true;
302
303     if (!io->busy && !io->dead) {
304         io->busy = true;
305         if (io->destroy != NULL)
306             io->destroy(&io->m->api, io, io->userdata);
307         mrp_free(io);
308     }
309     else
310         mrp_list_append(&m->io_dead, &io->hook);
311 }
312
313
314 static void io_set_destroy(pa_io_event *io, pa_io_event_destroy_cb_t cb)
315 {
316     mrp_debug("PA set I/O watch destroy callback for %p (fd %d) to %p",
317               io, io->fd, cb);
318
319     io->destroy = cb;
320 }
321
322
323
324
325 static void time_event_cb(mrp_timer_t *tmr, void *userdata)
326 {
327     pa_time_event *t = (pa_time_event *)userdata;
328
329     MRP_UNUSED(tmr);
330
331     mrp_debug("PA time event for timer %p", t);
332
333     mrp_del_timer(t->t);
334     t->t = NULL;
335
336     t->busy = true;
337     t->cb(&t->m->api, t, &t->tv, t->userdata);
338     t->busy = false;
339
340     if (t->dead) {
341         mrp_del_timer(t->t);
342         mrp_list_delete(&t->hook);
343         mrp_free(t);
344     }
345 }
346
347
348 static unsigned int timeval_diff(const struct timeval *from,
349                                  const struct timeval *to)
350 {
351     int msecs, musecs, diff;
352
353     msecs  = (to->tv_sec - from->tv_sec) * 1000;
354     musecs = ((int)to->tv_usec - (int)from->tv_usec) / 1000;
355
356     diff = msecs + musecs;
357
358     if (diff >= 0)
359         return (unsigned int)diff;
360     else
361         return 0;
362 }
363
364
365 static pa_time_event *time_new(pa_mainloop_api *api, const struct timeval *tv,
366                                pa_time_event_cb_t cb, void *userdata)
367 {
368     pa_murphy_mainloop *m = (pa_murphy_mainloop *)api->userdata;
369     pa_time_event      *t;
370     struct timeval      now;
371
372     gettimeofday(&now, NULL);
373
374     mrp_debug("PA create timer for %u msecs", timeval_diff(&now, tv));
375
376     t = mrp_allocz(sizeof(*t));
377
378     if (t == NULL)
379         return NULL;
380
381     mrp_list_init(&t->hook);
382
383     t->m        = m;
384     t->cb       = cb;
385     t->userdata = userdata;
386     t->t        = mrp_add_timer(m->ml, timeval_diff(&now, tv), time_event_cb, t);
387
388     if (t->t != NULL)
389         mrp_list_append(&m->time_events, &t->hook);
390     else {
391         mrp_free(t);
392         t = NULL;
393     }
394
395     return t;
396 }
397
398
399 static void time_restart(pa_time_event *t, const struct timeval *tv)
400 {
401     pa_murphy_mainloop *m = t->m;
402     struct timeval      now;
403
404     gettimeofday(&now, NULL);
405
406     mrp_debug("PA restart timer %p with %u msecs", t, timeval_diff(&now, tv));
407
408     mrp_del_timer(t->t);
409     t->t = NULL;
410
411     t->t = mrp_add_timer(m->ml, timeval_diff(&now, tv), time_event_cb, t);
412 }
413
414
415 static void time_free(pa_time_event *t)
416 {
417     pa_murphy_mainloop *m = t->m;
418
419     mrp_debug("PA free timer %p",  t);
420
421     mrp_list_delete(&t->hook);
422     mrp_del_timer(t->t);
423     t->t = NULL;
424
425     t->dead = true;
426
427     if (!t->busy && !t->dead) {
428         t->busy = true;
429         if (t->destroy != NULL)
430             t->destroy(&t->m->api, t, t->userdata);
431         mrp_free(t);
432     }
433     else
434         mrp_list_append(&m->time_dead, &t->hook);
435 }
436
437
438 static void time_set_destroy(pa_time_event *t, pa_time_event_destroy_cb_t cb)
439 {
440     mrp_debug("PA set timer destroy callback for %p to %p", t, cb);
441
442     t->destroy = cb;
443 }
444
445
446
447
448 static void defer_event_cb(mrp_deferred_t *def, void *userdata)
449 {
450     pa_defer_event *d = (pa_defer_event *)userdata;
451
452     MRP_UNUSED(def);
453
454     mrp_debug("PA defer event for %p", d);
455
456     d->busy = true;
457     d->cb(&d->m->api, d, d->userdata);
458     d->busy = false;
459
460     if (d->dead) {
461         mrp_del_deferred(d->d);
462         mrp_list_delete(&d->hook);
463         mrp_free(d);
464     }
465 }
466
467
468 static pa_defer_event *defer_new(pa_mainloop_api *api, pa_defer_event_cb_t cb,
469                                  void *userdata)
470 {
471     pa_murphy_mainloop *m = (pa_murphy_mainloop *)api->userdata;
472     pa_defer_event     *d;
473
474     mrp_debug("PA create defer event");
475
476     d = mrp_allocz(sizeof(*d));
477
478     if (d == NULL)
479         return NULL;
480
481     mrp_list_init(&d->hook);
482
483     d->m        = m;
484     d->cb       = cb;
485     d->userdata = userdata;
486     d->d        = mrp_add_deferred(m->ml, defer_event_cb, d);
487
488     if (d->d != NULL)
489         mrp_list_append(&m->defer_events, &d->hook);
490     else {
491         mrp_free(d);
492         d = NULL;
493     }
494
495     return d;
496 }
497
498
499 static void defer_enable(pa_defer_event *d, int enable)
500 {
501     mrp_debug("PA %s defer event %p", enable ? "enable" : "disable", d);
502
503     if (enable)
504         mrp_enable_deferred(d->d);
505     else
506         mrp_disable_deferred(d->d);
507 }
508
509
510 static void defer_free(pa_defer_event *d)
511 {
512     pa_murphy_mainloop *m = d->m;
513
514     mrp_debug("PA free defer event %p", d);
515
516     mrp_list_delete(&d->hook);
517     mrp_del_deferred(d->d);
518     d->d = NULL;
519
520     d->dead = true;
521
522     if (!d->busy && !d->dead) {
523         d->busy = true;
524         if (d->destroy != NULL)
525             d->destroy(&d->m->api, d, d->userdata);
526         mrp_free(d);
527     }
528     else
529         mrp_list_append(&m->defer_dead, &d->hook);
530 }
531
532
533 static void defer_set_destroy(pa_defer_event *d, pa_defer_event_destroy_cb_t cb)
534 {
535     mrp_debug("PA set defer event destroy callback for %p to %p", d, cb);
536
537     d->destroy = cb;
538 }
539
540
541 static void quit(pa_mainloop_api *api, int retval)
542 {
543     pa_murphy_mainloop *m = (pa_murphy_mainloop *)api->userdata;
544
545     mrp_mainloop_quit(m->ml, retval);
546 }
547
548
549
550 pa_mainloop_api *pa_murphy_mainloop_get_api(pa_murphy_mainloop *m)
551 {
552     pa_mainloop_api api = {
553         .userdata          = m,
554         .io_new            = io_new,
555         .io_enable         = io_enable,
556         .io_free           = io_free,
557         .io_set_destroy    = io_set_destroy,
558         .time_new          = time_new,
559         .time_restart      = time_restart,
560         .time_free         = time_free,
561         .time_set_destroy  = time_set_destroy,
562         .defer_new         = defer_new,
563         .defer_enable      = defer_enable,
564         .defer_free        = defer_free,
565         .defer_set_destroy = defer_set_destroy,
566         .quit              = quit
567     };
568
569     m->api = api;
570
571     return &m->api;
572 }