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)
298 /* count enabled watches */
300 link = _dbus_list_get_first_link (&callbacks);
303 DBusList *next = _dbus_list_get_next_link (&callbacks, link);
304 Callback *cb = link->data;
305 if (cb->type == CALLBACK_WATCH)
307 WatchCallback *wcb = WATCH_CALLBACK (cb);
309 if (dbus_watch_get_enabled (wcb->watch))
316 /* fill our array of fds and watches */
319 fds = dbus_new0 (DBusPollFD, n_fds);
322 bus_wait_for_memory ();
323 fds = dbus_new0 (DBusPollFD, n_fds);
326 watches_for_fds = dbus_new (WatchCallback*, n_fds);
327 while (watches_for_fds == NULL)
329 bus_wait_for_memory ();
330 watches_for_fds = dbus_new (WatchCallback*, n_fds);
334 link = _dbus_list_get_first_link (&callbacks);
337 DBusList *next = _dbus_list_get_next_link (&callbacks, link);
338 Callback *cb = link->data;
339 if (cb->type == CALLBACK_WATCH)
342 WatchCallback *wcb = WATCH_CALLBACK (cb);
344 if (dbus_watch_get_enabled (wcb->watch))
346 watches_for_fds[i] = wcb;
348 flags = dbus_watch_get_flags (wcb->watch);
350 fds[i].fd = dbus_watch_get_fd (wcb->watch);
351 if (flags & DBUS_WATCH_READABLE)
352 fds[i].events |= _DBUS_POLLIN;
353 if (flags & DBUS_WATCH_WRITABLE)
354 fds[i].events |= _DBUS_POLLOUT;
363 _dbus_assert (i == n_fds);
367 if (timeout_count > 0)
369 unsigned long tv_sec;
370 unsigned long tv_usec;
374 _dbus_get_current_time (&tv_sec, &tv_usec);
376 link = _dbus_list_get_first_link (&callbacks);
379 DBusList *next = _dbus_list_get_next_link (&callbacks, link);
380 Callback *cb = link->data;
382 if (cb->type == CALLBACK_TIMEOUT &&
383 dbus_timeout_get_enabled (TIMEOUT_CALLBACK (cb)->timeout))
385 TimeoutCallback *tcb = TIMEOUT_CALLBACK (cb);
386 unsigned long interval;
387 unsigned long elapsed;
389 if (tcb->last_tv_sec > tv_sec ||
390 (tcb->last_tv_sec == tv_sec &&
391 tcb->last_tv_usec > tv_usec))
393 /* Clock went backward, pretend timeout
394 * was just installed.
396 tcb->last_tv_sec = tv_sec;
397 tcb->last_tv_usec = tv_usec;
398 _dbus_verbose ("System clock went backward\n");
401 interval = dbus_timeout_get_interval (tcb->timeout);
404 (tv_sec - tcb->last_tv_sec) * 1000 +
405 (tv_usec - tcb->last_tv_usec) / 1000;
407 if (interval < elapsed)
409 else if (timeout < 0)
410 timeout = interval - elapsed;
412 timeout = MIN (((unsigned long)timeout), interval - elapsed);
414 _dbus_assert (timeout >= 0);
417 break; /* it's not going to get shorter... */
427 n_ready = _dbus_poll (fds, n_fds, timeout);
429 initial_serial = callback_list_serial;
431 if (timeout_count > 0)
433 unsigned long tv_sec;
434 unsigned long tv_usec;
436 _dbus_get_current_time (&tv_sec, &tv_usec);
438 /* It'd be nice to avoid this O(n) thingy here */
439 link = _dbus_list_get_first_link (&callbacks);
442 DBusList *next = _dbus_list_get_next_link (&callbacks, link);
443 Callback *cb = link->data;
445 if (initial_serial != callback_list_serial)
451 if (cb->type == CALLBACK_TIMEOUT &&
452 dbus_timeout_get_enabled (TIMEOUT_CALLBACK (cb)->timeout))
454 TimeoutCallback *tcb = TIMEOUT_CALLBACK (cb);
455 unsigned long interval;
456 unsigned long elapsed;
458 if (tcb->last_tv_sec > tv_sec ||
459 (tcb->last_tv_sec == tv_sec &&
460 tcb->last_tv_usec > tv_usec))
462 /* Clock went backward, pretend timeout
463 * was just installed.
465 tcb->last_tv_sec = tv_sec;
466 tcb->last_tv_usec = tv_usec;
467 _dbus_verbose ("System clock went backward\n");
471 interval = dbus_timeout_get_interval (tcb->timeout);
474 (tv_sec - tcb->last_tv_sec) * 1000 +
475 (tv_usec - tcb->last_tv_usec) / 1000;
478 _dbus_verbose (" interval = %lu elapsed = %lu\n",
482 if (interval <= elapsed)
484 /* Save last callback time and fire this timeout */
485 tcb->last_tv_sec = tv_sec;
486 tcb->last_tv_usec = tv_usec;
489 _dbus_verbose (" invoking timeout\n");
492 (* tcb->function) (tcb->timeout,
507 /* FIXME I think this "restart if we change the watches"
508 * approach could result in starving watches
509 * toward the end of the list.
511 if (initial_serial != callback_list_serial)
517 if (fds[i].revents != 0)
520 unsigned int condition;
522 wcb = watches_for_fds[i];
525 if (fds[i].revents & _DBUS_POLLIN)
526 condition |= DBUS_WATCH_READABLE;
527 if (fds[i].revents & _DBUS_POLLOUT)
528 condition |= DBUS_WATCH_WRITABLE;
529 if (fds[i].revents & _DBUS_POLLHUP)
530 condition |= DBUS_WATCH_HANGUP;
531 if (fds[i].revents & _DBUS_POLLERR)
532 condition |= DBUS_WATCH_ERROR;
534 /* condition may still be 0 if we got some
535 * weird POLLFOO thing like POLLWRBAND
538 if (condition != 0 &&
539 dbus_watch_get_enabled (wcb->watch))
541 (* wcb->function) (wcb->watch,
543 ((Callback*)wcb)->data);
555 dbus_free (watches_for_fds);
565 bus_loop_iterate (TRUE);