2 This file is part of avahi.
4 avahi is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
9 avahi is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
12 Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with avahi; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
24 #include <avahi-common/llist.h>
25 #include <avahi-common/malloc.h>
26 #include <avahi-common/timeval.h>
28 #include "glib-watch.h"
31 AvahiGLibPoll *glib_poll;
37 AvahiWatchCallback callback;
40 AVAHI_LLIST_FIELDS(AvahiWatch, watches);
44 AvahiGLibPoll *glib_poll;
48 struct timeval expiry;
50 AvahiTimeoutCallback callback;
53 AVAHI_LLIST_FIELDS(AvahiTimeout, timeouts);
56 struct AvahiGLibPoll {
59 GMainContext *context;
61 gboolean timeout_req_cleanup;
62 gboolean watch_req_cleanup;
64 AVAHI_LLIST_HEAD(AvahiWatch, watches);
65 AVAHI_LLIST_HEAD(AvahiTimeout, timeouts);
68 static void destroy_watch(AvahiWatch *w) {
72 g_source_remove_poll(&w->glib_poll->source, &w->pollfd);
74 AVAHI_LLIST_REMOVE(AvahiWatch, watches, w->glib_poll->watches, w);
79 static void cleanup_watches(AvahiGLibPoll *g, int all) {
83 for (w = g->watches; w; w = next) {
84 next = w->watches_next;
90 g->watch_req_cleanup = 0;
93 static gushort map_events_to_glib(AvahiWatchEvent events) {
95 (events & AVAHI_WATCH_IN ? G_IO_IN : 0) |
96 (events & AVAHI_WATCH_OUT ? G_IO_OUT : 0) |
97 (events & AVAHI_WATCH_ERR ? G_IO_ERR : 0) |
98 (events & AVAHI_WATCH_HUP ? G_IO_HUP : 0);
101 static AvahiWatchEvent map_events_from_glib(gushort events) {
103 (events & G_IO_IN ? AVAHI_WATCH_IN : 0) |
104 (events & G_IO_OUT ? AVAHI_WATCH_OUT : 0) |
105 (events & G_IO_ERR ? AVAHI_WATCH_ERR : 0) |
106 (events & G_IO_HUP ? AVAHI_WATCH_HUP : 0);
109 static AvahiWatch* watch_new(const AvahiPoll *api, int fd, AvahiWatchEvent events, AvahiWatchCallback callback, void *userdata) {
120 if (!(w = avahi_new(AvahiWatch, 1)))
125 w->pollfd.events = map_events_to_glib(events);
126 w->pollfd.revents = 0;
127 w->callback = callback;
128 w->userdata = userdata;
131 g_source_add_poll(&g->source, &w->pollfd);
132 w->pollfd_added = TRUE;
134 AVAHI_LLIST_PREPEND(AvahiWatch, watches, g->watches, w);
139 static void watch_update(AvahiWatch *w, AvahiWatchEvent events) {
143 w->pollfd.events = map_events_to_glib(events);
146 static AvahiWatchEvent watch_get_events(AvahiWatch *w) {
150 return map_events_from_glib(w->pollfd.revents);
153 static void watch_free(AvahiWatch *w) {
157 if (w->pollfd_added) {
158 g_source_remove_poll(&w->glib_poll->source, &w->pollfd);
159 w->pollfd_added = FALSE;
163 w->glib_poll->timeout_req_cleanup = TRUE;
166 static AvahiTimeout* timeout_new(const AvahiPoll *api, const struct timeval *tv, AvahiTimeoutCallback callback, void *userdata) {
176 if (!(t = avahi_new(AvahiTimeout, 1)))
182 if ((t->enabled = !!tv))
185 t->callback = callback;
186 t->userdata = userdata;
188 AVAHI_LLIST_PREPEND(AvahiTimeout, timeouts, g->timeouts, t);
193 static void timeout_update(AvahiTimeout *t, const struct timeval *tv) {
197 if ((t->enabled = !!tv))
201 static void timeout_free(AvahiTimeout *t) {
206 t->glib_poll->timeout_req_cleanup = TRUE;
209 static void destroy_timeout(AvahiTimeout *t) {
212 AVAHI_LLIST_REMOVE(AvahiTimeout, timeouts, t->glib_poll->timeouts, t);
216 static void cleanup_timeouts(AvahiGLibPoll *g, int all) {
217 AvahiTimeout *t, *next;
220 for (t = g->timeouts; t; t = next) {
221 next = t->timeouts_next;
227 g->timeout_req_cleanup = FALSE;
230 static AvahiTimeout* find_next_timeout(AvahiGLibPoll *g) {
231 AvahiTimeout *t, *n = NULL;
234 for (t = g->timeouts; t; t = t->timeouts_next) {
236 if (t->dead || !t->enabled)
239 if (!n || avahi_timeval_compare(&t->expiry, &n->expiry) < 0)
246 static void start_timeout_callback(AvahiTimeout *t) {
252 t->callback(t, t->userdata);
255 static gboolean prepare_func(GSource *source, gint *timeout) {
256 AvahiGLibPoll *g = (AvahiGLibPoll*) source;
257 AvahiTimeout *next_timeout;
262 if (g->watch_req_cleanup)
263 cleanup_watches(g, 0);
265 if (g->timeout_req_cleanup)
266 cleanup_timeouts(g, 0);
268 if ((next_timeout = find_next_timeout(g))) {
270 struct timeval tvnow;
273 g_source_get_current_time(source, &now);
274 tvnow.tv_sec = now.tv_sec;
275 tvnow.tv_usec = now.tv_usec;
277 usec = avahi_timeval_diff(&next_timeout->expiry, &tvnow);
284 *timeout = (gint) (usec / 1000);
291 static gboolean check_func(GSource *source) {
292 AvahiGLibPoll *g = (AvahiGLibPoll*) source;
294 AvahiTimeout *next_timeout;
298 if ((next_timeout = find_next_timeout(g))) {
300 struct timeval tvnow;
301 g_source_get_current_time(source, &now);
302 tvnow.tv_sec = now.tv_sec;
303 tvnow.tv_usec = now.tv_usec;
305 if (avahi_timeval_compare(&next_timeout->expiry, &tvnow) <= 0)
309 for (w = g->watches; w; w = w->watches_next)
310 if (w->pollfd.revents > 0)
316 static gboolean dispatch_func(GSource *source, AVAHI_GCC_UNUSED GSourceFunc callback, AVAHI_GCC_UNUSED gpointer userdata) {
317 AvahiGLibPoll* g = (AvahiGLibPoll*) source;
319 AvahiTimeout *next_timeout;
323 if ((next_timeout = find_next_timeout(g))) {
325 struct timeval tvnow;
326 g_source_get_current_time(source, &now);
327 tvnow.tv_sec = now.tv_sec;
328 tvnow.tv_usec = now.tv_usec;
330 if (avahi_timeval_compare(&next_timeout->expiry, &tvnow) < 0) {
331 start_timeout_callback(next_timeout);
336 for (w = g->watches; w; w = w->watches_next)
337 if (w->pollfd.revents > 0) {
339 w->callback(w, w->pollfd.fd, map_events_from_glib(w->pollfd.revents), w->userdata);
340 w->pollfd.revents = 0;
347 AvahiGLibPoll *avahi_glib_poll_new(GMainContext *context, gint priority) {
350 static GSourceFuncs source_funcs = {
359 g = (AvahiGLibPoll*) g_source_new(&source_funcs, sizeof(AvahiGLibPoll));
360 g_main_context_ref(g->context = context ? context : g_main_context_default());
364 g->api.watch_new = watch_new;
365 g->api.watch_free = watch_free;
366 g->api.watch_update = watch_update;
367 g->api.watch_get_events = watch_get_events;
369 g->api.timeout_new = timeout_new;
370 g->api.timeout_free = timeout_free;
371 g->api.timeout_update = timeout_update;
373 g->watch_req_cleanup = FALSE;
374 g->timeout_req_cleanup = FALSE;
376 AVAHI_LLIST_HEAD_INIT(AvahiWatch, g->watches);
377 AVAHI_LLIST_HEAD_INIT(AvahiTimeout, g->timeouts);
379 g_source_attach(&g->source, g->context);
380 g_source_set_priority(&g->source, priority);
381 g_source_set_can_recurse(&g->source, FALSE);
386 void avahi_glib_poll_free(AvahiGLibPoll *g) {
387 GSource *s = &g->source;
390 cleanup_watches(g, 1);
391 cleanup_timeouts(g, 1);
393 g_main_context_unref(g->context);
398 const AvahiPoll* avahi_glib_poll_get(AvahiGLibPoll *g) {