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