[glib/gwakeup: 2/6] add a couple of testcases for GWakeup
- From: Ryan Lortie <ryanl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/gwakeup: 2/6] add a couple of testcases for GWakeup
- Date: Mon, 25 Jul 2011 13:50:44 +0000 (UTC)
commit 4026b3317425ea7880930787faeedbe526588b11
Author: Ryan Lortie <desrt desrt ca>
Date: Mon Jul 25 15:07:16 2011 +0200
add a couple of testcases for GWakeup
gthread/tests/Makefile.am | 3 +
gthread/tests/gwakeup.c | 268 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 271 insertions(+), 0 deletions(-)
---
diff --git a/gthread/tests/Makefile.am b/gthread/tests/Makefile.am
index 925dbcd..4f5a252 100644
--- a/gthread/tests/Makefile.am
+++ b/gthread/tests/Makefile.am
@@ -43,3 +43,6 @@ spawn_multithreaded_LDADD = $(progs_ldadd) $(top_builddir)/gthread/libgthread
TEST_PROGS += spawn-singlethread
spawn_singlethread_SOURCES = spawn-singlethread.c
spawn_singlethread_LDADD = $(progs_ldadd) $(top_builddir)/gthread/libgthread-2.0.la
+
+TEST_PROGS += gwakeup
+gwakeup_LDADD = $(progs_ldadd) $(top_builddir)/gthread/libgthread-2.0.la
diff --git a/gthread/tests/gwakeup.c b/gthread/tests/gwakeup.c
new file mode 100644
index 0000000..e6c712e
--- /dev/null
+++ b/gthread/tests/gwakeup.c
@@ -0,0 +1,268 @@
+#include <unistd.h>
+#include <glib.h>
+
+#ifdef _WIN32
+void alarm (int sec) { }
+#endif
+
+static gboolean
+check_signaled (GWakeup *wakeup)
+{
+ GPollFD fd;
+
+ g_wakeup_get_pollfd (wakeup, &fd);
+ return g_poll (&fd, 1, 0);
+}
+
+static void
+wait_for_signaled (GWakeup *wakeup)
+{
+ GPollFD fd;
+
+ g_wakeup_get_pollfd (wakeup, &fd);
+ g_poll (&fd, 1, -1);
+}
+
+static void
+test_semantics (void)
+{
+ GWakeup *wakeup;
+ gint i;
+
+ /* prevent the test from deadlocking */
+ alarm (30);
+
+ wakeup = g_wakeup_new ();
+ g_assert (!check_signaled (wakeup));
+
+ g_wakeup_signal (wakeup);
+ g_assert (check_signaled (wakeup));
+
+ g_wakeup_acknowledge (wakeup);
+ g_assert (!check_signaled (wakeup));
+
+ g_wakeup_free (wakeup);
+
+ /* free unused */
+ wakeup = g_wakeup_new ();
+ g_wakeup_free (wakeup);
+
+ /* free while signaled */
+ wakeup = g_wakeup_new ();
+ g_wakeup_signal (wakeup);
+ g_wakeup_free (wakeup);
+
+ /* ensure excessive signalling doesn't deadlock */
+ wakeup = g_wakeup_new ();
+ for (i = 0; i < 1000000; i++)
+ g_wakeup_signal (wakeup);
+ g_assert (check_signaled (wakeup));
+
+ /* ensure a single acknowledgement is sufficient */
+ g_wakeup_acknowledge (wakeup);
+ g_assert (!check_signaled (wakeup));
+
+ g_wakeup_free (wakeup);
+
+ /* cancel the alarm */
+ alarm (0);
+}
+
+struct token
+{
+ gpointer owner;
+ gint ttl;
+};
+
+struct context
+{
+ GSList *pending_tokens;
+ GStaticMutex lock;
+ GWakeup *wakeup;
+ gboolean quit;
+};
+
+#define NUM_THREADS 50
+#define NUM_TOKENS 5
+#define TOKEN_TTL 100000
+
+static struct context contexts[NUM_THREADS];
+static GThread *threads[NUM_THREADS];
+static GWakeup *last_token_wakeup;
+static volatile gint tokens_alive;
+
+static void
+context_init (struct context *ctx)
+{
+ GStaticMutex lock = G_STATIC_MUTEX_INIT;
+
+ ctx->pending_tokens = NULL;
+ ctx->lock = lock;
+ ctx->wakeup = g_wakeup_new ();
+ ctx->quit = FALSE;
+}
+
+static void
+context_clear (struct context *ctx)
+{
+ g_assert (ctx->pending_tokens == NULL);
+ g_assert (ctx->quit);
+
+ g_wakeup_free (ctx->wakeup);
+}
+
+static void
+context_quit (struct context *ctx)
+{
+ ctx->quit = TRUE;
+ g_wakeup_signal (ctx->wakeup);
+}
+
+static struct token *
+context_pop_token (struct context *ctx)
+{
+ struct token *token;
+
+ g_static_mutex_lock (&ctx->lock);
+ token = ctx->pending_tokens->data;
+ ctx->pending_tokens = g_slist_remove_link (ctx->pending_tokens,
+ ctx->pending_tokens);
+ g_static_mutex_unlock (&ctx->lock);
+
+ return token;
+}
+
+static void
+context_push_token (struct context *ctx,
+ struct token *token)
+{
+ g_assert (token->owner == ctx);
+
+ g_static_mutex_lock (&ctx->lock);
+ ctx->pending_tokens = g_slist_prepend (ctx->pending_tokens, token);
+ g_static_mutex_unlock (&ctx->lock);
+
+ g_wakeup_signal (ctx->wakeup);
+}
+
+static void
+dispatch_token (struct token *token)
+{
+ if (token->ttl > 0)
+ {
+ struct context *ctx;
+ gint next_ctx;
+
+ next_ctx = g_test_rand_int_range (0, NUM_THREADS);
+ ctx = &contexts[next_ctx];
+ token->owner = ctx;
+ token->ttl--;
+
+ context_push_token (ctx, token);
+ }
+ else
+ {
+ g_slice_free (struct token, token);
+
+ if (g_atomic_int_dec_and_test (&tokens_alive))
+ g_wakeup_signal (last_token_wakeup);
+ }
+}
+
+static struct token *
+token_new (int ttl)
+{
+ struct token *token;
+
+ token = g_slice_new (struct token);
+ token->ttl = ttl;
+
+ g_atomic_int_inc (&tokens_alive);
+
+ return token;
+}
+
+static gpointer
+thread_func (gpointer data)
+{
+ struct context *ctx = data;
+
+ while (!ctx->quit)
+ {
+ wait_for_signaled (ctx->wakeup);
+ g_wakeup_acknowledge (ctx->wakeup);
+
+ while (ctx->pending_tokens)
+ {
+ struct token *token;
+
+ token = context_pop_token (ctx);
+ g_assert (token->owner == ctx);
+ dispatch_token (token);
+ }
+ }
+
+ return NULL;
+}
+
+static void
+test_threaded (void)
+{
+ gint i;
+
+ /* make sure we don't block forever */
+ alarm (30);
+
+ /* simple mainloop test based on GWakeup.
+ *
+ * create a bunch of contexts and a thread to 'run' each one. create
+ * some tokens and randomly pass them between the threads, until the
+ * TTL on each token is zero.
+ *
+ * when no tokens are left, signal that we are done. the mainthread
+ * will then signal each worker thread to exit and join them to make
+ * sure that works.
+ */
+
+ last_token_wakeup = g_wakeup_new ();
+
+ /* create contexts, assign to threads */
+ for (i = 0; i < NUM_THREADS; i++)
+ {
+ context_init (&contexts[i]);
+ threads[i] = g_thread_create (thread_func, &contexts[i], TRUE, NULL);
+ }
+
+ /* dispatch tokens */
+ for (i = 0; i < NUM_TOKENS; i++)
+ dispatch_token (token_new (TOKEN_TTL));
+
+ /* wait until all tokens are gone */
+ wait_for_signaled (last_token_wakeup);
+
+ /* ask threads to quit, join them, cleanup */
+ for (i = 0; i < NUM_THREADS; i++)
+ {
+ context_quit (&contexts[i]);
+ g_thread_join (threads[i]);
+ context_clear (&contexts[i]);
+ }
+
+ g_wakeup_free (last_token_wakeup);
+
+ /* cancel alarm */
+ alarm (0);
+}
+
+int
+main (int argc, char **argv)
+{
+ g_thread_init (NULL);
+
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/gwakeup/semantics", test_semantics);
+ g_test_add_func ("/gwakeup/threaded", test_threaded);
+
+ return g_test_run ();
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]