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