• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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