[telepathy-gabble/master] gabble_idle_add_weak(): don't remove the weak reference twice

Dafydd Harries dafydd.harries at collabora.co.uk
Fri Aug 14 05:34:24 PDT 2009


Also, add a test.
---
 src/util.c                    |   16 +++++++--
 tests/Makefile.am             |    1 +
 tests/test-gabble-idle-weak.c |   77 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 91 insertions(+), 3 deletions(-)
 create mode 100644 tests/test-gabble-idle-weak.c

diff --git a/src/util.c b/src/util.c
index c3d5b3d..78122dc 100644
--- a/src/util.c
+++ b/src/util.c
@@ -1030,8 +1030,6 @@ idle_removed (gpointer data)
 {
   WeakIdleCtx *ctx = (WeakIdleCtx *) data;
 
-  g_object_weak_unref (
-      ctx->object, idle_weak_ref_notify, GUINT_TO_POINTER (ctx->source_id));
   g_slice_free (WeakIdleCtx, ctx);
 }
 
@@ -1039,8 +1037,20 @@ static gboolean
 idle_callback (gpointer data)
 {
   WeakIdleCtx *ctx = (WeakIdleCtx *) data;
+  gboolean ret;
 
-  return ctx->function ((gpointer) ctx->object);
+  if (ctx->function ((gpointer) ctx->object))
+    {
+      return TRUE;
+    }
+  else
+    {
+      g_object_weak_unref (
+          ctx->object, idle_weak_ref_notify, GUINT_TO_POINTER (ctx->source_id));
+      return FALSE;
+    }
+
+  return ret;
 }
 
 /* Like g_idle_add(), but cancel the callback if the provided object is
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 356b472..6e58fea 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -7,6 +7,7 @@ noinst_PROGRAMS = \
 	test-base64 \
 	test-caps-hash \
 	test-dtube-unique-names \
+	test-gabble-idle-weak \
 	test-handles \
 	test-jid-decode \
 	test-parse-message \
diff --git a/tests/test-gabble-idle-weak.c b/tests/test-gabble-idle-weak.c
new file mode 100644
index 0000000..3342227
--- /dev/null
+++ b/tests/test-gabble-idle-weak.c
@@ -0,0 +1,77 @@
+
+#include <glib.h>
+
+#include "src/util.h"
+
+static gboolean idle_quit_called = FALSE;
+static GMainLoop *loop = NULL;
+static GObject *object;
+
+static gboolean
+idle_quit (gpointer data)
+{
+  /* This callback should be called exactly once per test. */
+  g_assert (idle_quit_called == FALSE);
+  idle_quit_called = TRUE;
+  g_assert (data == object);
+  g_main_loop_quit (loop);
+  return FALSE;
+}
+
+/* Test 1: Source removed before object finalised. */
+static void
+test_1 (void)
+{
+  idle_quit_called = FALSE;
+  object = g_object_new (G_TYPE_OBJECT, NULL);
+  g_object_set_data (object, "foo", GUINT_TO_POINTER (42));
+  loop = g_main_loop_new (NULL, FALSE);
+
+  gabble_idle_add_weak (idle_quit, object);
+  g_main_loop_run (loop);
+
+  g_object_unref (object);
+  g_main_loop_unref (loop);
+
+  g_assert (idle_quit_called == TRUE);
+}
+
+static gboolean
+idle_unref (gpointer data)
+{
+  g_object_unref (G_OBJECT (data));
+  return FALSE;
+}
+
+/* Test 2: Object finalised before source removed. */
+static void
+test_2 (void)
+{
+  idle_quit_called = FALSE;
+  object = g_object_new (G_TYPE_OBJECT, NULL);
+  g_object_set_data (object, "foo", GUINT_TO_POINTER (42));
+  loop = g_main_loop_new (NULL, FALSE);
+
+  g_idle_add (idle_unref, object);
+  /* This idle quit shouldn't be called because the previous idle will unref
+   * the object and trigger the weak notify.
+   */
+  gabble_idle_add_weak (idle_quit, object);
+  /* This one will be called, however. */
+  g_idle_add (idle_quit, object);
+  g_main_loop_run (loop);
+
+  g_main_loop_unref (loop);
+
+  g_assert (idle_quit_called == TRUE);
+}
+
+int
+main (void)
+{
+  g_type_init ();
+  test_1();
+  test_2();
+  return 0;
+}
+
-- 
1.5.6.5




More information about the telepathy-commits mailing list