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