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