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