2 * Copyright (c) 2014, Intel Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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.
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.
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>
39 struct pa_murphy_mainloop {
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;
52 pa_murphy_mainloop *m;
56 pa_io_event_destroy_cb_t destroy;
64 struct pa_time_event {
65 pa_murphy_mainloop *m;
68 pa_time_event_cb_t cb;
69 pa_time_event_destroy_cb_t destroy;
77 struct pa_defer_event {
78 pa_murphy_mainloop *m;
80 pa_defer_event_cb_t cb;
81 pa_defer_event_destroy_cb_t destroy;
89 pa_murphy_mainloop *pa_murphy_mainloop_new(mrp_mainloop_t *ml)
91 pa_murphy_mainloop *m;
96 m = mrp_allocz(sizeof(*m));
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);
113 static void cleanup_io_events(pa_murphy_mainloop *m)
115 mrp_list_hook_t *p, *n;
118 mrp_list_foreach(&m->io_events, p, n) {
119 io = mrp_list_entry(p, typeof(*io), hook);
121 mrp_list_delete(&io->hook);
122 mrp_del_io_watch(io->w);
125 if (io->destroy != NULL) {
127 io->destroy(&io->m->api, io, io->userdata);
133 mrp_list_foreach(&m->io_dead, p, n) {
134 io = mrp_list_entry(p, typeof(*io), hook);
135 mrp_list_delete(&io->hook);
141 static void cleanup_time_events(pa_murphy_mainloop *m)
143 mrp_list_hook_t *p, *n;
146 mrp_list_foreach(&m->time_events, p, n) {
147 t = mrp_list_entry(p, typeof(*t), hook);
149 mrp_list_delete(&t->hook);
153 if (t->destroy != NULL) {
155 t->destroy(&t->m->api, t, t->userdata);
161 mrp_list_foreach(&m->time_dead, p, n) {
162 t = mrp_list_entry(p, typeof(*t), hook);
163 mrp_list_delete(&t->hook);
169 static void cleanup_defer_events(pa_murphy_mainloop *m)
171 mrp_list_hook_t *p, *n;
174 mrp_list_foreach(&m->defer_events, p, n) {
175 d = mrp_list_entry(p, typeof(*d), hook);
177 mrp_list_delete(&d->hook);
178 mrp_del_deferred(d->d);
181 if (d->destroy != NULL) {
183 d->destroy(&d->m->api, d, d->userdata);
189 mrp_list_foreach(&m->defer_dead, p, n) {
190 d = mrp_list_entry(p, typeof(*d), hook);
191 mrp_list_delete(&d->hook);
197 void pa_murphy_mainloop_free(pa_murphy_mainloop *m)
202 cleanup_io_events(m);
203 cleanup_time_events(m);
204 cleanup_defer_events(m);
208 static void io_event_cb(mrp_io_watch_t *w, int fd, mrp_io_event_t events,
211 pa_io_event *io = (pa_io_event *)userdata;
212 pa_io_event_flags_t flags = 0;
216 mrp_debug("PA I/O event 0x%x for watch %p (fd %d)", events, io, fd);
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;
224 io->cb(&io->m->api, io, fd, flags, io->userdata);
228 mrp_list_delete(&io->hook);
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)
237 pa_murphy_mainloop *m = (pa_murphy_mainloop *)api->userdata;
238 mrp_io_event_t events = 0;
241 mrp_debug("PA create I/O watch for fd %d, events 0x%x", fd, e);
243 io = mrp_allocz(sizeof(*io));
248 mrp_list_init(&io->hook);
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;
258 io->userdata = userdata;
259 io->w = mrp_add_io_watch(m->ml, fd, events, io_event_cb, io);
262 mrp_list_append(&m->io_events, &io->hook);
272 static void io_enable(pa_io_event *io, pa_io_event_flags_t e)
274 pa_murphy_mainloop *m = io->m;
275 mrp_io_event_t events = 0;
277 mrp_debug("PA enable events 0x%x for I/O watch %p (fd %d)", e, io, io->fd);
279 mrp_del_io_watch(io->w);
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;
287 io->w = mrp_add_io_watch(m->ml, io->fd, events, io_event_cb, io);
291 static void io_free(pa_io_event *io)
293 pa_murphy_mainloop *m = io->m;
295 mrp_debug("PA free I/O watch %p (fd %d)", io, io->fd);
297 mrp_list_delete(&io->hook);
298 mrp_del_io_watch(io->w);
303 if (!io->busy && !io->dead) {
305 if (io->destroy != NULL)
306 io->destroy(&io->m->api, io, io->userdata);
310 mrp_list_append(&m->io_dead, &io->hook);
314 static void io_set_destroy(pa_io_event *io, pa_io_event_destroy_cb_t cb)
316 mrp_debug("PA set I/O watch destroy callback for %p (fd %d) to %p",
325 static void time_event_cb(mrp_timer_t *tmr, void *userdata)
327 pa_time_event *t = (pa_time_event *)userdata;
331 mrp_debug("PA time event for timer %p", t);
337 t->cb(&t->m->api, t, &t->tv, t->userdata);
342 mrp_list_delete(&t->hook);
348 static unsigned int timeval_diff(const struct timeval *from,
349 const struct timeval *to)
351 int msecs, musecs, diff;
353 msecs = (to->tv_sec - from->tv_sec) * 1000;
354 musecs = ((int)to->tv_usec - (int)from->tv_usec) / 1000;
356 diff = msecs + musecs;
359 return (unsigned int)diff;
365 static pa_time_event *time_new(pa_mainloop_api *api, const struct timeval *tv,
366 pa_time_event_cb_t cb, void *userdata)
368 pa_murphy_mainloop *m = (pa_murphy_mainloop *)api->userdata;
372 gettimeofday(&now, NULL);
374 mrp_debug("PA create timer for %u msecs", timeval_diff(&now, tv));
376 t = mrp_allocz(sizeof(*t));
381 mrp_list_init(&t->hook);
385 t->userdata = userdata;
386 t->t = mrp_add_timer(m->ml, timeval_diff(&now, tv), time_event_cb, t);
389 mrp_list_append(&m->time_events, &t->hook);
399 static void time_restart(pa_time_event *t, const struct timeval *tv)
401 pa_murphy_mainloop *m = t->m;
404 gettimeofday(&now, NULL);
406 mrp_debug("PA restart timer %p with %u msecs", t, timeval_diff(&now, tv));
411 t->t = mrp_add_timer(m->ml, timeval_diff(&now, tv), time_event_cb, t);
415 static void time_free(pa_time_event *t)
417 pa_murphy_mainloop *m = t->m;
419 mrp_debug("PA free timer %p", t);
421 mrp_list_delete(&t->hook);
427 if (!t->busy && !t->dead) {
429 if (t->destroy != NULL)
430 t->destroy(&t->m->api, t, t->userdata);
434 mrp_list_append(&m->time_dead, &t->hook);
438 static void time_set_destroy(pa_time_event *t, pa_time_event_destroy_cb_t cb)
440 mrp_debug("PA set timer destroy callback for %p to %p", t, cb);
448 static void defer_event_cb(mrp_deferred_t *def, void *userdata)
450 pa_defer_event *d = (pa_defer_event *)userdata;
454 mrp_debug("PA defer event for %p", d);
457 d->cb(&d->m->api, d, d->userdata);
461 mrp_del_deferred(d->d);
462 mrp_list_delete(&d->hook);
468 static pa_defer_event *defer_new(pa_mainloop_api *api, pa_defer_event_cb_t cb,
471 pa_murphy_mainloop *m = (pa_murphy_mainloop *)api->userdata;
474 mrp_debug("PA create defer event");
476 d = mrp_allocz(sizeof(*d));
481 mrp_list_init(&d->hook);
485 d->userdata = userdata;
486 d->d = mrp_add_deferred(m->ml, defer_event_cb, d);
489 mrp_list_append(&m->defer_events, &d->hook);
499 static void defer_enable(pa_defer_event *d, int enable)
501 mrp_debug("PA %s defer event %p", enable ? "enable" : "disable", d);
504 mrp_enable_deferred(d->d);
506 mrp_disable_deferred(d->d);
510 static void defer_free(pa_defer_event *d)
512 pa_murphy_mainloop *m = d->m;
514 mrp_debug("PA free defer event %p", d);
516 mrp_list_delete(&d->hook);
517 mrp_del_deferred(d->d);
522 if (!d->busy && !d->dead) {
524 if (d->destroy != NULL)
525 d->destroy(&d->m->api, d, d->userdata);
529 mrp_list_append(&m->defer_dead, &d->hook);
533 static void defer_set_destroy(pa_defer_event *d, pa_defer_event_destroy_cb_t cb)
535 mrp_debug("PA set defer event destroy callback for %p to %p", d, cb);
541 static void quit(pa_mainloop_api *api, int retval)
543 pa_murphy_mainloop *m = (pa_murphy_mainloop *)api->userdata;
545 mrp_mainloop_quit(m->ml, retval);
550 pa_mainloop_api *pa_murphy_mainloop_get_api(pa_murphy_mainloop *m)
552 pa_mainloop_api api = {
555 .io_enable = io_enable,
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,