X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=avahi-glib%2Fglib-watch.c;h=5b60bbc4cfcbe6c5922547bec031f97364bcc09c;hb=908e491f7d55209acfbb2595ab1ef5b24502d641;hp=4af23907f301c2bebc8cef2ff0653ca179e095de;hpb=4f0a5e7572a4257894b4bfede42c26d65152609e;p=catta diff --git a/avahi-glib/glib-watch.c b/avahi-glib/glib-watch.c index 4af2390..5b60bbc 100644 --- a/avahi-glib/glib-watch.c +++ b/avahi-glib/glib-watch.c @@ -1,18 +1,16 @@ -/* $Id$ */ - /*** This file is part of avahi. - + avahi is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + avahi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with avahi; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -25,32 +23,46 @@ #include #include +#include #include "glib-watch.h" struct AvahiWatch { AvahiGLibPoll *glib_poll; int dead; + GPollFD pollfd; int pollfd_added; + AvahiWatchCallback callback; void *userdata; AVAHI_LLIST_FIELDS(AvahiWatch, watches); }; +struct AvahiTimeout { + AvahiGLibPoll *glib_poll; + gboolean dead; + + gboolean enabled; + struct timeval expiry; + + AvahiTimeoutCallback callback; + void *userdata; + + AVAHI_LLIST_FIELDS(AvahiTimeout, timeouts); +}; + struct AvahiGLibPoll { GSource source; AvahiPoll api; GMainContext *context; - struct timeval wakeup; - AvahiWakeupCallback wakeup_callback; - void *wakeup_userdata; - - int req_cleanup; - - AVAHI_LLIST_HEAD(AvahiWatch, watches); + gboolean timeout_req_cleanup; + gboolean watch_req_cleanup; + + AVAHI_LLIST_HEAD(AvahiWatch, watches); + AVAHI_LLIST_HEAD(AvahiTimeout, timeouts); }; static void destroy_watch(AvahiWatch *w) { @@ -64,7 +76,7 @@ static void destroy_watch(AvahiWatch *w) { avahi_free(w); } -static void cleanup(AvahiGLibPoll *g, int all) { +static void cleanup_watches(AvahiGLibPoll *g, int all) { AvahiWatch *w, *next; assert(g); @@ -75,13 +87,29 @@ static void cleanup(AvahiGLibPoll *g, int all) { destroy_watch(w); } - g->req_cleanup = 0; + g->watch_req_cleanup = 0; +} + +static gushort map_events_to_glib(AvahiWatchEvent events) { + return + (events & AVAHI_WATCH_IN ? G_IO_IN : 0) | + (events & AVAHI_WATCH_OUT ? G_IO_OUT : 0) | + (events & AVAHI_WATCH_ERR ? G_IO_ERR : 0) | + (events & AVAHI_WATCH_HUP ? G_IO_HUP : 0); } -static AvahiWatch* watch_new(AvahiPoll *api, int fd, AvahiWatchEvent event, AvahiWatchCallback callback, void *userdata) { +static AvahiWatchEvent map_events_from_glib(gushort events) { + return + (events & G_IO_IN ? AVAHI_WATCH_IN : 0) | + (events & G_IO_OUT ? AVAHI_WATCH_OUT : 0) | + (events & G_IO_ERR ? AVAHI_WATCH_ERR : 0) | + (events & G_IO_HUP ? AVAHI_WATCH_HUP : 0); +} + +static AvahiWatch* watch_new(const AvahiPoll *api, int fd, AvahiWatchEvent events, AvahiWatchCallback callback, void *userdata) { AvahiWatch *w; AvahiGLibPoll *g; - + assert(api); assert(fd >= 0); assert(callback); @@ -91,21 +119,17 @@ static AvahiWatch* watch_new(AvahiPoll *api, int fd, AvahiWatchEvent event, Avah if (!(w = avahi_new(AvahiWatch, 1))) return NULL; - + w->glib_poll = g; w->pollfd.fd = fd; - w->pollfd.events = - (event & AVAHI_WATCH_IN ? G_IO_IN : 0) | - (event & AVAHI_WATCH_OUT ? G_IO_OUT : 0) | - (event & AVAHI_WATCH_ERR ? G_IO_ERR : 0) | - (event & AVAHI_WATCH_HUP ? G_IO_HUP : 0); - ; + w->pollfd.events = map_events_to_glib(events); + w->pollfd.revents = 0; w->callback = callback; w->userdata = userdata; - w->dead = 0; + w->dead = FALSE; g_source_add_poll(&g->source, &w->pollfd); - w->pollfd_added = 1; + w->pollfd_added = TRUE; AVAHI_LLIST_PREPEND(AvahiWatch, watches, g->watches, w); @@ -116,7 +140,14 @@ static void watch_update(AvahiWatch *w, AvahiWatchEvent events) { assert(w); assert(!w->dead); - w->pollfd.events = events; + w->pollfd.events = map_events_to_glib(events); +} + +static AvahiWatchEvent watch_get_events(AvahiWatch *w) { + assert(w); + assert(!w->dead); + + return map_events_from_glib(w->pollfd.revents); } static void watch_free(AvahiWatch *w) { @@ -125,62 +156,116 @@ static void watch_free(AvahiWatch *w) { if (w->pollfd_added) { g_source_remove_poll(&w->glib_poll->source, &w->pollfd); - w->pollfd_added = 0; + w->pollfd_added = FALSE; } - - w->dead = 1; - w->glib_poll->req_cleanup = 1; + + w->dead = TRUE; + w->glib_poll->timeout_req_cleanup = TRUE; } -static void set_wakeup(AvahiPoll *api, const struct timeval *tv, AvahiWakeupCallback callback, void *userdata) { +static AvahiTimeout* timeout_new(const AvahiPoll *api, const struct timeval *tv, AvahiTimeoutCallback callback, void *userdata) { + AvahiTimeout *t; AvahiGLibPoll *g; assert(api); + assert(callback); + g = api->userdata; + assert(g); - if (callback) { - if (tv) - g->wakeup = *tv; - else { - g->wakeup.tv_sec = 0; - g->wakeup.tv_usec = 0; - } - - g->wakeup_callback = callback; - g->wakeup_userdata = userdata; - } else - g->wakeup_callback = NULL; + if (!(t = avahi_new(AvahiTimeout, 1))) + return NULL; + + t->glib_poll = g; + t->dead = FALSE; + + if ((t->enabled = !!tv)) + t->expiry = *tv; + + t->callback = callback; + t->userdata = userdata; + + AVAHI_LLIST_PREPEND(AvahiTimeout, timeouts, g->timeouts, t); + + return t; } -static void start_wakeup_callback(AvahiGLibPoll *g) { - AvahiWakeupCallback callback; - void *userdata; +static void timeout_update(AvahiTimeout *t, const struct timeval *tv) { + assert(t); + assert(!t->dead); + if ((t->enabled = !!tv)) + t->expiry = *tv; +} + +static void timeout_free(AvahiTimeout *t) { + assert(t); + assert(!t->dead); + + t->dead = TRUE; + t->glib_poll->timeout_req_cleanup = TRUE; +} + +static void destroy_timeout(AvahiTimeout *t) { + assert(t); + + AVAHI_LLIST_REMOVE(AvahiTimeout, timeouts, t->glib_poll->timeouts, t); + avahi_free(t); +} + +static void cleanup_timeouts(AvahiGLibPoll *g, int all) { + AvahiTimeout *t, *next; assert(g); - /* Reset the wakeup functions, but allow changing of the two - values from the callback function */ + for (t = g->timeouts; t; t = next) { + next = t->timeouts_next; - callback = g->wakeup_callback; - userdata = g->wakeup_userdata; - g->wakeup_callback = NULL; - g->wakeup_userdata = NULL; + if (all || t->dead) + destroy_timeout(t); + } - assert(callback); - - callback(&g->api, userdata); + g->timeout_req_cleanup = FALSE; +} + +static AvahiTimeout* find_next_timeout(AvahiGLibPoll *g) { + AvahiTimeout *t, *n = NULL; + assert(g); + + for (t = g->timeouts; t; t = t->timeouts_next) { + + if (t->dead || !t->enabled) + continue; + + if (!n || avahi_timeval_compare(&t->expiry, &n->expiry) < 0) + n = t; + } + + return n; +} + +static void start_timeout_callback(AvahiTimeout *t) { + assert(t); + assert(!t->dead); + assert(t->enabled); + + t->enabled = 0; + t->callback(t, t->userdata); } static gboolean prepare_func(GSource *source, gint *timeout) { AvahiGLibPoll *g = (AvahiGLibPoll*) source; + AvahiTimeout *next_timeout; g_assert(g); g_assert(timeout); - if (g->req_cleanup) - cleanup(g, 0); - - if (g->wakeup_callback) { + if (g->watch_req_cleanup) + cleanup_watches(g, 0); + + if (g->timeout_req_cleanup) + cleanup_timeouts(g, 0); + + if ((next_timeout = find_next_timeout(g))) { GTimeVal now; struct timeval tvnow; AvahiUsec usec; @@ -188,65 +273,70 @@ static gboolean prepare_func(GSource *source, gint *timeout) { g_source_get_current_time(source, &now); tvnow.tv_sec = now.tv_sec; tvnow.tv_usec = now.tv_usec; - - usec = avahi_timeval_diff(&g->wakeup, &tvnow); - if (usec <= 0) + usec = avahi_timeval_diff(&next_timeout->expiry, &tvnow); + + if (usec <= 0) { + *timeout = 0; return TRUE; + } *timeout = (gint) (usec / 1000); - } - + } else + *timeout = -1; + return FALSE; } static gboolean check_func(GSource *source) { AvahiGLibPoll *g = (AvahiGLibPoll*) source; AvahiWatch *w; + AvahiTimeout *next_timeout; g_assert(g); - if (g->wakeup_callback) { + if ((next_timeout = find_next_timeout(g))) { GTimeVal now; struct timeval tvnow; g_source_get_current_time(source, &now); tvnow.tv_sec = now.tv_sec; tvnow.tv_usec = now.tv_usec; - - if (avahi_timeval_compare(&g->wakeup, &tvnow) < 0) + + if (avahi_timeval_compare(&next_timeout->expiry, &tvnow) <= 0) return TRUE; } for (w = g->watches; w; w = w->watches_next) if (w->pollfd.revents > 0) return TRUE; - + return FALSE; } -static gboolean dispatch_func(GSource *source, GSourceFunc callback, gpointer userdata) { +static gboolean dispatch_func(GSource *source, AVAHI_GCC_UNUSED GSourceFunc callback, AVAHI_GCC_UNUSED gpointer userdata) { AvahiGLibPoll* g = (AvahiGLibPoll*) source; AvahiWatch *w; - + AvahiTimeout *next_timeout; + g_assert(g); - if (g->wakeup_callback) { + if ((next_timeout = find_next_timeout(g))) { GTimeVal now; struct timeval tvnow; g_source_get_current_time(source, &now); tvnow.tv_sec = now.tv_sec; tvnow.tv_usec = now.tv_usec; - - if (avahi_timeval_compare(&g->wakeup, &tvnow) < 0) { - start_wakeup_callback(g); + + if (avahi_timeval_compare(&next_timeout->expiry, &tvnow) < 0) { + start_timeout_callback(next_timeout); return TRUE; } } - + for (w = g->watches; w; w = w->watches_next) if (w->pollfd.revents > 0) { assert(w->callback); - w->callback(w, w->pollfd.fd, w->pollfd.revents, w->userdata); + w->callback(w, w->pollfd.fd, map_events_from_glib(w->pollfd.revents), w->userdata); w->pollfd.revents = 0; return TRUE; } @@ -254,9 +344,9 @@ static gboolean dispatch_func(GSource *source, GSourceFunc callback, gpointer us return TRUE; } -AvahiGLibPoll *avahi_glib_poll_new(GMainContext *context) { +AvahiGLibPoll *avahi_glib_poll_new(GMainContext *context, gint priority) { AvahiGLibPoll *g; - + static GSourceFuncs source_funcs = { prepare_func, check_func, @@ -270,17 +360,25 @@ AvahiGLibPoll *avahi_glib_poll_new(GMainContext *context) { g_main_context_ref(g->context = context ? context : g_main_context_default()); g->api.userdata = g; + g->api.watch_new = watch_new; g->api.watch_free = watch_free; g->api.watch_update = watch_update; - g->api.set_wakeup = set_wakeup; + g->api.watch_get_events = watch_get_events; + + g->api.timeout_new = timeout_new; + g->api.timeout_free = timeout_free; + g->api.timeout_update = timeout_update; + + g->watch_req_cleanup = FALSE; + g->timeout_req_cleanup = FALSE; - g->wakeup_callback = NULL; - g->req_cleanup = 0; - AVAHI_LLIST_HEAD_INIT(AvahiWatch, g->watches); - + AVAHI_LLIST_HEAD_INIT(AvahiTimeout, g->timeouts); + g_source_attach(&g->source, g->context); + g_source_set_priority(&g->source, priority); + g_source_set_can_recurse(&g->source, FALSE); return g; } @@ -289,17 +387,15 @@ void avahi_glib_poll_free(AvahiGLibPoll *g) { GSource *s = &g->source; assert(g); -/* g_message("BEFORE"); */ - cleanup(g, 1); + cleanup_watches(g, 1); + cleanup_timeouts(g, 1); -/* g_message("MIDDLE"); */ g_main_context_unref(g->context); g_source_destroy(s); g_source_unref(s); -/* g_message("AFTER"); */ } -AvahiPoll* avahi_glib_poll_get(AvahiGLibPoll *g) { +const AvahiPoll* avahi_glib_poll_get(AvahiGLibPoll *g) { assert(g); return &g->api;