glib-unix: add function to ensure an fd is sealed
[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 /* We are testing some deprecated APIs here */
24 #define GLIB_DISABLE_DEPRECATION_WARNINGS
25
26 #include <glib.h>
27
28 #include <stdio.h>
29
30 static void
31 test_rec_mutex1 (void)
32 {
33   GRecMutex mutex;
34
35   g_rec_mutex_init (&mutex);
36   g_rec_mutex_lock (&mutex);
37   g_rec_mutex_unlock (&mutex);
38   g_rec_mutex_lock (&mutex);
39   g_rec_mutex_unlock (&mutex);
40   g_rec_mutex_clear (&mutex);
41 }
42
43 static void
44 test_rec_mutex2 (void)
45 {
46   static GRecMutex mutex;
47
48   g_rec_mutex_lock (&mutex);
49   g_rec_mutex_unlock (&mutex);
50   g_rec_mutex_lock (&mutex);
51   g_rec_mutex_unlock (&mutex);
52 }
53
54 static void
55 test_rec_mutex3 (void)
56 {
57   static GRecMutex mutex;
58   gboolean ret;
59
60   ret = g_rec_mutex_trylock (&mutex);
61   g_assert (ret);
62
63   ret = g_rec_mutex_trylock (&mutex);
64   g_assert (ret);
65
66   g_rec_mutex_unlock (&mutex);
67   g_rec_mutex_unlock (&mutex);
68 }
69
70 #define LOCKS      48
71 #define ITERATIONS 10000
72 #define THREADS    100
73
74
75 GThread   *owners[LOCKS];
76 GRecMutex  locks[LOCKS];
77
78 static void
79 acquire (gint nr)
80 {
81   GThread *self;
82
83   self = g_thread_self ();
84
85   if (!g_rec_mutex_trylock (&locks[nr]))
86     {
87       if (g_test_verbose ())
88         g_print ("thread %p going to block on lock %d\n", self, nr);
89
90       g_rec_mutex_lock (&locks[nr]);
91     }
92
93   g_assert (owners[nr] == NULL);   /* hopefully nobody else is here */
94   owners[nr] = self;
95
96   /* let some other threads try to ruin our day */
97   g_thread_yield ();
98   g_thread_yield ();
99
100   g_assert (owners[nr] == self);   /* hopefully this is still us... */
101
102   if (g_test_verbose ())
103     g_print ("thread %p recursively taking lock %d\n", self, nr);
104
105   g_rec_mutex_lock (&locks[nr]);  /* we're recursive, after all */
106
107   g_assert (owners[nr] == self);   /* hopefully this is still us... */
108
109   g_rec_mutex_unlock (&locks[nr]);
110
111   g_thread_yield ();
112   g_thread_yield ();
113
114   g_assert (owners[nr] == self);   /* hopefully this is still us... */
115   owners[nr] = NULL;               /* make way for the next guy */
116
117   g_rec_mutex_unlock (&locks[nr]);
118 }
119
120 static gpointer
121 thread_func (gpointer data)
122 {
123   gint i;
124   GRand *rand;
125
126   rand = g_rand_new ();
127
128   for (i = 0; i < ITERATIONS; i++)
129     acquire (g_rand_int_range (rand, 0, LOCKS));
130
131   g_rand_free (rand);
132
133   return NULL;
134 }
135
136 static void
137 test_rec_mutex4 (void)
138 {
139   gint i;
140   GThread *threads[THREADS];
141
142   for (i = 0; i < LOCKS; i++)
143     g_rec_mutex_init (&locks[i]);
144
145   for (i = 0; i < THREADS; i++)
146     threads[i] = g_thread_new ("test", thread_func, NULL);
147
148   for (i = 0; i < THREADS; i++)
149     g_thread_join (threads[i]);
150
151   for (i = 0; i < LOCKS; i++)
152     g_rec_mutex_clear (&locks[i]);
153
154   for (i = 0; i < LOCKS; i++)
155     g_assert (owners[i] == NULL);
156 }
157
158 #define COUNT_TO 100000000
159
160 static gint depth;
161
162 static gboolean
163 do_addition (gint *value)
164 {
165   static GRecMutex lock;
166   gboolean more;
167   gint i;
168
169   /* test performance of "good" cases (ie: short critical sections) */
170   for (i = 0; i < depth; i++)
171     g_rec_mutex_lock (&lock);
172
173   if ((more = *value != COUNT_TO))
174     if (*value != -1)
175       (*value)++;
176
177   for (i = 0; i < depth; i++)
178     g_rec_mutex_unlock (&lock);
179
180   return more;
181 }
182
183 static gpointer
184 addition_thread (gpointer value)
185 {
186   while (do_addition (value));
187
188   return NULL;
189 }
190
191 static void
192 test_mutex_perf (gconstpointer data)
193 {
194   gint c = GPOINTER_TO_INT (data);
195   GThread *threads[THREADS];
196   gint64 start_time;
197   gint n_threads;
198   gdouble rate;
199   gint x = -1;
200   gint i;
201
202   n_threads = c / 256;
203   depth = c % 256;
204
205   for (i = 0; i < n_threads - 1; i++)
206     threads[i] = g_thread_new ("test", addition_thread, &x);
207
208   /* avoid measuring thread setup/teardown time */
209   start_time = g_get_monotonic_time ();
210   g_atomic_int_set (&x, 0);
211   addition_thread (&x);
212   g_assert_cmpint (g_atomic_int_get (&x), ==, COUNT_TO);
213   rate = g_get_monotonic_time () - start_time;
214   rate = x / rate;
215
216   for (i = 0; i < n_threads - 1; i++)
217     g_thread_join (threads[i]);
218
219   g_test_maximized_result (rate, "%f mips", rate);
220 }
221
222
223 int
224 main (int argc, char *argv[])
225 {
226   g_test_init (&argc, &argv, NULL);
227
228   g_test_add_func ("/thread/rec-mutex1", test_rec_mutex1);
229   g_test_add_func ("/thread/rec-mutex2", test_rec_mutex2);
230   g_test_add_func ("/thread/rec-mutex3", test_rec_mutex3);
231   g_test_add_func ("/thread/rec-mutex4", test_rec_mutex4);
232
233   if (g_test_perf ())
234     {
235       gint i, j;
236
237       for (i = 0; i < 5; i++)
238         for (j = 1; j <= 5; j++)
239           {
240             gchar name[80];
241             guint c;
242
243             c = i * 256 + j;
244
245             if (i)
246               sprintf (name, "/thread/rec-mutex/perf/contended%d/depth%d", i, j);
247             else
248               sprintf (name, "/thread/rec-mutex/perf/uncontended/depth%d", j);
249
250             g_test_add_data_func (name, GINT_TO_POINTER (c), test_mutex_perf);
251           }
252     }
253
254   return g_test_run ();
255 }