From 1efd75a5d8502f644ef6f71bc295d85c47551426 Mon Sep 17 00:00:00 2001 From: Anders Carlsson Date: Tue, 5 Aug 2003 13:57:20 +0000 Subject: 2003-08-05 Anders Carlsson * glib/dbus-gmain.c: (watch_fd_new), (watch_fd_ref), (watch_fd_unref), (dbus_gsource_check), (dbus_gsource_dispatch), (add_watch), (remove_watch), (create_source): Refcount fds, fixes some reentrancy issues. --- ChangeLog | 7 ++++ glib/dbus-gmain.c | 116 ++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 85 insertions(+), 38 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1980a4c6..3a963e05 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2003-08-05 Anders Carlsson + + * glib/dbus-gmain.c: (watch_fd_new), (watch_fd_ref), + (watch_fd_unref), (dbus_gsource_check), (dbus_gsource_dispatch), + (add_watch), (remove_watch), (create_source): + Refcount fds, fixes some reentrancy issues. + 2003-07-30 Havoc Pennington * dbus/dbus-bus.c (init_connections_unlocked): fix default system diff --git a/glib/dbus-gmain.c b/glib/dbus-gmain.c index 9b14049d..d948b431 100644 --- a/glib/dbus-gmain.c +++ b/glib/dbus-gmain.c @@ -52,14 +52,53 @@ struct DBusGSource { GSource source; /**< the parent GSource */ - GList *poll_fds; /**< descriptors we're watching */ - GHashTable *watches; /**< hash of DBusWatch objects */ + GList *watch_fds; /**< descriptors we're watching */ GMainContext *context; /**< the GMainContext to use, NULL for default */ void *connection_or_server; /**< DBusConnection or DBusServer */ }; +typedef struct +{ + int refcount; + + GPollFD poll_fd; + DBusWatch *watch; + + unsigned int removed : 1; +} WatchFD; + +static WatchFD * +watch_fd_new (void) +{ + WatchFD *watch_fd; + + watch_fd = g_new0 (WatchFD, 1); + watch_fd->refcount = 1; + + return watch_fd; +} + +static void +watch_fd_ref (WatchFD *watch_fd) +{ + watch_fd->refcount += 1; +} + +static void +watch_fd_unref (WatchFD *watch_fd) +{ + watch_fd->refcount -= 1; + + if (watch_fd->refcount == 0) + { + g_assert (watch_fd->removed); + + g_free (watch_fd); + } +} + static dbus_int32_t connection_slot = -1; static dbus_int32_t server_slot = -1; @@ -116,13 +155,13 @@ dbus_gsource_check (GSource *source) DBusGSource *dbus_source = (DBusGSource *)source; GList *list; - list = dbus_source->poll_fds; + list = dbus_source->watch_fds; while (list) { - GPollFD *poll_fd = list->data; + WatchFD *watch_fd = list->data; - if (poll_fd->revents != 0) + if (watch_fd->poll_fd.revents != 0) return TRUE; list = list->next; @@ -152,35 +191,35 @@ dbus_gsource_dispatch (GSource *source, DBusGSource *dbus_source = (DBusGSource *)source; GList *copy, *list; - /* We need to traverse a copy of the list, since it can change in - dbus_watch_handle(). */ - copy = g_list_copy (dbus_source->poll_fds); - + /* Make a copy of the list and ref all WatchFDs */ + copy = g_list_copy (dbus_source->watch_fds); + g_list_foreach (copy, (GFunc)watch_fd_ref, NULL); + list = copy; while (list) { - GPollFD *poll_fd = list->data; + WatchFD *watch_fd = list->data; - if (poll_fd->revents != 0) + if (!watch_fd->removed && watch_fd->poll_fd.revents != 0) { - DBusWatch *watch = g_hash_table_lookup (dbus_source->watches, poll_fd); guint condition = 0; - if (poll_fd->revents & G_IO_IN) + if (watch_fd->poll_fd.revents & G_IO_IN) condition |= DBUS_WATCH_READABLE; - if (poll_fd->revents & G_IO_OUT) + if (watch_fd->poll_fd.revents & G_IO_OUT) condition |= DBUS_WATCH_WRITABLE; - if (poll_fd->revents & G_IO_ERR) + if (watch_fd->poll_fd.revents & G_IO_ERR) condition |= DBUS_WATCH_ERROR; - if (poll_fd->revents & G_IO_HUP) + if (watch_fd->poll_fd.revents & G_IO_HUP) condition |= DBUS_WATCH_HANGUP; - dbus_watch_handle (watch, condition); + dbus_watch_handle (watch_fd->watch, condition); } list = list->next; } + g_list_foreach (copy, (GFunc)watch_fd_unref, NULL); g_list_free (copy); return TRUE; @@ -230,7 +269,7 @@ static dbus_bool_t add_watch (DBusWatch *watch, gpointer data) { - GPollFD *poll_fd; + WatchFD *watch_fd; DBusGSource *dbus_source; guint flags; @@ -238,23 +277,24 @@ add_watch (DBusWatch *watch, return TRUE; dbus_source = data; - - poll_fd = g_new (GPollFD, 1); - poll_fd->fd = dbus_watch_get_fd (watch); - poll_fd->events = 0; + + watch_fd = watch_fd_new (); + watch_fd->poll_fd.fd = dbus_watch_get_fd (watch); + watch_fd->poll_fd.events = 0; flags = dbus_watch_get_flags (watch); - dbus_watch_set_data (watch, poll_fd, NULL); + dbus_watch_set_data (watch, watch_fd, (DBusFreeFunction)watch_fd_unref); if (flags & DBUS_WATCH_READABLE) - poll_fd->events |= G_IO_IN; + watch_fd->poll_fd.events |= G_IO_IN; if (flags & DBUS_WATCH_WRITABLE) - poll_fd->events |= G_IO_OUT; - poll_fd->events |= G_IO_ERR | G_IO_HUP; + watch_fd->poll_fd.events |= G_IO_OUT; + watch_fd->poll_fd.events |= G_IO_ERR | G_IO_HUP; - g_source_add_poll ((GSource *)dbus_source, poll_fd); + watch_fd->watch = watch; + + g_source_add_poll ((GSource *)dbus_source, &watch_fd->poll_fd); - dbus_source->poll_fds = g_list_prepend (dbus_source->poll_fds, poll_fd); - g_hash_table_insert (dbus_source->watches, poll_fd, watch); + dbus_source->watch_fds = g_list_prepend (dbus_source->watch_fds, watch_fd); return TRUE; } @@ -264,21 +304,22 @@ remove_watch (DBusWatch *watch, gpointer data) { DBusGSource *dbus_source = data; - GPollFD *poll_fd; + WatchFD *watch_fd; - poll_fd = dbus_watch_get_data (watch); - if (poll_fd == NULL) + watch_fd = dbus_watch_get_data (watch); + if (watch_fd == NULL) return; /* probably a not-enabled watch that was added */ + + watch_fd->removed = TRUE; + watch_fd->watch = NULL; - dbus_source->poll_fds = g_list_remove (dbus_source->poll_fds, poll_fd); - g_hash_table_remove (dbus_source->watches, poll_fd); - g_source_remove_poll ((GSource *)dbus_source, poll_fd); + dbus_source->watch_fds = g_list_remove (dbus_source->watch_fds, watch_fd); + + g_source_remove_poll ((GSource *)dbus_source, &watch_fd->poll_fd); dbus_watch_set_data (watch, NULL, NULL); /* needed due to watch_toggled * breaking add/remove symmetry */ - - g_free (poll_fd); } static void @@ -382,7 +423,6 @@ create_source (void *connection_or_server, source = g_source_new (funcs, sizeof (DBusGSource)); dbus_source = (DBusGSource *)source; - dbus_source->watches = g_hash_table_new (NULL, NULL); dbus_source->connection_or_server = connection_or_server; dbus_source->context = context; -- cgit