Add a non-trivial GRecMutex test
[platform/upstream/glib.git] / glib / tests / rec-mutex.c
1 /* Unit tests for GRecMutex
2  * Copyright (C) 2011 Red Hat, Inc
3  * Author: Matthias Clasen
4  *
5  * This work is provided "as is"; redistribution and modification
6  * in whole or in part, in any medium, physical or electronic is
7  * permitted without restriction.
8  *
9  * This work is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12  *
13  * In no event shall the authors or contributors be liable for any
14  * direct, indirect, incidental, special, exemplary, or consequential
15  * damages (including, but not limited to, procurement of substitute
16  * goods or services; loss of use, data, or profits; or business
17  * interruption) however caused and on any theory of liability, whether
18  * in contract, strict liability, or tort (including negligence or
19  * otherwise) arising in any way out of the use of this software, even
20  * if advised of the possibility of such damage.
21  */
22
23 #include <glib.h>
24
25 static void
26 test_rec_mutex1 (void)
27 {
28   GRecMutex mutex;
29
30   g_rec_mutex_init (&mutex);
31   g_rec_mutex_lock (&mutex);
32   g_rec_mutex_unlock (&mutex);
33   g_rec_mutex_lock (&mutex);
34   g_rec_mutex_unlock (&mutex);
35   g_rec_mutex_clear (&mutex);
36 }
37
38 static void
39 test_rec_mutex2 (void)
40 {
41   GRecMutex mutex = G_REC_MUTEX_INIT;
42
43   g_rec_mutex_lock (&mutex);
44   g_rec_mutex_unlock (&mutex);
45   g_rec_mutex_lock (&mutex);
46   g_rec_mutex_unlock (&mutex);
47   g_rec_mutex_clear (&mutex);
48 }
49
50 static void
51 test_rec_mutex3 (void)
52 {
53   GRecMutex mutex = G_REC_MUTEX_INIT;
54   gboolean ret;
55
56   ret = g_rec_mutex_trylock (&mutex);
57   g_assert (ret);
58
59   ret = g_rec_mutex_trylock (&mutex);
60   g_assert (ret);
61
62   g_rec_mutex_unlock (&mutex);
63   g_rec_mutex_unlock (&mutex);
64   g_rec_mutex_clear (&mutex);
65 }
66
67 #define LOCKS      48
68 #define ITERATIONS 10000
69 #define THREADS    100
70
71
72 GThread   *owners[LOCKS];
73 GRecMutex  locks[LOCKS];
74
75 static void
76 acquire (gint nr)
77 {
78   GThread *self;
79
80   self = g_thread_self ();
81
82   if (owners[nr] != NULL && owners[nr] != self)
83     {
84       if (g_test_verbose ())
85         g_print ("thread %p going to block on lock %d\n", self, nr);
86
87     }
88
89   g_rec_mutex_lock (&locks[nr]);
90
91   g_assert (owners[nr] == NULL);   /* hopefully nobody else is here */
92   owners[nr] = self;
93
94   /* let some other threads try to ruin our day */
95   g_thread_yield ();
96   g_thread_yield ();
97
98   g_assert (owners[nr] == self);   /* hopefully this is still us... */
99
100   g_rec_mutex_lock (&locks[nr]);  /* we're recursive, after all */
101
102   g_assert (owners[nr] == self);   /* hopefully this is still us... */
103
104   g_rec_mutex_unlock (&locks[nr]);
105
106   g_thread_yield ();
107   g_thread_yield ();
108
109   g_assert (owners[nr] == self);   /* hopefully this is still us... */
110   owners[nr] = NULL;               /* make way for the next guy */
111
112   g_rec_mutex_unlock (&locks[nr]);
113 }
114
115 static gpointer
116 thread_func (gpointer data)
117 {
118   gint i;
119   GRand *rand;
120
121   rand = g_rand_new ();
122
123   for (i = 0; i < ITERATIONS; i++)
124     acquire (g_rand_int_range (rand, 0, LOCKS));
125
126   g_rand_free (rand);
127
128   return NULL;
129 }
130
131 static void
132 test_rec_mutex4 (void)
133 {
134   gint i;
135   GThread *threads[THREADS];
136
137   for (i = 0; i < LOCKS; i++)
138     g_rec_mutex_init (&locks[i]);
139
140   for (i = 0; i < THREADS; i++)
141     threads[i] = g_thread_create (thread_func, NULL, TRUE, NULL);
142
143   for (i = 0; i < THREADS; i++)
144     g_thread_join (threads[i]);
145
146   for (i = 0; i < LOCKS; i++)
147     g_rec_mutex_clear (&locks[i]);
148
149   for (i = 0; i < LOCKS; i++)
150     g_assert (owners[i] == NULL);
151 }
152
153 int
154 main (int argc, char *argv[])
155 {
156   g_test_init (&argc, &argv, NULL);
157
158   g_test_add_func ("/thread/rec-mutex1", test_rec_mutex1);
159   g_test_add_func ("/thread/rec-mutex2", test_rec_mutex2);
160   g_test_add_func ("/thread/rec-mutex3", test_rec_mutex3);
161   g_test_add_func ("/thread/rec-mutex4", test_rec_mutex4);
162
163   return g_test_run ();
164 }