• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List

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

Generated on Fri Jul 11 2014 20:41:36 for D-Bus by  doxygen 1.7.1