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;
41 AvahiWatchCallback callback;
44 AVAHI_LLIST_FIELDS(AvahiWatch, watches);
47 struct AvahiSimplePoll {
49 AvahiPollFunc poll_func;
51 struct pollfd* pollfds;
52 int n_pollfds, max_pollfds, rebuild_pollfds;
54 struct timeval wakeup;
55 AvahiWakeupCallback wakeup_callback;
56 void *wakeup_userdata;
63 AVAHI_LLIST_HEAD(AvahiWatch, watches);
66 static AvahiWatch* watch_new(const AvahiPoll *api, int fd, AvahiWatchEvent event, AvahiWatchCallback callback, void *userdata) {
77 if (!(w = avahi_new(AvahiWatch, 1)))
82 w->pollfd.events = event;
83 w->callback = callback;
84 w->userdata = userdata;
87 if (s->n_pollfds < s->max_pollfds) {
88 /* If there's space for this pollfd, go on and allocate it */
89 w->idx = s->n_pollfds++;
90 s->pollfds[w->idx] = w->pollfd;
93 /* Unfortunately there's no place for this pollfd, so request a rebuild of the array */
95 s->rebuild_pollfds = 1;
98 AVAHI_LLIST_PREPEND(AvahiWatch, watches, s->watches, w);
104 static void watch_update(AvahiWatch *w, AvahiWatchEvent events) {
108 w->pollfd.events = events;
111 assert(w->simple_poll);
112 w->simple_poll->pollfds[w->idx] = w->pollfd;
114 w->simple_poll->rebuild_pollfds = 1;
117 static void remove_pollfd(AvahiWatch *w) {
123 if (w->idx == w->simple_poll->n_pollfds-1) {
125 /* This pollfd is at the end of the array, so we can easily cut it */
127 assert(w->simple_poll->n_pollfds > 0);
128 w->simple_poll->n_pollfds -= 1;
131 /* Unfortunately this pollfd is in the middle of the array, so request a rebuild of it */
132 w->simple_poll->rebuild_pollfds = 1;
135 static void watch_free(AvahiWatch *w) {
142 w->simple_poll->n_watches --;
143 w->simple_poll->req_cleanup = 1;
146 static void set_wakeup(const AvahiPoll *api, const struct timeval *tv, AvahiWakeupCallback callback, void *userdata) {
156 s->wakeup.tv_sec = 0;
157 s->wakeup.tv_usec = 0;
160 s->wakeup_callback = callback;
161 s->wakeup_userdata = userdata;
163 s->wakeup_callback = NULL;
166 static void destroy_watch(AvahiWatch *w) {
170 AVAHI_LLIST_REMOVE(AvahiWatch, watches, w->simple_poll->watches, w);
173 w->simple_poll->n_watches --;
178 static void cleanup(AvahiSimplePoll *s, int all) {
179 AvahiWatch *w, *next;
182 for (w = s->watches; w; w = next) {
183 next = w->watches_next;
192 AvahiSimplePoll *avahi_simple_poll_new(void) {
195 if (!(s = avahi_new(AvahiSimplePoll, 1)))
199 s->api.watch_new = watch_new;
200 s->api.watch_free = watch_free;
201 s->api.watch_update = watch_update;
202 s->api.set_wakeup = set_wakeup;
204 s->max_pollfds = s->n_pollfds = 0;
205 s->wakeup_callback = NULL;
206 s->rebuild_pollfds = 0;
211 avahi_simple_poll_set_func(s, NULL);
213 AVAHI_LLIST_HEAD_INIT(AvahiWatch, s->watches);
218 void avahi_simple_poll_free(AvahiSimplePoll *s) {
223 assert(s->n_watches == 0);
225 avahi_free(s->pollfds);
229 static int rebuild(AvahiSimplePoll *s) {
235 if (s->n_watches > s->max_pollfds) {
238 s->max_pollfds = s->n_watches + 10;
240 if (!(n = avahi_realloc(s->pollfds, sizeof(struct pollfd) * s->max_pollfds)))
246 for (idx = 0, w = s->watches; w; w = w->watches_next) {
251 assert(w->idx < s->max_pollfds);
252 s->pollfds[w->idx = idx++] = w->pollfd;
257 s->rebuild_pollfds = 0;
262 static int start_wakeup_callback(AvahiSimplePoll *s) {
263 AvahiWakeupCallback callback;
268 /* Reset the wakeup functions, but allow changing of the two
269 values from the callback function */
271 callback = s->wakeup_callback;
272 userdata = s->wakeup_userdata;
273 s->wakeup_callback = NULL;
274 s->wakeup_userdata = NULL;
278 callback(&s->api, userdata);
282 int avahi_simple_poll_iterate(AvahiSimplePoll *s, int timeout) {
286 /* Cleanup things first */
290 /* Check whether a quit was requested */
294 /* Do we need to rebuild our array of pollfds? */
295 if (s->rebuild_pollfds)
299 /* Calculate the wakeup time */
300 if (s->wakeup_callback) {
305 gettimeofday(&now, NULL);
306 usec = avahi_timeval_diff(&s->wakeup, &now);
309 /* Timeout elapsed */
311 return start_wakeup_callback(s);
313 /* Calculate sleep time. We add 1ms because otherwise we'd
314 * wake up too early most of the time */
315 t = (int) (usec / 1000) + 1;
317 if (timeout < 0 || timeout > t)
321 if ((r = s->poll_func(s->pollfds, s->n_pollfds, timeout)) < 0)
324 /* Check whether the wakeup time has been reached now */
325 if (s->wakeup_callback) {
328 gettimeofday(&now, NULL);
330 if (avahi_timeval_compare(&s->wakeup, &now) <= 0)
332 return start_wakeup_callback(s);
338 /* Look for some kind of I/O event */
340 for (w = s->watches; w; w = w->watches_next) {
346 assert(w->idx < s->n_pollfds);
348 if (s->pollfds[w->idx].revents > 0) {
349 /* We execute only on callback in every iteration */
350 w->callback(w, w->pollfd.fd, s->pollfds[w->idx].revents, w->userdata);
359 void avahi_simple_poll_quit(AvahiSimplePoll *w) {
365 const AvahiPoll* avahi_simple_poll_get(AvahiSimplePoll *s) {
371 void avahi_simple_poll_set_func(AvahiSimplePoll *s, AvahiPollFunc func) {
374 s->poll_func = func ? func : (AvahiPollFunc) poll;