test_pthread_mutex.c revision 8e88ea54ff19a3dd2cf5f5309ff13356a41d615a
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
46static void __attribute__((noreturn))
47panic(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
60static void __attribute__((noreturn))
61error(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 */
73static double
74time_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
82static void
83time_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 */
111static 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
122static 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 */
132static 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 */
171static 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
187static 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
204static 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
220static 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 */
278typedef struct {
279    pthread_mutex_t  mutex[1];
280    double           t0;
281    double           waitDelay;
282    double           spinDelay;
283} Test3State;
284
285static 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
298static 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
319static 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
343static 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
381int main(void)
382{
383    do_test_1();
384    do_test_2();
385    do_test_3(0.1);
386    return 0;
387}
388