1 /*
2 * Copyright (C) 2010 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <pthread.h>
30 #include <errno.h>
31 #include <string.h>
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35
36 /* Posix states that EDEADLK should be returned in case a deadlock condition
37 * is detected with a PTHREAD_MUTEX_ERRORCHECK lock() or trylock(), but
38 * GLibc returns EBUSY instead.
39 */
40 #ifdef HOST
41 # define ERRNO_PTHREAD_EDEADLK EBUSY
42 #else
43 # define ERRNO_PTHREAD_EDEADLK EDEADLK
44 #endif
45
46 static void __attribute__((noreturn))
panic(const char * func,const char * format,...)47 panic(const char* func, const char* format, ...)
48 {
49 va_list args;
50 fprintf(stderr, "%s: ", func);
51 va_start(args, format);
52 vfprintf(stderr, format, args);
53 va_end(args);
54 fprintf(stderr, "\n");
55 exit(1);
56 }
57
58 #define PANIC(...) panic(__FUNCTION__,__VA_ARGS__)
59
60 static void __attribute__((noreturn))
error(int errcode,const char * func,const char * format,...)61 error(int errcode, const char* func, const char* format, ...)
62 {
63 va_list args;
64 fprintf(stderr, "%s: ", func);
65 va_start(args, format);
66 vfprintf(stderr, format, args);
67 va_end(args);
68 fprintf(stderr, " error=%d: %s\n", errcode, strerror(errcode));
69 exit(1);
70 }
71
72 /* return current time in seconds as floating point value */
73 static double
time_now(void)74 time_now(void)
75 {
76 struct timespec ts[1];
77
78 clock_gettime(CLOCK_MONOTONIC, ts);
79 return (double)ts->tv_sec + ts->tv_nsec/1e9;
80 }
81
82 static void
time_sleep(double delay)83 time_sleep(double delay)
84 {
85 struct timespec ts;
86 int ret;
87
88 ts.tv_sec = (time_t)delay;
89 ts.tv_nsec = (long)((delay - ts.tv_sec)*1e9);
90
91 do {
92 ret = nanosleep(&ts, &ts);
93 } while (ret < 0 && errno == EINTR);
94 }
95
96 #define ERROR(errcode,...) error((errcode),__FUNCTION__,__VA_ARGS__)
97
98 #define TZERO(cond) \
99 { int _ret = (cond); if (_ret != 0) ERROR(_ret,"%d:%s", __LINE__, #cond); }
100
101 #define TTRUE(cond) \
102 { if (!(cond)) PANIC("%d:%s", __LINE__, #cond); }
103
104 #define TFALSE(cond) \
105 { if (!!(cond)) PANIC("%d:%s", __LINE__, #cond); }
106
107 #define TEXPECT_INT(cond,val) \
108 { int _ret = (cond); if (_ret != (val)) PANIC("%d:%s returned %d (%d expected)", __LINE__, #cond, _ret, (val)); }
109
110 /* perform a simple init/lock/unlock/destroy test on a mutex of given attributes */
do_test_mutex_1(pthread_mutexattr_t * attr)111 static void do_test_mutex_1(pthread_mutexattr_t *attr)
112 {
113 int ret;
114 pthread_mutex_t lock[1];
115
116 TZERO(pthread_mutex_init(lock, attr));
117 TZERO(pthread_mutex_lock(lock));
118 TZERO(pthread_mutex_unlock(lock));
119 TZERO(pthread_mutex_destroy(lock));
120 }
121
set_mutexattr_type(pthread_mutexattr_t * attr,int type)122 static void set_mutexattr_type(pthread_mutexattr_t *attr, int type)
123 {
124 int newtype;
125 TZERO(pthread_mutexattr_settype(attr, type));
126 newtype = ~type;
127 TZERO(pthread_mutexattr_gettype(attr, &newtype));
128 TEXPECT_INT(newtype,type);
129 }
130
131 /* simple init/lock/unlock/destroy on all mutex types */
do_test_1(void)132 static void do_test_1(void)
133 {
134 int ret, type;
135 pthread_mutexattr_t attr[1];
136
137 do_test_mutex_1(NULL);
138
139 /* non-shared version */
140
141 TZERO(pthread_mutexattr_init(attr));
142
143 set_mutexattr_type(attr, PTHREAD_MUTEX_NORMAL);
144 do_test_mutex_1(attr);
145
146 set_mutexattr_type(attr, PTHREAD_MUTEX_RECURSIVE);
147 do_test_mutex_1(attr);
148
149 set_mutexattr_type(attr, PTHREAD_MUTEX_ERRORCHECK);
150 do_test_mutex_1(attr);
151
152 TZERO(pthread_mutexattr_destroy(attr));
153
154 /* shared version */
155 TZERO(pthread_mutexattr_init(attr));
156 TZERO(pthread_mutexattr_setpshared(attr, PTHREAD_PROCESS_SHARED));
157
158 set_mutexattr_type(attr, PTHREAD_MUTEX_NORMAL);
159 do_test_mutex_1(attr);
160
161 set_mutexattr_type(attr, PTHREAD_MUTEX_RECURSIVE);
162 do_test_mutex_1(attr);
163
164 set_mutexattr_type(attr, PTHREAD_MUTEX_ERRORCHECK);
165 do_test_mutex_1(attr);
166
167 TZERO(pthread_mutexattr_destroy(attr));
168 }
169
170 /* perform init/trylock/unlock/destroy then init/lock/trylock/destroy */
do_test_mutex_2(pthread_mutexattr_t * attr)171 static void do_test_mutex_2(pthread_mutexattr_t *attr)
172 {
173 pthread_mutex_t lock[1];
174
175 TZERO(pthread_mutex_init(lock, attr));
176 TZERO(pthread_mutex_trylock(lock));
177 TZERO(pthread_mutex_unlock(lock));
178 TZERO(pthread_mutex_destroy(lock));
179
180 TZERO(pthread_mutex_init(lock, attr));
181 TZERO(pthread_mutex_trylock(lock));
182 TEXPECT_INT(pthread_mutex_trylock(lock),EBUSY);
183 TZERO(pthread_mutex_unlock(lock));
184 TZERO(pthread_mutex_destroy(lock));
185 }
186
do_test_mutex_2_rec(pthread_mutexattr_t * attr)187 static void do_test_mutex_2_rec(pthread_mutexattr_t *attr)
188 {
189 pthread_mutex_t lock[1];
190
191 TZERO(pthread_mutex_init(lock, attr));
192 TZERO(pthread_mutex_trylock(lock));
193 TZERO(pthread_mutex_unlock(lock));
194 TZERO(pthread_mutex_destroy(lock));
195
196 TZERO(pthread_mutex_init(lock, attr));
197 TZERO(pthread_mutex_trylock(lock));
198 TZERO(pthread_mutex_trylock(lock));
199 TZERO(pthread_mutex_unlock(lock));
200 TZERO(pthread_mutex_unlock(lock));
201 TZERO(pthread_mutex_destroy(lock));
202 }
203
do_test_mutex_2_chk(pthread_mutexattr_t * attr)204 static void do_test_mutex_2_chk(pthread_mutexattr_t *attr)
205 {
206 pthread_mutex_t lock[1];
207
208 TZERO(pthread_mutex_init(lock, attr));
209 TZERO(pthread_mutex_trylock(lock));
210 TZERO(pthread_mutex_unlock(lock));
211 TZERO(pthread_mutex_destroy(lock));
212
213 TZERO(pthread_mutex_init(lock, attr));
214 TZERO(pthread_mutex_trylock(lock));
215 TEXPECT_INT(pthread_mutex_trylock(lock),ERRNO_PTHREAD_EDEADLK);
216 TZERO(pthread_mutex_unlock(lock));
217 TZERO(pthread_mutex_destroy(lock));
218 }
219
do_test_2(void)220 static void do_test_2(void)
221 {
222 pthread_mutexattr_t attr[1];
223
224 do_test_mutex_2(NULL);
225
226 /* non-shared version */
227
228 TZERO(pthread_mutexattr_init(attr));
229
230 set_mutexattr_type(attr, PTHREAD_MUTEX_NORMAL);
231 do_test_mutex_2(attr);
232
233 set_mutexattr_type(attr, PTHREAD_MUTEX_RECURSIVE);
234 do_test_mutex_2_rec(attr);
235
236 set_mutexattr_type(attr, PTHREAD_MUTEX_ERRORCHECK);
237 do_test_mutex_2_chk(attr);
238
239 TZERO(pthread_mutexattr_destroy(attr));
240
241 /* shared version */
242 TZERO(pthread_mutexattr_init(attr));
243 TZERO(pthread_mutexattr_setpshared(attr, PTHREAD_PROCESS_SHARED));
244
245 set_mutexattr_type(attr, PTHREAD_MUTEX_NORMAL);
246 do_test_mutex_2(attr);
247
248 set_mutexattr_type(attr, PTHREAD_MUTEX_RECURSIVE);
249 do_test_mutex_2_rec(attr);
250
251 set_mutexattr_type(attr, PTHREAD_MUTEX_ERRORCHECK);
252 do_test_mutex_2_chk(attr);
253
254 TZERO(pthread_mutexattr_destroy(attr));
255 }
256
257 /* This is more complex example to test contention of mutexes.
258 * Essentially, what happens is this:
259 *
260 * - main thread creates a mutex and locks it
261 * - it then creates thread 1 and thread 2
262 *
263 * - it then record the current time, sleep for a specific 'waitDelay'
264 * then unlock the mutex.
265 *
266 * - thread 1 locks() the mutex. It shall be stopped for a least 'waitDelay'
267 * seconds. It then unlocks the mutex.
268 *
269 * - thread 2 trylocks() the mutex. In case of failure (EBUSY), it waits
270 * for a small amount of time (see 'spinDelay') and tries again, until
271 * it succeeds. It then unlocks the mutex.
272 *
273 * The goal of this test is to verify that thread 1 has been stopped
274 * for a sufficiently long time, and that thread 2 has been spinning for
275 * the same minimum period. There is no guarantee as to which thread is
276 * going to acquire the mutex first.
277 */
278 typedef struct {
279 pthread_mutex_t mutex[1];
280 double t0;
281 double waitDelay;
282 double spinDelay;
283 } Test3State;
284
do_mutex_test_3_t1(void * arg)285 static void* do_mutex_test_3_t1(void* arg)
286 {
287 Test3State *s = arg;
288 double t1;
289
290 TZERO(pthread_mutex_lock(s->mutex));
291 t1 = time_now();
292 //DEBUG ONLY: printf("t1-s->t0=%g waitDelay=%g\n", t1-s->t0, s->waitDelay);
293 TTRUE((t1-s->t0) >= s->waitDelay);
294 TZERO(pthread_mutex_unlock(s->mutex));
295 return NULL;
296 }
297
do_mutex_test_3_t2(void * arg)298 static void* do_mutex_test_3_t2(void* arg)
299 {
300 Test3State *s = arg;
301 double t1;
302
303 for (;;) {
304 int ret = pthread_mutex_trylock(s->mutex);
305 if (ret == 0)
306 break;
307 if (ret == EBUSY) {
308 time_sleep(s->spinDelay);
309 continue;
310 }
311 }
312 t1 = time_now();
313 TTRUE((t1-s->t0) >= s->waitDelay);
314 TZERO(pthread_mutex_unlock(s->mutex));
315 return NULL;
316 }
317
318
do_test_mutex_3(pthread_mutexattr_t * attr,double delay)319 static void do_test_mutex_3(pthread_mutexattr_t *attr, double delay)
320 {
321 Test3State s[1];
322 pthread_t th1, th2;
323 void* dummy;
324
325 TZERO(pthread_mutex_init(s->mutex, attr));
326 s->waitDelay = delay;
327 s->spinDelay = delay/20.;
328
329 TZERO(pthread_mutex_lock(s->mutex));
330
331 pthread_create(&th1, NULL, do_mutex_test_3_t1, s);
332 pthread_create(&th2, NULL, do_mutex_test_3_t2, s);
333
334 s->t0 = time_now();
335 time_sleep(delay);
336
337 TZERO(pthread_mutex_unlock(s->mutex));
338
339 TZERO(pthread_join(th1, &dummy));
340 TZERO(pthread_join(th2, &dummy));
341 }
342
do_test_3(double delay)343 static void do_test_3(double delay)
344 {
345 pthread_mutexattr_t attr[1];
346
347 do_test_mutex_3(NULL, delay);
348
349 /* non-shared version */
350
351 TZERO(pthread_mutexattr_init(attr));
352
353 set_mutexattr_type(attr, PTHREAD_MUTEX_NORMAL);
354 do_test_mutex_3(attr, delay);
355
356 set_mutexattr_type(attr, PTHREAD_MUTEX_RECURSIVE);
357 do_test_mutex_3(attr, delay);
358
359 set_mutexattr_type(attr, PTHREAD_MUTEX_ERRORCHECK);
360 do_test_mutex_3(attr, delay);
361
362 TZERO(pthread_mutexattr_destroy(attr));
363
364 /* shared version */
365 TZERO(pthread_mutexattr_init(attr));
366 TZERO(pthread_mutexattr_setpshared(attr, PTHREAD_PROCESS_SHARED));
367
368 set_mutexattr_type(attr, PTHREAD_MUTEX_NORMAL);
369 do_test_mutex_3(attr, delay);
370
371 set_mutexattr_type(attr, PTHREAD_MUTEX_RECURSIVE);
372 do_test_mutex_3(attr, delay);
373
374 set_mutexattr_type(attr, PTHREAD_MUTEX_ERRORCHECK);
375 do_test_mutex_3(attr, delay);
376
377 TZERO(pthread_mutexattr_destroy(attr));
378 }
379
380
main(void)381 int main(void)
382 {
383 do_test_1();
384 do_test_2();
385 do_test_3(0.1);
386 return 0;
387 }
388