2 * Copyright © 2008 Ryan Lortie
3 * Copyright © 2010 Codethink Limited
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * See the included COPYING file for more information.
13 /* LOCKS should be more than the number of contention
14 * counters in gthread.c in order to ensure we exercise
15 * the case where they overlap.
18 #define ITERATIONS 10000
23 #if TEST_EMULATED_FUTEX
24 /* this is defined for the 1bit-mutex-emufutex test.
26 * we want to test the emulated futex even if futex(2) is available.
29 /* side-step some glib build stuff */
30 #define GLIB_COMPILATION
32 /* rebuild gbitlock.c without futex support,
33 defining our own version of the g_bit_*lock symbols
35 #undef g_pointer_bit_lock
36 #undef g_pointer_bit_trylock
37 #undef g_pointer_bit_unlock
39 #define g_bit_lock _emufutex_g_bit_lock
40 #define g_bit_trylock _emufutex_g_bit_trylock
41 #define g_bit_unlock _emufutex_g_bit_unlock
42 #define g_pointer_bit_lock _emufutex_g_pointer_bit_lock
43 #define g_pointer_bit_trylock _emufutex_g_pointer_bit_trylock
44 #define g_pointer_bit_unlock _emufutex_g_pointer_bit_unlock
46 #define G_BIT_LOCK_FORCE_FUTEX_EMULATION
48 #include <glib/gbitlock.c>
51 volatile GThread *owners[LOCKS];
52 volatile gint locks[LOCKS];
53 volatile gpointer ptrs[LOCKS];
54 volatile gint bits[LOCKS];
58 gboolean use_pointers)
62 self = g_thread_self ();
64 g_assert_cmpint (((gsize) ptrs) % 8, ==, 0);
67 g_pointer_bit_trylock (&ptrs[nr], bits[nr])
68 : g_bit_trylock (&locks[nr], bits[nr])))
70 if (g_test_verbose ())
71 g_print ("thread %p going to block on lock %d\n", self, nr);
74 g_pointer_bit_lock (&ptrs[nr], bits[nr]);
76 g_bit_lock (&locks[nr], bits[nr]);
79 g_assert (owners[nr] == NULL); /* hopefully nobody else is here */
82 /* let some other threads try to ruin our day */
87 g_assert (owners[nr] == self); /* hopefully this is still us... */
88 owners[nr] = NULL; /* make way for the next guy */
91 g_pointer_bit_unlock (&ptrs[nr], bits[nr]);
93 g_bit_unlock (&locks[nr], bits[nr]);
97 thread_func (gpointer data)
99 gboolean use_pointers = GPOINTER_TO_INT (data);
103 rand = g_rand_new ();
105 for (i = 0; i < ITERATIONS; i++)
106 acquire (g_rand_int_range (rand, 0, LOCKS), use_pointers);
114 testcase (gconstpointer data)
116 gboolean use_pointers = GPOINTER_TO_INT (data);
117 GThread *threads[THREADS];
120 #ifdef TEST_EMULATED_FUTEX
121 #define SUFFIX "-emufutex"
123 /* ensure that we are using the emulated futex by checking
124 * (at compile-time) for the existance of 'g_futex_address_list'
126 g_assert (g_futex_address_list == NULL);
131 for (i = 0; i < LOCKS; i++)
132 bits[i] = g_random_int () % 32;
134 for (i = 0; i < THREADS; i++)
135 threads[i] = g_thread_new ("foo", thread_func,
136 GINT_TO_POINTER (use_pointers));
138 for (i = 0; i < THREADS; i++)
139 g_thread_join (threads[i]);
141 for (i = 0; i < LOCKS; i++)
143 g_assert (owners[i] == NULL);
144 g_assert (locks[i] == 0);
149 main (int argc, char **argv)
151 g_test_init (&argc, &argv, NULL);
153 g_test_add_data_func ("/glib/1bit-mutex" SUFFIX "/int", (gpointer) 0, testcase);
154 g_test_add_data_func ("/glib/1bit-mutex" SUFFIX "/pointer", (gpointer) 1, testcase);
156 return g_test_run ();