X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=avahi-glib%2Fglib-watch.c;h=f0fd934f73b5bb0390779628e9502e4a506c0c43;hb=a4572037763c65ec34ac921a6e15b936c6525b5d;hp=4af23907f301c2bebc8cef2ff0653ca179e095de;hpb=4f0a5e7572a4257894b4bfede42c26d65152609e;p=catta diff --git a/avahi-glib/glib-watch.c b/avahi-glib/glib-watch.c index 4af2390..f0fd934 100644 --- a/avahi-glib/glib-watch.c +++ b/avahi-glib/glib-watch.c @@ -25,32 +25,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; + gboolean timeout_req_cleanup; + gboolean watch_req_cleanup; - int req_cleanup; - - AVAHI_LLIST_HEAD(AvahiWatch, watches); + AVAHI_LLIST_HEAD(AvahiWatch, watches); + AVAHI_LLIST_HEAD(AvahiTimeout, timeouts); }; static void destroy_watch(AvahiWatch *w) { @@ -64,7 +78,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,10 +89,26 @@ 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; @@ -94,18 +124,14 @@ static AvahiWatch* watch_new(AvahiPoll *api, int fd, AvahiWatchEvent event, Avah 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 +142,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 +158,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->watch_req_cleanup) + cleanup_watches(g, 0); + + if (g->timeout_req_cleanup) + cleanup_timeouts(g, 0); - if (g->wakeup_callback) { + if ((next_timeout = find_next_timeout(g))) { GTimeVal now; struct timeval tvnow; AvahiUsec usec; @@ -189,13 +276,16 @@ static gboolean prepare_func(GSource *source, gint *timeout) { tvnow.tv_sec = now.tv_sec; tvnow.tv_usec = now.tv_usec; - usec = avahi_timeval_diff(&g->wakeup, &tvnow); + usec = avahi_timeval_diff(&next_timeout->expiry, &tvnow); - if (usec <= 0) + if (usec <= 0) { + *timeout = 0; return TRUE; + } *timeout = (gint) (usec / 1000); - } + } else + *timeout = -1; return FALSE; } @@ -203,17 +293,18 @@ static gboolean prepare_func(GSource *source, gint *timeout) { 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; } @@ -224,21 +315,22 @@ static gboolean check_func(GSource *source) { 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; } } @@ -246,7 +338,7 @@ static gboolean dispatch_func(GSource *source, GSourceFunc callback, gpointer us 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,7 +346,7 @@ 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 = { @@ -270,17 +362,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->wakeup_callback = NULL; - g->req_cleanup = 0; + g->watch_req_cleanup = FALSE; + g->timeout_req_cleanup = FALSE; 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 +389,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;