1/*** 2 This file is part of PulseAudio. 3 4 Copyright 2004-2006 Lennart Poettering 5 6 PulseAudio is free software; you can redistribute it and/or modify 7 it under the terms of the GNU Lesser General Public License as published 8 by the Free Software Foundation; either version 2.1 of the License, 9 or (at your option) any later version. 10 11 PulseAudio is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU Lesser General Public License 17 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 18***/ 19 20#ifdef HAVE_CONFIG_H 21#include <config.h> 22#endif 23 24#include <pulse/xmalloc.h> 25#include <pulse/timeval.h> 26 27#include <pulsecore/core-util.h> 28#include <pulsecore/log.h> 29#include <pulsecore/llist.h> 30 31#include <glib.h> 32#include "glib-mainloop.h" 33 34struct pa_io_event { 35 pa_glib_mainloop *mainloop; 36 int dead; 37 38 GPollFD poll_fd; 39 int poll_fd_added; 40 41 pa_io_event_cb_t callback; 42 void *userdata; 43 pa_io_event_destroy_cb_t destroy_callback; 44 45 PA_LLIST_FIELDS(pa_io_event); 46}; 47 48struct pa_time_event { 49 pa_glib_mainloop *mainloop; 50 int dead; 51 52 int enabled; 53 struct timeval timeval; 54 55 pa_time_event_cb_t callback; 56 void *userdata; 57 pa_time_event_destroy_cb_t destroy_callback; 58 59 PA_LLIST_FIELDS(pa_time_event); 60}; 61 62struct pa_defer_event { 63 pa_glib_mainloop *mainloop; 64 int dead; 65 66 int enabled; 67 68 pa_defer_event_cb_t callback; 69 void *userdata; 70 pa_defer_event_destroy_cb_t destroy_callback; 71 72 PA_LLIST_FIELDS(pa_defer_event); 73}; 74 75struct pa_glib_mainloop { 76 GSource source; 77 78 pa_mainloop_api api; 79 GMainContext *context; 80 81 PA_LLIST_HEAD(pa_io_event, io_events); 82 PA_LLIST_HEAD(pa_time_event, time_events); 83 PA_LLIST_HEAD(pa_defer_event, defer_events); 84 85 int n_enabled_defer_events, n_enabled_time_events; 86 int io_events_please_scan, time_events_please_scan, defer_events_please_scan; 87 88 pa_time_event *cached_next_time_event; 89}; 90 91static void cleanup_io_events(pa_glib_mainloop *g, int force) { 92 pa_io_event *e; 93 94 e = g->io_events; 95 while (e) { 96 pa_io_event *n = e->next; 97 98 if (!force && g->io_events_please_scan <= 0) 99 break; 100 101 if (force || e->dead) { 102 PA_LLIST_REMOVE(pa_io_event, g->io_events, e); 103 104 if (e->dead) { 105 g_assert(g->io_events_please_scan > 0); 106 g->io_events_please_scan--; 107 } 108 109 if (e->poll_fd_added) 110 g_source_remove_poll(&g->source, &e->poll_fd); 111 112 if (e->destroy_callback) 113 e->destroy_callback(&g->api, e, e->userdata); 114 115 pa_xfree(e); 116 } 117 118 e = n; 119 } 120 121 g_assert(g->io_events_please_scan == 0); 122} 123 124static void cleanup_time_events(pa_glib_mainloop *g, int force) { 125 pa_time_event *e; 126 127 e = g->time_events; 128 while (e) { 129 pa_time_event *n = e->next; 130 131 if (!force && g->time_events_please_scan <= 0) 132 break; 133 134 if (force || e->dead) { 135 PA_LLIST_REMOVE(pa_time_event, g->time_events, e); 136 137 if (e->dead) { 138 g_assert(g->time_events_please_scan > 0); 139 g->time_events_please_scan--; 140 } 141 142 if (!e->dead && e->enabled) { 143 g_assert(g->n_enabled_time_events > 0); 144 g->n_enabled_time_events--; 145 } 146 147 if (e->destroy_callback) 148 e->destroy_callback(&g->api, e, e->userdata); 149 150 pa_xfree(e); 151 } 152 153 e = n; 154 } 155 156 g_assert(g->time_events_please_scan == 0); 157} 158 159static void cleanup_defer_events(pa_glib_mainloop *g, int force) { 160 pa_defer_event *e; 161 162 e = g->defer_events; 163 while (e) { 164 pa_defer_event *n = e->next; 165 166 if (!force && g->defer_events_please_scan <= 0) 167 break; 168 169 if (force || e->dead) { 170 PA_LLIST_REMOVE(pa_defer_event, g->defer_events, e); 171 172 if (e->dead) { 173 g_assert(g->defer_events_please_scan > 0); 174 g->defer_events_please_scan--; 175 } 176 177 if (!e->dead && e->enabled) { 178 g_assert(g->n_enabled_defer_events > 0); 179 g->n_enabled_defer_events--; 180 } 181 182 if (e->destroy_callback) 183 e->destroy_callback(&g->api, e, e->userdata); 184 185 pa_xfree(e); 186 } 187 188 e = n; 189 } 190 191 g_assert(g->defer_events_please_scan == 0); 192} 193 194static gushort map_flags_to_glib(pa_io_event_flags_t flags) { 195 return (gushort) 196 ((flags & PA_IO_EVENT_INPUT ? G_IO_IN : 0) | 197 (flags & PA_IO_EVENT_OUTPUT ? G_IO_OUT : 0) | 198 (flags & PA_IO_EVENT_ERROR ? G_IO_ERR : 0) | 199 (flags & PA_IO_EVENT_HANGUP ? G_IO_HUP : 0)); 200} 201 202static pa_io_event_flags_t map_flags_from_glib(gushort flags) { 203 return 204 (flags & G_IO_IN ? PA_IO_EVENT_INPUT : 0) | 205 (flags & G_IO_OUT ? PA_IO_EVENT_OUTPUT : 0) | 206 (flags & G_IO_ERR ? PA_IO_EVENT_ERROR : 0) | 207 (flags & G_IO_HUP ? PA_IO_EVENT_HANGUP : 0); 208} 209 210static pa_io_event* glib_io_new( 211 pa_mainloop_api*m, 212 int fd, 213 pa_io_event_flags_t f, 214 pa_io_event_cb_t cb, 215 void *userdata) { 216 217 pa_io_event *e; 218 pa_glib_mainloop *g; 219 220 g_assert(m); 221 g_assert(m->userdata); 222 g_assert(fd >= 0); 223 g_assert(cb); 224 225 g = m->userdata; 226 227 e = pa_xnew(pa_io_event, 1); 228 e->mainloop = g; 229 e->dead = 0; 230 231 e->poll_fd.fd = fd; 232 e->poll_fd.events = map_flags_to_glib(f); 233 e->poll_fd.revents = 0; 234 235 e->callback = cb; 236 e->userdata = userdata; 237 e->destroy_callback = NULL; 238 239 PA_LLIST_PREPEND(pa_io_event, g->io_events, e); 240 241 g_source_add_poll(&g->source, &e->poll_fd); 242 e->poll_fd_added = 1; 243 244 return e; 245} 246 247static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f) { 248 g_assert(e); 249 g_assert(!e->dead); 250 251 e->poll_fd.events = map_flags_to_glib(f); 252} 253 254static void glib_io_free(pa_io_event*e) { 255 g_assert(e); 256 g_assert(!e->dead); 257 258 e->dead = 1; 259 e->mainloop->io_events_please_scan++; 260 261 if (e->poll_fd_added) { 262 g_source_remove_poll(&e->mainloop->source, &e->poll_fd); 263 e->poll_fd_added = 0; 264 } 265} 266 267static void glib_io_set_destroy(pa_io_event*e, pa_io_event_destroy_cb_t cb) { 268 g_assert(e); 269 g_assert(!e->dead); 270 271 e->destroy_callback = cb; 272} 273 274/* Time sources */ 275 276static pa_time_event* glib_time_new( 277 pa_mainloop_api*m, 278 const struct timeval *tv, 279 pa_time_event_cb_t cb, 280 void *userdata) { 281 282 pa_glib_mainloop *g; 283 pa_time_event *e; 284 285 g_assert(m); 286 g_assert(m->userdata); 287 g_assert(cb); 288 289 g = m->userdata; 290 291 e = pa_xnew(pa_time_event, 1); 292 e->mainloop = g; 293 e->dead = 0; 294 295 if ((e->enabled = !!tv)) { 296 e->timeval = *tv; 297 g->n_enabled_time_events++; 298 299 if (g->cached_next_time_event) { 300 g_assert(g->cached_next_time_event->enabled); 301 302 if (pa_timeval_cmp(tv, &g->cached_next_time_event->timeval) < 0) 303 g->cached_next_time_event = e; 304 } 305 } 306 307 e->callback = cb; 308 e->userdata = userdata; 309 e->destroy_callback = NULL; 310 311 PA_LLIST_PREPEND(pa_time_event, g->time_events, e); 312 313 return e; 314} 315 316static void glib_time_restart(pa_time_event*e, const struct timeval *tv) { 317 g_assert(e); 318 g_assert(!e->dead); 319 320 if (e->enabled && !tv) { 321 g_assert(e->mainloop->n_enabled_time_events > 0); 322 e->mainloop->n_enabled_time_events--; 323 } else if (!e->enabled && tv) 324 e->mainloop->n_enabled_time_events++; 325 326 if ((e->enabled = !!tv)) 327 e->timeval = *tv; 328 329 if (e->mainloop->cached_next_time_event == e) 330 e->mainloop->cached_next_time_event = NULL; 331 332 if (e->mainloop->cached_next_time_event && e->enabled) { 333 g_assert(e->mainloop->cached_next_time_event->enabled); 334 335 if (pa_timeval_cmp(tv, &e->mainloop->cached_next_time_event->timeval) < 0) 336 e->mainloop->cached_next_time_event = e; 337 } 338} 339 340static void glib_time_free(pa_time_event *e) { 341 g_assert(e); 342 g_assert(!e->dead); 343 344 e->dead = 1; 345 e->mainloop->time_events_please_scan++; 346 347 if (e->enabled) 348 e->mainloop->n_enabled_time_events--; 349 350 if (e->mainloop->cached_next_time_event == e) 351 e->mainloop->cached_next_time_event = NULL; 352} 353 354static void glib_time_set_destroy(pa_time_event *e, pa_time_event_destroy_cb_t cb) { 355 g_assert(e); 356 g_assert(!e->dead); 357 358 e->destroy_callback = cb; 359} 360 361/* Deferred sources */ 362 363static pa_defer_event* glib_defer_new( 364 pa_mainloop_api*m, 365 pa_defer_event_cb_t cb, 366 void *userdata) { 367 368 pa_defer_event *e; 369 pa_glib_mainloop *g; 370 371 g_assert(m); 372 g_assert(m->userdata); 373 g_assert(cb); 374 375 g = m->userdata; 376 377 e = pa_xnew(pa_defer_event, 1); 378 e->mainloop = g; 379 e->dead = 0; 380 381 e->enabled = 1; 382 g->n_enabled_defer_events++; 383 384 e->callback = cb; 385 e->userdata = userdata; 386 e->destroy_callback = NULL; 387 388 PA_LLIST_PREPEND(pa_defer_event, g->defer_events, e); 389 return e; 390} 391 392static void glib_defer_enable(pa_defer_event *e, int b) { 393 g_assert(e); 394 g_assert(!e->dead); 395 396 if (e->enabled && !b) { 397 g_assert(e->mainloop->n_enabled_defer_events > 0); 398 e->mainloop->n_enabled_defer_events--; 399 } else if (!e->enabled && b) 400 e->mainloop->n_enabled_defer_events++; 401 402 e->enabled = b; 403} 404 405static void glib_defer_free(pa_defer_event *e) { 406 g_assert(e); 407 g_assert(!e->dead); 408 409 e->dead = 1; 410 e->mainloop->defer_events_please_scan++; 411 412 if (e->enabled) { 413 g_assert(e->mainloop->n_enabled_defer_events > 0); 414 e->mainloop->n_enabled_defer_events--; 415 } 416} 417 418static void glib_defer_set_destroy(pa_defer_event *e, pa_defer_event_destroy_cb_t cb) { 419 g_assert(e); 420 g_assert(!e->dead); 421 422 e->destroy_callback = cb; 423} 424 425/* quit() */ 426 427static void glib_quit(pa_mainloop_api*a, int retval) { 428 429 g_warning("quit() ignored"); 430 431 /* NOOP */ 432} 433 434static pa_time_event* find_next_time_event(pa_glib_mainloop *g) { 435 pa_time_event *t, *n = NULL; 436 g_assert(g); 437 438 if (g->cached_next_time_event) 439 return g->cached_next_time_event; 440 441 for (t = g->time_events; t; t = t->next) { 442 443 if (t->dead || !t->enabled) 444 continue; 445 446 if (!n || pa_timeval_cmp(&t->timeval, &n->timeval) < 0) { 447 n = t; 448 449 /* Shortcut for tv = { 0, 0 } */ 450 if (n->timeval.tv_sec <= 0) 451 break; 452 } 453 } 454 455 g->cached_next_time_event = n; 456 return n; 457} 458 459static void scan_dead(pa_glib_mainloop *g) { 460 g_assert(g); 461 462 if (g->io_events_please_scan) 463 cleanup_io_events(g, 0); 464 465 if (g->time_events_please_scan) 466 cleanup_time_events(g, 0); 467 468 if (g->defer_events_please_scan) 469 cleanup_defer_events(g, 0); 470} 471 472static gboolean prepare_func(GSource *source, gint *timeout) { 473 pa_glib_mainloop *g = (pa_glib_mainloop*) source; 474 475 g_assert(g); 476 g_assert(timeout); 477 478 scan_dead(g); 479 480 if (g->n_enabled_defer_events) { 481 *timeout = 0; 482 return TRUE; 483 } else if (g->n_enabled_time_events) { 484 pa_time_event *t; 485 gint64 now; 486 struct timeval tvnow; 487 pa_usec_t usec; 488 489 t = find_next_time_event(g); 490 g_assert(t); 491 492 now = g_get_real_time(); 493 pa_timeval_store(&tvnow, now); 494 495 if (pa_timeval_cmp(&t->timeval, &tvnow) <= 0) { 496 *timeout = 0; 497 return TRUE; 498 } 499 usec = pa_timeval_diff(&t->timeval, &tvnow); 500 *timeout = (gint) (usec / 1000); 501 } else 502 *timeout = -1; 503 504 return FALSE; 505} 506static gboolean check_func(GSource *source) { 507 pa_glib_mainloop *g = (pa_glib_mainloop*) source; 508 pa_io_event *e; 509 510 g_assert(g); 511 512 if (g->n_enabled_defer_events) 513 return TRUE; 514 else if (g->n_enabled_time_events) { 515 pa_time_event *t; 516 gint64 now; 517 struct timeval tvnow; 518 519 t = find_next_time_event(g); 520 g_assert(t); 521 522 now = g_get_real_time(); 523 pa_timeval_store(&tvnow, now); 524 525 if (pa_timeval_cmp(&t->timeval, &tvnow) <= 0) 526 return TRUE; 527 } 528 529 for (e = g->io_events; e; e = e->next) 530 if (!e->dead && e->poll_fd.revents != 0) 531 return TRUE; 532 533 return FALSE; 534} 535 536static gboolean dispatch_func(GSource *source, GSourceFunc callback, gpointer userdata) { 537 pa_glib_mainloop *g = (pa_glib_mainloop*) source; 538 pa_io_event *e; 539 540 g_assert(g); 541 542 if (g->n_enabled_defer_events) { 543 pa_defer_event *d; 544 545 for (d = g->defer_events; d; d = d->next) { 546 if (d->dead || !d->enabled) 547 continue; 548 549 break; 550 } 551 552 g_assert(d); 553 554 d->callback(&g->api, d, d->userdata); 555 return TRUE; 556 } 557 558 if (g->n_enabled_time_events) { 559 gint64 now; 560 struct timeval tvnow; 561 pa_time_event *t; 562 563 t = find_next_time_event(g); 564 g_assert(t); 565 566 now = g_get_real_time(); 567 pa_timeval_store(&tvnow, now); 568 569 if (pa_timeval_cmp(&t->timeval, &tvnow) <= 0) { 570 571 /* Disable time event */ 572 glib_time_restart(t, NULL); 573 574 t->callback(&g->api, t, &t->timeval, t->userdata); 575 return TRUE; 576 } 577 } 578 579 for (e = g->io_events; e; e = e->next) 580 if (!e->dead && e->poll_fd.revents != 0) { 581 e->callback(&g->api, e, e->poll_fd.fd, map_flags_from_glib(e->poll_fd.revents), e->userdata); 582 e->poll_fd.revents = 0; 583 return TRUE; 584 } 585 586 return FALSE; 587} 588 589static const pa_mainloop_api vtable = { 590 .userdata = NULL, 591 592 .io_new = glib_io_new, 593 .io_enable = glib_io_enable, 594 .io_free = glib_io_free, 595 .io_set_destroy = glib_io_set_destroy, 596 597 .time_new = glib_time_new, 598 .time_restart = glib_time_restart, 599 .time_free = glib_time_free, 600 .time_set_destroy = glib_time_set_destroy, 601 602 .defer_new = glib_defer_new, 603 .defer_enable = glib_defer_enable, 604 .defer_free = glib_defer_free, 605 .defer_set_destroy = glib_defer_set_destroy, 606 607 .quit = glib_quit, 608}; 609 610pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c) { 611 pa_glib_mainloop *g; 612 613 static GSourceFuncs source_funcs = { 614 prepare_func, 615 check_func, 616 dispatch_func, 617 NULL, 618 NULL, 619 NULL 620 }; 621 622 g = (pa_glib_mainloop*) g_source_new(&source_funcs, sizeof(pa_glib_mainloop)); 623 g_main_context_ref(g->context = c ? c : g_main_context_default()); 624 625 g->api = vtable; 626 g->api.userdata = g; 627 628 PA_LLIST_HEAD_INIT(pa_io_event, g->io_events); 629 PA_LLIST_HEAD_INIT(pa_time_event, g->time_events); 630 PA_LLIST_HEAD_INIT(pa_defer_event, g->defer_events); 631 632 g->n_enabled_defer_events = g->n_enabled_time_events = 0; 633 g->io_events_please_scan = g->time_events_please_scan = g->defer_events_please_scan = 0; 634 635 g->cached_next_time_event = NULL; 636 637 g_source_attach(&g->source, g->context); 638 g_source_set_can_recurse(&g->source, FALSE); 639 640 return g; 641} 642 643void pa_glib_mainloop_free(pa_glib_mainloop* g) { 644 g_assert(g); 645 646 cleanup_io_events(g, 1); 647 cleanup_defer_events(g, 1); 648 cleanup_time_events(g, 1); 649 650 g_main_context_unref(g->context); 651 g_source_destroy(&g->source); 652 g_source_unref(&g->source); 653} 654 655pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g) { 656 g_assert(g); 657 658 return &g->api; 659} 660