Home | History | Annotate | Download | only in dbus
      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
     39 static const char*
     40 watch_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 
     58 struct 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 
     75 typedef 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 
     84 static TimeoutCallback*
     85 timeout_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 
     99 static void
    100 timeout_callback_free (TimeoutCallback *cb)
    101 {
    102   dbus_free (cb);
    103 }
    104 
    105 static void
    106 free_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 
    127 DBusLoop*
    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 
    158 DBusLoop *
    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 
    169 void
    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 
    191 static DBusList **
    192 ensure_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 
    216 static void
    217 cull_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 
    237 static dbus_bool_t
    238 gc_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 
    254 static void
    255 refresh_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 
    290 dbus_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 
    334 void
    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 
    341 void
    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 
    389 dbus_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 
    413 void
    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  */
    444 static dbus_bool_t
    445 check_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 
    534 dbus_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 
    572 dbus_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 
    589 dbus_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 
    890 void
    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 
    911 void
    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 
    922 int
    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 
    933 void
    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