diff -r 000000000000 -r e4d67989cc36 glib/tsrc/BC/tests/thread-test.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/glib/tsrc/BC/tests/thread-test.c Tue Feb 02 02:01:42 2010 +0200 @@ -0,0 +1,421 @@ +/* Portion Copyright © 2008-09 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.*/ +#undef G_DISABLE_ASSERT +#undef G_LOG_DOMAIN + +#include +#include + +#ifdef SYMBIAN +#include +#include "mrt2_glib2_test.h" +#endif /*SYMBIAN*/ + + +/* GMutex */ + +static GMutex* test_g_mutex_mutex = NULL; +static guint test_g_mutex_int = 0; +static gboolean test_g_mutex_thread_ready; +G_LOCK_DEFINE_STATIC (test_g_mutex); + +static gpointer +test_g_mutex_thread (gpointer data) +{ + g_assert (GPOINTER_TO_INT (data) == 42); + g_assert (g_mutex_trylock (test_g_mutex_mutex) == FALSE); + g_assert (G_TRYLOCK (test_g_mutex) == FALSE); + test_g_mutex_thread_ready = TRUE; + g_mutex_lock (test_g_mutex_mutex); + g_assert (test_g_mutex_int == 42); + g_mutex_unlock (test_g_mutex_mutex); + + return GINT_TO_POINTER (41); +} + +static void +test_g_mutex (void) +{ + GThread *thread; + test_g_mutex_mutex = g_mutex_new (); + + g_assert (g_mutex_trylock (test_g_mutex_mutex)); + g_assert (G_TRYLOCK (test_g_mutex)); + test_g_mutex_thread_ready = FALSE; + thread = g_thread_create (test_g_mutex_thread, GINT_TO_POINTER (42), + TRUE, NULL); + /* This busy wait is only for testing purposes and not an example of + * good code!*/ + while (!test_g_mutex_thread_ready) + g_usleep (G_USEC_PER_SEC / 5); + test_g_mutex_int = 42; + G_UNLOCK (test_g_mutex); + g_mutex_unlock (test_g_mutex_mutex); + g_assert (GPOINTER_TO_INT (g_thread_join (thread)) == 41); + g_mutex_free (test_g_mutex_mutex); +} + +/* GStaticRecMutex */ + +static GStaticRecMutex test_g_static_rec_mutex_mutex = G_STATIC_REC_MUTEX_INIT; +static guint test_g_static_rec_mutex_int = 0; +static gboolean test_g_static_rec_mutex_thread_ready; + +static gpointer +test_g_static_rec_mutex_thread (gpointer data) +{ + g_assert (GPOINTER_TO_INT (data) == 42); + g_assert (g_static_rec_mutex_trylock (&test_g_static_rec_mutex_mutex) + == FALSE); + test_g_static_rec_mutex_thread_ready = TRUE; + g_static_rec_mutex_lock (&test_g_static_rec_mutex_mutex); + g_static_rec_mutex_lock (&test_g_static_rec_mutex_mutex); + g_assert (test_g_static_rec_mutex_int == 42); + test_g_static_rec_mutex_thread_ready = FALSE; + g_static_rec_mutex_unlock (&test_g_static_rec_mutex_mutex); + g_static_rec_mutex_unlock (&test_g_static_rec_mutex_mutex); + + g_thread_exit (GINT_TO_POINTER (43)); + + g_assert_not_reached (); + return NULL; +} + +static void +test_g_static_rec_mutex (void) +{ + GThread *thread; + + g_assert (g_static_rec_mutex_trylock (&test_g_static_rec_mutex_mutex)); + test_g_static_rec_mutex_thread_ready = FALSE; + thread = g_thread_create (test_g_static_rec_mutex_thread, + GINT_TO_POINTER (42), TRUE, NULL); + /* This busy wait is only for testing purposes and not an example of + * good code!*/ + while (!test_g_static_rec_mutex_thread_ready) + g_usleep (G_USEC_PER_SEC / 5); + + g_assert (g_static_rec_mutex_trylock (&test_g_static_rec_mutex_mutex)); + test_g_static_rec_mutex_int = 41; + g_static_rec_mutex_unlock (&test_g_static_rec_mutex_mutex); + test_g_static_rec_mutex_int = 42; + g_static_rec_mutex_unlock (&test_g_static_rec_mutex_mutex); + + /* This busy wait is only for testing purposes and not an example of + * good code!*/ + while (test_g_static_rec_mutex_thread_ready) + g_usleep (G_USEC_PER_SEC / 5); + + g_static_rec_mutex_lock (&test_g_static_rec_mutex_mutex); + test_g_static_rec_mutex_int = 0; + g_static_rec_mutex_unlock (&test_g_static_rec_mutex_mutex); + + g_assert (GPOINTER_TO_INT (g_thread_join (thread)) == 43); +} + +/* GStaticPrivate */ + +#define THREADS 10 + +static GStaticPrivate test_g_static_private_private1 = G_STATIC_PRIVATE_INIT; +static GStaticPrivate test_g_static_private_private2 = G_STATIC_PRIVATE_INIT; +static GStaticMutex test_g_static_private_mutex = G_STATIC_MUTEX_INIT; +static guint test_g_static_private_counter = 0; +static guint test_g_static_private_ready = 0; + +static gpointer +test_g_static_private_constructor (void) +{ + g_static_mutex_lock (&test_g_static_private_mutex); + test_g_static_private_counter++; + g_static_mutex_unlock (&test_g_static_private_mutex); + return g_new (guint,1); +} + +static void +test_g_static_private_destructor (gpointer data) +{ + g_static_mutex_lock (&test_g_static_private_mutex); + test_g_static_private_counter--; + g_static_mutex_unlock (&test_g_static_private_mutex); + g_free (data); +} + + +static gpointer +test_g_static_private_thread (gpointer data) +{ + guint number = GPOINTER_TO_INT (data); + guint i; + guint *private1, *private2; + for (i = 0; i < 10; i++) + { + number = number * 11 + 1; /* A very simple and bad RNG ;-) */ + private1 = g_static_private_get (&test_g_static_private_private1); + if (!private1 || number % 7 > 3) + { + private1 = test_g_static_private_constructor (); + g_static_private_set (&test_g_static_private_private1, private1, + test_g_static_private_destructor); + } + *private1 = number; + private2 = g_static_private_get (&test_g_static_private_private2); + if (!private2 || number % 13 > 5) + { + private2 = test_g_static_private_constructor (); + g_static_private_set (&test_g_static_private_private2, private2, + test_g_static_private_destructor); + } + *private2 = number * 2; + g_usleep (G_USEC_PER_SEC / 5); + g_assert (number == *private1); + g_assert (number * 2 == *private2); + } + g_static_mutex_lock (&test_g_static_private_mutex); + test_g_static_private_ready++; + g_static_mutex_unlock (&test_g_static_private_mutex); + + /* Busy wait is not nice but that's just a test */ + while (test_g_static_private_ready != 0) + g_usleep (G_USEC_PER_SEC / 5); + + for (i = 0; i < 10; i++) + { + private2 = g_static_private_get (&test_g_static_private_private2); + number = number * 11 + 1; /* A very simple and bad RNG ;-) */ + if (!private2 || number % 13 > 5) + { + private2 = test_g_static_private_constructor (); + g_static_private_set (&test_g_static_private_private2, private2, + test_g_static_private_destructor); + } + *private2 = number * 2; + g_usleep (G_USEC_PER_SEC / 5); + g_assert (number * 2 == *private2); + } + + return GINT_TO_POINTER (GPOINTER_TO_INT (data) * 3); +} + +static void +test_g_static_private (void) +{ + GThread *threads[THREADS]; + guint i; + + test_g_static_private_ready = 0; + + for (i = 0; i < THREADS; i++) + { + threads[i] = g_thread_create (test_g_static_private_thread, + GINT_TO_POINTER (i), TRUE, NULL); + } + + /* Busy wait is not nice but that's just a test */ + while (test_g_static_private_ready != THREADS) + g_usleep (G_USEC_PER_SEC / 5); + + /* Reuse the static private */ + g_static_private_free (&test_g_static_private_private2); + g_static_private_init (&test_g_static_private_private2); + + test_g_static_private_ready = 0; + + for (i = 0; i < THREADS; i++) + g_assert (GPOINTER_TO_INT (g_thread_join (threads[i])) == i * 3); + + g_assert (test_g_static_private_counter == 0); +} + +/* GStaticRWLock */ + +/* -1 = writing; >0 = # of readers */ +static gint test_g_static_rw_lock_state = 0; +G_LOCK_DEFINE (test_g_static_rw_lock_state); + +static gboolean test_g_static_rw_lock_run = TRUE; +static GStaticRWLock test_g_static_rw_lock_lock = G_STATIC_RW_LOCK_INIT; + +static gpointer +test_g_static_rw_lock_thread (gpointer data) +{ + while (test_g_static_rw_lock_run) + { + if (g_random_double() > .2) /* I'm a reader */ + { + + if (g_random_double() > .2) /* I'll block */ + g_static_rw_lock_reader_lock (&test_g_static_rw_lock_lock); + else /* I'll only try */ + if (!g_static_rw_lock_reader_trylock (&test_g_static_rw_lock_lock)) + continue; + G_LOCK (test_g_static_rw_lock_state); + g_assert (test_g_static_rw_lock_state >= 0); + test_g_static_rw_lock_state++; + G_UNLOCK (test_g_static_rw_lock_state); + + g_usleep (g_random_int_range (20,1000)); + + G_LOCK (test_g_static_rw_lock_state); + test_g_static_rw_lock_state--; + G_UNLOCK (test_g_static_rw_lock_state); + + g_static_rw_lock_reader_unlock (&test_g_static_rw_lock_lock); + } + else /* I'm a writer */ + { + + if (g_random_double() > .2) /* I'll block */ + g_static_rw_lock_writer_lock (&test_g_static_rw_lock_lock); + else /* I'll only try */ + if (!g_static_rw_lock_writer_trylock (&test_g_static_rw_lock_lock)) + continue; + G_LOCK (test_g_static_rw_lock_state); + g_assert (test_g_static_rw_lock_state == 0); + test_g_static_rw_lock_state = -1; + G_UNLOCK (test_g_static_rw_lock_state); + + g_usleep (g_random_int_range (20,1000)); + + G_LOCK (test_g_static_rw_lock_state); + test_g_static_rw_lock_state = 0; + G_UNLOCK (test_g_static_rw_lock_state); + + g_static_rw_lock_writer_unlock (&test_g_static_rw_lock_lock); + } + } + return NULL; +} + +static void +test_g_static_rw_lock () +{ + GThread *threads[THREADS]; + guint i; + for (i = 0; i < THREADS; i++) + { + threads[i] = g_thread_create (test_g_static_rw_lock_thread, + NULL, TRUE, NULL); + } + g_usleep (G_USEC_PER_SEC * 5); + test_g_static_rw_lock_run = FALSE; + for (i = 0; i < THREADS; i++) + { + g_thread_join (threads[i]); + } + g_assert (test_g_static_rw_lock_state == 0); +} + +#define G_ONCE_SIZE 100 +#define G_ONCE_THREADS 10 + +G_LOCK_DEFINE (test_g_once); +static guint test_g_once_guint_array[G_ONCE_SIZE]; +static GOnce test_g_once_array[G_ONCE_SIZE]; + +static gpointer +test_g_once_init_func(gpointer arg) +{ + guint *count = arg; + g_usleep (g_random_int_range (20,1000)); + (*count)++; + g_usleep (g_random_int_range (20,1000)); + return arg; +} + +static gpointer +test_g_once_thread (gpointer ignore) +{ + guint i; + G_LOCK (test_g_once); + /* Don't start before all threads are created */ + G_UNLOCK (test_g_once); + for (i = 0; i < 1000; i++) + { + guint pos = g_random_int_range (0, G_ONCE_SIZE); + gpointer ret = g_once (test_g_once_array + pos, test_g_once_init_func, + test_g_once_guint_array + pos); + g_assert (ret == test_g_once_guint_array + pos); + } + + /* Make sure, that all counters are touched at least once */ + for (i = 0; i < G_ONCE_SIZE; i++) + { + gpointer ret = g_once (test_g_once_array + i, test_g_once_init_func, + test_g_once_guint_array + i); + g_assert (ret == test_g_once_guint_array + i); + } + + return NULL; +} + +static void +test_g_thread_once (void) +{ + static GOnce once_init = G_ONCE_INIT; + GThread *threads[G_ONCE_THREADS]; + guint i; + for (i = 0; i < G_ONCE_SIZE; i++) + { + test_g_once_array[i] = once_init; + test_g_once_guint_array[i] = i; + } + G_LOCK (test_g_once); + for (i = 0; i < G_ONCE_THREADS; i++) + { + threads[i] = g_thread_create (test_g_once_thread, GUINT_TO_POINTER(i%2), + TRUE, NULL); + } + G_UNLOCK (test_g_once); + for (i = 0; i < G_ONCE_THREADS; i++) + { + g_thread_join (threads[i]); + } + + for (i = 0; i < G_ONCE_SIZE; i++) + { + g_assert (test_g_once_guint_array[i] == i + 1); + } +} + +/* run all the tests */ +void +run_all_tests() +{ + test_g_mutex (); + test_g_static_rec_mutex (); + test_g_static_private (); + test_g_static_rw_lock (); + test_g_thread_once (); +} + +int +main (int argc, + char *argv[]) +{ + #ifdef SYMBIAN + + g_log_set_handler (NULL, G_LOG_FLAG_FATAL| G_LOG_FLAG_RECURSION | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG, &mrtLogHandler, NULL); + g_set_print_handler(mrtPrintHandler); + #endif /*SYMBIAN*/ + + + /* Only run the test, if threads are enabled and a default thread + implementation is available */ +#if defined(G_THREADS_ENABLED) && ! defined(G_THREADS_IMPL_NONE) + g_thread_init (NULL); + run_all_tests (); + + /* Now we rerun all tests, but this time we fool the system into + * thinking, that the available thread system is not native, but + * userprovided. */ + + g_thread_use_default_impl = FALSE; + run_all_tests (); + +#endif + +#ifdef SYMBIAN + testResultXml("thread-test"); +#endif /* EMULATOR */ + return 0; +}