1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 2/* dbus-mainloop.c Main loop utility 3 * 4 * Copyright © 2003, 2004 Red Hat, Inc. 5 * Copyright © 2011 Nokia Corporation 6 * 7 * Licensed under the Academic Free License version 2.1 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 * 23 */ 24 25#include <config.h> 26#include "dbus-mainloop.h" 27 28#ifndef DOXYGEN_SHOULD_SKIP_THIS 29 30#include <dbus/dbus-hash.h> 31#include <dbus/dbus-list.h> 32#include <dbus/dbus-socket-set.h> 33#include <dbus/dbus-watch.h> 34 35#define MAINLOOP_SPEW 0 36 37#if MAINLOOP_SPEW 38#ifdef DBUS_ENABLE_VERBOSE_MODE 39static const char* 40watch_flags_to_string (int flags) 41{ 42 const char *watch_type; 43 44 if ((flags & DBUS_WATCH_READABLE) && 45 (flags & DBUS_WATCH_WRITABLE)) 46 watch_type = "readwrite"; 47 else if (flags & DBUS_WATCH_READABLE) 48 watch_type = "read"; 49 else if (flags & DBUS_WATCH_WRITABLE) 50 watch_type = "write"; 51 else 52 watch_type = "not read or write"; 53 return watch_type; 54} 55#endif /* DBUS_ENABLE_VERBOSE_MODE */ 56#endif /* MAINLOOP_SPEW */ 57 58struct DBusLoop 59{ 60 int refcount; 61 /** fd => dbus_malloc'd DBusList ** of references to DBusWatch */ 62 DBusHashTable *watches; 63 DBusSocketSet *socket_set; 64 DBusList *timeouts; 65 int callback_list_serial; 66 int watch_count; 67 int timeout_count; 68 int depth; /**< number of recursive runs */ 69 DBusList *need_dispatch; 70 /** TRUE if we will skip a watch next time because it was OOM; becomes 71 * FALSE between polling, and dealing with the results of the poll */ 72 unsigned oom_watch_pending : 1; 73}; 74 75typedef struct 76{ 77 DBusTimeout *timeout; 78 unsigned long last_tv_sec; 79 unsigned long last_tv_usec; 80} TimeoutCallback; 81 82#define TIMEOUT_CALLBACK(callback) ((TimeoutCallback*)callback) 83 84static TimeoutCallback* 85timeout_callback_new (DBusTimeout *timeout) 86{ 87 TimeoutCallback *cb; 88 89 cb = dbus_new (TimeoutCallback, 1); 90 if (cb == NULL) 91 return NULL; 92 93 cb->timeout = timeout; 94 _dbus_get_monotonic_time (&cb->last_tv_sec, 95 &cb->last_tv_usec); 96 return cb; 97} 98 99static void 100timeout_callback_free (TimeoutCallback *cb) 101{ 102 dbus_free (cb); 103} 104 105static void 106free_watch_table_entry (void *data) 107{ 108 DBusList **watches = data; 109 DBusWatch *watch; 110 111 /* DBusHashTable sometimes calls free_function(NULL) even if you never 112 * have NULL as a value */ 113 if (watches == NULL) 114 return; 115 116 for (watch = _dbus_list_pop_first (watches); 117 watch != NULL; 118 watch = _dbus_list_pop_first (watches)) 119 { 120 _dbus_watch_unref (watch); 121 } 122 123 _dbus_assert (*watches == NULL); 124 dbus_free (watches); 125} 126 127DBusLoop* 128_dbus_loop_new (void) 129{ 130 DBusLoop *loop; 131 132 loop = dbus_new0 (DBusLoop, 1); 133 if (loop == NULL) 134 return NULL; 135 136 loop->watches = _dbus_hash_table_new (DBUS_HASH_INT, NULL, 137 free_watch_table_entry); 138 139 loop->socket_set = _dbus_socket_set_new (0); 140 141 if (loop->watches == NULL || loop->socket_set == NULL) 142 { 143 if (loop->watches != NULL) 144 _dbus_hash_table_unref (loop->watches); 145 146 if (loop->socket_set != NULL) 147 _dbus_socket_set_free (loop->socket_set); 148 149 dbus_free (loop); 150 return NULL; 151 } 152 153 loop->refcount = 1; 154 155 return loop; 156} 157 158DBusLoop * 159_dbus_loop_ref (DBusLoop *loop) 160{ 161 _dbus_assert (loop != NULL); 162 _dbus_assert (loop->refcount > 0); 163 164 loop->refcount += 1; 165 166 return loop; 167} 168 169void 170_dbus_loop_unref (DBusLoop *loop) 171{ 172 _dbus_assert (loop != NULL); 173 _dbus_assert (loop->refcount > 0); 174 175 loop->refcount -= 1; 176 if (loop->refcount == 0) 177 { 178 while (loop->need_dispatch) 179 { 180 DBusConnection *connection = _dbus_list_pop_first (&loop->need_dispatch); 181 182 dbus_connection_unref (connection); 183 } 184 185 _dbus_hash_table_unref (loop->watches); 186 _dbus_socket_set_free (loop->socket_set); 187 dbus_free (loop); 188 } 189} 190 191static DBusList ** 192ensure_watch_table_entry (DBusLoop *loop, 193 int fd) 194{ 195 DBusList **watches; 196 197 watches = _dbus_hash_table_lookup_int (loop->watches, fd); 198 199 if (watches == NULL) 200 { 201 watches = dbus_new0 (DBusList *, 1); 202 203 if (watches == NULL) 204 return watches; 205 206 if (!_dbus_hash_table_insert_int (loop->watches, fd, watches)) 207 { 208 dbus_free (watches); 209 watches = NULL; 210 } 211 } 212 213 return watches; 214} 215 216static void 217cull_watches_for_invalid_fd (DBusLoop *loop, 218 int fd) 219{ 220 DBusList *link; 221 DBusList **watches; 222 223 _dbus_warn ("invalid request, socket fd %d not open\n", fd); 224 watches = _dbus_hash_table_lookup_int (loop->watches, fd); 225 226 if (watches != NULL) 227 { 228 for (link = _dbus_list_get_first_link (watches); 229 link != NULL; 230 link = _dbus_list_get_next_link (watches, link)) 231 _dbus_watch_invalidate (link->data); 232 } 233 234 _dbus_hash_table_remove_int (loop->watches, fd); 235} 236 237static dbus_bool_t 238gc_watch_table_entry (DBusLoop *loop, 239 DBusList **watches, 240 int fd) 241{ 242 /* If watches is already NULL we have nothing to do */ 243 if (watches == NULL) 244 return FALSE; 245 246 /* We can't GC hash table entries if they're non-empty lists */ 247 if (*watches != NULL) 248 return FALSE; 249 250 _dbus_hash_table_remove_int (loop->watches, fd); 251 return TRUE; 252} 253 254static void 255refresh_watches_for_fd (DBusLoop *loop, 256 DBusList **watches, 257 int fd) 258{ 259 DBusList *link; 260 unsigned int flags = 0; 261 dbus_bool_t interested = FALSE; 262 263 _dbus_assert (fd != -1); 264 265 if (watches == NULL) 266 watches = _dbus_hash_table_lookup_int (loop->watches, fd); 267 268 /* we allocated this in the first _dbus_loop_add_watch for the fd, and keep 269 * it until there are none left */ 270 _dbus_assert (watches != NULL); 271 272 for (link = _dbus_list_get_first_link (watches); 273 link != NULL; 274 link = _dbus_list_get_next_link (watches, link)) 275 { 276 if (dbus_watch_get_enabled (link->data) && 277 !_dbus_watch_get_oom_last_time (link->data)) 278 { 279 flags |= dbus_watch_get_flags (link->data); 280 interested = TRUE; 281 } 282 } 283 284 if (interested) 285 _dbus_socket_set_enable (loop->socket_set, fd, flags); 286 else 287 _dbus_socket_set_disable (loop->socket_set, fd); 288} 289 290dbus_bool_t 291_dbus_loop_add_watch (DBusLoop *loop, 292 DBusWatch *watch) 293{ 294 int fd; 295 DBusList **watches; 296 297 fd = dbus_watch_get_socket (watch); 298 _dbus_assert (fd != -1); 299 300 watches = ensure_watch_table_entry (loop, fd); 301 302 if (watches == NULL) 303 return FALSE; 304 305 if (!_dbus_list_append (watches, _dbus_watch_ref (watch))) 306 { 307 _dbus_watch_unref (watch); 308 gc_watch_table_entry (loop, watches, fd); 309 310 return FALSE; 311 } 312 313 if (_dbus_list_length_is_one (watches)) 314 { 315 if (!_dbus_socket_set_add (loop->socket_set, fd, 316 dbus_watch_get_flags (watch), 317 dbus_watch_get_enabled (watch))) 318 { 319 _dbus_hash_table_remove_int (loop->watches, fd); 320 return FALSE; 321 } 322 } 323 else 324 { 325 /* we're modifying, not adding, which can't fail with OOM */ 326 refresh_watches_for_fd (loop, watches, fd); 327 } 328 329 loop->callback_list_serial += 1; 330 loop->watch_count += 1; 331 return TRUE; 332} 333 334void 335_dbus_loop_toggle_watch (DBusLoop *loop, 336 DBusWatch *watch) 337{ 338 refresh_watches_for_fd (loop, NULL, dbus_watch_get_socket (watch)); 339} 340 341void 342_dbus_loop_remove_watch (DBusLoop *loop, 343 DBusWatch *watch) 344{ 345 DBusList **watches; 346 DBusList *link; 347 int fd; 348 349 /* This relies on people removing watches before they invalidate them, 350 * which has been safe since fd.o #33336 was fixed. Assert about it 351 * so we don't regress. */ 352 fd = dbus_watch_get_socket (watch); 353 _dbus_assert (fd != -1); 354 355 watches = _dbus_hash_table_lookup_int (loop->watches, fd); 356 357 if (watches != NULL) 358 { 359 link = _dbus_list_get_first_link (watches); 360 while (link != NULL) 361 { 362 DBusList *next = _dbus_list_get_next_link (watches, link); 363 DBusWatch *this = link->data; 364 365 if (this == watch) 366 { 367 _dbus_list_remove_link (watches, link); 368 loop->callback_list_serial += 1; 369 loop->watch_count -= 1; 370 _dbus_watch_unref (this); 371 372 /* if that was the last watch for that fd, drop the hash table 373 * entry, and stop reserving space for it in the socket set */ 374 if (gc_watch_table_entry (loop, watches, fd)) 375 { 376 _dbus_socket_set_remove (loop->socket_set, fd); 377 } 378 379 return; 380 } 381 382 link = next; 383 } 384 } 385 386 _dbus_warn ("could not find watch %p to remove\n", watch); 387} 388 389dbus_bool_t 390_dbus_loop_add_timeout (DBusLoop *loop, 391 DBusTimeout *timeout) 392{ 393 TimeoutCallback *tcb; 394 395 tcb = timeout_callback_new (timeout); 396 if (tcb == NULL) 397 return FALSE; 398 399 if (_dbus_list_append (&loop->timeouts, tcb)) 400 { 401 loop->callback_list_serial += 1; 402 loop->timeout_count += 1; 403 } 404 else 405 { 406 timeout_callback_free (tcb); 407 return FALSE; 408 } 409 410 return TRUE; 411} 412 413void 414_dbus_loop_remove_timeout (DBusLoop *loop, 415 DBusTimeout *timeout) 416{ 417 DBusList *link; 418 419 link = _dbus_list_get_first_link (&loop->timeouts); 420 while (link != NULL) 421 { 422 DBusList *next = _dbus_list_get_next_link (&loop->timeouts, link); 423 TimeoutCallback *this = link->data; 424 425 if (this->timeout == timeout) 426 { 427 _dbus_list_remove_link (&loop->timeouts, link); 428 loop->callback_list_serial += 1; 429 loop->timeout_count -= 1; 430 timeout_callback_free (this); 431 432 return; 433 } 434 435 link = next; 436 } 437 438 _dbus_warn ("could not find timeout %p to remove\n", timeout); 439} 440 441/* Convolutions from GLib, there really must be a better way 442 * to do this. 443 */ 444static dbus_bool_t 445check_timeout (unsigned long tv_sec, 446 unsigned long tv_usec, 447 TimeoutCallback *tcb, 448 int *timeout) 449{ 450 long sec_remaining; 451 long msec_remaining; 452 unsigned long expiration_tv_sec; 453 unsigned long expiration_tv_usec; 454 long interval_seconds; 455 long interval_milliseconds; 456 int interval; 457 458 /* I'm pretty sure this function could suck (a lot) less */ 459 460 interval = dbus_timeout_get_interval (tcb->timeout); 461 462 interval_seconds = interval / 1000L; 463 interval_milliseconds = interval % 1000L; 464 465 expiration_tv_sec = tcb->last_tv_sec + interval_seconds; 466 expiration_tv_usec = tcb->last_tv_usec + interval_milliseconds * 1000; 467 if (expiration_tv_usec >= 1000000) 468 { 469 expiration_tv_usec -= 1000000; 470 expiration_tv_sec += 1; 471 } 472 473 sec_remaining = expiration_tv_sec - tv_sec; 474 /* need to force this to be signed, as it is intended to sometimes 475 * produce a negative result 476 */ 477 msec_remaining = ((long) expiration_tv_usec - (long) tv_usec) / 1000L; 478 479#if MAINLOOP_SPEW 480 _dbus_verbose ("Interval is %ld seconds %ld msecs\n", 481 interval_seconds, 482 interval_milliseconds); 483 _dbus_verbose ("Now is %lu seconds %lu usecs\n", 484 tv_sec, tv_usec); 485 _dbus_verbose ("Last is %lu seconds %lu usecs\n", 486 tcb->last_tv_sec, tcb->last_tv_usec); 487 _dbus_verbose ("Exp is %lu seconds %lu usecs\n", 488 expiration_tv_sec, expiration_tv_usec); 489 _dbus_verbose ("Pre-correction, sec_remaining %ld msec_remaining %ld\n", 490 sec_remaining, msec_remaining); 491#endif 492 493 /* We do the following in a rather convoluted fashion to deal with 494 * the fact that we don't have an integral type big enough to hold 495 * the difference of two timevals in milliseconds. 496 */ 497 if (sec_remaining < 0 || (sec_remaining == 0 && msec_remaining < 0)) 498 { 499 *timeout = 0; 500 } 501 else 502 { 503 if (msec_remaining < 0) 504 { 505 msec_remaining += 1000; 506 sec_remaining -= 1; 507 } 508 509 if (sec_remaining > (_DBUS_INT_MAX / 1000) || 510 msec_remaining > _DBUS_INT_MAX) 511 *timeout = _DBUS_INT_MAX; 512 else 513 *timeout = sec_remaining * 1000 + msec_remaining; 514 } 515 516 if (*timeout > interval) 517 { 518 /* This indicates that the system clock probably moved backward */ 519 _dbus_verbose ("System clock set backward! Resetting timeout.\n"); 520 521 tcb->last_tv_sec = tv_sec; 522 tcb->last_tv_usec = tv_usec; 523 524 *timeout = interval; 525 } 526 527#if MAINLOOP_SPEW 528 _dbus_verbose (" timeout expires in %d milliseconds\n", *timeout); 529#endif 530 531 return *timeout == 0; 532} 533 534dbus_bool_t 535_dbus_loop_dispatch (DBusLoop *loop) 536{ 537 538#if MAINLOOP_SPEW 539 _dbus_verbose (" %d connections to dispatch\n", _dbus_list_get_length (&loop->need_dispatch)); 540#endif 541 542 if (loop->need_dispatch == NULL) 543 return FALSE; 544 545 next: 546 while (loop->need_dispatch != NULL) 547 { 548 DBusConnection *connection = _dbus_list_pop_first (&loop->need_dispatch); 549 550 while (TRUE) 551 { 552 DBusDispatchStatus status; 553 554 status = dbus_connection_dispatch (connection); 555 556 if (status == DBUS_DISPATCH_COMPLETE) 557 { 558 dbus_connection_unref (connection); 559 goto next; 560 } 561 else 562 { 563 if (status == DBUS_DISPATCH_NEED_MEMORY) 564 _dbus_wait_for_memory (); 565 } 566 } 567 } 568 569 return TRUE; 570} 571 572dbus_bool_t 573_dbus_loop_queue_dispatch (DBusLoop *loop, 574 DBusConnection *connection) 575{ 576 if (_dbus_list_append (&loop->need_dispatch, connection)) 577 { 578 dbus_connection_ref (connection); 579 return TRUE; 580 } 581 else 582 return FALSE; 583} 584 585/* Returns TRUE if we invoked any timeouts or have ready file 586 * descriptors, which is just used in test code as a debug hack 587 */ 588 589dbus_bool_t 590_dbus_loop_iterate (DBusLoop *loop, 591 dbus_bool_t block) 592{ 593#define N_STACK_DESCRIPTORS 64 594 dbus_bool_t retval; 595 DBusSocketEvent ready_fds[N_STACK_DESCRIPTORS]; 596 int i; 597 DBusList *link; 598 int n_ready; 599 int initial_serial; 600 long timeout; 601 int orig_depth; 602 603 retval = FALSE; 604 605 orig_depth = loop->depth; 606 607#if MAINLOOP_SPEW 608 _dbus_verbose ("Iteration block=%d depth=%d timeout_count=%d watch_count=%d\n", 609 block, loop->depth, loop->timeout_count, loop->watch_count); 610#endif 611 612 if (_dbus_hash_table_get_n_entries (loop->watches) == 0 && 613 loop->timeouts == NULL) 614 goto next_iteration; 615 616 timeout = -1; 617 if (loop->timeout_count > 0) 618 { 619 unsigned long tv_sec; 620 unsigned long tv_usec; 621 622 _dbus_get_monotonic_time (&tv_sec, &tv_usec); 623 624 link = _dbus_list_get_first_link (&loop->timeouts); 625 while (link != NULL) 626 { 627 DBusList *next = _dbus_list_get_next_link (&loop->timeouts, link); 628 TimeoutCallback *tcb = link->data; 629 630 if (dbus_timeout_get_enabled (tcb->timeout)) 631 { 632 int msecs_remaining; 633 634 check_timeout (tv_sec, tv_usec, tcb, &msecs_remaining); 635 636 if (timeout < 0) 637 timeout = msecs_remaining; 638 else 639 timeout = MIN (msecs_remaining, timeout); 640 641#if MAINLOOP_SPEW 642 _dbus_verbose (" timeout added, %d remaining, aggregate timeout %ld\n", 643 msecs_remaining, timeout); 644#endif 645 646 _dbus_assert (timeout >= 0); 647 648 if (timeout == 0) 649 break; /* it's not going to get shorter... */ 650 } 651#if MAINLOOP_SPEW 652 else 653 { 654 _dbus_verbose (" skipping disabled timeout\n"); 655 } 656#endif 657 658 link = next; 659 } 660 } 661 662 /* Never block if we have stuff to dispatch */ 663 if (!block || loop->need_dispatch != NULL) 664 { 665 timeout = 0; 666#if MAINLOOP_SPEW 667 _dbus_verbose (" timeout is 0 as we aren't blocking\n"); 668#endif 669 } 670 671 /* if a watch was OOM last time, don't wait longer than the OOM 672 * wait to re-enable it 673 */ 674 if (loop->oom_watch_pending) 675 timeout = MIN (timeout, _dbus_get_oom_wait ()); 676 677#if MAINLOOP_SPEW 678 _dbus_verbose (" polling on %d descriptors timeout %ld\n", n_fds, timeout); 679#endif 680 681 n_ready = _dbus_socket_set_poll (loop->socket_set, ready_fds, 682 _DBUS_N_ELEMENTS (ready_fds), timeout); 683 684 /* re-enable any watches we skipped this time */ 685 if (loop->oom_watch_pending) 686 { 687 DBusHashIter hash_iter; 688 689 loop->oom_watch_pending = FALSE; 690 691 _dbus_hash_iter_init (loop->watches, &hash_iter); 692 693 while (_dbus_hash_iter_next (&hash_iter)) 694 { 695 DBusList **watches; 696 int fd; 697 dbus_bool_t changed; 698 699 changed = FALSE; 700 fd = _dbus_hash_iter_get_int_key (&hash_iter); 701 watches = _dbus_hash_iter_get_value (&hash_iter); 702 703 for (link = _dbus_list_get_first_link (watches); 704 link != NULL; 705 link = _dbus_list_get_next_link (watches, link)) 706 { 707 DBusWatch *watch = link->data; 708 709 if (_dbus_watch_get_oom_last_time (watch)) 710 { 711 _dbus_watch_set_oom_last_time (watch, FALSE); 712 changed = TRUE; 713 } 714 } 715 716 if (changed) 717 refresh_watches_for_fd (loop, watches, fd); 718 } 719 720 retval = TRUE; /* return TRUE here to keep the loop going, 721 * since we don't know the watch was inactive */ 722 } 723 724 initial_serial = loop->callback_list_serial; 725 726 if (loop->timeout_count > 0) 727 { 728 unsigned long tv_sec; 729 unsigned long tv_usec; 730 731 _dbus_get_monotonic_time (&tv_sec, &tv_usec); 732 733 /* It'd be nice to avoid this O(n) thingy here */ 734 link = _dbus_list_get_first_link (&loop->timeouts); 735 while (link != NULL) 736 { 737 DBusList *next = _dbus_list_get_next_link (&loop->timeouts, link); 738 TimeoutCallback *tcb = link->data; 739 740 if (initial_serial != loop->callback_list_serial) 741 goto next_iteration; 742 743 if (loop->depth != orig_depth) 744 goto next_iteration; 745 746 if (dbus_timeout_get_enabled (tcb->timeout)) 747 { 748 int msecs_remaining; 749 750 if (check_timeout (tv_sec, tv_usec, 751 tcb, &msecs_remaining)) 752 { 753 /* Save last callback time and fire this timeout */ 754 tcb->last_tv_sec = tv_sec; 755 tcb->last_tv_usec = tv_usec; 756 757#if MAINLOOP_SPEW 758 _dbus_verbose (" invoking timeout\n"); 759#endif 760 761 /* can theoretically return FALSE on OOM, but we just 762 * let it fire again later - in practice that's what 763 * every wrapper callback in dbus-daemon used to do */ 764 dbus_timeout_handle (tcb->timeout); 765 766 retval = TRUE; 767 } 768 else 769 { 770#if MAINLOOP_SPEW 771 _dbus_verbose (" timeout has not expired\n"); 772#endif 773 } 774 } 775#if MAINLOOP_SPEW 776 else 777 { 778 _dbus_verbose (" skipping invocation of disabled timeout\n"); 779 } 780#endif 781 782 link = next; 783 } 784 } 785 786 if (n_ready > 0) 787 { 788 for (i = 0; i < n_ready; i++) 789 { 790 DBusList **watches; 791 DBusList *next; 792 unsigned int condition; 793 dbus_bool_t any_oom; 794 795 /* FIXME I think this "restart if we change the watches" 796 * approach could result in starving watches 797 * toward the end of the list. 798 */ 799 if (initial_serial != loop->callback_list_serial) 800 goto next_iteration; 801 802 if (loop->depth != orig_depth) 803 goto next_iteration; 804 805 _dbus_assert (ready_fds[i].flags != 0); 806 807 if (_DBUS_UNLIKELY (ready_fds[i].flags & _DBUS_WATCH_NVAL)) 808 { 809 cull_watches_for_invalid_fd (loop, ready_fds[i].fd); 810 goto next_iteration; 811 } 812 813 condition = ready_fds[i].flags; 814 _dbus_assert ((condition & _DBUS_WATCH_NVAL) == 0); 815 816 /* condition may still be 0 if we got some 817 * weird POLLFOO thing like POLLWRBAND 818 */ 819 if (condition == 0) 820 continue; 821 822 watches = _dbus_hash_table_lookup_int (loop->watches, 823 ready_fds[i].fd); 824 825 if (watches == NULL) 826 continue; 827 828 any_oom = FALSE; 829 830 for (link = _dbus_list_get_first_link (watches); 831 link != NULL; 832 link = next) 833 { 834 DBusWatch *watch = link->data; 835 836 next = _dbus_list_get_next_link (watches, link); 837 838 if (dbus_watch_get_enabled (watch)) 839 { 840 dbus_bool_t oom; 841 842 oom = !dbus_watch_handle (watch, condition); 843 844 if (oom) 845 { 846 _dbus_watch_set_oom_last_time (watch, TRUE); 847 loop->oom_watch_pending = TRUE; 848 any_oom = TRUE; 849 } 850 851#if MAINLOOP_SPEW 852 _dbus_verbose (" Invoked watch, oom = %d\n", oom); 853#endif 854 retval = TRUE; 855 856 /* We re-check this every time, in case the callback 857 * added/removed watches, which might make our position in 858 * the linked list invalid. See the FIXME above. */ 859 if (initial_serial != loop->callback_list_serial || 860 loop->depth != orig_depth) 861 { 862 if (any_oom) 863 refresh_watches_for_fd (loop, NULL, ready_fds[i].fd); 864 865 goto next_iteration; 866 } 867 } 868 } 869 870 if (any_oom) 871 refresh_watches_for_fd (loop, watches, ready_fds[i].fd); 872 } 873 } 874 875 next_iteration: 876#if MAINLOOP_SPEW 877 _dbus_verbose (" moving to next iteration\n"); 878#endif 879 880 if (_dbus_loop_dispatch (loop)) 881 retval = TRUE; 882 883#if MAINLOOP_SPEW 884 _dbus_verbose ("Returning %d\n", retval); 885#endif 886 887 return retval; 888} 889 890void 891_dbus_loop_run (DBusLoop *loop) 892{ 893 int our_exit_depth; 894 895 _dbus_assert (loop->depth >= 0); 896 897 _dbus_loop_ref (loop); 898 899 our_exit_depth = loop->depth; 900 loop->depth += 1; 901 902 _dbus_verbose ("Running main loop, depth %d -> %d\n", 903 loop->depth - 1, loop->depth); 904 905 while (loop->depth != our_exit_depth) 906 _dbus_loop_iterate (loop, TRUE); 907 908 _dbus_loop_unref (loop); 909} 910 911void 912_dbus_loop_quit (DBusLoop *loop) 913{ 914 _dbus_assert (loop->depth > 0); 915 916 loop->depth -= 1; 917 918 _dbus_verbose ("Quit main loop, depth %d -> %d\n", 919 loop->depth + 1, loop->depth); 920} 921 922int 923_dbus_get_oom_wait (void) 924{ 925#ifdef DBUS_BUILD_TESTS 926 /* make tests go fast */ 927 return 0; 928#else 929 return 500; 930#endif 931} 932 933void 934_dbus_wait_for_memory (void) 935{ 936 _dbus_verbose ("Waiting for more memory\n"); 937 _dbus_sleep_milliseconds (_dbus_get_oom_wait ()); 938} 939 940#endif /* !DOXYGEN_SHOULD_SKIP_THIS */ 941