dbus-mainloop.c

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

Generated on Sat Dec 6 19:43:43 2008 for D-Bus by  doxygen 1.5.1