test g_once_init_*() before and after g_thread_init() and test concurrency
authorTim Janik <timj@imendio.com>
Mon, 13 Aug 2007 12:25:21 +0000 (12:25 +0000)
committerTim Janik <timj@src.gnome.org>
Mon, 13 Aug 2007 12:25:21 +0000 (12:25 +0000)
Mon Aug 13 14:21:44 2007  Tim Janik  <timj@imendio.com>

        * tests/onceinit.c: test g_once_init_*() before and after
        g_thread_init() and test concurrency resolution.

svn path=/trunk/; revision=5698

ChangeLog
tests/Makefile.am
tests/onceinit.c [new file with mode: 0644]

index 67a5c42..d0cc465 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Mon Aug 13 14:21:44 2007  Tim Janik  <timj@imendio.com>
+
+       * tests/onceinit.c: test g_once_init_*() before and after
+       g_thread_init() and test concurrency resolution.
+
 Mon Aug 13 14:18:22 2007  Tim Janik  <timj@imendio.com>
 
        * glib/gthread.c (g_thread_create_full): prevent linking a freed
index 9088136..5bed3e4 100644 (file)
@@ -91,6 +91,7 @@ test_programs =                                       \
        markup-escape-test                      \
        module-test                             \
        node-test                               \
+       onceinit                                \
        option-test                             \
        patterntest                             \
        printf-test                             \
@@ -163,6 +164,7 @@ markup_escape_test_LDADD = $(progs_ldadd)
 module_test_LDADD = $(module_ldadd) $(module_test_exp)
 module_test_LDFLAGS = $(G_MODULE_LDFLAGS)
 node_test_LDADD = $(progs_ldadd)
+onceinit_LDADD = $(thread_ldadd)
 option_test_LDADD = $(progs_ldadd)
 printf_test_LDADD = $(progs_ldadd)
 queue_test_LDADD = $(progs_ldadd)
diff --git a/tests/onceinit.c b/tests/onceinit.c
new file mode 100644 (file)
index 0000000..0aee759
--- /dev/null
@@ -0,0 +1,144 @@
+/* g_once_init_*() test
+ * Copyright (C) 2007 Tim Janik
+ *
+ * This work is provided "as is"; redistribution and modification
+ * in whole or in part, in any medium, physical or electronic is
+ * permitted without restriction.
+
+ * This work is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ * In no event shall the authors or contributors be liable for any
+ * direct, indirect, incidental, special, exemplary, or consequential
+ * damages (including, but not limited to, procurement of substitute
+ * goods or services; loss of use, data, or profits; or business
+ * interruption) however caused and on any theory of liability, whether
+ * in contract, strict liability, or tort (including negligence or
+ * otherwise) arising in any way out of the use of this software, even
+ * if advised of the possibility of such damage.
+ */
+#include <glib.h>
+#include <stdlib.h>
+
+#define N_THREADS               (11)
+
+static GMutex      *tmutex = NULL;
+static GCond       *tcond = NULL;
+static volatile int tmain_call_count = 0;
+static char         dummy_value = 'x';
+
+static void
+assert_singleton_execution1 (void)
+{
+  static volatile int seen_execution = 0;
+  int old_seen_execution = g_atomic_int_exchange_and_add (&seen_execution, 1);
+  if (old_seen_execution != 0)
+    g_error ("%s: function executed more than once", G_STRFUNC);
+}
+
+static void
+assert_singleton_execution2 (void)
+{
+  static volatile int seen_execution = 0;
+  int old_seen_execution = g_atomic_int_exchange_and_add (&seen_execution, 1);
+  if (old_seen_execution != 0)
+    g_error ("%s: function executed more than once", G_STRFUNC);
+}
+
+static void
+assert_singleton_execution3 (void)
+{
+  static volatile int seen_execution = 0;
+  int old_seen_execution = g_atomic_int_exchange_and_add (&seen_execution, 1);
+  if (old_seen_execution != 0)
+    g_error ("%s: function executed more than once", G_STRFUNC);
+}
+
+static void
+initializer1 (void)
+{
+  static volatile gsize initialized = 0;
+  if (g_once_init_enter (&initialized))
+    {
+      gsize initval = 42;
+      assert_singleton_execution1();
+      g_once_init_leave (&initialized, initval);
+    }
+}
+
+static gpointer
+initializer2 (void)
+{
+  static volatile gsize initialized = 0;
+  if (g_once_init_enter (&initialized))
+    {
+      void *pointer_value = &dummy_value;
+      assert_singleton_execution2();
+      g_once_init_leave (&initialized, (gsize) pointer_value);
+    }
+  return (void*) initialized;
+}
+
+static void
+initializer3 (void)
+{
+  static volatile gsize initialized = 0;
+  if (g_once_init_enter (&initialized))
+    {
+      gsize initval = 42;
+      assert_singleton_execution3();
+      g_usleep (25 * 1000);     /* waste time for multiple threads to wait */
+      g_once_init_leave (&initialized, initval);
+    }
+}
+
+static gpointer
+tmain_call_initializer3 (gpointer user_data)
+{
+  g_mutex_lock (tmutex);
+  g_cond_wait (tcond, tmutex);
+  g_mutex_unlock (tmutex);
+  //g_printf ("[");
+  initializer3();
+  //g_printf ("]\n");
+  g_atomic_int_exchange_and_add (&tmain_call_count, 1);
+  return NULL;
+}
+
+int
+main (int   argc,
+      char *argv[])
+{
+  GThread *threads[11];
+  int i;
+  /* test simple initializer */
+  initializer1();
+  initializer1();
+  /* test pointer initializer */
+  void *p = initializer2();
+  g_assert (p == &dummy_value);
+  p = initializer2();
+  g_assert (p == &dummy_value);
+  /* setup threads */
+  g_thread_init (NULL);
+  tmutex = g_mutex_new ();
+  tcond = g_cond_new ();
+  /* start multiple threads for initializer3() */
+  g_mutex_lock (tmutex);
+  for (i = 0; i < N_THREADS; i++)
+    threads[i] = g_thread_create (tmain_call_initializer3, 0, FALSE, NULL);
+  g_mutex_unlock (tmutex);
+  /* concurrently call initializer3() */
+  g_cond_broadcast (tcond);
+  /* loop until all threads passed the call to initializer3() */
+  while (g_atomic_int_get (&tmain_call_count) < i)
+    {
+      if (rand() % 2)
+        g_thread_yield();   /* concurrent shuffling for single core */
+      else
+        g_usleep (1000);    /* concurrent shuffling for multi core */
+      g_cond_broadcast (tcond);
+    }
+  return 0;
+}