From 1ce6d47e3a5efea2211569b97af81a6305eaf13b Mon Sep 17 00:00:00 2001 From: Tim Janik Date: Mon, 13 Aug 2007 12:25:21 +0000 Subject: [PATCH] test g_once_init_*() before and after g_thread_init() and test concurrency Mon Aug 13 14:21:44 2007 Tim Janik * tests/onceinit.c: test g_once_init_*() before and after g_thread_init() and test concurrency resolution. svn path=/trunk/; revision=5698 --- ChangeLog | 5 ++ tests/Makefile.am | 2 + tests/onceinit.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 tests/onceinit.c diff --git a/ChangeLog b/ChangeLog index 67a5c42..d0cc465 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Mon Aug 13 14:21:44 2007 Tim Janik + + * 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 * glib/gthread.c (g_thread_create_full): prevent linking a freed diff --git a/tests/Makefile.am b/tests/Makefile.am index 9088136..5bed3e4 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -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 index 0000000..0aee759 --- /dev/null +++ b/tests/onceinit.c @@ -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 +#include + +#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; +} -- 2.7.4