[glib/halfline/debug-metrics: 1/12] Add g_source_set_dispose_function() for setting a dispose function for GSource
- From: Ray Strode <halfline src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/halfline/debug-metrics: 1/12] Add g_source_set_dispose_function() for setting a dispose function for GSource
- Date: Tue, 21 Dec 2021 17:45:09 +0000 (UTC)
commit eddb95d5918ba215720ecf0d235a3fcc4ccae59f
Author: Sebastian Dröge <sebastian centricular com>
Date: Sun Oct 20 11:10:21 2019 +0300
Add g_source_set_dispose_function() for setting a dispose function for GSource
This allows GSource implementors to safely clear any other references to
the GSource while the GSource is still valid, unlike when doing the same
from the finalize function.
After the dispose function has run, it is valid for the reference count
of the GSource to be > 0 again to allow the case where another thread in
the mean-time got access to the GSource reference before the dispose
function was called.
This allows fixing a thread-safety issue in the GCancellable, GstBus and
various other GSource implementations.
glib/gmain.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
glib/gmain.h | 20 ++++++++++++++++++++
2 files changed, 77 insertions(+)
---
diff --git a/glib/gmain.c b/glib/gmain.c
index e4381f629..2f4f578d1 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -357,6 +357,8 @@ struct _GSourcePrivate
* let it remain empty on Windows) to avoid #ifdef all over the place.
*/
GSList *fds;
+
+ GSourceDisposeFunc dispose;
};
typedef struct _GSourceIter
@@ -932,6 +934,39 @@ g_source_new (GSourceFuncs *source_funcs,
return source;
}
+/**
+ * g_source_set_dispose_function:
+ * @source: A #GSource to set the dispose function on
+ * @dispose: #GSourceDisposeFunc to set on the source
+ *
+ * Set @dispose as dispose function on @source. @dispose will be called once
+ * the reference count of @source reaches 0 but before any of the state of the
+ * source is freed, especially before the finalize function is called.
+ *
+ * This means that at this point @source is still a valid #GSource and it is
+ * allow for the reference count to increase again until @dispose returns.
+ *
+ * The dispose function can be used to clear any "weak" references to the
+ * @source in other data structures in a thread-safe way where it is possible
+ * for another thread to increase the reference count of @source again while
+ * it is being freed.
+ *
+ * The finalize function can not be used for this purpose as at that point
+ * @source is already partially freed and not valid anymore.
+ *
+ * This should only ever be called from #GSource implementations.
+ *
+ * Since: 2.64
+ **/
+void
+g_source_set_dispose_function (GSource *source,
+ GSourceDisposeFunc dispose)
+{
+ g_return_if_fail (source != NULL);
+ g_return_if_fail (source->priv->dispose == NULL);
+ source->priv->dispose = dispose;
+}
+
/* Holds context's lock */
static void
g_source_iter_init (GSourceIter *iter,
@@ -2085,6 +2120,28 @@ g_source_unref_internal (GSource *source,
source->ref_count--;
if (source->ref_count == 0)
{
+ /* If there's a dispose function, call this first */
+ if (source->priv->dispose)
+ {
+ /* Temporarily increase the ref count again so that GSource methods
+ * can be called from dispose(). */
+ g_atomic_int_inc (&source->ref_count);
+ if (context)
+ UNLOCK_CONTEXT (context);
+ source->priv->dispose (source);
+ if (context)
+ LOCK_CONTEXT (context);
+
+ /* Now the reference count might be bigger than 0 again, in which
+ * case we simply return from here before freeing the source */
+ if (!g_atomic_int_dec_and_test (&source->ref_count))
+ {
+ if (!have_lock && context)
+ UNLOCK_CONTEXT (context);
+ return;
+ }
+ }
+
TRACE (GLIB_SOURCE_BEFORE_FREE (source, context,
source->source_funcs->finalize));
diff --git a/glib/gmain.h b/glib/gmain.h
index 76e2c14c1..365422bf0 100644
--- a/glib/gmain.h
+++ b/glib/gmain.h
@@ -182,6 +182,19 @@ typedef gboolean (*GSourceFunc) (gpointer user_data);
typedef void (*GChildWatchFunc) (GPid pid,
gint status,
gpointer user_data);
+
+
+/**
+ * GSourceDisposeFunc:
+ * @source: #GSource that is currently being disposed
+ *
+ * Dispose function for @source. See g_source_set_dispose_function() for
+ * details.
+ *
+ * Since: 2.64
+ */
+typedef void (*GSourceDisposeFunc) (GSource *source);
+
struct _GSource
{
/*< private >*/
@@ -431,6 +444,13 @@ GMainContext *g_main_loop_get_context (GMainLoop *loop);
GLIB_AVAILABLE_IN_ALL
GSource *g_source_new (GSourceFuncs *source_funcs,
guint struct_size);
+
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+GLIB_AVAILABLE_IN_ALL
+void g_source_set_dispose_function (GSource *source,
+ GSourceDisposeFunc dispose);
+G_GNUC_END_IGNORE_DEPRECATIONS
+
GLIB_AVAILABLE_IN_ALL
GSource *g_source_ref (GSource *source);
GLIB_AVAILABLE_IN_ALL
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]