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