X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=avahi-glib%2Fglib-watch.c;h=e6def467050da96cbe02bfb918cc57613261aecb;hb=50be1d3adfb0d0c378b3464a99690441ab1e5f14;hp=7eab84be1a87453787feda873dc329e3ef408825;hpb=5d047523c87ba11aad8c384f7ffde25b4dd746ed;p=catta diff --git a/avahi-glib/glib-watch.c b/avahi-glib/glib-watch.c index 7eab84b..e6def46 100644 --- a/avahi-glib/glib-watch.c +++ b/avahi-glib/glib-watch.c @@ -31,27 +31,39 @@ 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; - gboolean use_wakeup; - int req_cleanup; - - AvahiGLibProcessCallback process_callback; - void *userdata; + gboolean timeout_req_cleanup; + gboolean watch_req_cleanup; AVAHI_LLIST_HEAD(AvahiWatch, watches); + AVAHI_LLIST_HEAD(AvahiTimeout, timeouts); }; static void destroy_watch(AvahiWatch *w) { @@ -65,7 +77,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); @@ -76,10 +88,10 @@ static void cleanup(AvahiGLibPoll *g, int all) { destroy_watch(w); } - g->req_cleanup = 0; + g->watch_req_cleanup = 0; } -static AvahiWatch* watch_new(AvahiPoll *api, int fd, AvahiWatchEvent event, AvahiWatchCallback callback, void *userdata) { +static AvahiWatch* watch_new(const AvahiPoll *api, int fd, AvahiWatchEvent event, AvahiWatchCallback callback, void *userdata) { AvahiWatch *w; AvahiGLibPoll *g; @@ -100,13 +112,13 @@ static AvahiWatch* watch_new(AvahiPoll *api, int fd, AvahiWatchEvent event, Avah (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.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); @@ -120,39 +132,129 @@ static void watch_update(AvahiWatch *w, AvahiWatchEvent events) { w->pollfd.events = events; } +static AvahiWatchEvent watch_get_events(AvahiWatch *w) { + assert(w); + assert(!w->dead); + + return w->pollfd.revents; +} + static void watch_free(AvahiWatch *w) { assert(w); assert(!w->dead); if (w->pollfd_added) { g_source_remove_poll(&w->glib_poll->source, &w->pollfd); - w->pollfd_added = 0; + w->pollfd_added = TRUE; } - w->dead = 1; - w->glib_poll->req_cleanup = 1; + w->dead = TRUE; + w->glib_poll->timeout_req_cleanup = TRUE; } -static void set_wakeup_time(AvahiPoll *api, const struct timeval *tv) { +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 (!(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 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); + + for (t = g->timeouts; t; t = next) { + next = t->timeouts_next; - if (tv) { - g->wakeup = *tv; - g->use_wakeup = 1; - } else - g->use_wakeup = 0; + if (all || t->dead) + destroy_timeout(t); + } + + 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->use_wakeup) { + 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; @@ -161,7 +263,7 @@ 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) return TRUE; @@ -175,9 +277,21 @@ 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 ((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(&next_timeout->expiry, &tvnow) < 0) + return TRUE; + } + for (w = g->watches; w; w = w->watches_next) if (w->pollfd.revents > 0) return TRUE; @@ -188,29 +302,35 @@ static gboolean check_func(GSource *source) { static gboolean dispatch_func(GSource *source, GSourceFunc callback, gpointer userdata) { AvahiGLibPoll* g = (AvahiGLibPoll*) source; AvahiWatch *w; + AvahiTimeout *next_timeout; g_assert(g); - if (g->req_cleanup) - cleanup(g, 0); - - if (g->process_callback) - g->process_callback(g, g->userdata); + 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(&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->pollfd.revents = 0; + return TRUE; } - if (g->req_cleanup) - cleanup(g, 0); - return TRUE; } -AvahiGLibPoll *avahi_glib_poll_new(GMainContext *context, AvahiGLibProcessCallback callback, void *userdata) { +AvahiGLibPoll *avahi_glib_poll_new(GMainContext *context, gint priority) { AvahiGLibPoll *g; static GSourceFuncs source_funcs = { @@ -226,19 +346,24 @@ AvahiGLibPoll *avahi_glib_poll_new(GMainContext *context, AvahiGLibProcessCallba 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_time = set_wakeup_time; + 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->use_wakeup = 0; - g->process_callback = callback; - g->userdata = userdata; - 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); return g; } @@ -247,14 +372,15 @@ void avahi_glib_poll_free(AvahiGLibPoll *g) { GSource *s = &g->source; assert(g); - cleanup(g, 1); - + cleanup_watches(g, 1); + cleanup_timeouts(g, 1); + g_main_context_unref(g->context); g_source_destroy(s); g_source_unref(s); } -AvahiPoll* avahi_glib_poll_get(AvahiGLibPoll *g) { +const AvahiPoll* avahi_glib_poll_get(AvahiGLibPoll *g) { assert(g); return &g->api;