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 #include <pthread.h>
     29 #include <errno.h>
     30 #include <string.h>
     31 #include <stdarg.h>
     32 #include <stdio.h>
     33 #include <stdlib.h>
     34 
     35 /* Posix states that EDEADLK should be returned in case a deadlock condition
     36  * is detected with a PTHREAD_MUTEX_ERRORCHECK lock() or trylock(), but
     37  * GLibc returns EBUSY instead.
     38  */
     39 #ifdef HOST
     40 #  define ERRNO_PTHREAD_EDEADLK   EBUSY
     41 #else
     42 #  define ERRNO_PTHREAD_EDEADLK   EDEADLK
     43 #endif
     44 
     45 static void __attribute__((noreturn))
     46 panic(const char* func, const char* format, ...)
     47 {
     48     va_list  args;
     49     fprintf(stderr, "%s: ", func);
     50     va_start(args, format);
     51     vfprintf(stderr, format, args);
     52     va_end(args);
     53     fprintf(stderr, "\n");
     54     exit(1);
     55 }
     56 
     57 #define  PANIC(...)   panic(__FUNCTION__,__VA_ARGS__)
     58 
     59 static void __attribute__((noreturn))
     60 error(int  errcode, const char* func, const char* format, ...)
     61 {
     62     va_list  args;
     63     fprintf(stderr, "%s: ", func);
     64     va_start(args, format);
     65     vfprintf(stderr, format, args);
     66     va_end(args);
     67     fprintf(stderr, " error=%d: %s\n", errcode, strerror(errcode));
     68     exit(1);
     69 }
     70 
     71 /* return current time in seconds as floating point value */
     72 static double
     73 time_now(void)
     74 {
     75     struct timespec ts[1];
     76 
     77     clock_gettime(CLOCK_MONOTONIC, ts);
     78     return (double)ts->tv_sec + ts->tv_nsec/1e9;
     79 }
     80 
     81 static void
     82 time_sleep(double  delay)
     83 {
     84     struct timespec ts;
     85     int             ret;
     86 
     87     ts.tv_sec  = (time_t)delay;
     88     ts.tv_nsec = (long)((delay - ts.tv_sec)*1e9);
     89 
     90     do {
     91         ret = nanosleep(&ts, &ts);
     92     } while (ret < 0 && errno == EINTR);
     93 }
     94 
     95 #define  ERROR(errcode,...)   error((errcode),__FUNCTION__,__VA_ARGS__)
     96 
     97 #define  TZERO(cond)   \
     98     { int _ret = (cond); if (_ret != 0) ERROR(_ret,"%d:%s", __LINE__, #cond); }
     99 
    100 #define  TTRUE(cond)   \
    101     { if (!(cond)) PANIC("%d:%s", __LINE__, #cond); }
    102 
    103 #define  TFALSE(cond)   \
    104     { if (!!(cond)) PANIC("%d:%s", __LINE__, #cond); }
    105 
    106 #define  TEXPECT_INT(cond,val) \
    107     { int _ret = (cond); if (_ret != (val)) PANIC("%d:%s returned %d (%d expected)", __LINE__, #cond, _ret, (val)); }
    108 
    109 /* perform a simple init/lock/unlock/destroy test on a rwlock of given attributes */
    110 static void do_test_rwlock_rd1(pthread_rwlockattr_t *attr)
    111 {
    112     int               ret;
    113     pthread_rwlock_t  lock[1];
    114 
    115     TZERO(pthread_rwlock_init(lock, attr));
    116     TZERO(pthread_rwlock_rdlock(lock));
    117     TZERO(pthread_rwlock_unlock(lock));
    118     TZERO(pthread_rwlock_destroy(lock));
    119 }
    120 
    121 static void do_test_rwlock_wr1(pthread_rwlockattr_t *attr)
    122 {
    123     int               ret;
    124     pthread_rwlock_t  lock[1];
    125 
    126     TZERO(pthread_rwlock_init(lock, attr));
    127     TZERO(pthread_rwlock_wrlock(lock));
    128     TZERO(pthread_rwlock_unlock(lock));
    129     TZERO(pthread_rwlock_destroy(lock));
    130 }
    131 
    132 static void set_rwlockattr_shared(pthread_rwlockattr_t *attr, int shared)
    133 {
    134     int  newshared;
    135     TZERO(pthread_rwlockattr_setpshared(attr, shared));
    136     newshared = ~shared;
    137     TZERO(pthread_rwlockattr_getpshared(attr, &newshared));
    138     TEXPECT_INT(newshared,shared);
    139 }
    140 
    141 /* simple init/lock/unlock/destroy on all rwlock types */
    142 static void do_test_1(void)
    143 {
    144     int                  ret, type;
    145     pthread_rwlockattr_t  attr[1];
    146 
    147     do_test_rwlock_rd1(NULL);
    148     do_test_rwlock_wr1(NULL);
    149 
    150     /* non-shared version */
    151 
    152     TZERO(pthread_rwlockattr_init(attr));
    153 
    154     set_rwlockattr_shared(attr, PTHREAD_PROCESS_PRIVATE);
    155     do_test_rwlock_rd1(attr);
    156     do_test_rwlock_wr1(attr);
    157 
    158     set_rwlockattr_shared(attr, PTHREAD_PROCESS_SHARED);
    159     do_test_rwlock_rd1(attr);
    160     do_test_rwlock_wr1(attr);
    161 
    162     TZERO(pthread_rwlockattr_destroy(attr));
    163 }
    164 
    165 static void do_test_rwlock_rd2_rec(pthread_rwlockattr_t *attr)
    166 {
    167     pthread_rwlock_t  lock[1];
    168 
    169     TZERO(pthread_rwlock_init(lock, attr));
    170     TZERO(pthread_rwlock_tryrdlock(lock));
    171     TZERO(pthread_rwlock_unlock(lock));
    172     TZERO(pthread_rwlock_destroy(lock));
    173 
    174     TZERO(pthread_rwlock_init(lock, attr));
    175     TZERO(pthread_rwlock_tryrdlock(lock));
    176     TZERO(pthread_rwlock_tryrdlock(lock));
    177     TZERO(pthread_rwlock_unlock(lock));
    178     TZERO(pthread_rwlock_unlock(lock));
    179     TZERO(pthread_rwlock_destroy(lock));
    180 }
    181 
    182 static void do_test_rwlock_wr2_rec(pthread_rwlockattr_t *attr)
    183 {
    184     pthread_rwlock_t  lock[1];
    185 
    186     TZERO(pthread_rwlock_init(lock, attr));
    187     TZERO(pthread_rwlock_trywrlock(lock));
    188     TZERO(pthread_rwlock_unlock(lock));
    189     TZERO(pthread_rwlock_destroy(lock));
    190 
    191     TZERO(pthread_rwlock_init(lock, attr));
    192     TZERO(pthread_rwlock_trywrlock(lock));
    193 #ifdef HOST
    194     /* The host implementation (GLibc) does not support recursive
    195      * write locks */
    196     TEXPECT_INT(pthread_rwlock_trywrlock(lock),EBUSY);
    197 #else
    198     /* Our implementation supports recursive write locks ! */
    199     TZERO(pthread_rwlock_trywrlock(lock));
    200     TZERO(pthread_rwlock_unlock(lock));
    201 #endif
    202     TZERO(pthread_rwlock_unlock(lock));
    203     TZERO(pthread_rwlock_destroy(lock));
    204 }
    205 
    206 static void do_test_2(void)
    207 {
    208     pthread_rwlockattr_t  attr[1];
    209 
    210     do_test_rwlock_rd2_rec(NULL);
    211     do_test_rwlock_wr2_rec(NULL);
    212 
    213     /* non-shared version */
    214 
    215     TZERO(pthread_rwlockattr_init(attr));
    216 
    217     set_rwlockattr_shared(attr, PTHREAD_PROCESS_PRIVATE);
    218     do_test_rwlock_rd2_rec(attr);
    219     do_test_rwlock_wr2_rec(attr);
    220 
    221     set_rwlockattr_shared(attr, PTHREAD_PROCESS_SHARED);
    222     do_test_rwlock_rd2_rec(attr);
    223     do_test_rwlock_wr2_rec(attr);
    224 
    225     TZERO(pthread_rwlockattr_destroy(attr));
    226 }
    227 
    228 /* This is more complex example to test contention of rwlockes.
    229  * Essentially, what happens is this:
    230  *
    231  * - main thread creates a rwlock and rdlocks it
    232  * - it then creates thread 1 and thread 2
    233  *
    234  * - it then record the current time, sleep for a specific 'waitDelay'
    235  *   then unlock the rwlock.
    236  *
    237  * - thread 1 tryrdlocks() the rwlock. It shall acquire the lock
    238  *   immediately, then release it, then wrlock().
    239  *
    240  * - thread 2 trywrlocks() the rwlock. In case of failure (EBUSY), it waits
    241  *   for a small amount of time (see 'spinDelay') and tries again, until
    242  *   it succeeds. It then unlocks the rwlock.
    243  *
    244  * The goal of this test is to verify that thread 1 has been stopped
    245  * for a sufficiently long time (in the wrlock), and that thread 2 has
    246  * been spinning for the same minimum period. There is no guarantee as
    247  * to which thread is going to acquire the rwlock first.
    248  */
    249 typedef struct {
    250     pthread_rwlock_t  rwlock[1];
    251     double            t0;
    252     double            waitDelay;
    253     double            spinDelay;
    254 } Test3State;
    255 
    256 static void* do_rwlock_test_rd3_t1(void* arg)
    257 {
    258     Test3State *s = arg;
    259     double      t1;
    260 
    261     /* try-acquire the lock, should succeed immediately */
    262     TZERO(pthread_rwlock_tryrdlock(s->rwlock));
    263     TZERO(pthread_rwlock_unlock(s->rwlock));
    264 
    265     /* wrlock() the lock, now */
    266     TZERO(pthread_rwlock_wrlock(s->rwlock));
    267 
    268     t1 = time_now();
    269     //DEBUG ONLY: printf("t1-s->t0=%g waitDelay=%g\n", t1-s->t0, s->waitDelay);
    270     TTRUE((t1-s->t0) >= s->waitDelay);
    271     TZERO(pthread_rwlock_unlock(s->rwlock));
    272     return NULL;
    273 }
    274 
    275 static void* do_rwlock_test_rd3_t2(void* arg)
    276 {
    277     Test3State *s = arg;
    278     double      t1;
    279 
    280     for (;;) {
    281         int ret = pthread_rwlock_trywrlock(s->rwlock);
    282         if (ret == 0)
    283             break;
    284         if (ret == EBUSY) {
    285             time_sleep(s->spinDelay);
    286             continue;
    287         }
    288     }
    289     t1 = time_now();
    290     TTRUE((t1-s->t0) >= s->waitDelay);
    291     TZERO(pthread_rwlock_unlock(s->rwlock));
    292     return NULL;
    293 }
    294 
    295 
    296 static void do_test_rwlock_rd3(pthread_rwlockattr_t *attr, double delay)
    297 {
    298     Test3State  s[1];
    299     pthread_t   th1, th2;
    300     void*       dummy;
    301 
    302     TZERO(pthread_rwlock_init(s->rwlock, attr));
    303     s->waitDelay = delay;
    304     s->spinDelay = delay/20.;
    305 
    306     TZERO(pthread_rwlock_rdlock(s->rwlock));
    307 
    308     pthread_create(&th1, NULL, do_rwlock_test_rd3_t1, s);
    309     pthread_create(&th2, NULL, do_rwlock_test_rd3_t2, s);
    310 
    311     s->t0 = time_now();
    312     time_sleep(delay);
    313 
    314     TZERO(pthread_rwlock_unlock(s->rwlock));
    315 
    316     TZERO(pthread_join(th1, &dummy));
    317     TZERO(pthread_join(th2, &dummy));
    318 }
    319 
    320 static void do_test_3(double  delay)
    321 {
    322     pthread_rwlockattr_t  attr[1];
    323 
    324     do_test_rwlock_rd3(NULL, delay);
    325 
    326     /* non-shared version */
    327 
    328     TZERO(pthread_rwlockattr_init(attr));
    329 
    330     set_rwlockattr_shared(attr, PTHREAD_PROCESS_PRIVATE);
    331     do_test_rwlock_rd3(attr, delay);
    332 
    333     set_rwlockattr_shared(attr, PTHREAD_PROCESS_SHARED);
    334     do_test_rwlock_rd3(attr, delay);
    335 
    336     TZERO(pthread_rwlockattr_destroy(attr));
    337 }
    338 
    339 
    340 int main(void)
    341 {
    342     do_test_1();
    343     do_test_2();
    344     do_test_3(0.1);
    345     return 0;
    346 }
    347