[libdazzle/libdazzle-3-28] cancellable: try harder with release with weak refs
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libdazzle/libdazzle-3-28] cancellable: try harder with release with weak refs
- Date: Tue, 19 Jun 2018 01:25:28 +0000 (UTC)
commit cc3cb2d78df5ab7867a4b08a3b058ff63c7e330f
Author: Christian Hergert <chergert redhat com>
Date: Mon Jun 18 18:23:51 2018 -0700
cancellable: try harder with release with weak refs
This still isn't enough to catch a case I'm seeing in Builder, but it does
increase our chances of releasing the structure sooner. If we loose any
of our objects, we want to release the signal connection immediately (and
ultimately the info struct).
src/util/dzl-cancellable.c | 65 +++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 61 insertions(+), 4 deletions(-)
---
diff --git a/src/util/dzl-cancellable.c b/src/util/dzl-cancellable.c
index 208e202..c59de83 100644
--- a/src/util/dzl-cancellable.c
+++ b/src/util/dzl-cancellable.c
@@ -25,11 +25,16 @@
#include "util/dzl-cancellable.h"
#include "util/dzl-macros.h"
+#define CHAINED_INFO_MAGIC 0x81734637
+
typedef struct
{
- GWeakRef self;
- GWeakRef other;
- gulong other_handler;
+ guint magic;
+ volatile gint ref_count;
+ GMutex mutex;
+ GWeakRef self;
+ GWeakRef other;
+ gulong other_handler;
} ChainedInfo;
static void
@@ -40,6 +45,10 @@ chained_info_free (gpointer data)
g_autoptr(GCancellable) other = NULL;
g_assert (info != NULL);
+ g_assert (info->magic == CHAINED_INFO_MAGIC);
+ g_assert (info->ref_count == 0);
+
+ info->magic = 0;
self = g_weak_ref_get (&info->self);
other = g_weak_ref_get (&info->other);
@@ -52,9 +61,37 @@ chained_info_free (gpointer data)
g_weak_ref_clear (&info->other);
g_weak_ref_clear (&info->self);
+ g_mutex_clear (&info->mutex);
+
g_slice_free (ChainedInfo, info);
}
+static void
+chained_info_unref (ChainedInfo *info)
+{
+ g_autoptr(GCancellable) other = NULL;
+
+ g_assert (info != NULL);
+ g_assert (info->ref_count > 0);
+ g_assert (info->magic == CHAINED_INFO_MAGIC);
+
+ if ((other = g_weak_ref_get (&info->other)))
+ {
+ gulong handler_id;
+
+ g_mutex_lock (&info->mutex);
+ handler_id = info->other_handler;
+ info->other_handler = 0;
+ g_mutex_unlock (&info->mutex);
+
+ if (handler_id)
+ g_signal_handler_disconnect (other, handler_id);
+ }
+
+ if (g_atomic_int_dec_and_test (&info->ref_count))
+ chained_info_free (info);
+}
+
static void
dzl_cancellable_cancelled_cb (GCancellable *other,
ChainedInfo *info)
@@ -63,6 +100,8 @@ dzl_cancellable_cancelled_cb (GCancellable *other,
g_assert (G_IS_CANCELLABLE (other));
g_assert (info != NULL);
+ g_assert (info->ref_count > 0);
+ g_assert (info->magic == CHAINED_INFO_MAGIC);
self = g_weak_ref_get (&info->self);
@@ -75,6 +114,19 @@ dzl_cancellable_cancelled_cb (GCancellable *other,
dzl_clear_signal_handler (other, &info->other_handler);
}
+static void
+dzl_cancellable_weak_cb (gpointer data,
+ GObject *where_object_was)
+{
+ ChainedInfo *info = data;
+
+ g_assert (info != NULL);
+ g_assert (info->ref_count > 0);
+ g_assert (info->magic == CHAINED_INFO_MAGIC);
+
+ chained_info_unref (info);
+}
+
/**
* dzl_cancellable_chain:
* @self: (nullable): a #GCancellable or %NULL
@@ -122,12 +174,17 @@ dzl_cancellable_chain (GCancellable *self,
*/
info = g_slice_new0 (ChainedInfo);
+ info->magic = CHAINED_INFO_MAGIC;
+ info->ref_count = 3;
+ g_mutex_init (&info->mutex);
g_weak_ref_init (&info->self, self);
g_weak_ref_init (&info->other, other);
+ g_object_weak_ref (G_OBJECT (self), dzl_cancellable_weak_cb, info);
+ g_object_weak_ref (G_OBJECT (other), dzl_cancellable_weak_cb, info);
info->other_handler = g_cancellable_connect (other,
G_CALLBACK (dzl_cancellable_cancelled_cb),
info,
- chained_info_free);
+ (GDestroyNotify)chained_info_unref);
return self;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]