D-Bus  1.8.16
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 struct DBusLoop
38 {
39  int refcount;
41  DBusHashTable *watches;
42  DBusSocketSet *socket_set;
43  DBusList *timeouts;
44  int callback_list_serial;
45  int watch_count;
46  int timeout_count;
47  int depth;
48  DBusList *need_dispatch;
51  unsigned oom_watch_pending : 1;
52 };
53 
54 typedef struct
55 {
56  DBusTimeout *timeout;
57  unsigned long last_tv_sec;
58  unsigned long last_tv_usec;
59 } TimeoutCallback;
60 
61 #define TIMEOUT_CALLBACK(callback) ((TimeoutCallback*)callback)
62 
63 static TimeoutCallback*
64 timeout_callback_new (DBusTimeout *timeout)
65 {
66  TimeoutCallback *cb;
67 
68  cb = dbus_new (TimeoutCallback, 1);
69  if (cb == NULL)
70  return NULL;
71 
72  cb->timeout = timeout;
73  _dbus_get_monotonic_time (&cb->last_tv_sec,
74  &cb->last_tv_usec);
75  return cb;
76 }
77 
78 static void
79 timeout_callback_free (TimeoutCallback *cb)
80 {
81  dbus_free (cb);
82 }
83 
84 static void
85 free_watch_table_entry (void *data)
86 {
87  DBusList **watches = data;
88  DBusWatch *watch;
89 
90  /* DBusHashTable sometimes calls free_function(NULL) even if you never
91  * have NULL as a value */
92  if (watches == NULL)
93  return;
94 
95  for (watch = _dbus_list_pop_first (watches);
96  watch != NULL;
97  watch = _dbus_list_pop_first (watches))
98  {
99  _dbus_watch_unref (watch);
100  }
101 
102  _dbus_assert (*watches == NULL);
103  dbus_free (watches);
104 }
105 
106 DBusLoop*
107 _dbus_loop_new (void)
108 {
109  DBusLoop *loop;
110 
111  loop = dbus_new0 (DBusLoop, 1);
112  if (loop == NULL)
113  return NULL;
114 
115  loop->watches = _dbus_hash_table_new (DBUS_HASH_INT, NULL,
116  free_watch_table_entry);
117 
118  loop->socket_set = _dbus_socket_set_new (0);
119 
120  if (loop->watches == NULL || loop->socket_set == NULL)
121  {
122  if (loop->watches != NULL)
123  _dbus_hash_table_unref (loop->watches);
124 
125  if (loop->socket_set != NULL)
126  _dbus_socket_set_free (loop->socket_set);
127 
128  dbus_free (loop);
129  return NULL;
130  }
131 
132  loop->refcount = 1;
133 
134  return loop;
135 }
136 
137 DBusLoop *
138 _dbus_loop_ref (DBusLoop *loop)
139 {
140  _dbus_assert (loop != NULL);
141  _dbus_assert (loop->refcount > 0);
142 
143  loop->refcount += 1;
144 
145  return loop;
146 }
147 
148 void
149 _dbus_loop_unref (DBusLoop *loop)
150 {
151  _dbus_assert (loop != NULL);
152  _dbus_assert (loop->refcount > 0);
153 
154  loop->refcount -= 1;
155  if (loop->refcount == 0)
156  {
157  while (loop->need_dispatch)
158  {
159  DBusConnection *connection = _dbus_list_pop_first (&loop->need_dispatch);
160 
161  dbus_connection_unref (connection);
162  }
163 
164  _dbus_hash_table_unref (loop->watches);
165  _dbus_socket_set_free (loop->socket_set);
166  dbus_free (loop);
167  }
168 }
169 
170 static DBusList **
171 ensure_watch_table_entry (DBusLoop *loop,
172  int fd)
173 {
174  DBusList **watches;
175 
176  watches = _dbus_hash_table_lookup_int (loop->watches, fd);
177 
178  if (watches == NULL)
179  {
180  watches = dbus_new0 (DBusList *, 1);
181 
182  if (watches == NULL)
183  return watches;
184 
185  if (!_dbus_hash_table_insert_int (loop->watches, fd, watches))
186  {
187  dbus_free (watches);
188  watches = NULL;
189  }
190  }
191 
192  return watches;
193 }
194 
195 static void
196 cull_watches_for_invalid_fd (DBusLoop *loop,
197  int fd)
198 {
199  DBusList *link;
200  DBusList **watches;
201 
202  _dbus_warn ("invalid request, socket fd %d not open\n", fd);
203  watches = _dbus_hash_table_lookup_int (loop->watches, fd);
204 
205  if (watches != NULL)
206  {
207  for (link = _dbus_list_get_first_link (watches);
208  link != NULL;
209  link = _dbus_list_get_next_link (watches, link))
211  }
212 
213  _dbus_hash_table_remove_int (loop->watches, fd);
214 }
215 
216 static dbus_bool_t
217 gc_watch_table_entry (DBusLoop *loop,
218  DBusList **watches,
219  int fd)
220 {
221  /* If watches is already NULL we have nothing to do */
222  if (watches == NULL)
223  return FALSE;
224 
225  /* We can't GC hash table entries if they're non-empty lists */
226  if (*watches != NULL)
227  return FALSE;
228 
229  _dbus_hash_table_remove_int (loop->watches, fd);
230  return TRUE;
231 }
232 
233 static void
234 refresh_watches_for_fd (DBusLoop *loop,
235  DBusList **watches,
236  int fd)
237 {
238  DBusList *link;
239  unsigned int flags = 0;
240  dbus_bool_t interested = FALSE;
241 
242  _dbus_assert (fd != -1);
243 
244  if (watches == NULL)
245  watches = _dbus_hash_table_lookup_int (loop->watches, fd);
246 
247  /* we allocated this in the first _dbus_loop_add_watch for the fd, and keep
248  * it until there are none left */
249  _dbus_assert (watches != NULL);
250 
251  for (link = _dbus_list_get_first_link (watches);
252  link != NULL;
253  link = _dbus_list_get_next_link (watches, link))
254  {
255  if (dbus_watch_get_enabled (link->data) &&
256  !_dbus_watch_get_oom_last_time (link->data))
257  {
258  flags |= dbus_watch_get_flags (link->data);
259  interested = TRUE;
260  }
261  }
262 
263  if (interested)
264  _dbus_socket_set_enable (loop->socket_set, fd, flags);
265  else
266  _dbus_socket_set_disable (loop->socket_set, fd);
267 }
268 
270 _dbus_loop_add_watch (DBusLoop *loop,
271  DBusWatch *watch)
272 {
273  int fd;
274  DBusList **watches;
275 
276  fd = dbus_watch_get_socket (watch);
277  _dbus_assert (fd != -1);
278 
279  watches = ensure_watch_table_entry (loop, fd);
280 
281  if (watches == NULL)
282  return FALSE;
283 
284  if (!_dbus_list_append (watches, _dbus_watch_ref (watch)))
285  {
286  _dbus_watch_unref (watch);
287  gc_watch_table_entry (loop, watches, fd);
288 
289  return FALSE;
290  }
291 
292  if (_dbus_list_length_is_one (watches))
293  {
294  if (!_dbus_socket_set_add (loop->socket_set, fd,
295  dbus_watch_get_flags (watch),
296  dbus_watch_get_enabled (watch)))
297  {
298  _dbus_hash_table_remove_int (loop->watches, fd);
299  return FALSE;
300  }
301  }
302  else
303  {
304  /* we're modifying, not adding, which can't fail with OOM */
305  refresh_watches_for_fd (loop, watches, fd);
306  }
307 
308  loop->callback_list_serial += 1;
309  loop->watch_count += 1;
310  return TRUE;
311 }
312 
313 void
314 _dbus_loop_toggle_watch (DBusLoop *loop,
315  DBusWatch *watch)
316 {
317  refresh_watches_for_fd (loop, NULL, dbus_watch_get_socket (watch));
318 }
319 
320 void
321 _dbus_loop_remove_watch (DBusLoop *loop,
322  DBusWatch *watch)
323 {
324  DBusList **watches;
325  DBusList *link;
326  int fd;
327 
328  /* This relies on people removing watches before they invalidate them,
329  * which has been safe since fd.o #33336 was fixed. Assert about it
330  * so we don't regress. */
331  fd = dbus_watch_get_socket (watch);
332  _dbus_assert (fd != -1);
333 
334  watches = _dbus_hash_table_lookup_int (loop->watches, fd);
335 
336  if (watches != NULL)
337  {
338  link = _dbus_list_get_first_link (watches);
339  while (link != NULL)
340  {
341  DBusList *next = _dbus_list_get_next_link (watches, link);
342  DBusWatch *this = link->data;
343 
344  if (this == watch)
345  {
346  _dbus_list_remove_link (watches, link);
347  loop->callback_list_serial += 1;
348  loop->watch_count -= 1;
349  _dbus_watch_unref (this);
350 
351  /* if that was the last watch for that fd, drop the hash table
352  * entry, and stop reserving space for it in the socket set */
353  if (gc_watch_table_entry (loop, watches, fd))
354  {
355  _dbus_socket_set_remove (loop->socket_set, fd);
356  }
357 
358  return;
359  }
360 
361  link = next;
362  }
363  }
364 
365  _dbus_warn ("could not find watch %p to remove\n", watch);
366 }
367 
369 _dbus_loop_add_timeout (DBusLoop *loop,
370  DBusTimeout *timeout)
371 {
372  TimeoutCallback *tcb;
373 
374  tcb = timeout_callback_new (timeout);
375  if (tcb == NULL)
376  return FALSE;
377 
378  if (_dbus_list_append (&loop->timeouts, tcb))
379  {
380  loop->callback_list_serial += 1;
381  loop->timeout_count += 1;
382  }
383  else
384  {
385  timeout_callback_free (tcb);
386  return FALSE;
387  }
388 
389  return TRUE;
390 }
391 
392 void
393 _dbus_loop_remove_timeout (DBusLoop *loop,
394  DBusTimeout *timeout)
395 {
396  DBusList *link;
397 
398  link = _dbus_list_get_first_link (&loop->timeouts);
399  while (link != NULL)
400  {
401  DBusList *next = _dbus_list_get_next_link (&loop->timeouts, link);
402  TimeoutCallback *this = link->data;
403 
404  if (this->timeout == timeout)
405  {
406  _dbus_list_remove_link (&loop->timeouts, link);
407  loop->callback_list_serial += 1;
408  loop->timeout_count -= 1;
409  timeout_callback_free (this);
410 
411  return;
412  }
413 
414  link = next;
415  }
416 
417  _dbus_warn ("could not find timeout %p to remove\n", timeout);
418 }
419 
420 /* Convolutions from GLib, there really must be a better way
421  * to do this.
422  */
423 static dbus_bool_t
424 check_timeout (unsigned long tv_sec,
425  unsigned long tv_usec,
426  TimeoutCallback *tcb,
427  int *timeout)
428 {
429  long sec_remaining;
430  long msec_remaining;
431  unsigned long expiration_tv_sec;
432  unsigned long expiration_tv_usec;
433  long interval_seconds;
434  long interval_milliseconds;
435  int interval;
436 
437  /* I'm pretty sure this function could suck (a lot) less */
438 
439  interval = dbus_timeout_get_interval (tcb->timeout);
440 
441  interval_seconds = interval / 1000L;
442  interval_milliseconds = interval % 1000L;
443 
444  expiration_tv_sec = tcb->last_tv_sec + interval_seconds;
445  expiration_tv_usec = tcb->last_tv_usec + interval_milliseconds * 1000;
446  if (expiration_tv_usec >= 1000000)
447  {
448  expiration_tv_usec -= 1000000;
449  expiration_tv_sec += 1;
450  }
451 
452  sec_remaining = expiration_tv_sec - tv_sec;
453  /* need to force this to be signed, as it is intended to sometimes
454  * produce a negative result
455  */
456  msec_remaining = ((long) expiration_tv_usec - (long) tv_usec) / 1000L;
457 
458 #if MAINLOOP_SPEW
459  _dbus_verbose ("Interval is %ld seconds %ld msecs\n",
460  interval_seconds,
461  interval_milliseconds);
462  _dbus_verbose ("Now is %lu seconds %lu usecs\n",
463  tv_sec, tv_usec);
464  _dbus_verbose ("Last is %lu seconds %lu usecs\n",
465  tcb->last_tv_sec, tcb->last_tv_usec);
466  _dbus_verbose ("Exp is %lu seconds %lu usecs\n",
467  expiration_tv_sec, expiration_tv_usec);
468  _dbus_verbose ("Pre-correction, sec_remaining %ld msec_remaining %ld\n",
469  sec_remaining, msec_remaining);
470 #endif
471 
472  /* We do the following in a rather convoluted fashion to deal with
473  * the fact that we don't have an integral type big enough to hold
474  * the difference of two timevals in milliseconds.
475  */
476  if (sec_remaining < 0 || (sec_remaining == 0 && msec_remaining < 0))
477  {
478  *timeout = 0;
479  }
480  else
481  {
482  if (msec_remaining < 0)
483  {
484  msec_remaining += 1000;
485  sec_remaining -= 1;
486  }
487 
488  if (sec_remaining > (_DBUS_INT_MAX / 1000) ||
489  msec_remaining > _DBUS_INT_MAX)
490  *timeout = _DBUS_INT_MAX;
491  else
492  *timeout = sec_remaining * 1000 + msec_remaining;
493  }
494 
495  if (*timeout > interval)
496  {
497  /* This indicates that the system clock probably moved backward */
498  _dbus_verbose ("System clock set backward! Resetting timeout.\n");
499 
500  tcb->last_tv_sec = tv_sec;
501  tcb->last_tv_usec = tv_usec;
502 
503  *timeout = interval;
504  }
505 
506 #if MAINLOOP_SPEW
507  _dbus_verbose (" timeout expires in %d milliseconds\n", *timeout);
508 #endif
509 
510  return *timeout == 0;
511 }
512 
514 _dbus_loop_dispatch (DBusLoop *loop)
515 {
516 
517 #if MAINLOOP_SPEW
518  _dbus_verbose (" %d connections to dispatch\n", _dbus_list_get_length (&loop->need_dispatch));
519 #endif
520 
521  if (loop->need_dispatch == NULL)
522  return FALSE;
523 
524  next:
525  while (loop->need_dispatch != NULL)
526  {
527  DBusConnection *connection = _dbus_list_pop_first (&loop->need_dispatch);
528 
529  while (TRUE)
530  {
531  DBusDispatchStatus status;
532 
533  status = dbus_connection_dispatch (connection);
534 
535  if (status == DBUS_DISPATCH_COMPLETE)
536  {
537  dbus_connection_unref (connection);
538  goto next;
539  }
540  else
541  {
542  if (status == DBUS_DISPATCH_NEED_MEMORY)
543  _dbus_wait_for_memory ();
544  }
545  }
546  }
547 
548  return TRUE;
549 }
550 
552 _dbus_loop_queue_dispatch (DBusLoop *loop,
553  DBusConnection *connection)
554 {
555  if (_dbus_list_append (&loop->need_dispatch, connection))
556  {
557  dbus_connection_ref (connection);
558  return TRUE;
559  }
560  else
561  return FALSE;
562 }
563 
564 /* Returns TRUE if we invoked any timeouts or have ready file
565  * descriptors, which is just used in test code as a debug hack
566  */
567 
569 _dbus_loop_iterate (DBusLoop *loop,
570  dbus_bool_t block)
571 {
572 #define N_STACK_DESCRIPTORS 64
573  dbus_bool_t retval;
574  DBusSocketEvent ready_fds[N_STACK_DESCRIPTORS];
575  int i;
576  DBusList *link;
577  int n_ready;
578  int initial_serial;
579  long timeout;
580  int orig_depth;
581 
582  retval = FALSE;
583 
584  orig_depth = loop->depth;
585 
586 #if MAINLOOP_SPEW
587  _dbus_verbose ("Iteration block=%d depth=%d timeout_count=%d watch_count=%d\n",
588  block, loop->depth, loop->timeout_count, loop->watch_count);
589 #endif
590 
591  if (_dbus_hash_table_get_n_entries (loop->watches) == 0 &&
592  loop->timeouts == NULL)
593  goto next_iteration;
594 
595  timeout = -1;
596  if (loop->timeout_count > 0)
597  {
598  unsigned long tv_sec;
599  unsigned long tv_usec;
600 
601  _dbus_get_monotonic_time (&tv_sec, &tv_usec);
602 
603  link = _dbus_list_get_first_link (&loop->timeouts);
604  while (link != NULL)
605  {
606  DBusList *next = _dbus_list_get_next_link (&loop->timeouts, link);
607  TimeoutCallback *tcb = link->data;
608 
609  if (dbus_timeout_get_enabled (tcb->timeout))
610  {
611  int msecs_remaining;
612 
613  check_timeout (tv_sec, tv_usec, tcb, &msecs_remaining);
614 
615  if (timeout < 0)
616  timeout = msecs_remaining;
617  else
618  timeout = MIN (msecs_remaining, timeout);
619 
620 #if MAINLOOP_SPEW
621  _dbus_verbose (" timeout added, %d remaining, aggregate timeout %ld\n",
622  msecs_remaining, timeout);
623 #endif
624 
625  _dbus_assert (timeout >= 0);
626 
627  if (timeout == 0)
628  break; /* it's not going to get shorter... */
629  }
630 #if MAINLOOP_SPEW
631  else
632  {
633  _dbus_verbose (" skipping disabled timeout\n");
634  }
635 #endif
636 
637  link = next;
638  }
639  }
640 
641  /* Never block if we have stuff to dispatch */
642  if (!block || loop->need_dispatch != NULL)
643  {
644  timeout = 0;
645 #if MAINLOOP_SPEW
646  _dbus_verbose (" timeout is 0 as we aren't blocking\n");
647 #endif
648  }
649 
650  /* if a watch was OOM last time, don't wait longer than the OOM
651  * wait to re-enable it
652  */
653  if (loop->oom_watch_pending)
654  timeout = MIN (timeout, _dbus_get_oom_wait ());
655 
656 #if MAINLOOP_SPEW
657  _dbus_verbose (" polling on %d descriptors timeout %ld\n", _DBUS_N_ELEMENTS (ready_fds), timeout);
658 #endif
659 
660  n_ready = _dbus_socket_set_poll (loop->socket_set, ready_fds,
661  _DBUS_N_ELEMENTS (ready_fds), timeout);
662 
663  /* re-enable any watches we skipped this time */
664  if (loop->oom_watch_pending)
665  {
666  DBusHashIter hash_iter;
667 
668  loop->oom_watch_pending = FALSE;
669 
670  _dbus_hash_iter_init (loop->watches, &hash_iter);
671 
672  while (_dbus_hash_iter_next (&hash_iter))
673  {
674  DBusList **watches;
675  int fd;
676  dbus_bool_t changed;
677 
678  changed = FALSE;
679  fd = _dbus_hash_iter_get_int_key (&hash_iter);
680  watches = _dbus_hash_iter_get_value (&hash_iter);
681 
682  for (link = _dbus_list_get_first_link (watches);
683  link != NULL;
684  link = _dbus_list_get_next_link (watches, link))
685  {
686  DBusWatch *watch = link->data;
687 
688  if (_dbus_watch_get_oom_last_time (watch))
689  {
690  _dbus_watch_set_oom_last_time (watch, FALSE);
691  changed = TRUE;
692  }
693  }
694 
695  if (changed)
696  refresh_watches_for_fd (loop, watches, fd);
697  }
698 
699  retval = TRUE; /* return TRUE here to keep the loop going,
700  * since we don't know the watch was inactive */
701  }
702 
703  initial_serial = loop->callback_list_serial;
704 
705  if (loop->timeout_count > 0)
706  {
707  unsigned long tv_sec;
708  unsigned long tv_usec;
709 
710  _dbus_get_monotonic_time (&tv_sec, &tv_usec);
711 
712  /* It'd be nice to avoid this O(n) thingy here */
713  link = _dbus_list_get_first_link (&loop->timeouts);
714  while (link != NULL)
715  {
716  DBusList *next = _dbus_list_get_next_link (&loop->timeouts, link);
717  TimeoutCallback *tcb = link->data;
718 
719  if (initial_serial != loop->callback_list_serial)
720  goto next_iteration;
721 
722  if (loop->depth != orig_depth)
723  goto next_iteration;
724 
725  if (dbus_timeout_get_enabled (tcb->timeout))
726  {
727  int msecs_remaining;
728 
729  if (check_timeout (tv_sec, tv_usec,
730  tcb, &msecs_remaining))
731  {
732  /* Save last callback time and fire this timeout */
733  tcb->last_tv_sec = tv_sec;
734  tcb->last_tv_usec = tv_usec;
735 
736 #if MAINLOOP_SPEW
737  _dbus_verbose (" invoking timeout\n");
738 #endif
739 
740  /* can theoretically return FALSE on OOM, but we just
741  * let it fire again later - in practice that's what
742  * every wrapper callback in dbus-daemon used to do */
743  dbus_timeout_handle (tcb->timeout);
744 
745  retval = TRUE;
746  }
747  else
748  {
749 #if MAINLOOP_SPEW
750  _dbus_verbose (" timeout has not expired\n");
751 #endif
752  }
753  }
754 #if MAINLOOP_SPEW
755  else
756  {
757  _dbus_verbose (" skipping invocation of disabled timeout\n");
758  }
759 #endif
760 
761  link = next;
762  }
763  }
764 
765  if (n_ready > 0)
766  {
767  for (i = 0; i < n_ready; i++)
768  {
769  DBusList **watches;
770  DBusList *next;
771  unsigned int condition;
772  dbus_bool_t any_oom;
773 
774  /* FIXME I think this "restart if we change the watches"
775  * approach could result in starving watches
776  * toward the end of the list.
777  */
778  if (initial_serial != loop->callback_list_serial)
779  goto next_iteration;
780 
781  if (loop->depth != orig_depth)
782  goto next_iteration;
783 
784  _dbus_assert (ready_fds[i].flags != 0);
785 
786  if (_DBUS_UNLIKELY (ready_fds[i].flags & _DBUS_WATCH_NVAL))
787  {
788  cull_watches_for_invalid_fd (loop, ready_fds[i].fd);
789  goto next_iteration;
790  }
791 
792  condition = ready_fds[i].flags;
793  _dbus_assert ((condition & _DBUS_WATCH_NVAL) == 0);
794 
795  /* condition may still be 0 if we got some
796  * weird POLLFOO thing like POLLWRBAND
797  */
798  if (condition == 0)
799  continue;
800 
801  watches = _dbus_hash_table_lookup_int (loop->watches,
802  ready_fds[i].fd);
803 
804  if (watches == NULL)
805  continue;
806 
807  any_oom = FALSE;
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  loop->oom_watch_pending = TRUE;
827  any_oom = TRUE;
828  }
829 
830 #if MAINLOOP_SPEW
831  _dbus_verbose (" Invoked watch, oom = %d\n", oom);
832 #endif
833  retval = TRUE;
834 
835  /* We re-check this every time, in case the callback
836  * added/removed watches, which might make our position in
837  * the linked list invalid. See the FIXME above. */
838  if (initial_serial != loop->callback_list_serial ||
839  loop->depth != orig_depth)
840  {
841  if (any_oom)
842  refresh_watches_for_fd (loop, NULL, ready_fds[i].fd);
843 
844  goto next_iteration;
845  }
846  }
847  }
848 
849  if (any_oom)
850  refresh_watches_for_fd (loop, watches, ready_fds[i].fd);
851  }
852  }
853 
854  next_iteration:
855 #if MAINLOOP_SPEW
856  _dbus_verbose (" moving to next iteration\n");
857 #endif
858 
859  if (_dbus_loop_dispatch (loop))
860  retval = TRUE;
861 
862 #if MAINLOOP_SPEW
863  _dbus_verbose ("Returning %d\n", retval);
864 #endif
865 
866  return retval;
867 }
868 
869 void
870 _dbus_loop_run (DBusLoop *loop)
871 {
872  int our_exit_depth;
873 
874  _dbus_assert (loop->depth >= 0);
875 
876  _dbus_loop_ref (loop);
877 
878  our_exit_depth = loop->depth;
879  loop->depth += 1;
880 
881  _dbus_verbose ("Running main loop, depth %d -> %d\n",
882  loop->depth - 1, loop->depth);
883 
884  while (loop->depth != our_exit_depth)
885  _dbus_loop_iterate (loop, TRUE);
886 
887  _dbus_loop_unref (loop);
888 }
889 
890 void
891 _dbus_loop_quit (DBusLoop *loop)
892 {
893  _dbus_assert (loop->depth > 0);
894 
895  loop->depth -= 1;
896 
897  _dbus_verbose ("Quit main loop, depth %d -> %d\n",
898  loop->depth + 1, loop->depth);
899 }
900 
901 int
902 _dbus_get_oom_wait (void)
903 {
904 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
905  /* make tests go fast */
906  return 0;
907 #else
908  return 500;
909 #endif
910 }
911 
912 void
913 _dbus_wait_for_memory (void)
914 {
915  _dbus_verbose ("Waiting for more memory\n");
916  _dbus_sleep_milliseconds (_dbus_get_oom_wait ());
917 }
918 
919 #endif /* !DOXYGEN_SHOULD_SKIP_THIS */
Internals of DBusTimeout.
Definition: dbus-timeout.c:40
int _dbus_hash_table_get_n_entries(DBusHashTable *table)
Gets the number of hash entries in a hash table.
Definition: dbus-hash.c:1397
DBusDispatchStatus
Indicates the status of incoming data on a DBusConnection.
Implementation of DBusWatch.
Definition: dbus-watch.c:40
#define NULL
A null pointer, defined appropriately for C or C++.
More memory is needed to continue.
void dbus_free(void *memory)
Frees a block of memory previously allocated by dbus_malloc() or dbus_malloc0().
Definition: dbus-memory.c:701
dbus_bool_t _dbus_list_length_is_one(DBusList **list)
Check whether length is exactly one.
Definition: dbus-list.c:783
void _dbus_watch_invalidate(DBusWatch *watch)
Clears the file descriptor from a now-invalid watch object so that no one tries to use it...
Definition: dbus-watch.c:169
#define dbus_new(type, count)
Safe macro for using dbus_malloc().
Definition: dbus-memory.h:58
DBUS_EXPORT dbus_bool_t dbus_watch_get_enabled(DBusWatch *watch)
Returns whether a watch is enabled or not.
Definition: dbus-watch.c:667
void _dbus_list_remove_link(DBusList **list, DBusList *link)
Removes a link from the list.
Definition: dbus-list.c:527
DBusConnection * dbus_connection_ref(DBusConnection *connection)
Increments the reference count of a DBusConnection.
#define _dbus_assert(condition)
Aborts with an error message if the condition is false.
void * data
Data stored at this element.
Definition: dbus-list.h:38
Implementation details of DBusConnection.
dbus_bool_t _dbus_hash_table_remove_int(DBusHashTable *table, int key)
Removes the hash entry for the given key.
Definition: dbus-hash.c:1151
void _dbus_hash_table_unref(DBusHashTable *table)
Decrements the reference count for a hash table, freeing the hash table if the count reaches zero...
Definition: dbus-hash.c:361
Hash iterator object.
Definition: dbus-hash.h:49
#define _dbus_list_get_next_link(list, link)
Gets the next link in the list, or NULL if there are no more links.
Definition: dbus-list.h:90
#define _DBUS_INT_MAX
Maximum value of type "int".
void * _dbus_hash_table_lookup_int(DBusHashTable *table, int key)
Looks up the value for a given integer in a hash table of type DBUS_HASH_INT.
Definition: dbus-hash.c:1074
void _dbus_get_monotonic_time(long *tv_sec, long *tv_usec)
Get current time, as in gettimeofday().
DBUS_EXPORT dbus_bool_t dbus_timeout_get_enabled(DBusTimeout *timeout)
Returns whether a timeout is enabled or not.
Definition: dbus-timeout.c:486
int _dbus_hash_iter_get_int_key(DBusHashIter *iter)
Gets the key for the current entry.
Definition: dbus-hash.c:659
Hash keys are integers.
Definition: dbus-hash.h:70
#define dbus_new0(type, count)
Safe macro for using dbus_malloc0().
Definition: dbus-memory.h:59
DBusHashTable * _dbus_hash_table_new(DBusHashType type, DBusFreeFunction key_free_function, DBusFreeFunction value_free_function)
Constructs a new hash table.
Definition: dbus-hash.c:285
dbus_uint32_t dbus_bool_t
A boolean, valid values are TRUE and FALSE.
Definition: dbus-types.h:35
DBUS_EXPORT int dbus_watch_get_socket(DBusWatch *watch)
Returns a socket to be watched, on UNIX this will return -1 if our transport is not socket-based so d...
Definition: dbus-watch.c:586
DBUS_EXPORT dbus_bool_t dbus_timeout_handle(DBusTimeout *timeout)
Calls the timeout handler for this timeout.
Definition: dbus-timeout.c:472
DBusDispatchStatus dbus_connection_dispatch(DBusConnection *connection)
Processes any incoming data.
All currently available data has been processed.
void _dbus_warn(const char *format,...)
Prints a warning message to stderr.
dbus_bool_t _dbus_list_append(DBusList **list, void *data)
Appends a value to the list.
Definition: dbus-list.c:270
dbus_bool_t _dbus_hash_iter_next(DBusHashIter *iter)
Move the hash iterator forward one step, to the next hash entry.
Definition: dbus-hash.c:543
void * _dbus_list_pop_first(DBusList **list)
Removes the first value in the list and returns it.
Definition: dbus-list.c:649
#define _DBUS_N_ELEMENTS(array)
Computes the number of elements in a fixed-size array using sizeof().
dbus_bool_t _dbus_hash_table_insert_int(DBusHashTable *table, int key, void *value)
Creates a hash entry with the given key and value.
Definition: dbus-hash.c:1248
#define TRUE
Expands to "1".
DBusWatch * _dbus_watch_ref(DBusWatch *watch)
Increments the reference count of a DBusWatch object.
Definition: dbus-watch.c:124
A node in a linked list.
Definition: dbus-list.h:34
int _dbus_list_get_length(DBusList **list)
Gets the length of a list.
Definition: dbus-list.c:730
void _dbus_hash_iter_init(DBusHashTable *table, DBusHashIter *iter)
Initializes a hash table iterator.
Definition: dbus-hash.c:517
void * _dbus_hash_iter_get_value(DBusHashIter *iter)
Gets the value of the current entry.
Definition: dbus-hash.c:613
DBusList * _dbus_list_get_first_link(DBusList **list)
Gets the first link in the list.
Definition: dbus-list.c:567
#define FALSE
Expands to "0".
DBUS_EXPORT dbus_bool_t dbus_watch_handle(DBusWatch *watch, unsigned int flags)
Called to notify the D-Bus library when a previously-added watch is ready for reading or writing...
Definition: dbus-watch.c:698
void _dbus_watch_unref(DBusWatch *watch)
Decrements the reference count of a DBusWatch object and finalizes the object if the count reaches ze...
Definition: dbus-watch.c:138
DBUS_EXPORT unsigned int dbus_watch_get_flags(DBusWatch *watch)
Gets flags from DBusWatchFlags indicating what conditions should be monitored on the file descriptor...
Definition: dbus-watch.c:607
void dbus_connection_unref(DBusConnection *connection)
Decrements the reference count of a DBusConnection, and finalizes it if the count reaches zero...
Internals of DBusHashTable.
Definition: dbus-hash.c:168
void _dbus_sleep_milliseconds(int milliseconds)
Sleeps the given number of milliseconds.
DBUS_EXPORT int dbus_timeout_get_interval(DBusTimeout *timeout)
Gets the timeout interval.
Definition: dbus-timeout.c:416