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