4 This file is part of avahi.
6 avahi is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as
8 published by the Free Software Foundation; either version 2.1 of the
9 License, or (at your option) any later version.
11 avahi is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
14 Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with avahi; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
31 #include <avahi-common/llist.h>
32 #include <avahi-common/malloc.h>
34 #include "simple-watch.h"
37 AvahiSimplePoll *simple_poll;
43 AvahiWatchCallback callback;
46 AVAHI_LLIST_FIELDS(AvahiWatch, watches);
50 AvahiSimplePoll *simple_poll;
54 struct timeval expiry;
56 AvahiTimeoutCallback callback;
59 AVAHI_LLIST_FIELDS(AvahiTimeout, timeouts);
62 struct AvahiSimplePoll {
64 AvahiPollFunc poll_func;
66 struct pollfd* pollfds;
67 int n_pollfds, max_pollfds, rebuild_pollfds;
69 int watch_req_cleanup, timeout_req_cleanup;
74 AVAHI_LLIST_HEAD(AvahiWatch, watches);
75 AVAHI_LLIST_HEAD(AvahiTimeout, timeouts);
78 static AvahiWatch* watch_new(const AvahiPoll *api, int fd, AvahiWatchEvent event, AvahiWatchCallback callback, void *userdata) {
89 if (!(w = avahi_new(AvahiWatch, 1)))
96 w->pollfd.events = event;
98 w->callback = callback;
99 w->userdata = userdata;
101 if (s->n_pollfds < s->max_pollfds) {
102 /* If there's space for this pollfd, go on and allocate it */
103 w->idx = s->n_pollfds++;
104 s->pollfds[w->idx] = w->pollfd;
107 /* Unfortunately there's no place for this pollfd, so request a rebuild of the array */
109 s->rebuild_pollfds = 1;
112 AVAHI_LLIST_PREPEND(AvahiWatch, watches, s->watches, w);
118 static void watch_update(AvahiWatch *w, AvahiWatchEvent events) {
122 w->pollfd.events = events;
125 assert(w->simple_poll);
126 w->simple_poll->pollfds[w->idx] = w->pollfd;
128 w->simple_poll->rebuild_pollfds = 1;
131 static AvahiWatchEvent watch_get_events(AvahiWatch *w) {
135 if (w->idx != -1 && w->simple_poll->events_valid)
136 return w->simple_poll->pollfds[w->idx].revents;
141 static void remove_pollfd(AvahiWatch *w) {
147 if (w->idx == w->simple_poll->n_pollfds-1) {
149 /* This pollfd is at the end of the array, so we can easily cut it */
151 assert(w->simple_poll->n_pollfds > 0);
152 w->simple_poll->n_pollfds -= 1;
155 /* Unfortunately this pollfd is in the middle of the array, so request a rebuild of it */
156 w->simple_poll->rebuild_pollfds = 1;
159 static void watch_free(AvahiWatch *w) {
166 w->simple_poll->n_watches --;
167 w->simple_poll->watch_req_cleanup = 1;
170 static void destroy_watch(AvahiWatch *w) {
174 AVAHI_LLIST_REMOVE(AvahiWatch, watches, w->simple_poll->watches, w);
177 w->simple_poll->n_watches --;
182 static void cleanup_watches(AvahiSimplePoll *s, int all) {
183 AvahiWatch *w, *next;
186 for (w = s->watches; w; w = next) {
187 next = w->watches_next;
193 s->timeout_req_cleanup = 0;
196 static AvahiTimeout* timeout_new(const AvahiPoll *api, const struct timeval *tv, AvahiTimeoutCallback callback, void *userdata) {
206 if (!(t = avahi_new(AvahiTimeout, 1)))
212 if ((t->enabled = !!tv))
215 t->callback = callback;
216 t->userdata = userdata;
218 AVAHI_LLIST_PREPEND(AvahiTimeout, timeouts, s->timeouts, t);
223 static void timeout_update(AvahiTimeout *t, const struct timeval *tv) {
227 if ((t->enabled = !!tv))
231 static void timeout_free(AvahiTimeout *t) {
236 t->simple_poll->timeout_req_cleanup = 1;
240 static void destroy_timeout(AvahiTimeout *t) {
243 AVAHI_LLIST_REMOVE(AvahiTimeout, timeouts, t->simple_poll->timeouts, t);
248 static void cleanup_timeouts(AvahiSimplePoll *s, int all) {
249 AvahiTimeout *t, *next;
252 for (t = s->timeouts; t; t = next) {
253 next = t->timeouts_next;
259 s->timeout_req_cleanup = 0;
262 AvahiSimplePoll *avahi_simple_poll_new(void) {
265 if (!(s = avahi_new(AvahiSimplePoll, 1)))
270 s->api.watch_new = watch_new;
271 s->api.watch_free = watch_free;
272 s->api.watch_update = watch_update;
273 s->api.watch_get_events = watch_get_events;
275 s->api.timeout_new = timeout_new;
276 s->api.timeout_free = timeout_free;
277 s->api.timeout_update = timeout_update;
280 s->max_pollfds = s->n_pollfds = 0;
281 s->rebuild_pollfds = 0;
286 s->watch_req_cleanup = 0;
287 s->timeout_req_cleanup = 0;
289 avahi_simple_poll_set_func(s, NULL);
291 AVAHI_LLIST_HEAD_INIT(AvahiWatch, s->watches);
292 AVAHI_LLIST_HEAD_INIT(AvahiTimeout, s->timeouts);
297 void avahi_simple_poll_free(AvahiSimplePoll *s) {
300 cleanup_timeouts(s, 1);
301 cleanup_watches(s, 1);
302 assert(s->n_watches == 0);
304 avahi_free(s->pollfds);
308 static int rebuild(AvahiSimplePoll *s) {
314 if (s->n_watches > s->max_pollfds) {
317 s->max_pollfds = s->n_watches + 10;
319 if (!(n = avahi_realloc(s->pollfds, sizeof(struct pollfd) * s->max_pollfds)))
325 for (idx = 0, w = s->watches; w; w = w->watches_next) {
330 assert(w->idx < s->max_pollfds);
331 s->pollfds[w->idx = idx++] = w->pollfd;
336 s->rebuild_pollfds = 0;
341 static AvahiTimeout* find_next_timeout(AvahiSimplePoll *s) {
342 AvahiTimeout *t, *n = NULL;
345 for (t = s->timeouts; t; t = t->timeouts_next) {
347 if (t->dead || !t->enabled)
350 if (!n || avahi_timeval_compare(&t->expiry, &n->expiry) < 0)
357 static int start_timeout_callback(AvahiTimeout *t) {
363 t->callback(t, t->userdata);
367 int avahi_simple_poll_iterate(AvahiSimplePoll *s, int timeout) {
369 AvahiTimeout *next_timeout;
372 /* Cleanup things first */
373 if (s->watch_req_cleanup)
374 cleanup_watches(s, 0);
376 if (s->timeout_req_cleanup)
377 cleanup_timeouts(s, 0);
379 /* Check whether a quit was requested */
383 /* Do we need to rebuild our array of pollfds? */
384 if (s->rebuild_pollfds)
389 /* Calculate the wakeup time */
390 if ((next_timeout = find_next_timeout(s))) {
395 gettimeofday(&now, NULL);
396 usec = avahi_timeval_diff(&next_timeout->expiry, &now);
399 /* Timeout elapsed */
401 /* The events poll() returned in the last call are now no longer valid */
403 return start_timeout_callback(next_timeout);
406 /* Calculate sleep time. We add 1ms because otherwise we'd
407 * wake up too early most of the time */
408 t = (int) (usec / 1000) + 1;
410 if (timeout < 0 || timeout > t)
414 if ((r = s->poll_func(s->pollfds, s->n_pollfds, timeout)) < 0)
417 /* The pollf events are now valid again */
420 /* Check whether the wakeup time has been reached now */
424 gettimeofday(&now, NULL);
426 if (avahi_timeval_compare(&next_timeout->expiry, &now) <= 0)
428 return start_timeout_callback(next_timeout);
434 /* Look for some kind of I/O event */
436 for (w = s->watches; w; w = w->watches_next) {
442 assert(w->idx < s->n_pollfds);
444 if (s->pollfds[w->idx].revents > 0) {
445 /* We execute only on callback in every iteration */
446 w->callback(w, w->pollfd.fd, s->pollfds[w->idx].revents, w->userdata);
455 void avahi_simple_poll_quit(AvahiSimplePoll *w) {
461 const AvahiPoll* avahi_simple_poll_get(AvahiSimplePoll *s) {
467 void avahi_simple_poll_set_func(AvahiSimplePoll *s, AvahiPollFunc func) {
470 s->poll_func = func ? func : (AvahiPollFunc) poll;