[glib] Add regression test for GWeakRef used to cache a singleton



commit 146aa7aa1777b84137fb1f3d4035b0f1d11e76c9
Author: Simon McVittie <simon mcvittie collabora co uk>
Date:   Wed Dec 7 15:04:13 2011 +0000

    Add regression test for GWeakRef used to cache a singleton
    
    https://bugzilla.gnome.org/show_bug.cgi?id=548954

 gobject/tests/threadtests.c |  121 +++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 121 insertions(+), 0 deletions(-)
---
diff --git a/gobject/tests/threadtests.c b/gobject/tests/threadtests.c
index 72392b4..c14997c 100644
--- a/gobject/tests/threadtests.c
+++ b/gobject/tests/threadtests.c
@@ -204,6 +204,126 @@ test_threaded_object_init (void)
   g_thread_join (creator);
 }
 
+typedef struct {
+    MyTester0 *strong;
+    guint unref_delay;
+} UnrefInThreadData;
+
+static gpointer
+unref_in_thread (gpointer p)
+{
+  UnrefInThreadData *data = p;
+
+  g_usleep (data->unref_delay);
+  g_object_unref (data->strong);
+
+  return NULL;
+}
+
+/* undefine to see this test fail without GWeakRef */
+#define HAVE_G_WEAK_REF
+
+#define SLEEP_MIN_USEC 1
+#define SLEEP_MAX_USEC 10
+
+static void
+test_threaded_weak_ref (void)
+{
+  guint i;
+  guint get_wins = 0, unref_wins = 0;
+  guint n;
+
+  if (g_test_thorough ())
+    n = NUM_COUNTER_INCREMENTS;
+  else
+    n = NUM_COUNTER_INCREMENTS / 20;
+
+  for (i = 0; i < n; i++)
+    {
+      UnrefInThreadData data;
+#ifdef HAVE_G_WEAK_REF
+      /* GWeakRef<MyTester0> in C++ terms */
+      GWeakRef weak;
+#else
+      gpointer weak;
+#endif
+      MyTester0 *strengthened;
+      guint get_delay;
+      GThread *thread;
+      GError *error = NULL;
+
+      if (g_test_verbose () && (i % (n/20)) == 0)
+        g_print ("%u%%\n", ((i * 100) / n));
+
+      /* Have an object and a weak ref to it */
+      data.strong = g_object_new (my_tester0_get_type (), NULL);
+
+#ifdef HAVE_G_WEAK_REF
+      g_weak_ref_init (&weak, data.strong);
+#else
+      weak = data.strong;
+      g_object_add_weak_pointer ((GObject *) weak, &weak);
+#endif
+
+      /* Delay for a random time on each side of the race, to perturb the
+       * timing. Ideally, we want each side to win half the races; on
+       * smcv's laptop, these timings are about right.
+       */
+      data.unref_delay = g_random_int_range (SLEEP_MIN_USEC / 2, SLEEP_MAX_USEC / 2);
+      get_delay = g_random_int_range (SLEEP_MIN_USEC, SLEEP_MAX_USEC);
+
+      /* One half of the race is to unref the shared object */
+      thread = g_thread_create (unref_in_thread, &data, TRUE, &error);
+      g_assert_no_error (error);
+
+      /* The other half of the race is to get the object from the "global
+       * singleton"
+       */
+      g_usleep (get_delay);
+
+#ifdef HAVE_G_WEAK_REF
+      strengthened = g_weak_ref_get (&weak);
+#else
+      /* Spot the unsafe pointer access! In GDBusConnection this is rather
+       * better-hidden, but ends up with essentially the same thing, albeit
+       * cleared in dispose() rather than by a traditional weak pointer
+       */
+      strengthened = weak;
+
+      if (strengthened != NULL)
+        g_object_ref (strengthened);
+#endif
+
+      if (strengthened != NULL)
+        g_assert (G_IS_OBJECT (strengthened));
+
+      /* Wait for the thread to run */
+      g_thread_join (thread);
+
+      if (strengthened != NULL)
+        {
+          get_wins++;
+          g_assert (G_IS_OBJECT (strengthened));
+          g_object_unref (strengthened);
+        }
+      else
+        {
+          unref_wins++;
+        }
+
+#ifdef HAVE_G_WEAK_REF
+      g_weak_ref_clear (&weak);
+#else
+      if (weak != NULL)
+        g_object_remove_weak_pointer (weak, &weak);
+#endif
+    }
+
+  if (g_test_verbose ())
+    g_print ("Race won by get %u times, unref %u times\n",
+             get_wins, unref_wins);
+}
+
 int
 main (int   argc,
       char *argv[])
@@ -213,6 +333,7 @@ main (int   argc,
 
   g_test_add_func ("/GObject/threaded-class-init", test_threaded_class_init);
   g_test_add_func ("/GObject/threaded-object-init", test_threaded_object_init);
+  g_test_add_func ("/GObject/threaded-weak-ref", test_threaded_weak_ref);
 
   return g_test_run();
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]