[glib/glib-2-52] gmain: Allow GSource methods to be called from a finalize() callback
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/glib-2-52] gmain: Allow GSource methods to be called from a finalize() callback
- Date: Thu, 11 May 2017 08:11:48 +0000 (UTC)
commit c589084003aadb2cd17d45160a1e46a40f4a3716
Author: Philip Withnall <withnall endlessm com>
Date: Mon Apr 24 21:38:59 2017 +0100
gmain: Allow GSource methods to be called from a finalize() callback
Temporarily increase the ref count of a GSource to 1 while calling its
finalize() callback, so that the finalize() implementation can call
GSource methods (like g_source_set_ready_time()) without causing
critical warnings. It’s safe to call those methods at this point, as the
source has been destroyed, but nothing has been freed.
This is an indirect way of fixing a race between GCancellable and
GCancellableSource, whereby the GCancellable::cancelled callback for the
GCancellableSource is not disconnected until the GCancellableSource’s
finalize() function is called. Previously, this meant there was a window
in which the GCancellableSource’s ref count was 0, but the ::cancelled
callback was still connected, and could legitimately be called as a
result of another thread calling g_cancellable_cancel() on the
GCancellable. The callback calls g_source_set_ready_time() on the
GSource, and there’s no thread-safe way of checking whether the GSource
has been destroyed. Instead, we have to change GSource so its ref count
is only decremented to 0 inside the locked section in
g_source_unref_internal() *after* the finalize() function has been
called, and hence after the GCancellable::cancelled callback has been
disconnected. The use of g_cancellable_disconnect() ensures that the
callback disconnection is thread safe.
Signed-off-by: Philip Withnall <withnall endlessm com>
https://bugzilla.gnome.org/show_bug.cgi?id=781601
glib/gmain.c | 4 ++++
glib/gmain.h | 5 ++++-
2 files changed, 8 insertions(+), 1 deletions(-)
---
diff --git a/glib/gmain.c b/glib/gmain.c
index af0a29a..7a5ec1f 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -2112,11 +2112,15 @@ g_source_unref_internal (GSource *source,
if (source->source_funcs->finalize)
{
+ /* Temporarily increase the ref count again so that GSource methods
+ * can be called from finalize(). */
+ source->ref_count++;
if (context)
UNLOCK_CONTEXT (context);
source->source_funcs->finalize (source);
if (context)
LOCK_CONTEXT (context);
+ source->ref_count--;
}
g_free (source->name);
diff --git a/glib/gmain.h b/glib/gmain.h
index e8cdeed..26400d4 100644
--- a/glib/gmain.h
+++ b/glib/gmain.h
@@ -104,7 +104,10 @@ typedef struct _GSourceCallbackFuncs GSourceCallbackFuncs;
* are needed for this type of event source. The return value of the
* @dispatch function should be #G_SOURCE_REMOVE if the source should be
* removed or #G_SOURCE_CONTINUE to keep it.
- * @finalize: Called when the source is finalized.
+ * @finalize: Called when the source is finalized. At this point, the source
+ * will have been destroyed, had its callback cleared, and have been removed
+ * from its #GMainContext, but it will still have its final reference count;
+ * so methods can be called on it from within this function.
*
* The `GSourceFuncs` struct contains a table of
* functions used to handle event sources in a generic manner.
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]