D-Bus  1.10.12
dbus-mainloop.c
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 /* dbus-mainloop.c  Main loop utility
00003  *
00004  * Copyright © 2003, 2004  Red Hat, Inc.
00005  * Copyright © 2011 Nokia Corporation
00006  *
00007  * Licensed under the Academic Free License version 2.1
00008  * 
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  * 
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00022  *
00023  */
00024 
00025 #include <config.h>
00026 #include "dbus-mainloop.h"
00027 
00028 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00029 
00030 #include <dbus/dbus-hash.h>
00031 #include <dbus/dbus-list.h>
00032 #include <dbus/dbus-socket-set.h>
00033 #include <dbus/dbus-watch.h>
00034 
00035 #define MAINLOOP_SPEW 0
00036 
00037 struct DBusLoop
00038 {
00039   int refcount;
00041   DBusHashTable *watches;
00042   DBusSocketSet *socket_set;
00043   DBusList *timeouts;
00044   int callback_list_serial;
00045   int watch_count;
00046   int timeout_count;
00047   int depth; 
00048   DBusList *need_dispatch;
00051   unsigned oom_watch_pending : 1;
00052 };
00053 
00054 typedef struct
00055 {
00056   DBusTimeout *timeout;
00057   long last_tv_sec;
00058   long last_tv_usec;
00059 } TimeoutCallback;
00060 
00061 #define TIMEOUT_CALLBACK(callback) ((TimeoutCallback*)callback)
00062 
00063 static TimeoutCallback*
00064 timeout_callback_new (DBusTimeout         *timeout)
00065 {
00066   TimeoutCallback *cb;
00067 
00068   cb = dbus_new (TimeoutCallback, 1);
00069   if (cb == NULL)
00070     return NULL;
00071 
00072   cb->timeout = timeout;
00073   _dbus_get_monotonic_time (&cb->last_tv_sec,
00074                             &cb->last_tv_usec);
00075   return cb;
00076 }
00077 
00078 static void
00079 timeout_callback_free (TimeoutCallback *cb)
00080 {
00081   dbus_free (cb);
00082 }
00083 
00084 static void
00085 free_watch_table_entry (void *data)
00086 {
00087   DBusList **watches = data;
00088   DBusWatch *watch;
00089 
00090   /* DBusHashTable sometimes calls free_function(NULL) even if you never
00091    * have NULL as a value */
00092   if (watches == NULL)
00093     return;
00094 
00095   for (watch = _dbus_list_pop_first (watches);
00096       watch != NULL;
00097       watch = _dbus_list_pop_first (watches))
00098     {
00099       _dbus_watch_unref (watch);
00100     }
00101 
00102   _dbus_assert (*watches == NULL);
00103   dbus_free (watches);
00104 }
00105 
00106 DBusLoop*
00107 _dbus_loop_new (void)
00108 {
00109   DBusLoop *loop;
00110 
00111   loop = dbus_new0 (DBusLoop, 1);
00112   if (loop == NULL)
00113     return NULL;
00114 
00115   loop->watches = _dbus_hash_table_new (DBUS_HASH_POLLABLE, NULL,
00116                                         free_watch_table_entry);
00117 
00118   loop->socket_set = _dbus_socket_set_new (0);
00119 
00120   if (loop->watches == NULL || loop->socket_set == NULL)
00121     {
00122       if (loop->watches != NULL)
00123         _dbus_hash_table_unref (loop->watches);
00124 
00125       if (loop->socket_set != NULL)
00126         _dbus_socket_set_free (loop->socket_set);
00127 
00128       dbus_free (loop);
00129       return NULL;
00130     }
00131 
00132   loop->refcount = 1;
00133 
00134   return loop;
00135 }
00136 
00137 DBusLoop *
00138 _dbus_loop_ref (DBusLoop *loop)
00139 {
00140   _dbus_assert (loop != NULL);
00141   _dbus_assert (loop->refcount > 0);
00142 
00143   loop->refcount += 1;
00144 
00145   return loop;
00146 }
00147 
00148 void
00149 _dbus_loop_unref (DBusLoop *loop)
00150 {
00151   _dbus_assert (loop != NULL);
00152   _dbus_assert (loop->refcount > 0);
00153 
00154   loop->refcount -= 1;
00155   if (loop->refcount == 0)
00156     {
00157       while (loop->need_dispatch)
00158         {
00159           DBusConnection *connection = _dbus_list_pop_first (&loop->need_dispatch);
00160 
00161           dbus_connection_unref (connection);
00162         }
00163 
00164       _dbus_hash_table_unref (loop->watches);
00165       _dbus_socket_set_free (loop->socket_set);
00166       dbus_free (loop);
00167     }
00168 }
00169 
00170 static DBusList **
00171 ensure_watch_table_entry (DBusLoop    *loop,
00172                           DBusPollable fd)
00173 {
00174   DBusList **watches;
00175 
00176   watches = _dbus_hash_table_lookup_pollable (loop->watches, fd);
00177 
00178   if (watches == NULL)
00179     {
00180       watches = dbus_new0 (DBusList *, 1);
00181 
00182       if (watches == NULL)
00183         return watches;
00184 
00185       if (!_dbus_hash_table_insert_pollable (loop->watches, fd, watches))
00186         {
00187           dbus_free (watches);
00188           watches = NULL;
00189         }
00190     }
00191 
00192   return watches;
00193 }
00194 
00195 static void
00196 cull_watches_for_invalid_fd (DBusLoop     *loop,
00197                              DBusPollable  fd)
00198 {
00199   DBusList *link;
00200   DBusList **watches;
00201 
00202   _dbus_warn ("invalid request, socket fd %" DBUS_POLLABLE_FORMAT " not open\n",
00203               _dbus_pollable_printable (fd));
00204   watches = _dbus_hash_table_lookup_pollable (loop->watches, fd);
00205 
00206   if (watches != NULL)
00207     {
00208       for (link = _dbus_list_get_first_link (watches);
00209           link != NULL;
00210           link = _dbus_list_get_next_link (watches, link))
00211         _dbus_watch_invalidate (link->data);
00212     }
00213 
00214   _dbus_hash_table_remove_pollable (loop->watches, fd);
00215 }
00216 
00217 static dbus_bool_t
00218 gc_watch_table_entry (DBusLoop      *loop,
00219                       DBusList     **watches,
00220                       DBusPollable   fd)
00221 {
00222   /* If watches is already NULL we have nothing to do */
00223   if (watches == NULL)
00224     return FALSE;
00225 
00226   /* We can't GC hash table entries if they're non-empty lists */
00227   if (*watches != NULL)
00228     return FALSE;
00229 
00230   _dbus_hash_table_remove_pollable (loop->watches, fd);
00231   return TRUE;
00232 }
00233 
00234 static void
00235 refresh_watches_for_fd (DBusLoop      *loop,
00236                         DBusList     **watches,
00237                         DBusPollable   fd)
00238 {
00239   DBusList *link;
00240   unsigned int flags = 0;
00241   dbus_bool_t interested = FALSE;
00242 
00243   _dbus_assert (_dbus_pollable_is_valid (fd));
00244 
00245   if (watches == NULL)
00246     watches = _dbus_hash_table_lookup_pollable (loop->watches, fd);
00247 
00248   /* we allocated this in the first _dbus_loop_add_watch for the fd, and keep
00249    * it until there are none left */
00250   _dbus_assert (watches != NULL);
00251 
00252   for (link = _dbus_list_get_first_link (watches);
00253       link != NULL;
00254       link = _dbus_list_get_next_link (watches, link))
00255     {
00256       if (dbus_watch_get_enabled (link->data) &&
00257           !_dbus_watch_get_oom_last_time (link->data))
00258         {
00259           flags |= dbus_watch_get_flags (link->data);
00260           interested = TRUE;
00261         }
00262     }
00263 
00264   if (interested)
00265     _dbus_socket_set_enable (loop->socket_set, fd, flags);
00266   else
00267     _dbus_socket_set_disable (loop->socket_set, fd);
00268 }
00269 
00270 dbus_bool_t
00271 _dbus_loop_add_watch (DBusLoop  *loop,
00272                       DBusWatch *watch)
00273 {
00274   DBusPollable fd;
00275   DBusList **watches;
00276 
00277   fd = _dbus_watch_get_pollable (watch);
00278   _dbus_assert (_dbus_pollable_is_valid (fd));
00279 
00280   watches = ensure_watch_table_entry (loop, fd);
00281 
00282   if (watches == NULL)
00283     return FALSE;
00284 
00285   if (!_dbus_list_append (watches, _dbus_watch_ref (watch)))
00286     {
00287       _dbus_watch_unref (watch);
00288       gc_watch_table_entry (loop, watches, fd);
00289 
00290       return FALSE;
00291     }
00292 
00293   if (_dbus_list_length_is_one (watches))
00294     {
00295       if (!_dbus_socket_set_add (loop->socket_set, fd,
00296                                  dbus_watch_get_flags (watch),
00297                                  dbus_watch_get_enabled (watch)))
00298         {
00299           _dbus_hash_table_remove_pollable (loop->watches, fd);
00300           return FALSE;
00301         }
00302     }
00303   else
00304     {
00305       /* we're modifying, not adding, which can't fail with OOM */
00306       refresh_watches_for_fd (loop, watches, fd);
00307     }
00308 
00309   loop->callback_list_serial += 1;
00310   loop->watch_count += 1;
00311   return TRUE;
00312 }
00313 
00314 void
00315 _dbus_loop_toggle_watch (DBusLoop          *loop,
00316                          DBusWatch         *watch)
00317 {
00318   refresh_watches_for_fd (loop, NULL, _dbus_watch_get_pollable (watch));
00319 }
00320 
00321 void
00322 _dbus_loop_remove_watch (DBusLoop         *loop,
00323                          DBusWatch        *watch)
00324 {
00325   DBusList **watches;
00326   DBusList *link;
00327   DBusPollable fd;
00328 
00329   /* This relies on people removing watches before they invalidate them,
00330    * which has been safe since fd.o #33336 was fixed. Assert about it
00331    * so we don't regress. */
00332   fd = _dbus_watch_get_pollable (watch);
00333   _dbus_assert (_dbus_pollable_is_valid (fd));
00334 
00335   watches = _dbus_hash_table_lookup_pollable (loop->watches, fd);
00336 
00337   if (watches != NULL)
00338     {
00339       link = _dbus_list_get_first_link (watches);
00340       while (link != NULL)
00341         {
00342           DBusList *next = _dbus_list_get_next_link (watches, link);
00343           DBusWatch *this = link->data;
00344 
00345           if (this == watch)
00346             {
00347               _dbus_list_remove_link (watches, link);
00348               loop->callback_list_serial += 1;
00349               loop->watch_count -= 1;
00350               _dbus_watch_unref (this);
00351 
00352               /* if that was the last watch for that fd, drop the hash table
00353                * entry, and stop reserving space for it in the socket set */
00354               if (gc_watch_table_entry (loop, watches, fd))
00355                 {
00356                   _dbus_socket_set_remove (loop->socket_set, fd);
00357                 }
00358 
00359               return;
00360             }
00361 
00362           link = next;
00363          }
00364      }
00365 
00366   _dbus_warn ("could not find watch %p to remove\n", watch);
00367 }
00368 
00369 dbus_bool_t
00370 _dbus_loop_add_timeout (DBusLoop           *loop,
00371                         DBusTimeout        *timeout)
00372 {
00373   TimeoutCallback *tcb;
00374 
00375   tcb = timeout_callback_new (timeout);
00376   if (tcb == NULL)
00377     return FALSE;
00378 
00379   if (_dbus_list_append (&loop->timeouts, tcb))
00380     {
00381       loop->callback_list_serial += 1;
00382       loop->timeout_count += 1;
00383     }
00384   else
00385     {
00386       timeout_callback_free (tcb);
00387       return FALSE;
00388     }
00389   
00390   return TRUE;
00391 }
00392 
00393 void
00394 _dbus_loop_remove_timeout (DBusLoop           *loop,
00395                            DBusTimeout        *timeout)
00396 {
00397   DBusList *link;
00398   
00399   link = _dbus_list_get_first_link (&loop->timeouts);
00400   while (link != NULL)
00401     {
00402       DBusList *next = _dbus_list_get_next_link (&loop->timeouts, link);
00403       TimeoutCallback *this = link->data;
00404 
00405       if (this->timeout == timeout)
00406         {
00407           _dbus_list_remove_link (&loop->timeouts, link);
00408           loop->callback_list_serial += 1;
00409           loop->timeout_count -= 1;
00410           timeout_callback_free (this);
00411 
00412           return;
00413         }
00414       
00415       link = next;
00416     }
00417 
00418   _dbus_warn ("could not find timeout %p to remove\n", timeout);
00419 }
00420 
00421 /* Convolutions from GLib, there really must be a better way
00422  * to do this.
00423  */
00424 static dbus_bool_t
00425 check_timeout (long            tv_sec,
00426                long            tv_usec,
00427                TimeoutCallback *tcb,
00428                int             *timeout)
00429 {
00430   long sec_remaining;
00431   long msec_remaining;
00432   long expiration_tv_sec;
00433   long expiration_tv_usec;
00434   long interval_seconds;
00435   long interval_milliseconds;
00436   int interval;
00437 
00438   /* I'm pretty sure this function could suck (a lot) less */
00439   
00440   interval = dbus_timeout_get_interval (tcb->timeout);
00441   
00442   interval_seconds = interval / 1000L;
00443   interval_milliseconds = interval % 1000L;
00444   
00445   expiration_tv_sec = tcb->last_tv_sec + interval_seconds;
00446   expiration_tv_usec = tcb->last_tv_usec + interval_milliseconds * 1000;
00447   if (expiration_tv_usec >= 1000000)
00448     {
00449       expiration_tv_usec -= 1000000;
00450       expiration_tv_sec += 1;
00451     }
00452   
00453   sec_remaining = expiration_tv_sec - tv_sec;
00454   msec_remaining = (expiration_tv_usec - tv_usec) / 1000L;
00455 
00456 #if MAINLOOP_SPEW
00457   _dbus_verbose ("Interval is %ld seconds %ld msecs\n",
00458                  interval_seconds,
00459                  interval_milliseconds);
00460   _dbus_verbose ("Now is  %lu seconds %lu usecs\n",
00461                  tv_sec, tv_usec);
00462   _dbus_verbose ("Last is %lu seconds %lu usecs\n",
00463                  tcb->last_tv_sec, tcb->last_tv_usec);
00464   _dbus_verbose ("Exp is  %lu seconds %lu usecs\n",
00465                  expiration_tv_sec, expiration_tv_usec);
00466   _dbus_verbose ("Pre-correction, sec_remaining %ld msec_remaining %ld\n",
00467                  sec_remaining, msec_remaining);
00468 #endif
00469   
00470   /* We do the following in a rather convoluted fashion to deal with
00471    * the fact that we don't have an integral type big enough to hold
00472    * the difference of two timevals in milliseconds.
00473    */
00474   if (sec_remaining < 0 || (sec_remaining == 0 && msec_remaining < 0))
00475     {
00476       *timeout = 0;
00477     }
00478   else
00479     {
00480       if (msec_remaining < 0)
00481         {
00482           msec_remaining += 1000;
00483           sec_remaining -= 1;
00484         }
00485 
00486       if (sec_remaining > (_DBUS_INT_MAX / 1000) ||
00487           msec_remaining > _DBUS_INT_MAX)
00488         *timeout = _DBUS_INT_MAX;
00489       else
00490         *timeout = sec_remaining * 1000 + msec_remaining;        
00491     }
00492 
00493   if (*timeout > interval)
00494     {
00495       /* This indicates that the system clock probably moved backward */
00496       _dbus_verbose ("System clock set backward! Resetting timeout.\n");
00497       
00498       tcb->last_tv_sec = tv_sec;
00499       tcb->last_tv_usec = tv_usec;
00500 
00501       *timeout = interval;
00502     }
00503   
00504 #if MAINLOOP_SPEW
00505   _dbus_verbose ("  timeout expires in %d milliseconds\n", *timeout);
00506 #endif
00507   
00508   return *timeout == 0;
00509 }
00510 
00511 dbus_bool_t
00512 _dbus_loop_dispatch (DBusLoop *loop)
00513 {
00514 
00515 #if MAINLOOP_SPEW
00516   _dbus_verbose ("  %d connections to dispatch\n", _dbus_list_get_length (&loop->need_dispatch));
00517 #endif
00518   
00519   if (loop->need_dispatch == NULL)
00520     return FALSE;
00521   
00522  next:
00523   while (loop->need_dispatch != NULL)
00524     {
00525       DBusConnection *connection = _dbus_list_pop_first (&loop->need_dispatch);
00526       
00527       while (TRUE)
00528         {
00529           DBusDispatchStatus status;
00530           
00531           status = dbus_connection_dispatch (connection);
00532 
00533           if (status == DBUS_DISPATCH_COMPLETE)
00534             {
00535               dbus_connection_unref (connection);
00536               goto next;
00537             }
00538           else
00539             {
00540               if (status == DBUS_DISPATCH_NEED_MEMORY)
00541                 _dbus_wait_for_memory ();
00542             }
00543         }
00544     }
00545 
00546   return TRUE;
00547 }
00548 
00549 dbus_bool_t
00550 _dbus_loop_queue_dispatch (DBusLoop       *loop,
00551                            DBusConnection *connection)
00552 {
00553   if (_dbus_list_append (&loop->need_dispatch, connection))
00554     {
00555       dbus_connection_ref (connection);
00556       return TRUE;
00557     }
00558   else
00559     return FALSE;
00560 }
00561 
00562 /* Returns TRUE if we invoked any timeouts or have ready file
00563  * descriptors, which is just used in test code as a debug hack
00564  */
00565 
00566 dbus_bool_t
00567 _dbus_loop_iterate (DBusLoop     *loop,
00568                     dbus_bool_t   block)
00569 {  
00570 #define N_STACK_DESCRIPTORS 64
00571   dbus_bool_t retval;
00572   DBusSocketEvent ready_fds[N_STACK_DESCRIPTORS];
00573   int i;
00574   DBusList *link;
00575   int n_ready;
00576   int initial_serial;
00577   long timeout;
00578   int orig_depth;
00579 
00580   retval = FALSE;      
00581 
00582   orig_depth = loop->depth;
00583   
00584 #if MAINLOOP_SPEW
00585   _dbus_verbose ("Iteration block=%d depth=%d timeout_count=%d watch_count=%d\n",
00586                  block, loop->depth, loop->timeout_count, loop->watch_count);
00587 #endif
00588 
00589   if (_dbus_hash_table_get_n_entries (loop->watches) == 0 &&
00590       loop->timeouts == NULL)
00591     goto next_iteration;
00592 
00593   timeout = -1;
00594   if (loop->timeout_count > 0)
00595     {
00596       long tv_sec;
00597       long tv_usec;
00598       
00599       _dbus_get_monotonic_time (&tv_sec, &tv_usec);
00600 
00601       link = _dbus_list_get_first_link (&loop->timeouts);
00602       while (link != NULL)
00603         {
00604           DBusList *next = _dbus_list_get_next_link (&loop->timeouts, link);
00605           TimeoutCallback *tcb = link->data;
00606 
00607           if (dbus_timeout_get_enabled (tcb->timeout))
00608             {
00609               int msecs_remaining;
00610 
00611               check_timeout (tv_sec, tv_usec, tcb, &msecs_remaining);
00612 
00613               if (timeout < 0)
00614                 timeout = msecs_remaining;
00615               else
00616                 timeout = MIN (msecs_remaining, timeout);
00617 
00618 #if MAINLOOP_SPEW
00619               _dbus_verbose ("  timeout added, %d remaining, aggregate timeout %ld\n",
00620                              msecs_remaining, timeout);
00621 #endif
00622               
00623               _dbus_assert (timeout >= 0);
00624                   
00625               if (timeout == 0)
00626                 break; /* it's not going to get shorter... */
00627             }
00628 #if MAINLOOP_SPEW
00629           else
00630             {
00631               _dbus_verbose ("  skipping disabled timeout\n");
00632             }
00633 #endif
00634           
00635           link = next;
00636         }
00637     }
00638 
00639   /* Never block if we have stuff to dispatch */
00640   if (!block || loop->need_dispatch != NULL)
00641     {
00642       timeout = 0;
00643 #if MAINLOOP_SPEW
00644       _dbus_verbose ("  timeout is 0 as we aren't blocking\n");
00645 #endif
00646     }
00647 
00648   /* if a watch was OOM last time, don't wait longer than the OOM
00649    * wait to re-enable it
00650    */
00651   if (loop->oom_watch_pending)
00652     timeout = MIN (timeout, _dbus_get_oom_wait ());
00653 
00654 #if MAINLOOP_SPEW
00655   _dbus_verbose ("  polling on %d descriptors timeout %ld\n", _DBUS_N_ELEMENTS (ready_fds), timeout);
00656 #endif
00657 
00658   n_ready = _dbus_socket_set_poll (loop->socket_set, ready_fds,
00659                                    _DBUS_N_ELEMENTS (ready_fds), timeout);
00660 
00661   /* re-enable any watches we skipped this time */
00662   if (loop->oom_watch_pending)
00663     {
00664       DBusHashIter hash_iter;
00665 
00666       loop->oom_watch_pending = FALSE;
00667 
00668       _dbus_hash_iter_init (loop->watches, &hash_iter);
00669 
00670       while (_dbus_hash_iter_next (&hash_iter))
00671         {
00672           DBusList **watches;
00673           DBusPollable fd;
00674           dbus_bool_t changed;
00675 
00676           changed = FALSE;
00677           fd = _dbus_hash_iter_get_pollable_key (&hash_iter);
00678           watches = _dbus_hash_iter_get_value (&hash_iter);
00679 
00680           for (link = _dbus_list_get_first_link (watches);
00681               link != NULL;
00682               link = _dbus_list_get_next_link (watches, link))
00683             {
00684               DBusWatch *watch = link->data;
00685 
00686               if (_dbus_watch_get_oom_last_time (watch))
00687                 {
00688                   _dbus_watch_set_oom_last_time (watch, FALSE);
00689                   changed = TRUE;
00690                 }
00691             }
00692 
00693           if (changed)
00694             refresh_watches_for_fd (loop, watches, fd);
00695         }
00696 
00697       retval = TRUE; /* return TRUE here to keep the loop going,
00698                       * since we don't know the watch was inactive */
00699     }
00700 
00701   initial_serial = loop->callback_list_serial;
00702 
00703   if (loop->timeout_count > 0)
00704     {
00705       long tv_sec;
00706       long tv_usec;
00707 
00708       _dbus_get_monotonic_time (&tv_sec, &tv_usec);
00709 
00710       /* It'd be nice to avoid this O(n) thingy here */
00711       link = _dbus_list_get_first_link (&loop->timeouts);
00712       while (link != NULL)
00713         {
00714           DBusList *next = _dbus_list_get_next_link (&loop->timeouts, link);
00715           TimeoutCallback *tcb = link->data;
00716 
00717           if (initial_serial != loop->callback_list_serial)
00718             goto next_iteration;
00719 
00720           if (loop->depth != orig_depth)
00721             goto next_iteration;
00722 
00723           if (dbus_timeout_get_enabled (tcb->timeout))
00724             {
00725               int msecs_remaining;
00726               
00727               if (check_timeout (tv_sec, tv_usec,
00728                                  tcb, &msecs_remaining))
00729                 {
00730                   /* Save last callback time and fire this timeout */
00731                   tcb->last_tv_sec = tv_sec;
00732                   tcb->last_tv_usec = tv_usec;
00733 
00734 #if MAINLOOP_SPEW
00735                   _dbus_verbose ("  invoking timeout\n");
00736 #endif
00737 
00738                   /* can theoretically return FALSE on OOM, but we just
00739                    * let it fire again later - in practice that's what
00740                    * every wrapper callback in dbus-daemon used to do */
00741                   dbus_timeout_handle (tcb->timeout);
00742 
00743                   retval = TRUE;
00744                 }
00745               else
00746                 {
00747 #if MAINLOOP_SPEW
00748                   _dbus_verbose ("  timeout has not expired\n");
00749 #endif
00750                 }
00751             }
00752 #if MAINLOOP_SPEW
00753           else
00754             {
00755               _dbus_verbose ("  skipping invocation of disabled timeout\n");
00756             }
00757 #endif
00758 
00759           link = next;
00760         }
00761     }
00762 
00763   if (n_ready > 0)
00764     {
00765       for (i = 0; i < n_ready; i++)
00766         {
00767           DBusList **watches;
00768           DBusList *next;
00769           unsigned int condition;
00770           dbus_bool_t any_oom;
00771 
00772           /* FIXME I think this "restart if we change the watches"
00773            * approach could result in starving watches
00774            * toward the end of the list.
00775            */
00776           if (initial_serial != loop->callback_list_serial)
00777             goto next_iteration;
00778 
00779           if (loop->depth != orig_depth)
00780             goto next_iteration;
00781 
00782           _dbus_assert (ready_fds[i].flags != 0);
00783 
00784           if (_DBUS_UNLIKELY (ready_fds[i].flags & _DBUS_WATCH_NVAL))
00785             {
00786               cull_watches_for_invalid_fd (loop, ready_fds[i].fd);
00787               goto next_iteration;
00788             }
00789 
00790           condition = ready_fds[i].flags;
00791           _dbus_assert ((condition & _DBUS_WATCH_NVAL) == 0);
00792 
00793           /* condition may still be 0 if we got some
00794            * weird POLLFOO thing like POLLWRBAND
00795            */
00796           if (condition == 0)
00797             continue;
00798 
00799           watches = _dbus_hash_table_lookup_pollable (loop->watches,
00800                                                       ready_fds[i].fd);
00801 
00802           if (watches == NULL)
00803             continue;
00804 
00805           any_oom = FALSE;
00806 
00807           for (link = _dbus_list_get_first_link (watches);
00808               link != NULL;
00809               link = next)
00810             {
00811               DBusWatch *watch = link->data;
00812 
00813               next = _dbus_list_get_next_link (watches, link);
00814 
00815               if (dbus_watch_get_enabled (watch))
00816                 {
00817                   dbus_bool_t oom;
00818 
00819                   oom = !dbus_watch_handle (watch, condition);
00820 
00821                   if (oom)
00822                     {
00823                       _dbus_watch_set_oom_last_time (watch, TRUE);
00824                       loop->oom_watch_pending = TRUE;
00825                       any_oom = TRUE;
00826                     }
00827 
00828 #if MAINLOOP_SPEW
00829                   _dbus_verbose ("  Invoked watch, oom = %d\n", oom);
00830 #endif
00831                   retval = TRUE;
00832 
00833                   /* We re-check this every time, in case the callback
00834                    * added/removed watches, which might make our position in
00835                    * the linked list invalid. See the FIXME above. */
00836                   if (initial_serial != loop->callback_list_serial ||
00837                       loop->depth != orig_depth)
00838                     {
00839                       if (any_oom)
00840                         refresh_watches_for_fd (loop, NULL, ready_fds[i].fd);
00841 
00842                       goto next_iteration;
00843                     }
00844                 }
00845             }
00846 
00847           if (any_oom)
00848             refresh_watches_for_fd (loop, watches, ready_fds[i].fd);
00849         }
00850     }
00851       
00852  next_iteration:
00853 #if MAINLOOP_SPEW
00854   _dbus_verbose ("  moving to next iteration\n");
00855 #endif
00856 
00857   if (_dbus_loop_dispatch (loop))
00858     retval = TRUE;
00859   
00860 #if MAINLOOP_SPEW
00861   _dbus_verbose ("Returning %d\n", retval);
00862 #endif
00863   
00864   return retval;
00865 }
00866 
00867 void
00868 _dbus_loop_run (DBusLoop *loop)
00869 {
00870   int our_exit_depth;
00871 
00872   _dbus_assert (loop->depth >= 0);
00873   
00874   _dbus_loop_ref (loop);
00875   
00876   our_exit_depth = loop->depth;
00877   loop->depth += 1;
00878 
00879   _dbus_verbose ("Running main loop, depth %d -> %d\n",
00880                  loop->depth - 1, loop->depth);
00881   
00882   while (loop->depth != our_exit_depth)
00883     _dbus_loop_iterate (loop, TRUE);
00884 
00885   _dbus_loop_unref (loop);
00886 }
00887 
00888 void
00889 _dbus_loop_quit (DBusLoop *loop)
00890 {
00891   _dbus_assert (loop->depth > 0);  
00892   
00893   loop->depth -= 1;
00894 
00895   _dbus_verbose ("Quit main loop, depth %d -> %d\n",
00896                  loop->depth + 1, loop->depth);
00897 }
00898 
00899 int
00900 _dbus_get_oom_wait (void)
00901 {
00902 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00903   /* make tests go fast */
00904   return 0;
00905 #else
00906   return 500;
00907 #endif
00908 }
00909 
00910 void
00911 _dbus_wait_for_memory (void)
00912 {
00913   _dbus_verbose ("Waiting for more memory\n");
00914   _dbus_sleep_milliseconds (_dbus_get_oom_wait ());
00915 }
00916 
00917 #endif /* !DOXYGEN_SHOULD_SKIP_THIS */