Merge remote-tracking branch 'gvdb/master'
[platform/upstream/glib.git] / glib / tests / 1bit-mutex.c
1 /*
2  * Copyright © 2008 Ryan Lortie
3  * Copyright © 2010 Codethink Limited
4  *
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.
9  *
10  * See the included COPYING file for more information.
11  */
12
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.
16  */
17 #define LOCKS      48
18 #define ITERATIONS 10000
19 #define THREADS    100
20
21 #include <glib.h>
22
23 #if TEST_EMULATED_FUTEX
24   /* this is defined for the 1bit-mutex-emufutex test.
25    *
26    * we want to test the emulated futex even if futex(2) is available.
27    */
28
29   /* side-step some glib build stuff */
30   #define GLIB_COMPILATION
31
32   /* rebuild gbitlock.c without futex support,
33      defining our own version of the g_bit_*lock symbols
34    */
35   #undef g_pointer_bit_lock
36   #undef g_pointer_bit_trylock
37   #undef g_pointer_bit_unlock
38
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
45
46   #define G_BIT_LOCK_FORCE_FUTEX_EMULATION
47
48   #include <glib/gbitlock.c>
49 #endif
50
51 volatile GThread *owners[LOCKS];
52 volatile gint     locks[LOCKS];
53 volatile gpointer ptrs[LOCKS];
54 volatile gint     bits[LOCKS];
55
56 static void
57 acquire (int      nr,
58          gboolean use_pointers)
59 {
60   GThread *self;
61
62   self = g_thread_self ();
63
64   g_assert_cmpint (((gsize) ptrs) % sizeof(gint), ==, 0);
65
66   if (!(use_pointers ?
67           g_pointer_bit_trylock (&ptrs[nr], bits[nr])
68         : g_bit_trylock (&locks[nr], bits[nr])))
69     {
70       if (g_test_verbose ())
71         g_print ("thread %p going to block on lock %d\n", self, nr);
72
73       if (use_pointers)
74         g_pointer_bit_lock (&ptrs[nr], bits[nr]);
75       else
76         g_bit_lock (&locks[nr], bits[nr]);
77     }
78
79   g_assert (owners[nr] == NULL);   /* hopefully nobody else is here */
80   owners[nr] = self;
81
82   /* let some other threads try to ruin our day */
83   g_thread_yield ();
84   g_thread_yield ();
85   g_thread_yield ();
86
87   g_assert (owners[nr] == self);   /* hopefully this is still us... */
88   owners[nr] = NULL;               /* make way for the next guy */
89
90   if (use_pointers)
91     g_pointer_bit_unlock (&ptrs[nr], bits[nr]);
92   else
93     g_bit_unlock (&locks[nr], bits[nr]);
94 }
95
96 static gpointer
97 thread_func (gpointer data)
98 {
99   gboolean use_pointers = GPOINTER_TO_INT (data);
100   gint i;
101   GRand *rand;
102
103   rand = g_rand_new ();
104
105   for (i = 0; i < ITERATIONS; i++)
106     acquire (g_rand_int_range (rand, 0, LOCKS), use_pointers);
107
108   g_rand_free (rand);
109
110   return NULL;
111 }
112
113 static void
114 testcase (gconstpointer data)
115 {
116   gboolean use_pointers = GPOINTER_TO_INT (data);
117   GThread *threads[THREADS];
118   int i;
119
120 #ifdef TEST_EMULATED_FUTEX
121   #define SUFFIX "-emufutex"
122
123   /* ensure that we are using the emulated futex by checking
124    * (at compile-time) for the existance of 'g_futex_address_list'
125    */
126   g_assert (g_futex_address_list == NULL);
127 #else
128   #define SUFFIX ""
129 #endif
130
131   for (i = 0; i < LOCKS; i++)
132     bits[i] = g_random_int () % 32;
133
134   for (i = 0; i < THREADS; i++)
135     threads[i] = g_thread_new ("foo", thread_func,
136                                GINT_TO_POINTER (use_pointers));
137
138   for (i = 0; i < THREADS; i++)
139     g_thread_join (threads[i]);
140
141   for (i = 0; i < LOCKS; i++)
142     {
143       g_assert (owners[i] == NULL);
144       g_assert (locks[i] == 0);
145     }
146 }
147
148 int
149 main (int argc, char **argv)
150 {
151   g_test_init (&argc, &argv, NULL);
152
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);
155
156   return g_test_run ();
157 }