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
35static const char*
36watch_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
54struct 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
65typedef enum
66{
67  CALLBACK_WATCH,
68  CALLBACK_TIMEOUT
69} CallbackType;
70
71typedef struct
72{
73  int refcount;
74  CallbackType type;
75  void *data;
76  DBusFreeFunction free_data_func;
77} Callback;
78
79typedef 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
88typedef 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
100static WatchCallback*
101watch_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
123static TimeoutCallback*
124timeout_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
147static Callback *
148callback_ref (Callback *cb)
149{
150  _dbus_assert (cb->refcount > 0);
151
152  cb->refcount += 1;
153
154  return cb;
155}
156
157static void
158callback_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
173static dbus_bool_t
174add_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
195static void
196remove_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
216DBusLoop*
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
230DBusLoop *
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
241void
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
261dbus_bool_t
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
284void
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
315dbus_bool_t
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
338void
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 */
372static dbus_bool_t
373check_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
462dbus_bool_t
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
500dbus_bool_t
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
517dbus_bool_t
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
858void
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
879void
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
890int
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
901void
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