From: Lennart Poettering Date: Sun, 14 Aug 2005 22:11:35 +0000 (+0000) Subject: * add new priority parameter to avahi_glib_poll_new() X-Git-Url: https://git.meshlink.io/?a=commitdiff_plain;h=769c00f228ba0d37217aaf1424dedde390e7a01c;p=catta * add new priority parameter to avahi_glib_poll_new() * beef up AvahiPoll a little to contain real timeout events * cleanups in avahi-client * drop glib dependency * port to AvahiPoll system * put some "const"s and "static"s in to make gcc shut up * change all uses of malloc/free to avahi_malloc/avahi_new/avahi_free git-svn-id: file:///home/lennart/svn/public/avahi/trunk@324 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe --- diff --git a/avahi-client/Makefile.am b/avahi-client/Makefile.am index 2c80e84..4b755fc 100644 --- a/avahi-client/Makefile.am +++ b/avahi-client/Makefile.am @@ -35,6 +35,7 @@ avahi_clientinclude_HEADERS = \ noinst_HEADERS = \ internal.h + dbus-watch-glue.h noinst_PROGRAMS = \ client-test @@ -45,11 +46,15 @@ lib_LTLIBRARIES = \ libavahi_client_la_SOURCES = \ client.c client.h \ entrygroup.c \ - browser.c + browser.c \ + dbus-watch-glue.c + +libavahi_client_la_CFLAGS = $(AM_CFLAGS) +libavahi_client_la_LIBADD = $(AM_LDADD) client_test_SOURCES = \ client-test.c client_test_CFLAGS = $(AM_CFLAGS) -client_test_LDADD = $(AM_LDADD) libavahi-client.la ../avahi-common/libavahi-common.la +client_test_LDADD = $(AM_LDADD) libavahi-client.la ../avahi-common/libavahi-common.la ../avahi-glib/libavahi-glib.la endif diff --git a/avahi-client/browser.c b/avahi-client/browser.c index a20b5d2..e994d2a 100644 --- a/avahi-client/browser.c +++ b/avahi-client/browser.c @@ -23,10 +23,6 @@ #include #endif -#include -#include -#include -#include #include #include #include @@ -34,14 +30,18 @@ #include #include -#include +#include +#include +#include +#include +#include #include "client.h" #include "internal.h" /* AvahiDomainBrowser */ -AvahiDomainBrowser* avahi_domain_browser_new (AvahiClient *client, AvahiIfIndex interface, AvahiProtocol protocol, char *domain, AvahiDomainBrowserType btype, AvahiDomainBrowserCallback callback, void *user_data) +AvahiDomainBrowser* avahi_domain_browser_new (AvahiClient *client, AvahiIfIndex interface, AvahiProtocol protocol, const char *domain, AvahiDomainBrowserType btype, AvahiDomainBrowserCallback callback, void *user_data) { AvahiDomainBrowser *tmp = NULL; DBusMessage *message = NULL, *reply; @@ -70,7 +70,7 @@ AvahiDomainBrowser* avahi_domain_browser_new (AvahiClient *client, AvahiIfIndex if (dbus_error_is_set (&error) || path == NULL) goto dbus_error; - tmp = malloc (sizeof (AvahiDomainBrowser)); + tmp = avahi_new (AvahiDomainBrowser, 1); tmp->client = client; tmp->callback = callback; tmp->user_data = user_data; @@ -107,12 +107,12 @@ avahi_domain_browser_free (AvahiDomainBrowser *b) AVAHI_LLIST_REMOVE(AvahiDomainBrowser, domain_browsers, client->domain_browsers, b); - free (b); + avahi_free (b); return avahi_client_set_errno (client, AVAHI_OK); } -char* +const char* avahi_domain_browser_path (AvahiDomainBrowser *b) { return b->path; @@ -161,7 +161,7 @@ out: } /* AvahiServiceTypeBrowser */ -AvahiServiceTypeBrowser* avahi_service_type_browser_new (AvahiClient *client, AvahiIfIndex interface, AvahiProtocol protocol, char *domain, AvahiServiceTypeBrowserCallback callback, void *user_data) +AvahiServiceTypeBrowser* avahi_service_type_browser_new (AvahiClient *client, AvahiIfIndex interface, AvahiProtocol protocol, const char *domain, AvahiServiceTypeBrowserCallback callback, void *user_data) { AvahiServiceTypeBrowser *tmp = NULL; DBusMessage *message = NULL, *reply; @@ -192,7 +192,7 @@ AvahiServiceTypeBrowser* avahi_service_type_browser_new (AvahiClient *client, Av if (dbus_error_is_set (&error) || path == NULL) goto dbus_error; - tmp = malloc (sizeof (AvahiServiceTypeBrowser)); + tmp = avahi_new(AvahiServiceTypeBrowser, 1); tmp->client = client; tmp->callback = callback; tmp->user_data = user_data; @@ -229,12 +229,12 @@ avahi_service_type_browser_free (AvahiServiceTypeBrowser *b) AVAHI_LLIST_REMOVE(AvahiServiceTypeBrowser, service_type_browsers, b->client->service_type_browsers, b); - free (b); + avahi_free (b); return avahi_client_set_errno (client, AVAHI_OK); } -char* +const char* avahi_service_type_browser_path (AvahiServiceTypeBrowser *b) { return b->path; @@ -288,7 +288,7 @@ out: /* AvahiServiceBrowser */ -AvahiServiceBrowser* avahi_service_browser_new (AvahiClient *client, AvahiIfIndex interface, AvahiProtocol protocol, char *type, char *domain, AvahiServiceBrowserCallback callback, void *user_data) +AvahiServiceBrowser* avahi_service_browser_new (AvahiClient *client, AvahiIfIndex interface, AvahiProtocol protocol, const char *type, const char *domain, AvahiServiceBrowserCallback callback, void *user_data) { AvahiServiceBrowser *tmp = NULL; DBusMessage *message = NULL, *reply; @@ -322,7 +322,7 @@ AvahiServiceBrowser* avahi_service_browser_new (AvahiClient *client, AvahiIfInde if (dbus_error_is_set (&error) || path == NULL) goto dbus_error; - tmp = malloc (sizeof (AvahiServiceBrowser)); + tmp = avahi_new(AvahiServiceBrowser, 1); tmp->client = client; tmp->callback = callback; tmp->user_data = user_data; @@ -359,12 +359,12 @@ avahi_service_browser_free (AvahiServiceBrowser *b) AVAHI_LLIST_REMOVE(AvahiServiceBrowser, service_browsers, b->client->service_browsers, b); - free (b); + avahi_free (b); return avahi_client_set_errno (client, AVAHI_OK); } -char* +const char* avahi_service_browser_path (AvahiServiceBrowser *b) { return b->path; diff --git a/avahi-client/client-test.c b/avahi-client/client-test.c index 352ee58..2189467 100644 --- a/avahi-client/client-test.c +++ b/avahi-client/client-test.c @@ -25,53 +25,55 @@ #include #include +#include +#include #include #include -void +static void avahi_client_callback (AvahiClient *c, AvahiClientState state, void *user_data) { printf ("XXX: Callback on client, state -> %d, data -> %s\n", state, (char*)user_data); } -void +static void avahi_entry_group_callback (AvahiEntryGroup *g, AvahiEntryGroupState state, void *user_data) { printf ("XXX: Callback on %s, state -> %d, data -> %s\n", avahi_entry_group_path (g), state, (char*)user_data); } -void -avahi_domain_browser_callback (AvahiDomainBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, char *domain, void *user_data) +static void +avahi_domain_browser_callback (AvahiDomainBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *domain, void *user_data) { printf ("XXX: Callback on %s, interface (%d), protocol (%d), event (%d), domain (%s), data (%s)\n", avahi_domain_browser_path (b), interface, protocol, event, domain, (char*)user_data); } -void -avahi_service_browser_callback (AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, char *name, char *type, char *domain, void *user_data) +static void +avahi_service_browser_callback (AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, void *user_data) { printf ("XXX: Callback on %s, interface (%d), protocol (%d), event (%d), name (%s), type (%s), domain (%s), data (%s)\n", avahi_service_browser_path (b), interface, protocol, event, name, type, domain, (char*)user_data); } -void -avahi_service_type_browser_callback (AvahiServiceTypeBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, char *type, char *domain, void *user_data) +static void +avahi_service_type_browser_callback (AvahiServiceTypeBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *type, const char *domain, void *user_data) { printf ("XXX: Callback on %s, interface (%d), protocol (%d), event (%d), type (%s), domain (%s), data (%s)\n", avahi_service_type_browser_path (b), interface, protocol, event, type, domain, (char*)user_data); } -gboolean +static gboolean test_free_domain_browser (gpointer data) { - printf ("XXX: freeing domain browser\n"); AvahiServiceBrowser *b = data; + printf ("XXX: freeing domain browser\n"); avahi_service_browser_free (b); return FALSE; } -gboolean +static gboolean test_free_entry_group (gpointer data) { - printf ("XXX: freeing entry group\n"); AvahiEntryGroup *g = data; + printf ("XXX: freeing entry group\n"); avahi_entry_group_free (g); return FALSE; } @@ -85,11 +87,15 @@ main (int argc, char *argv[]) AvahiDomainBrowser *domain; AvahiServiceBrowser *sb; AvahiServiceTypeBrowser *st; + AvahiGLibPoll *glib_poll; char *ret; + avahi_set_allocator(avahi_glib_allocator()); + + glib_poll = avahi_glib_poll_new(NULL, G_PRIORITY_DEFAULT); loop = g_main_loop_new (NULL, FALSE); - avahi = avahi_client_new (avahi_client_callback, "omghai2u"); + avahi = avahi_client_new (avahi_glib_poll_get(glib_poll), avahi_client_callback, "omghai2u"); g_assert (avahi != NULL); diff --git a/avahi-client/client.c b/avahi-client/client.c index ad64946..7edc469 100644 --- a/avahi-client/client.c +++ b/avahi-client/client.c @@ -27,15 +27,16 @@ #include #include #include +#include #include #include #include #include -#include #include +#include "dbus-watch-glue.h" #include "client.h" #include "internal.h" @@ -58,7 +59,7 @@ void avahi_client_state_change (AvahiClient *client, int state) client->callback (client, state, client->user_data); } -void +static void avahi_client_state_request_callback (DBusPendingCall *call, void *data) { AvahiClient *client = data; @@ -87,7 +88,7 @@ avahi_client_state_request_callback (DBusPendingCall *call, void *data) dbus_pending_call_unref (call); } -void +static void avahi_client_schedule_state_request (AvahiClient *client) { DBusMessage *message; @@ -116,7 +117,7 @@ filter_func (DBusConnection *bus, DBusMessage *message, void *data) dbus_error_init (&error); if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) { - gchar *name, *old, *new; + char *name, *old, *new; dbus_message_get_args(message, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &old, DBUS_TYPE_STRING, &new, DBUS_TYPE_INVALID); if (dbus_error_is_set (&error)) { @@ -181,14 +182,14 @@ out: } AvahiClient * -avahi_client_new (AvahiClientCallback callback, void *user_data) +avahi_client_new (const AvahiPoll *poll_api, AvahiClientCallback callback, void *user_data) { AvahiClient *tmp = NULL; DBusError error; dbus_error_init (&error); - if (!(tmp = malloc(sizeof(AvahiClient)))) + if (!(tmp = avahi_new(AvahiClient, 1))) goto fail; AVAHI_LLIST_HEAD_INIT(AvahiEntryGroup, tmp->groups); @@ -196,14 +197,18 @@ avahi_client_new (AvahiClientCallback callback, void *user_data) AVAHI_LLIST_HEAD_INIT(AvahiServiceBrowser, tmp->service_browsers); AVAHI_LLIST_HEAD_INIT(AvahiServiceTypeBrowser, tmp->service_type_browsers); + tmp->poll_api = poll_api; tmp->bus = dbus_bus_get (DBUS_BUS_SYSTEM, &error); if (dbus_error_is_set (&error)) { goto fail; } - dbus_connection_setup_with_g_main (tmp->bus, NULL); - dbus_connection_set_exit_on_disconnect (tmp->bus, FALSE); +/* dbus_connection_setup_with_g_main (tmp->bus, NULL); */ +/* dbus_connection_set_exit_on_disconnect (tmp->bus, FALSE); */ + + if (avahi_dbus_connection_glue(tmp->bus, poll_api) < 0) + goto fail; if (!dbus_connection_add_filter (tmp->bus, filter_func, tmp, NULL)) { @@ -243,7 +248,7 @@ avahi_client_new (AvahiClientCallback callback, void *user_data) return tmp; fail: - free (tmp); + avahi_free (tmp); if (dbus_error_is_set(&error)) dbus_error_free(&error); @@ -252,7 +257,7 @@ fail: } static char* -avahi_client_get_string_reply_and_block (AvahiClient *client, char *method, char *param) +avahi_client_get_string_reply_and_block (AvahiClient *client, const char *method, const char *param) { DBusMessage *message; DBusMessage *reply; @@ -303,7 +308,7 @@ avahi_client_get_string_reply_and_block (AvahiClient *client, char *method, char return NULL; } - new = strdup (ret); + new = avahi_strdup (ret); avahi_client_set_errno (client, AVAHI_OK); return new; diff --git a/avahi-client/client.h b/avahi-client/client.h index 16e9998..de6f207 100644 --- a/avahi-client/client.h +++ b/avahi-client/client.h @@ -28,6 +28,7 @@ #include #include #include +#include /** \file client.h Definitions and functions for the client API over D-Bus */ @@ -58,16 +59,16 @@ typedef void (*AvahiClientCallback) (AvahiClient *s, AvahiClientState state, voi typedef void (*AvahiEntryGroupCallback) (AvahiEntryGroup *g, AvahiEntryGroupState state, void* userdata); /** The function prototype for the callback of an AvahiDomainBrowser */ -typedef void (*AvahiDomainBrowserCallback) (AvahiDomainBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, char *domain, void *user_data); +typedef void (*AvahiDomainBrowserCallback) (AvahiDomainBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *domain, void *user_data); /** The function prototype for the callback of an AvahiServiceBrowser */ -typedef void (*AvahiServiceBrowserCallback) (AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, char *name, char *type, char *domain, void *user_data); +typedef void (*AvahiServiceBrowserCallback) (AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, void *user_data); /** The function prototype for the callback of an AvahiServiceTypeBrowser */ -typedef void (*AvahiServiceTypeBrowserCallback) (AvahiServiceTypeBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, char *type, char *domain, void *user_data); +typedef void (*AvahiServiceTypeBrowserCallback) (AvahiServiceTypeBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *type, const char *domain, void *user_data); /** Creates a new client instance */ -AvahiClient* avahi_client_new (AvahiClientCallback callback, void *user_data); +AvahiClient* avahi_client_new (const AvahiPoll *poll_api, AvahiClientCallback callback, void *user_data); /** Get the version of the server */ char* avahi_client_get_version_string (AvahiClient*); @@ -118,19 +119,19 @@ avahi_entry_group_add_service (AvahiEntryGroup *group, AvahiStringList *txt); /** Get the D-Bus path of an AvahiEntryGroup object, for debugging purposes only. */ -char* avahi_entry_group_path (AvahiEntryGroup *); +const char* avahi_entry_group_path (AvahiEntryGroup *); /** Browse for domains on the local network */ AvahiDomainBrowser* avahi_domain_browser_new (AvahiClient *client, AvahiIfIndex interface, AvahiProtocol protocol, - char *domain, + const char *domain, AvahiDomainBrowserType btype, AvahiDomainBrowserCallback callback, void *user_data); /** Get the D-Bus path of an AvahiDomainBrowser object, for debugging purposes only. */ -char* avahi_domain_browser_path (AvahiDomainBrowser *); +const char* avahi_domain_browser_path (AvahiDomainBrowser *); /** Cleans up and frees an AvahiDomainBrowser object */ int avahi_domain_browser_free (AvahiDomainBrowser *); @@ -140,12 +141,12 @@ AvahiServiceTypeBrowser* avahi_service_type_browser_new ( AvahiClient *client, AvahiIfIndex interface, AvahiProtocol protocol, - char *domain, + const char *domain, AvahiServiceTypeBrowserCallback callback, void *user_data); /** Get the D-Bus path of an AvahiServiceTypeBrowser object, for debugging purposes only. */ -char* avahi_service_type_browser_path (AvahiServiceTypeBrowser *); +const char* avahi_service_type_browser_path (AvahiServiceTypeBrowser *); /** Cleans up and frees an AvahiServiceTypeBrowser object */ int avahi_service_type_browser_free (AvahiServiceTypeBrowser *); @@ -155,13 +156,13 @@ AvahiServiceBrowser* avahi_service_browser_new ( AvahiClient *client, AvahiIfIndex interface, AvahiProtocol protocol, - char *type, - char *domain, + const char *type, + const char *domain, AvahiServiceBrowserCallback callback, void *user_data); /** Get the D-Bus path of an AvahiServiceBrowser object, for debugging purposes only. */ -char* avahi_service_browser_path (AvahiServiceBrowser *); +const char* avahi_service_browser_path (AvahiServiceBrowser *); /* Cleans up and frees an AvahiServiceBrowser object */ int avahi_service_browser_free (AvahiServiceBrowser *); diff --git a/avahi-client/dbus-watch-glue.c b/avahi-client/dbus-watch-glue.c new file mode 100644 index 0000000..025aeac --- /dev/null +++ b/avahi-client/dbus-watch-glue.c @@ -0,0 +1,234 @@ +/* $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 + USA. +***/ + +#include + +#include + +#include "dbus-watch-glue.h" + +static AvahiWatchEvent translate_dbus_to_avahi(unsigned int f) { + AvahiWatchEvent e = 0; + + if (f & DBUS_WATCH_READABLE) + e |= AVAHI_WATCH_IN; + if (f & DBUS_WATCH_WRITABLE) + e |= AVAHI_WATCH_OUT; + if (f & DBUS_WATCH_ERROR) + e |= AVAHI_WATCH_ERR; + if (f & DBUS_WATCH_HANGUP) + e |= AVAHI_WATCH_HUP; + + return e; +} + +static unsigned int translate_avahi_to_dbus(AvahiWatchEvent e) { + unsigned int f = 0; + + if (e & AVAHI_WATCH_IN) + f |= DBUS_WATCH_READABLE; + if (e & AVAHI_WATCH_OUT) + f |= DBUS_WATCH_WRITABLE; + if (e & AVAHI_WATCH_ERR) + f |= DBUS_WATCH_ERROR; + if (e & AVAHI_WATCH_HUP) + f |= DBUS_WATCH_HANGUP; + + return f; +} + +static void watch_callback(AvahiWatch *avahi_watch, int fd, AvahiWatchEvent events, void *userdata) { + DBusWatch *dbus_watch = userdata; + assert(avahi_watch); + assert(dbus_watch); + + dbus_watch_handle(dbus_watch, translate_avahi_to_dbus(events)); + /* Ignore the return value */ +} + +static dbus_bool_t update_watch(const AvahiPoll *poll_api, DBusWatch *dbus_watch) { + AvahiWatch *avahi_watch; + dbus_bool_t b; + + assert(dbus_watch); + + avahi_watch = dbus_watch_get_data(dbus_watch); + + b = dbus_watch_get_enabled(dbus_watch); + + if (b && !avahi_watch) { + + if (!(avahi_watch = poll_api->watch_new( + poll_api, + dbus_watch_get_fd(dbus_watch), + translate_dbus_to_avahi(dbus_watch_get_flags(dbus_watch)), + watch_callback, + dbus_watch))) + return FALSE; + + dbus_watch_set_data(dbus_watch, avahi_watch, (DBusFreeFunction) poll_api->watch_free); + + } else if (!b && avahi_watch) { + + poll_api->watch_free(avahi_watch); + dbus_watch_set_data(dbus_watch, NULL, NULL); + + } else if (avahi_watch) { + + /* Update flags */ + poll_api->watch_update(avahi_watch, dbus_watch_get_flags(dbus_watch)); + } + + return TRUE; +} + +static dbus_bool_t add_watch(DBusWatch *dbus_watch, void *userdata) { + const AvahiPoll *poll_api = (const AvahiPoll*) userdata; + + assert(dbus_watch); + assert(poll_api); + + return update_watch(poll_api, dbus_watch); +} + +static void remove_watch(DBusWatch *dbus_watch, void *userdata) { + const AvahiPoll *poll_api = (const AvahiPoll*) userdata; + AvahiWatch *avahi_watch; + + assert(dbus_watch); + assert(poll_api); + + avahi_watch = dbus_watch_get_data(dbus_watch); + poll_api->watch_free(avahi_watch); + dbus_watch_set_data(dbus_watch, NULL, NULL); +} + +static void watch_toggled(DBusWatch *dbus_watch, void *userdata) { + const AvahiPoll *poll_api = (const AvahiPoll*) userdata; + + assert(dbus_watch); + assert(poll_api); + + update_watch(poll_api, dbus_watch); +} + +typedef struct TimeoutData { + const AvahiPoll *poll_api; + AvahiTimeout *avahi_timeout; + DBusTimeout *dbus_timeout; +} TimeoutData; + +static void update_timeout(TimeoutData *timeout) { + assert(timeout); + + if (dbus_timeout_get_enabled(timeout->dbus_timeout)) { + struct timeval tv; + avahi_elapse_time(&tv, dbus_timeout_get_interval(timeout->dbus_timeout), 0); + timeout->poll_api->timeout_update(timeout-> + avahi_timeout, &tv); + } else + timeout->poll_api->timeout_update(timeout->avahi_timeout, NULL); + +} + +static void timeout_callback(AvahiTimeout *avahi_timeout, void *userdata) { + TimeoutData *timeout = userdata; + + assert(avahi_timeout); + assert(timeout); + + dbus_timeout_handle(timeout->dbus_timeout); + /* Ignore the return value */ + + update_timeout(timeout); +} + +static dbus_bool_t add_timeout(DBusTimeout *dbus_timeout, void *userdata) { + TimeoutData *timeout; + const AvahiPoll *poll_api = (const AvahiPoll*) userdata; + struct timeval tv; + dbus_bool_t b; + + assert(dbus_timeout); + assert(poll_api); + + if (!(timeout = avahi_new(TimeoutData, 1))) + return FALSE; + + timeout->dbus_timeout = dbus_timeout; + timeout->poll_api = poll_api; + + if ((b = dbus_timeout_get_enabled(dbus_timeout))) + avahi_elapse_time(&tv, dbus_timeout_get_interval(dbus_timeout), 0); + + if (!(timeout->avahi_timeout = poll_api->timeout_new( + poll_api, + b ? &tv : NULL, + timeout_callback, + dbus_timeout))) { + avahi_free(timeout); + return FALSE; + } + + dbus_timeout_set_data(dbus_timeout, timeout, NULL); + return TRUE; +} + +static void remove_timeout(DBusTimeout *dbus_timeout, void *userdata) { + TimeoutData *timeout; + const AvahiPoll *poll_api = (const AvahiPoll*) userdata; + + assert(dbus_timeout); + assert(poll_api); + + timeout = dbus_timeout_get_data(dbus_timeout); + assert(timeout); + + poll_api->timeout_free(timeout->avahi_timeout); + avahi_free(timeout); + dbus_timeout_set_data(dbus_timeout, NULL, NULL); +} + +static void timeout_toggled(DBusTimeout *dbus_timeout, void *userdata) { + TimeoutData *timeout; + const AvahiPoll *poll_api = (const AvahiPoll*) userdata; + + assert(dbus_timeout); + assert(poll_api); + + timeout = dbus_timeout_get_data(dbus_timeout); + assert(timeout); + + update_timeout(timeout); +} + +int avahi_dbus_connection_glue(DBusConnection *c, const AvahiPoll *poll_api) { + assert(c); + assert(poll_api); + + if (!(dbus_connection_set_watch_functions(c, add_watch, remove_watch, watch_toggled, (void*) poll_api, NULL))) + return -1; + + if (!(dbus_connection_set_timeout_functions(c, add_timeout, remove_timeout, timeout_toggled, (void*) poll_api, NULL))) + return -1; + + return 0; +} diff --git a/avahi-client/dbus-watch-glue.h b/avahi-client/dbus-watch-glue.h new file mode 100644 index 0000000..e815b45 --- /dev/null +++ b/avahi-client/dbus-watch-glue.h @@ -0,0 +1,31 @@ +#ifndef foodbuswatchgluehfoo +#define foodbuswatchgluehfoo + +/* $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 + USA. +***/ + +#include + +#include + +int avahi_dbus_connection_glue(DBusConnection *c, const AvahiPoll *poll_api); + +#endif diff --git a/avahi-client/entrygroup.c b/avahi-client/entrygroup.c index 93c3fd6..6335755 100644 --- a/avahi-client/entrygroup.c +++ b/avahi-client/entrygroup.c @@ -23,18 +23,17 @@ #include #endif -#include -#include -#include -#include #include #include #include #include -#include -#include +#include +#include +#include +#include +#include #include "client.h" #include "internal.h" @@ -88,11 +87,11 @@ avahi_entry_group_new (AvahiClient *client, AvahiEntryGroupCallback callback, vo goto fail; } - tmp = malloc (sizeof (AvahiEntryGroup)); + tmp = avahi_new(AvahiEntryGroup, 1); tmp->client = client; - tmp->path = strdup (path); + tmp->path = avahi_strdup (path); tmp->callback = callback; tmp->user_data = user_data; @@ -104,7 +103,7 @@ avahi_entry_group_new (AvahiClient *client, AvahiEntryGroupCallback callback, vo return tmp; fail: - if (tmp) free (tmp); + if (tmp) avahi_free (tmp); if (message) dbus_message_unref (message); return NULL; } @@ -128,7 +127,7 @@ avahi_entry_group_free (AvahiEntryGroup *group) AVAHI_LLIST_REMOVE(AvahiEntryGroup, groups, client->groups, group); - free (group); + avahi_free (group); return avahi_client_set_errno (client, AVAHI_OK); } @@ -252,7 +251,7 @@ avahi_entry_group_add_service (AvahiEntryGroup *group, /* Assemble the AvahiStringList into an Array of Array of Bytes to send over dbus */ for (p = txt; p != NULL; p = p->next) { DBusMessageIter sub2; - const guint8 *data = p->text; + const uint8_t *data = p->text; dbus_message_iter_open_container(&sub, DBUS_TYPE_ARRAY, "y", &sub2); dbus_message_iter_append_fixed_array(&sub2, DBUS_TYPE_BYTE, &data, p->size); @@ -267,7 +266,7 @@ avahi_entry_group_add_service (AvahiEntryGroup *group, } /* XXX: debug function */ -char* avahi_entry_group_path (AvahiEntryGroup *group) +const char* avahi_entry_group_path (AvahiEntryGroup *group) { if (group != NULL) return group->path; else return NULL; diff --git a/avahi-client/internal.h b/avahi-client/internal.h index d37958e..6058e20 100644 --- a/avahi-client/internal.h +++ b/avahi-client/internal.h @@ -27,6 +27,7 @@ struct _AvahiClient { + const AvahiPoll *poll_api; DBusConnection *bus; int error; AvahiClientCallback callback; diff --git a/avahi-common/simple-watch.c b/avahi-common/simple-watch.c index 5e03fe4..c3ed86f 100644 --- a/avahi-common/simple-watch.c +++ b/avahi-common/simple-watch.c @@ -36,14 +36,29 @@ struct AvahiWatch { AvahiSimplePoll *simple_poll; int dead; + int idx; struct pollfd pollfd; + AvahiWatchCallback callback; void *userdata; AVAHI_LLIST_FIELDS(AvahiWatch, watches); }; +struct AvahiTimeout { + AvahiSimplePoll *simple_poll; + int dead; + + int enabled; + struct timeval expiry; + + AvahiTimeoutCallback callback; + void *userdata; + + AVAHI_LLIST_FIELDS(AvahiTimeout, timeouts); +}; + struct AvahiSimplePoll { AvahiPoll api; AvahiPollFunc poll_func; @@ -51,16 +66,13 @@ struct AvahiSimplePoll { struct pollfd* pollfds; int n_pollfds, max_pollfds, rebuild_pollfds; - struct timeval wakeup; - AvahiWakeupCallback wakeup_callback; - void *wakeup_userdata; - - int req_cleanup; - + int watch_req_cleanup, timeout_req_cleanup; int quit; + int events_valid; int n_watches; AVAHI_LLIST_HEAD(AvahiWatch, watches); + AVAHI_LLIST_HEAD(AvahiTimeout, timeouts); }; static AvahiWatch* watch_new(const AvahiPoll *api, int fd, AvahiWatchEvent event, AvahiWatchCallback callback, void *userdata) { @@ -78,11 +90,13 @@ static AvahiWatch* watch_new(const AvahiPoll *api, int fd, AvahiWatchEvent event return NULL; w->simple_poll = s; + w->dead = 0; + w->pollfd.fd = fd; w->pollfd.events = event; + w->callback = callback; w->userdata = userdata; - w->dead = 0; if (s->n_pollfds < s->max_pollfds) { /* If there's space for this pollfd, go on and allocate it */ @@ -114,6 +128,16 @@ static void watch_update(AvahiWatch *w, AvahiWatchEvent events) { w->simple_poll->rebuild_pollfds = 1; } +static AvahiWatchEvent watch_get_events(AvahiWatch *w) { + assert(w); + assert(!w->dead); + + if (w->idx != -1 && w->simple_poll->events_valid) + return w->simple_poll->pollfds[w->idx].revents; + + return 0; +} + static void remove_pollfd(AvahiWatch *w) { assert(w); @@ -140,27 +164,7 @@ static void watch_free(AvahiWatch *w) { w->dead = 1; w->simple_poll->n_watches --; - w->simple_poll->req_cleanup = 1; -} - -static void set_wakeup(const AvahiPoll *api, const struct timeval *tv, AvahiWakeupCallback callback, void *userdata) { - AvahiSimplePoll *s; - - assert(api); - s = api->userdata; - - if (callback) { - if (tv) - s->wakeup = *tv; - else { - s->wakeup.tv_sec = 0; - s->wakeup.tv_usec = 0; - } - - s->wakeup_callback = callback; - s->wakeup_userdata = userdata; - } else - s->wakeup_callback = NULL; + w->simple_poll->watch_req_cleanup = 1; } static void destroy_watch(AvahiWatch *w) { @@ -175,7 +179,7 @@ static void destroy_watch(AvahiWatch *w) { avahi_free(w); } -static void cleanup(AvahiSimplePoll *s, int all) { +static void cleanup_watches(AvahiSimplePoll *s, int all) { AvahiWatch *w, *next; assert(s); @@ -186,7 +190,73 @@ static void cleanup(AvahiSimplePoll *s, int all) { destroy_watch(w); } - s->req_cleanup = 0; + s->timeout_req_cleanup = 0; +} + +static AvahiTimeout* timeout_new(const AvahiPoll *api, const struct timeval *tv, AvahiTimeoutCallback callback, void *userdata) { + AvahiTimeout *t; + AvahiSimplePoll *s; + + assert(api); + assert(callback); + + s = api->userdata; + assert(s); + + if (!(t = avahi_new(AvahiTimeout, 1))) + return NULL; + + t->simple_poll = s; + t->dead = 0; + + if ((t->enabled = !!tv)) + t->expiry = *tv; + + t->callback = callback; + t->userdata = userdata; + + AVAHI_LLIST_PREPEND(AvahiTimeout, timeouts, s->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 = 1; + t->simple_poll->timeout_req_cleanup = 1; +} + + +static void destroy_timeout(AvahiTimeout *t) { + assert(t); + + AVAHI_LLIST_REMOVE(AvahiTimeout, timeouts, t->simple_poll->timeouts, t); + + avahi_free(t); +} + +static void cleanup_timeouts(AvahiSimplePoll *s, int all) { + AvahiTimeout *t, *next; + assert(s); + + for (t = s->timeouts; t; t = next) { + next = t->timeouts_next; + + if (all || t->dead) + destroy_timeout(t); + } + + s->timeout_req_cleanup = 0; } AvahiSimplePoll *avahi_simple_poll_new(void) { @@ -196,21 +266,30 @@ AvahiSimplePoll *avahi_simple_poll_new(void) { return NULL; s->api.userdata = s; + s->api.watch_new = watch_new; s->api.watch_free = watch_free; s->api.watch_update = watch_update; - s->api.set_wakeup = set_wakeup; + s->api.watch_get_events = watch_get_events; + + s->api.timeout_new = timeout_new; + s->api.timeout_free = timeout_free; + s->api.timeout_update = timeout_update; + s->pollfds = NULL; s->max_pollfds = s->n_pollfds = 0; - s->wakeup_callback = NULL; s->rebuild_pollfds = 0; s->quit = 0; s->n_watches = 0; - s->req_cleanup = 0; + s->events_valid = 0; + + s->watch_req_cleanup = 0; + s->timeout_req_cleanup = 0; avahi_simple_poll_set_func(s, NULL); AVAHI_LLIST_HEAD_INIT(AvahiWatch, s->watches); + AVAHI_LLIST_HEAD_INIT(AvahiTimeout, s->timeouts); return s; } @@ -218,8 +297,8 @@ AvahiSimplePoll *avahi_simple_poll_new(void) { void avahi_simple_poll_free(AvahiSimplePoll *s) { assert(s); - cleanup(s, 1); - + cleanup_timeouts(s, 1); + cleanup_watches(s, 1); assert(s->n_watches == 0); avahi_free(s->pollfds); @@ -253,39 +332,49 @@ static int rebuild(AvahiSimplePoll *s) { } s->n_pollfds = idx; - + s->events_valid = 0; s->rebuild_pollfds = 0; return 0; } -static int start_wakeup_callback(AvahiSimplePoll *s) { - AvahiWakeupCallback callback; - void *userdata; - +static AvahiTimeout* find_next_timeout(AvahiSimplePoll *s) { + AvahiTimeout *t, *n = NULL; assert(s); - /* Reset the wakeup functions, but allow changing of the two - values from the callback function */ + for (t = s->timeouts; t; t = t->timeouts_next) { + + if (t->dead || !t->enabled) + continue; + + if (!n || avahi_timeval_compare(&t->expiry, &n->expiry) < 0) + n = t; + } - callback = s->wakeup_callback; - userdata = s->wakeup_userdata; - s->wakeup_callback = NULL; - s->wakeup_userdata = NULL; + return n; +} - assert(callback); - - callback(&s->api, userdata); +static int start_timeout_callback(AvahiTimeout *t) { + assert(t); + assert(!t->dead); + assert(t->enabled); + + t->enabled = 0; + t->callback(t, t->userdata); return 0; } int avahi_simple_poll_iterate(AvahiSimplePoll *s, int timeout) { int r; + AvahiTimeout *next_timeout; assert(s); /* Cleanup things first */ - if (s->req_cleanup) - cleanup(s, 0); + if (s->watch_req_cleanup) + cleanup_watches(s, 0); + + if (s->timeout_req_cleanup) + cleanup_timeouts(s, 0); /* Check whether a quit was requested */ if (s->quit) @@ -296,19 +385,23 @@ int avahi_simple_poll_iterate(AvahiSimplePoll *s, int timeout) { if (rebuild(s) < 0) return -1; + /* Calculate the wakeup time */ - if (s->wakeup_callback) { + if ((next_timeout = find_next_timeout(s))) { struct timeval now; int t; AvahiUsec usec; gettimeofday(&now, NULL); - usec = avahi_timeval_diff(&s->wakeup, &now); + usec = avahi_timeval_diff(&next_timeout->expiry, &now); - if (usec <= 0) + if (usec <= 0) { /* Timeout elapsed */ - return start_wakeup_callback(s); + /* The events poll() returned in the last call are now no longer valid */ + s->events_valid = 0; + return start_timeout_callback(next_timeout); + } /* Calculate sleep time. We add 1ms because otherwise we'd * wake up too early most of the time */ @@ -321,15 +414,18 @@ int avahi_simple_poll_iterate(AvahiSimplePoll *s, int timeout) { if ((r = s->poll_func(s->pollfds, s->n_pollfds, timeout)) < 0) return -1; + /* The pollf events are now valid again */ + s->events_valid = 1; + /* Check whether the wakeup time has been reached now */ - if (s->wakeup_callback) { + if (next_timeout) { struct timeval now; gettimeofday(&now, NULL); - if (avahi_timeval_compare(&s->wakeup, &now) <= 0) + if (avahi_timeval_compare(&next_timeout->expiry, &now) <= 0) /* Time elapsed */ - return start_wakeup_callback(s); + return start_timeout_callback(next_timeout); } if (r > 0) { diff --git a/avahi-common/watch-test.c b/avahi-common/watch-test.c index a9e3e02..ffb2149 100644 --- a/avahi-common/watch-test.c +++ b/avahi-common/watch-test.c @@ -52,7 +52,7 @@ static void callback(AvahiWatch *w, int fd, AvahiWatchEvent event, void *userdat } } -static void wakeup(AvahiPoll *_api, void *userdata) { +static void wakeup(AvahiTimeout *t, void *userdata) { static int i = 0; struct timeval tv; @@ -62,7 +62,7 @@ static void wakeup(AvahiPoll *_api, void *userdata) { avahi_simple_poll_quit(simple_poll); else { avahi_elapse_time(&tv, 1000, 0); - api->set_wakeup(api, &tv, wakeup, NULL); + api->timeout_update(t, &tv); } } @@ -75,7 +75,7 @@ int main(int argc, char *argv[]) { api->watch_new(api, 0, AVAHI_WATCH_IN, callback, NULL); avahi_elapse_time(&tv, 1000, 0); - api->set_wakeup(api, &tv, wakeup, NULL); + api->timeout_new(api, &tv, wakeup, NULL); /* Our main loop */ for (;;) diff --git a/avahi-common/watch.h b/avahi-common/watch.h index 75f53b3..7bab4f8 100644 --- a/avahi-common/watch.h +++ b/avahi-common/watch.h @@ -36,6 +36,9 @@ AVAHI_C_DECL_BEGIN /** An I/O watch object */ typedef struct AvahiWatch AvahiWatch; +/** An I/O watch object */ +typedef struct AvahiTimeout AvahiTimeout; + /** An event polling abstraction object */ typedef struct AvahiPoll AvahiPoll; @@ -50,8 +53,8 @@ typedef enum { /** Called whenever an I/O event happens on an I/O watch */ typedef void (*AvahiWatchCallback)(AvahiWatch *w, int fd, AvahiWatchEvent event, void *userdata); -/** Called when the wakeup time is reached */ -typedef void (*AvahiWakeupCallback)(AvahiPoll *api, void *userdata); +/** Called when the timeout is reached */ +typedef void (*AvahiTimeoutCallback)(AvahiTimeout *t, void *userdata); /** Defines an abstracted event polling API. This may be used to connect Avahi to other main loops. This is losely based on Unix @@ -60,7 +63,7 @@ typedef void (*AvahiWakeupCallback)(AvahiPoll *api, void *userdata); to define a single wakeup time.*/ struct AvahiPoll { - /** Some abstract user data usable by the implementor of the API */ + /** Some abstract user data usable by the provider of the API */ void* userdata; /** Create a new watch for the specified file descriptor and for @@ -68,17 +71,28 @@ struct AvahiPoll { * whenever any of the events happens. */ AvahiWatch* (*watch_new)(const AvahiPoll *api, int fd, AvahiWatchEvent event, AvahiWatchCallback callback, void *userdata); - /** Update the events to wait for. */ + /** Update the events to wait for. It is safe to call this function from an AvahiWatchCallback */ void (*watch_update)(AvahiWatch *w, AvahiWatchEvent event); - /** Free a watch */ + /** Return the events that happened. It is safe to call this function from an AvahiWatchCallback */ + AvahiWatchEvent (*watch_get_events)(AvahiWatch *w); + + /** Free a watch. It is safe to call this function from an AvahiWatchCallback */ void (*watch_free)(AvahiWatch *w); /** Set a wakeup time for the polling loop. The API will call the - callback function when the absolute time *tv is reached. If *tv is - NULL, the callback will be called in the next main loop - iteration. If callback is NULL the wakeup time is disabled. */ - void (*set_wakeup)(const AvahiPoll *api, const struct timeval *tv, AvahiWakeupCallback callback, void *userdata); + callback function when the absolute time *tv is reached. If tv is + NULL, the timeout is disabled. After the timeout expired the + callback function will be called and the timeout is disabled. You + can reenable it by calling timeout_update() */ + AvahiTimeout* (*timeout_new)(const AvahiPoll *api, const struct timeval *tv, AvahiTimeoutCallback callback, void *userdata); + + /** Update the absolute expiration time for a timeout, If tv is + * null, the timeout is disabled. It is safe to call this function from an AvahiTimeoutCallback */ + void (*timeout_update)(AvahiTimeout *, const struct timeval *tv); + + /** Free a timeout. It is safe to call this function from an AvahiTimeoutCallback */ + void (*timeout_free)(AvahiTimeout *t); }; #ifndef DOXYGEN_SHOULD_SKIP_THIS diff --git a/avahi-core/avahi-test.c b/avahi-core/avahi-test.c index 2713185..375fb7d 100644 --- a/avahi-core/avahi-test.c +++ b/avahi-core/avahi-test.c @@ -226,7 +226,7 @@ int main(int argc, char *argv[]) { int error; avahi_set_allocator(avahi_glib_allocator()); - glib_poll = avahi_glib_poll_new(NULL); + glib_poll = avahi_glib_poll_new(NULL, G_PRIORITY_DEFAULT); avahi_server_config_init(&config); /* config.host_name = g_strdup("test"); */ diff --git a/avahi-core/conformance-test.c b/avahi-core/conformance-test.c index b786e85..fab9b56 100644 --- a/avahi-core/conformance-test.c +++ b/avahi-core/conformance-test.c @@ -109,7 +109,7 @@ int main(int argc, char *argv[]) { avahi_set_allocator(avahi_glib_allocator()); - glib_poll = avahi_glib_poll_new(NULL); + glib_poll = avahi_glib_poll_new(NULL, G_PRIORITY_DEFAULT); avahi = avahi_server_new(avahi_glib_poll_get(glib_poll), NULL, server_callback, NULL, &error); diff --git a/avahi-core/timeeventq.c b/avahi-core/timeeventq.c index bb9a5cd..5e24ba3 100644 --- a/avahi-core/timeeventq.c +++ b/avahi-core/timeeventq.c @@ -44,6 +44,7 @@ struct AvahiTimeEvent { struct AvahiTimeEventQueue { const AvahiPoll *poll_api; AvahiPrioQueue *prioq; + AvahiTimeout *timeout; }; static int compare(const void* _a, const void* _b) { @@ -58,19 +59,17 @@ static int compare(const void* _a, const void* _b) { return avahi_timeval_compare(&a->last_run, &b->last_run); } -static void expiration_event(AvahiPoll *poll_api, void *userdata); - -static void update_wakeup(AvahiTimeEventQueue *q) { +static void update_timeout(AvahiTimeEventQueue *q) { + AvahiTimeEvent *e; assert(q); - if (q->prioq->root) { - AvahiTimeEvent *e = q->prioq->root->data; - q->poll_api->set_wakeup(q->poll_api, &e->expiry, expiration_event, q); - } else - q->poll_api->set_wakeup(q->poll_api, NULL, NULL, NULL); + if ((e = avahi_time_event_queue_root(q))) + q->poll_api->timeout_update(q->timeout, &e->expiry); + else + q->poll_api->timeout_update(q->timeout, NULL); } -void expiration_event(AvahiPoll *poll_api, void *userdata) { +static void expiration_event(AvahiTimeout *timeout, void *userdata) { struct timeval now; AvahiTimeEventQueue *q = userdata; AvahiTimeEvent *e; @@ -92,7 +91,7 @@ void expiration_event(AvahiPoll *poll_api, void *userdata) { } } - update_wakeup(q); + update_timeout(q); } static void fix_expiry_time(AvahiTimeEvent *e) { @@ -113,27 +112,39 @@ AvahiTimeEventQueue* avahi_time_event_queue_new(const AvahiPoll *poll_api) { goto oom; } + q->poll_api = poll_api; + if (!(q->prioq = avahi_prio_queue_new(compare))) goto oom; - q->poll_api = poll_api; + if (!(q->timeout = poll_api->timeout_new(poll_api, NULL, expiration_event, q))) + goto oom; + return q; oom: - if (q) + if (q) { avahi_free(q); + + if (q->prioq) + avahi_prio_queue_free(q->prioq); + } return NULL; } void avahi_time_event_queue_free(AvahiTimeEventQueue *q) { + AvahiTimeEvent *e; + assert(q); - while (q->prioq->root) - avahi_time_event_free(q->prioq->root->data); + while ((e = avahi_time_event_queue_root(q))) + avahi_time_event_free(e); avahi_prio_queue_free(q->prioq); + q->poll_api->timeout_free(q->timeout); + avahi_free(q); } @@ -175,7 +186,7 @@ AvahiTimeEvent* avahi_time_event_new( return NULL; } - update_wakeup(q); + update_timeout(q); return e; } @@ -188,7 +199,7 @@ void avahi_time_event_free(AvahiTimeEvent *e) { avahi_prio_queue_remove(q->prioq, e->node); avahi_free(e); - update_wakeup(q); + update_timeout(q); } void avahi_time_event_update(AvahiTimeEvent *e, const struct timeval *timeval) { @@ -199,7 +210,7 @@ void avahi_time_event_update(AvahiTimeEvent *e, const struct timeval *timeval) { fix_expiry_time(e); avahi_prio_queue_shuffle(e->queue->prioq, e->node); - update_wakeup(e->queue); + update_timeout(e->queue); } AvahiTimeEvent* avahi_time_event_queue_root(AvahiTimeEventQueue *q) { diff --git a/avahi-daemon/main.c b/avahi-daemon/main.c index e9030aa..04a632b 100644 --- a/avahi-daemon/main.c +++ b/avahi-daemon/main.c @@ -604,7 +604,7 @@ static gint run_server(DaemonConfig *c) { g_assert(c); - poll_api = avahi_glib_poll_new(NULL); + poll_api = avahi_glib_poll_new(NULL, G_PRIORITY_DEFAULT); loop = g_main_loop_new(NULL, FALSE); if (daemon_signal_init(SIGINT, SIGQUIT, SIGHUP, SIGTERM, SIGUSR1, 0) < 0) { diff --git a/avahi-glib/glib-watch-test.c b/avahi-glib/glib-watch-test.c index 17b334d..73114d1 100644 --- a/avahi-glib/glib-watch-test.c +++ b/avahi-glib/glib-watch-test.c @@ -52,7 +52,7 @@ static void callback(AvahiWatch *w, int fd, AvahiWatchEvent event, void *userdat } } -static void wakeup(AvahiPoll *_api, void *userdata) { +static void wakeup(AvahiTimeout *t, void *userdata) { struct timeval tv; static int i = 0; @@ -62,26 +62,28 @@ static void wakeup(AvahiPoll *_api, void *userdata) { g_main_loop_quit(loop); avahi_elapse_time(&tv, 1000, 0); - api->set_wakeup(api, &tv, wakeup, NULL); + api->timeout_update(t, &tv); } int main(int argc, char *argv[]) { - AvahiGLibPoll *s; + AvahiGLibPoll *g; struct timeval tv; - s = avahi_glib_poll_new(NULL); - assert(s); + g = avahi_glib_poll_new(NULL, G_PRIORITY_DEFAULT); + assert(g); - api = avahi_glib_poll_get(s); + api = avahi_glib_poll_get(g); api->watch_new(api, 0, AVAHI_WATCH_IN, callback, NULL); avahi_elapse_time(&tv, 1000, 0); - api->set_wakeup(api, &tv, wakeup, NULL); + api->timeout_new(api, &tv, wakeup, NULL); loop = g_main_loop_new(NULL, FALSE); g_main_loop_run(loop); g_main_loop_unref(loop); + + avahi_glib_poll_free(g); return 0; } diff --git a/avahi-glib/glib-watch.c b/avahi-glib/glib-watch.c index f099e5a..e6def46 100644 --- a/avahi-glib/glib-watch.c +++ b/avahi-glib/glib-watch.c @@ -31,26 +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; - AvahiWakeupCallback wakeup_callback; - void *wakeup_userdata; - - int req_cleanup; + gboolean timeout_req_cleanup; + gboolean watch_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 +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); @@ -75,7 +88,7 @@ static void cleanup(AvahiGLibPoll *g, int all) { destroy_watch(w); } - g->req_cleanup = 0; + g->watch_req_cleanup = 0; } static AvahiWatch* watch_new(const AvahiPoll *api, int fd, AvahiWatchEvent event, AvahiWatchCallback callback, void *userdata) { @@ -99,13 +112,13 @@ static AvahiWatch* watch_new(const AvahiPoll *api, int fd, AvahiWatchEvent event (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); @@ -119,68 +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(const 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,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; @@ -203,17 +277,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; } @@ -227,18 +302,19 @@ 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->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; } } @@ -254,7 +330,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 +346,24 @@ 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); return g; } @@ -289,14 +372,12 @@ 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"); */ } const AvahiPoll* avahi_glib_poll_get(AvahiGLibPoll *g) { diff --git a/avahi-glib/glib-watch.h b/avahi-glib/glib-watch.h index 4fa8a3b..0833bdc 100644 --- a/avahi-glib/glib-watch.h +++ b/avahi-glib/glib-watch.h @@ -33,14 +33,14 @@ AVAHI_C_DECL_BEGIN #endif -/** GLib main loop adapter */ +/** GLib main loop adapter. You can safely cast this into a GSource */ typedef struct AvahiGLibPoll AvahiGLibPoll; /** Create a new GLib main loop adapter attached to the specified context. If context is NULL, the default main loop context is used. You can attach as many AvahiGLibPoll objects to the same context - as you want. */ -AvahiGLibPoll *avahi_glib_poll_new(GMainContext *context); + as you want. priority takes on of GLib's G_PRIORITY constants. */ +AvahiGLibPoll *avahi_glib_poll_new(GMainContext *context, gint priority); /** Free GLib main loop adapter */ void avahi_glib_poll_free(AvahiGLibPoll *g);