1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* loop.c Main loop for daemon
4 * Copyright (C) 2003 Red Hat, Inc.
6 * Licensed under the Academic Free License version 1.2
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.
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.
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
26 #include <dbus/dbus-list.h>
27 #include <dbus/dbus-sysdeps.h>
29 static DBusList *callbacks = NULL;
30 static int callback_list_serial = 0;
31 static int watch_count = 0;
32 static int timeout_count = 0;
33 static dbus_bool_t exited = FALSE;
45 DBusFreeFunction free_data_func;
51 BusWatchFunction function;
59 BusTimeoutFunction function;
60 unsigned long last_tv_sec;
61 unsigned long last_tv_usec;
64 #define WATCH_CALLBACK(callback) ((WatchCallback*)callback)
65 #define TIMEOUT_CALLBACK(callback) ((TimeoutCallback*)callback)
68 watch_callback_new (DBusWatch *watch,
69 BusWatchFunction function,
71 DBusFreeFunction free_data_func)
75 cb = dbus_new (WatchCallback, 1);
80 cb->function = function;
81 cb->callback.type = CALLBACK_WATCH;
82 cb->callback.data = data;
83 cb->callback.free_data_func = free_data_func;
88 static TimeoutCallback*
89 timeout_callback_new (DBusTimeout *timeout,
90 BusTimeoutFunction function,
92 DBusFreeFunction free_data_func)
96 cb = dbus_new (TimeoutCallback, 1);
100 cb->timeout = timeout;
101 cb->function = function;
102 _dbus_get_current_time (&cb->last_tv_sec,
104 cb->callback.type = CALLBACK_TIMEOUT;
105 cb->callback.data = data;
106 cb->callback.free_data_func = free_data_func;
112 callback_free (Callback *cb)
114 if (cb->free_data_func)
115 (* cb->free_data_func) (cb->data);
121 add_callback (Callback *cb)
123 if (!_dbus_list_append (&callbacks, cb))
126 callback_list_serial += 1;
133 case CALLBACK_TIMEOUT:
142 remove_callback (DBusList *link)
144 Callback *cb = link->data;
151 case CALLBACK_TIMEOUT:
157 _dbus_list_remove_link (&callbacks, link);
158 callback_list_serial += 1;
162 bus_loop_add_watch (DBusWatch *watch,
163 BusWatchFunction function,
165 DBusFreeFunction free_data_func)
169 wcb = watch_callback_new (watch, function, data, free_data_func);
173 if (!add_callback ((Callback*) wcb))
175 wcb->callback.free_data_func = NULL; /* don't want to have this side effect */
176 callback_free ((Callback*) wcb);
184 bus_loop_remove_watch (DBusWatch *watch,
185 BusWatchFunction function,
190 link = _dbus_list_get_first_link (&callbacks);
193 DBusList *next = _dbus_list_get_next_link (&callbacks, link);
194 Callback *this = link->data;
196 if (this->type == CALLBACK_WATCH &&
197 WATCH_CALLBACK (this)->watch == watch &&
198 this->data == data &&
199 WATCH_CALLBACK (this)->function == function)
201 remove_callback (link);
209 _dbus_warn ("could not find watch %p function %p data %p to remove\n",
210 watch, function, data);
214 bus_loop_add_timeout (DBusTimeout *timeout,
215 BusTimeoutFunction function,
217 DBusFreeFunction free_data_func)
219 TimeoutCallback *tcb;
221 tcb = timeout_callback_new (timeout, function, data, free_data_func);
225 if (!add_callback ((Callback*) tcb))
227 tcb->callback.free_data_func = NULL; /* don't want to have this side effect */
228 callback_free ((Callback*) tcb);
236 bus_loop_remove_timeout (DBusTimeout *timeout,
237 BusTimeoutFunction function,
242 link = _dbus_list_get_first_link (&callbacks);
245 DBusList *next = _dbus_list_get_next_link (&callbacks, link);
246 Callback *this = link->data;
248 if (this->type == CALLBACK_TIMEOUT &&
249 TIMEOUT_CALLBACK (this)->timeout == timeout &&
250 this->data == data &&
251 TIMEOUT_CALLBACK (this)->function == function)
253 remove_callback (link);
261 _dbus_warn ("could not find timeout %p function %p data %p to remove\n",
262 timeout, function, data);
265 /* Returns TRUE if we have any timeouts or ready file descriptors,
266 * which is just used in test code as a debug hack
270 bus_loop_iterate (dbus_bool_t block)
275 WatchCallback **watches_for_fds;
285 watches_for_fds = NULL;
288 _dbus_verbose (" iterate %d timeouts %d watches\n",
289 timeout_count, watch_count);
292 if (callbacks == NULL)
302 fds = dbus_new0 (DBusPollFD, n_fds);
305 bus_wait_for_memory ();
306 fds = dbus_new0 (DBusPollFD, n_fds);
309 watches_for_fds = dbus_new (WatchCallback*, n_fds);
310 while (watches_for_fds == NULL)
312 bus_wait_for_memory ();
313 watches_for_fds = dbus_new (WatchCallback*, n_fds);
317 link = _dbus_list_get_first_link (&callbacks);
320 DBusList *next = _dbus_list_get_next_link (&callbacks, link);
321 Callback *cb = link->data;
322 if (cb->type == CALLBACK_WATCH)
325 WatchCallback *wcb = WATCH_CALLBACK (cb);
327 watches_for_fds[i] = wcb;
329 flags = dbus_watch_get_flags (wcb->watch);
331 fds[i].fd = dbus_watch_get_fd (wcb->watch);
332 if (flags & DBUS_WATCH_READABLE)
333 fds[i].events |= _DBUS_POLLIN;
334 if (flags & DBUS_WATCH_WRITABLE)
335 fds[i].events |= _DBUS_POLLOUT;
343 _dbus_assert (i == n_fds);
347 if (timeout_count > 0)
349 unsigned long tv_sec;
350 unsigned long tv_usec;
354 _dbus_get_current_time (&tv_sec, &tv_usec);
356 link = _dbus_list_get_first_link (&callbacks);
359 DBusList *next = _dbus_list_get_next_link (&callbacks, link);
360 Callback *cb = link->data;
362 if (cb->type == CALLBACK_TIMEOUT)
364 TimeoutCallback *tcb = TIMEOUT_CALLBACK (cb);
365 unsigned long interval;
366 unsigned long elapsed;
368 if (tcb->last_tv_sec > tv_sec ||
369 (tcb->last_tv_sec == tv_sec &&
370 tcb->last_tv_usec > tv_usec))
372 /* Clock went backward, pretend timeout
373 * was just installed.
375 tcb->last_tv_sec = tv_sec;
376 tcb->last_tv_usec = tv_usec;
377 _dbus_verbose ("System clock went backward\n");
380 interval = dbus_timeout_get_interval (tcb->timeout);
383 (tv_sec - tcb->last_tv_sec) * 1000 +
384 (tv_usec - tcb->last_tv_usec) / 1000;
386 if (interval < elapsed)
388 else if (timeout < 0)
389 timeout = interval - elapsed;
391 timeout = MIN (((unsigned long)timeout), interval - elapsed);
393 _dbus_assert (timeout >= 0);
396 break; /* it's not going to get shorter... */
406 n_ready = _dbus_poll (fds, n_fds, timeout);
408 initial_serial = callback_list_serial;
410 if (timeout_count > 0)
412 unsigned long tv_sec;
413 unsigned long tv_usec;
415 _dbus_get_current_time (&tv_sec, &tv_usec);
417 /* It'd be nice to avoid this O(n) thingy here */
418 link = _dbus_list_get_first_link (&callbacks);
421 DBusList *next = _dbus_list_get_next_link (&callbacks, link);
422 Callback *cb = link->data;
424 if (initial_serial != callback_list_serial)
430 if (cb->type == CALLBACK_TIMEOUT)
432 TimeoutCallback *tcb = TIMEOUT_CALLBACK (cb);
433 unsigned long interval;
434 unsigned long elapsed;
436 if (tcb->last_tv_sec > tv_sec ||
437 (tcb->last_tv_sec == tv_sec &&
438 tcb->last_tv_usec > tv_usec))
440 /* Clock went backward, pretend timeout
441 * was just installed.
443 tcb->last_tv_sec = tv_sec;
444 tcb->last_tv_usec = tv_usec;
445 _dbus_verbose ("System clock went backward\n");
449 interval = dbus_timeout_get_interval (tcb->timeout);
452 (tv_sec - tcb->last_tv_sec) * 1000 +
453 (tv_usec - tcb->last_tv_usec) / 1000;
456 _dbus_verbose (" interval = %lu elapsed = %lu\n",
460 if (interval <= elapsed)
462 /* Save last callback time and fire this timeout */
463 tcb->last_tv_sec = tv_sec;
464 tcb->last_tv_usec = tv_usec;
467 _dbus_verbose (" invoking timeout\n");
470 (* tcb->function) (tcb->timeout,
485 /* FIXME I think this "restart if we change the watches"
486 * approach could result in starving watches
487 * toward the end of the list.
489 if (initial_serial != callback_list_serial)
495 if (fds[i].revents != 0)
498 unsigned int condition;
500 wcb = watches_for_fds[i];
503 if (fds[i].revents & _DBUS_POLLIN)
504 condition |= DBUS_WATCH_READABLE;
505 if (fds[i].revents & _DBUS_POLLOUT)
506 condition |= DBUS_WATCH_WRITABLE;
507 if (fds[i].revents & _DBUS_POLLHUP)
508 condition |= DBUS_WATCH_HANGUP;
509 if (fds[i].revents & _DBUS_POLLERR)
510 condition |= DBUS_WATCH_ERROR;
512 /* condition may still be 0 if we got some
513 * weird POLLFOO thing like POLLWRBAND
518 (* wcb->function) (wcb->watch,
520 ((Callback*)wcb)->data);
532 dbus_free (watches_for_fds);
542 bus_loop_iterate (TRUE);