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) {
167 w->simple_poll->n_watches --;
168 w->simple_poll->watch_req_cleanup = 1;
171 static void destroy_watch(AvahiWatch *w) {
175 AVAHI_LLIST_REMOVE(AvahiWatch, watches, w->simple_poll->watches, w);
178 w->simple_poll->n_watches --;
183 static void cleanup_watches(AvahiSimplePoll *s, int all) {
184 AvahiWatch *w, *next;
187 for (w = s->watches; w; w = next) {
188 next = w->watches_next;
194 s->timeout_req_cleanup = 0;
197 static AvahiTimeout* timeout_new(const AvahiPoll *api, const struct timeval *tv, AvahiTimeoutCallback callback, void *userdata) {
207 if (!(t = avahi_new(AvahiTimeout, 1)))
213 if ((t->enabled = !!tv))
216 t->callback = callback;
217 t->userdata = userdata;
219 AVAHI_LLIST_PREPEND(AvahiTimeout, timeouts, s->timeouts, t);
224 static void timeout_update(AvahiTimeout *t, const struct timeval *tv) {
228 if ((t->enabled = !!tv))
232 static void timeout_free(AvahiTimeout *t) {
237 t->simple_poll->timeout_req_cleanup = 1;
241 static void destroy_timeout(AvahiTimeout *t) {
244 AVAHI_LLIST_REMOVE(AvahiTimeout, timeouts, t->simple_poll->timeouts, t);
249 static void cleanup_timeouts(AvahiSimplePoll *s, int all) {
250 AvahiTimeout *t, *next;
253 for (t = s->timeouts; t; t = next) {
254 next = t->timeouts_next;
260 s->timeout_req_cleanup = 0;
263 AvahiSimplePoll *avahi_simple_poll_new(void) {
266 if (!(s = avahi_new(AvahiSimplePoll, 1)))
271 s->api.watch_new = watch_new;
272 s->api.watch_free = watch_free;
273 s->api.watch_update = watch_update;
274 s->api.watch_get_events = watch_get_events;
276 s->api.timeout_new = timeout_new;
277 s->api.timeout_free = timeout_free;
278 s->api.timeout_update = timeout_update;
281 s->max_pollfds = s->n_pollfds = 0;
282 s->rebuild_pollfds = 0;
287 s->watch_req_cleanup = 0;
288 s->timeout_req_cleanup = 0;
290 avahi_simple_poll_set_func(s, NULL);
292 AVAHI_LLIST_HEAD_INIT(AvahiWatch, s->watches);
293 AVAHI_LLIST_HEAD_INIT(AvahiTimeout, s->timeouts);
298 void avahi_simple_poll_free(AvahiSimplePoll *s) {
301 cleanup_timeouts(s, 1);
302 cleanup_watches(s, 1);
303 assert(s->n_watches == 0);
305 avahi_free(s->pollfds);
309 static int rebuild(AvahiSimplePoll *s) {
315 if (s->n_watches > s->max_pollfds) {
318 s->max_pollfds = s->n_watches + 10;
320 if (!(n = avahi_realloc(s->pollfds, sizeof(struct pollfd) * s->max_pollfds)))
326 for (idx = 0, w = s->watches; w; w = w->watches_next) {
331 assert(w->idx < s->max_pollfds);
332 s->pollfds[w->idx = idx++] = w->pollfd;
337 s->rebuild_pollfds = 0;
342 static AvahiTimeout* find_next_timeout(AvahiSimplePoll *s) {
343 AvahiTimeout *t, *n = NULL;
346 for (t = s->timeouts; t; t = t->timeouts_next) {
348 if (t->dead || !t->enabled)
351 if (!n || avahi_timeval_compare(&t->expiry, &n->expiry) < 0)
358 static int start_timeout_callback(AvahiTimeout *t) {
364 t->callback(t, t->userdata);
368 int avahi_simple_poll_iterate(AvahiSimplePoll *s, int timeout) {
370 AvahiTimeout *next_timeout;
373 /* Cleanup things first */
374 if (s->watch_req_cleanup)
375 cleanup_watches(s, 0);
377 if (s->timeout_req_cleanup)
378 cleanup_timeouts(s, 0);
380 /* Check whether a quit was requested */
384 /* Do we need to rebuild our array of pollfds? */
385 if (s->rebuild_pollfds)
390 /* Calculate the wakeup time */
391 if ((next_timeout = find_next_timeout(s))) {
396 gettimeofday(&now, NULL);
397 usec = avahi_timeval_diff(&next_timeout->expiry, &now);
400 /* Timeout elapsed */
402 /* The events poll() returned in the last call are now no longer valid */
404 return start_timeout_callback(next_timeout);
407 /* Calculate sleep time. We add 1ms because otherwise we'd
408 * wake up too early most of the time */
409 t = (int) (usec / 1000) + 1;
411 if (timeout < 0 || timeout > t)
415 if ((r = s->poll_func(s->pollfds, s->n_pollfds, timeout)) < 0)
418 /* The pollf events are now valid again */
421 /* Check whether the wakeup time has been reached now */
425 gettimeofday(&now, NULL);
427 if (avahi_timeval_compare(&next_timeout->expiry, &now) <= 0)
429 return start_timeout_callback(next_timeout);
435 /* Look for some kind of I/O event */
437 for (w = s->watches; w; w = w->watches_next) {
443 assert(w->idx < s->n_pollfds);
445 if (s->pollfds[w->idx].revents > 0) {
446 /* We execute only on callback in every iteration */
447 w->callback(w, w->pollfd.fd, s->pollfds[w->idx].revents, w->userdata);
456 void avahi_simple_poll_quit(AvahiSimplePoll *w) {
462 const AvahiPoll* avahi_simple_poll_get(AvahiSimplePoll *s) {
468 void avahi_simple_poll_set_func(AvahiSimplePoll *s, AvahiPollFunc func) {
471 s->poll_func = func ? func : (AvahiPollFunc) poll;