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