Main Page | Modules | Data Structures | File List | Data Fields | Related Pages

dbus-mainloop.c

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

Generated on Tue Feb 10 18:14:04 2004 for D-BUS by doxygen 1.3.5