Home | History | Annotate | Download | only in common
      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))
     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))
     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
     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
     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 */
    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 
    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 */
    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 */
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    381 int main(void)
    382 {
    383     do_test_1();
    384     do_test_2();
    385     do_test_3(0.1);
    386     return 0;
    387 }
    388