00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045 #ifndef _ASTERISK_LOCK_H
00046 #define _ASTERISK_LOCK_H
00047
00048 #include <pthread.h>
00049 #include <netdb.h>
00050 #include <time.h>
00051 #include <sys/param.h>
00052 #include <unistd.h>
00053
00054 #ifndef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
00055 #include "asterisk/time.h"
00056 #endif
00057 #include "asterisk/logger.h"
00058
00059
00060
00061
00062 #ifndef HAVE_MTX_PROFILE
00063 #define __MTX_PROF(a) return pthread_mutex_lock((a))
00064 #else
00065 #define __MTX_PROF(a) do { \
00066 int i; \
00067 \
00068 ast_mark(mtx_prof, 1); \
00069 i = pthread_mutex_trylock((a)); \
00070 ast_mark(mtx_prof, 0); \
00071 if (!i) \
00072 return i; \
00073 else \
00074 return pthread_mutex_lock((a)); \
00075 } while (0)
00076 #endif
00077
00078 #define AST_PTHREADT_NULL (pthread_t) -1
00079 #define AST_PTHREADT_STOP (pthread_t) -2
00080
00081 #if defined(SOLARIS) || defined(BSD)
00082 #define AST_MUTEX_INIT_W_CONSTRUCTORS
00083 #endif
00084
00085
00086
00087 #if defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
00088 #define PTHREAD_MUTEX_INIT_VALUE PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
00089 #define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE_NP
00090 #else
00091 #define PTHREAD_MUTEX_INIT_VALUE PTHREAD_MUTEX_INITIALIZER
00092 #define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE
00093 #endif
00094
00095 #ifdef DEBUG_THREADS
00096
00097 #define __ast_mutex_logger(...) do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0)
00098
00099 #ifdef THREAD_CRASH
00100 #define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
00101 #else
00102 #define DO_THREAD_CRASH do { } while (0)
00103 #endif
00104
00105 #include <errno.h>
00106 #include <string.h>
00107 #include <stdio.h>
00108
00109 #define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, 1, { NULL }, { 0 }, 0, { NULL }, { 0 }, PTHREAD_MUTEX_INIT_VALUE }
00110 #define AST_MUTEX_INIT_VALUE_NOTRACKING \
00111 { PTHREAD_MUTEX_INIT_VALUE, 0, { NULL }, { 0 }, 0, { NULL }, { 0 }, PTHREAD_MUTEX_INIT_VALUE }
00112
00113 #define AST_MAX_REENTRANCY 10
00114
00115 struct ast_mutex_info {
00116 pthread_mutex_t mutex;
00117
00118 unsigned int track:1;
00119 const char *file[AST_MAX_REENTRANCY];
00120 int lineno[AST_MAX_REENTRANCY];
00121 int reentrancy;
00122 const char *func[AST_MAX_REENTRANCY];
00123 pthread_t thread[AST_MAX_REENTRANCY];
00124 pthread_mutex_t reentr_mutex;
00125 };
00126
00127 typedef struct ast_mutex_info ast_mutex_t;
00128
00129 typedef pthread_cond_t ast_cond_t;
00130
00131 static pthread_mutex_t empty_mutex;
00132
00133 enum ast_lock_type {
00134 AST_MUTEX,
00135 AST_RDLOCK,
00136 AST_WRLOCK,
00137 };
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147 #if !defined(LOW_MEMORY)
00148 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
00149 int line_num, const char *func, const char *lock_name, void *lock_addr);
00150 #else
00151 #define ast_store_lock_info(I,DONT,CARE,ABOUT,THE,PARAMETERS)
00152 #endif
00153
00154
00155
00156
00157
00158 #if !defined(LOW_MEMORY)
00159 void ast_mark_lock_acquired(void *lock_addr);
00160 #else
00161 #define ast_mark_lock_acquired(ignore)
00162 #endif
00163
00164
00165
00166
00167 #if !defined(LOW_MEMORY)
00168 void ast_mark_lock_failed(void *lock_addr);
00169 #else
00170 #define ast_mark_lock_failed(ignore)
00171 #endif
00172
00173
00174
00175
00176
00177
00178
00179 #if !defined(LOW_MEMORY)
00180 void ast_remove_lock_info(void *lock_addr);
00181 #else
00182 #define ast_remove_lock_info(ignore)
00183 #endif
00184
00185
00186
00187
00188
00189
00190
00191 #if !defined(LOW_MEMORY)
00192 int ast_find_lock_info(void *lock_addr, char *filename, size_t filename_size, int *lineno, char *func, size_t func_size, char *mutex_name, size_t mutex_name_size);
00193 #else
00194 #define ast_find_lock_info(a,b,c,d,e,f,g,h) -1
00195 #endif
00196
00197
00198
00199
00200
00201
00202
00203 #define DEADLOCK_AVOIDANCE(lock) \
00204 do { \
00205 char __filename[80], __func[80], __mutex_name[80]; \
00206 int __lineno; \
00207 int __res = ast_find_lock_info(lock, __filename, sizeof(__filename), &__lineno, __func, sizeof(__func), __mutex_name, sizeof(__mutex_name)); \
00208 ast_mutex_unlock(lock); \
00209 usleep(1); \
00210 if (__res < 0) { \
00211 ast_mutex_lock(lock); \
00212 } else { \
00213 __ast_pthread_mutex_lock(__filename, __lineno, __func, __mutex_name, lock); \
00214 } \
00215 } while (0)
00216
00217 static void __attribute__((constructor)) init_empty_mutex(void)
00218 {
00219 memset(&empty_mutex, 0, sizeof(empty_mutex));
00220 }
00221
00222 static inline void ast_reentrancy_lock(ast_mutex_t *p_ast_mutex)
00223 {
00224 pthread_mutex_lock(&p_ast_mutex->reentr_mutex);
00225 }
00226
00227 static inline void ast_reentrancy_unlock(ast_mutex_t *p_ast_mutex)
00228 {
00229 pthread_mutex_unlock(&p_ast_mutex->reentr_mutex);
00230 }
00231
00232 static inline void ast_reentrancy_init(ast_mutex_t *p_ast_mutex)
00233 {
00234 int i;
00235 pthread_mutexattr_t reentr_attr;
00236
00237 for (i = 0; i < AST_MAX_REENTRANCY; i++) {
00238 p_ast_mutex->file[i] = NULL;
00239 p_ast_mutex->lineno[i] = 0;
00240 p_ast_mutex->func[i] = NULL;
00241 p_ast_mutex->thread[i] = 0;
00242 }
00243
00244 p_ast_mutex->reentrancy = 0;
00245
00246 pthread_mutexattr_init(&reentr_attr);
00247 pthread_mutexattr_settype(&reentr_attr, AST_MUTEX_KIND);
00248 pthread_mutex_init(&p_ast_mutex->reentr_mutex, &reentr_attr);
00249 pthread_mutexattr_destroy(&reentr_attr);
00250 }
00251
00252 static inline void delete_reentrancy_cs(ast_mutex_t * p_ast_mutex)
00253 {
00254 pthread_mutex_destroy(&p_ast_mutex->reentr_mutex);
00255 }
00256
00257 static inline int __ast_pthread_mutex_init(int track, const char *filename, int lineno, const char *func,
00258 const char *mutex_name, ast_mutex_t *t)
00259 {
00260 int res;
00261 pthread_mutexattr_t attr;
00262
00263 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00264
00265 if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00266
00267
00268
00269
00270
00271
00272 return 0;
00273 }
00274
00275 #endif
00276
00277 ast_reentrancy_init(t);
00278 t->track = track;
00279
00280 pthread_mutexattr_init(&attr);
00281 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
00282
00283 res = pthread_mutex_init(&t->mutex, &attr);
00284 pthread_mutexattr_destroy(&attr);
00285 return res;
00286 }
00287
00288 #define ast_mutex_init(pmutex) __ast_pthread_mutex_init(1, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
00289 #define ast_mutex_init_notracking(pmutex) \
00290 __ast_pthread_mutex_init(0, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
00291
00292 static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
00293 const char *mutex_name, ast_mutex_t *t)
00294 {
00295 int res;
00296 int canlog = strcmp(filename, "logger.c") & t->track;
00297
00298 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00299 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00300
00301
00302
00303
00304
00305
00306 __ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is uninitialized.\n",
00307 filename, lineno, func, mutex_name);
00308 return 0;
00309 }
00310 #endif
00311
00312 res = pthread_mutex_trylock(&t->mutex);
00313 switch (res) {
00314 case 0:
00315 pthread_mutex_unlock(&t->mutex);
00316 break;
00317 case EINVAL:
00318 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
00319 filename, lineno, func, mutex_name);
00320 break;
00321 case EBUSY:
00322 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
00323 filename, lineno, func, mutex_name);
00324 ast_reentrancy_lock(t);
00325 __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
00326 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
00327 ast_reentrancy_unlock(t);
00328 break;
00329 }
00330
00331 if ((res = pthread_mutex_destroy(&t->mutex)))
00332 __ast_mutex_logger("%s line %d (%s): Error destroying mutex %s: %s\n",
00333 filename, lineno, func, mutex_name, strerror(res));
00334 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
00335 else
00336 t->mutex = PTHREAD_MUTEX_INIT_VALUE;
00337 #endif
00338 ast_reentrancy_lock(t);
00339 t->file[0] = filename;
00340 t->lineno[0] = lineno;
00341 t->func[0] = func;
00342 t->reentrancy = 0;
00343 t->thread[0] = 0;
00344 ast_reentrancy_unlock(t);
00345 delete_reentrancy_cs(t);
00346
00347 return res;
00348 }
00349
00350 static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
00351 const char* mutex_name, ast_mutex_t *t)
00352 {
00353 int res;
00354 int canlog = strcmp(filename, "logger.c") & t->track;
00355
00356 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
00357 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00358
00359
00360
00361
00362 res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
00363 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00364 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
00365 filename, lineno, func, mutex_name);
00366 return res;
00367 }
00368 }
00369 #endif
00370
00371 if (t->track)
00372 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
00373
00374 #ifdef DETECT_DEADLOCKS
00375 {
00376 time_t seconds = time(NULL);
00377 time_t wait_time, reported_wait = 0;
00378 do {
00379 #ifdef HAVE_MTX_PROFILE
00380 ast_mark(mtx_prof, 1);
00381 #endif
00382 res = pthread_mutex_trylock(&t->mutex);
00383 #ifdef HAVE_MTX_PROFILE
00384 ast_mark(mtx_prof, 0);
00385 #endif
00386 if (res == EBUSY) {
00387 wait_time = time(NULL) - seconds;
00388 if (wait_time > reported_wait && (wait_time % 5) == 0) {
00389 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
00390 filename, lineno, func, (int) wait_time, mutex_name);
00391 ast_reentrancy_lock(t);
00392 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
00393 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1],
00394 t->func[t->reentrancy-1], mutex_name);
00395 ast_reentrancy_unlock(t);
00396 reported_wait = wait_time;
00397 }
00398 usleep(200);
00399 }
00400 } while (res == EBUSY);
00401 }
00402 #else
00403 #ifdef HAVE_MTX_PROFILE
00404 ast_mark(mtx_prof, 1);
00405 res = pthread_mutex_trylock(&t->mutex);
00406 ast_mark(mtx_prof, 0);
00407 if (res)
00408 #endif
00409 res = pthread_mutex_lock(&t->mutex);
00410 #endif
00411
00412 if (!res) {
00413 ast_reentrancy_lock(t);
00414 if (t->reentrancy < AST_MAX_REENTRANCY) {
00415 t->file[t->reentrancy] = filename;
00416 t->lineno[t->reentrancy] = lineno;
00417 t->func[t->reentrancy] = func;
00418 t->thread[t->reentrancy] = pthread_self();
00419 t->reentrancy++;
00420 } else {
00421 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
00422 filename, lineno, func, mutex_name);
00423 }
00424 ast_reentrancy_unlock(t);
00425 if (t->track)
00426 ast_mark_lock_acquired(&t->mutex);
00427 } else {
00428 if (t->track)
00429 ast_remove_lock_info(&t->mutex);
00430 __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
00431 filename, lineno, func, strerror(res));
00432 DO_THREAD_CRASH;
00433 }
00434
00435 return res;
00436 }
00437
00438 static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
00439 const char* mutex_name, ast_mutex_t *t)
00440 {
00441 int res;
00442 int canlog = strcmp(filename, "logger.c") & t->track;
00443
00444 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
00445 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00446
00447
00448
00449
00450 res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
00451 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00452 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
00453 filename, lineno, func, mutex_name);
00454 return res;
00455 }
00456 }
00457 #endif
00458
00459 if (t->track)
00460 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
00461
00462 if (!(res = pthread_mutex_trylock(&t->mutex))) {
00463 ast_reentrancy_lock(t);
00464 if (t->reentrancy < AST_MAX_REENTRANCY) {
00465 t->file[t->reentrancy] = filename;
00466 t->lineno[t->reentrancy] = lineno;
00467 t->func[t->reentrancy] = func;
00468 t->thread[t->reentrancy] = pthread_self();
00469 t->reentrancy++;
00470 } else {
00471 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
00472 filename, lineno, func, mutex_name);
00473 }
00474 ast_reentrancy_unlock(t);
00475 if (t->track)
00476 ast_mark_lock_acquired(&t->mutex);
00477 } else if (t->track) {
00478 ast_mark_lock_failed(&t->mutex);
00479 }
00480
00481 return res;
00482 }
00483
00484 static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
00485 const char *mutex_name, ast_mutex_t *t)
00486 {
00487 int res;
00488 int canlog = strcmp(filename, "logger.c") & t->track;
00489
00490 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00491 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00492 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00493 filename, lineno, func, mutex_name);
00494 res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
00495 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00496 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
00497 filename, lineno, func, mutex_name);
00498 }
00499 return res;
00500 }
00501 #endif
00502
00503 ast_reentrancy_lock(t);
00504 if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
00505 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
00506 filename, lineno, func, mutex_name);
00507 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
00508 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
00509 DO_THREAD_CRASH;
00510 }
00511
00512 if (--t->reentrancy < 0) {
00513 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
00514 filename, lineno, func, mutex_name);
00515 t->reentrancy = 0;
00516 }
00517
00518 if (t->reentrancy < AST_MAX_REENTRANCY) {
00519 t->file[t->reentrancy] = NULL;
00520 t->lineno[t->reentrancy] = 0;
00521 t->func[t->reentrancy] = NULL;
00522 t->thread[t->reentrancy] = 0;
00523 }
00524 ast_reentrancy_unlock(t);
00525
00526 if (t->track)
00527 ast_remove_lock_info(&t->mutex);
00528
00529 if ((res = pthread_mutex_unlock(&t->mutex))) {
00530 __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n",
00531 filename, lineno, func, strerror(res));
00532 DO_THREAD_CRASH;
00533 }
00534
00535 return res;
00536 }
00537
00538 static inline int __ast_cond_init(const char *filename, int lineno, const char *func,
00539 const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
00540 {
00541 return pthread_cond_init(cond, cond_attr);
00542 }
00543
00544 static inline int __ast_cond_signal(const char *filename, int lineno, const char *func,
00545 const char *cond_name, ast_cond_t *cond)
00546 {
00547 return pthread_cond_signal(cond);
00548 }
00549
00550 static inline int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
00551 const char *cond_name, ast_cond_t *cond)
00552 {
00553 return pthread_cond_broadcast(cond);
00554 }
00555
00556 static inline int __ast_cond_destroy(const char *filename, int lineno, const char *func,
00557 const char *cond_name, ast_cond_t *cond)
00558 {
00559 return pthread_cond_destroy(cond);
00560 }
00561
00562 static inline int __ast_cond_wait(const char *filename, int lineno, const char *func,
00563 const char *cond_name, const char *mutex_name,
00564 ast_cond_t *cond, ast_mutex_t *t)
00565 {
00566 int res;
00567 int canlog = strcmp(filename, "logger.c") & t->track;
00568
00569 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00570 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00571 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00572 filename, lineno, func, mutex_name);
00573 res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
00574 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00575 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
00576 filename, lineno, func, mutex_name);
00577 }
00578 return res;
00579 }
00580 #endif
00581
00582 ast_reentrancy_lock(t);
00583 if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
00584 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
00585 filename, lineno, func, mutex_name);
00586 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
00587 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
00588 DO_THREAD_CRASH;
00589 }
00590
00591 if (--t->reentrancy < 0) {
00592 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
00593 filename, lineno, func, mutex_name);
00594 t->reentrancy = 0;
00595 }
00596
00597 if (t->reentrancy < AST_MAX_REENTRANCY) {
00598 t->file[t->reentrancy] = NULL;
00599 t->lineno[t->reentrancy] = 0;
00600 t->func[t->reentrancy] = NULL;
00601 t->thread[t->reentrancy] = 0;
00602 }
00603 ast_reentrancy_unlock(t);
00604
00605 if (t->track)
00606 ast_remove_lock_info(&t->mutex);
00607
00608 if ((res = pthread_cond_wait(cond, &t->mutex))) {
00609 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
00610 filename, lineno, func, strerror(res));
00611 DO_THREAD_CRASH;
00612 } else {
00613 ast_reentrancy_lock(t);
00614 if (t->reentrancy < AST_MAX_REENTRANCY) {
00615 t->file[t->reentrancy] = filename;
00616 t->lineno[t->reentrancy] = lineno;
00617 t->func[t->reentrancy] = func;
00618 t->thread[t->reentrancy] = pthread_self();
00619 t->reentrancy++;
00620 } else {
00621 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
00622 filename, lineno, func, mutex_name);
00623 }
00624 ast_reentrancy_unlock(t);
00625
00626 if (t->track)
00627 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
00628 }
00629
00630 return res;
00631 }
00632
00633 static inline int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
00634 const char *cond_name, const char *mutex_name, ast_cond_t *cond,
00635 ast_mutex_t *t, const struct timespec *abstime)
00636 {
00637 int res;
00638 int canlog = strcmp(filename, "logger.c") & t->track;
00639
00640 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00641 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00642 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00643 filename, lineno, func, mutex_name);
00644 res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
00645 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00646 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
00647 filename, lineno, func, mutex_name);
00648 }
00649 return res;
00650 }
00651 #endif
00652
00653 ast_reentrancy_lock(t);
00654 if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
00655 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
00656 filename, lineno, func, mutex_name);
00657 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
00658 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
00659 DO_THREAD_CRASH;
00660 }
00661
00662 if (--t->reentrancy < 0) {
00663 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
00664 filename, lineno, func, mutex_name);
00665 t->reentrancy = 0;
00666 }
00667
00668 if (t->reentrancy < AST_MAX_REENTRANCY) {
00669 t->file[t->reentrancy] = NULL;
00670 t->lineno[t->reentrancy] = 0;
00671 t->func[t->reentrancy] = NULL;
00672 t->thread[t->reentrancy] = 0;
00673 }
00674 ast_reentrancy_unlock(t);
00675
00676 if (t->track)
00677 ast_remove_lock_info(&t->mutex);
00678
00679 if ((res = pthread_cond_timedwait(cond, &t->mutex, abstime)) && (res != ETIMEDOUT)) {
00680 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
00681 filename, lineno, func, strerror(res));
00682 DO_THREAD_CRASH;
00683 } else {
00684 ast_reentrancy_lock(t);
00685 if (t->reentrancy < AST_MAX_REENTRANCY) {
00686 t->file[t->reentrancy] = filename;
00687 t->lineno[t->reentrancy] = lineno;
00688 t->func[t->reentrancy] = func;
00689 t->thread[t->reentrancy] = pthread_self();
00690 t->reentrancy++;
00691 } else {
00692 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
00693 filename, lineno, func, mutex_name);
00694 }
00695 ast_reentrancy_unlock(t);
00696
00697 if (t->track)
00698 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
00699 }
00700
00701 return res;
00702 }
00703
00704 #define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00705 #define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00706 #define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00707 #define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00708 #define ast_cond_init(cond, attr) __ast_cond_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond, attr)
00709 #define ast_cond_destroy(cond) __ast_cond_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
00710 #define ast_cond_signal(cond) __ast_cond_signal(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
00711 #define ast_cond_broadcast(cond) __ast_cond_broadcast(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
00712 #define ast_cond_wait(cond, mutex) __ast_cond_wait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex)
00713 #define ast_cond_timedwait(cond, mutex, time) __ast_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex, time)
00714
00715 #else
00716
00717 #define DEADLOCK_AVOIDANCE(lock) \
00718 ast_mutex_unlock(lock); \
00719 usleep(1); \
00720 ast_mutex_lock(lock);
00721
00722
00723 typedef pthread_mutex_t ast_mutex_t;
00724
00725 #define AST_MUTEX_INIT_VALUE ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
00726 #define AST_MUTEX_INIT_VALUE_NOTRACKING \
00727 ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
00728
00729 #define ast_mutex_init_notracking(m) ast_mutex_init(m)
00730
00731 static inline int ast_mutex_init(ast_mutex_t *pmutex)
00732 {
00733 int res;
00734 pthread_mutexattr_t attr;
00735
00736 pthread_mutexattr_init(&attr);
00737 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
00738
00739 res = pthread_mutex_init(pmutex, &attr);
00740 pthread_mutexattr_destroy(&attr);
00741 return res;
00742 }
00743
00744 #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
00745
00746 static inline int ast_mutex_unlock(ast_mutex_t *pmutex)
00747 {
00748 return pthread_mutex_unlock(pmutex);
00749 }
00750
00751 static inline int ast_mutex_destroy(ast_mutex_t *pmutex)
00752 {
00753 return pthread_mutex_destroy(pmutex);
00754 }
00755
00756 static inline int ast_mutex_lock(ast_mutex_t *pmutex)
00757 {
00758 __MTX_PROF(pmutex);
00759 }
00760
00761 static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
00762 {
00763 return pthread_mutex_trylock(pmutex);
00764 }
00765
00766 typedef pthread_cond_t ast_cond_t;
00767
00768 static inline int ast_cond_init(ast_cond_t *cond, pthread_condattr_t *cond_attr)
00769 {
00770 return pthread_cond_init(cond, cond_attr);
00771 }
00772
00773 static inline int ast_cond_signal(ast_cond_t *cond)
00774 {
00775 return pthread_cond_signal(cond);
00776 }
00777
00778 static inline int ast_cond_broadcast(ast_cond_t *cond)
00779 {
00780 return pthread_cond_broadcast(cond);
00781 }
00782
00783 static inline int ast_cond_destroy(ast_cond_t *cond)
00784 {
00785 return pthread_cond_destroy(cond);
00786 }
00787
00788 static inline int ast_cond_wait(ast_cond_t *cond, ast_mutex_t *t)
00789 {
00790 return pthread_cond_wait(cond, t);
00791 }
00792
00793 static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime)
00794 {
00795 return pthread_cond_timedwait(cond, t, abstime);
00796 }
00797
00798 #endif
00799
00800 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
00801
00802
00803 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track) \
00804 scope ast_mutex_t mutex = init_val; \
00805 static void __attribute__((constructor)) init_##mutex(void) \
00806 { \
00807 if (track) \
00808 ast_mutex_init(&mutex); \
00809 else \
00810 ast_mutex_init_notracking(&mutex); \
00811 } \
00812 static void __attribute__((destructor)) fini_##mutex(void) \
00813 { \
00814 ast_mutex_destroy(&mutex); \
00815 }
00816 #else
00817
00818 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track) \
00819 scope ast_mutex_t mutex = init_val
00820 #endif
00821
00822 #define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
00823 #define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
00824 #define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
00825 #define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
00826 #define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init
00827 #define pthread_mutex_destroy use_ast_mutex_destroy_instead_of_pthread_mutex_destroy
00828 #define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t
00829 #define pthread_cond_init use_ast_cond_init_instead_of_pthread_cond_init
00830 #define pthread_cond_destroy use_ast_cond_destroy_instead_of_pthread_cond_destroy
00831 #define pthread_cond_signal use_ast_cond_signal_instead_of_pthread_cond_signal
00832 #define pthread_cond_broadcast use_ast_cond_broadcast_instead_of_pthread_cond_broadcast
00833 #define pthread_cond_wait use_ast_cond_wait_instead_of_pthread_cond_wait
00834 #define pthread_cond_timedwait use_ast_cond_timedwait_instead_of_pthread_cond_timedwait
00835
00836 #define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE, 1)
00837 #define AST_MUTEX_DEFINE_STATIC_NOTRACKING(mutex) __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE_NOTRACKING, 0)
00838
00839 #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
00840
00841 #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
00842
00843 #ifndef __linux__
00844 #define pthread_create __use_ast_pthread_create_instead__
00845 #endif
00846
00847 typedef pthread_rwlock_t ast_rwlock_t;
00848
00849 #ifdef HAVE_PTHREAD_RWLOCK_INITIALIZER
00850 #define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
00851 #else
00852 #define AST_RWLOCK_INIT_VALUE NULL
00853 #endif
00854
00855 #ifdef DEBUG_THREADS
00856
00857 #define ast_rwlock_init(rwlock) __ast_rwlock_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)
00858
00859
00860 static inline int __ast_rwlock_init(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *prwlock)
00861 {
00862 int res;
00863 pthread_rwlockattr_t attr;
00864 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00865 int canlog = strcmp(filename, "logger.c");
00866
00867 if (*prwlock != ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
00868 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
00869 filename, lineno, func, rwlock_name);
00870 return 0;
00871 }
00872 #endif
00873 pthread_rwlockattr_init(&attr);
00874
00875 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
00876 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
00877 #endif
00878
00879 res = pthread_rwlock_init(prwlock, &attr);
00880 pthread_rwlockattr_destroy(&attr);
00881 return res;
00882 }
00883
00884 #define ast_rwlock_destroy(rwlock) __ast_rwlock_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)
00885
00886 static inline int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *prwlock)
00887 {
00888 int res;
00889 int canlog = strcmp(filename, "logger.c");
00890
00891 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00892 if (*prwlock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
00893 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
00894 filename, lineno, func, rwlock_name);
00895 return 0;
00896 }
00897 #endif
00898
00899 if ((res = pthread_rwlock_destroy(prwlock)))
00900 __ast_mutex_logger("%s line %d (%s): Error destroying rwlock %s: %s\n",
00901 filename, lineno, func, rwlock_name, strerror(res));
00902
00903 return res;
00904 }
00905
00906 #define ast_rwlock_unlock(a) \
00907 _ast_rwlock_unlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
00908
00909 static inline int _ast_rwlock_unlock(ast_rwlock_t *lock, const char *name,
00910 const char *file, int line, const char *func)
00911 {
00912 int res;
00913 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00914 int canlog = strcmp(file, "logger.c");
00915
00916 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
00917 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
00918 file, line, func, name);
00919 res = __ast_rwlock_init(file, line, func, name, lock);
00920 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
00921 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
00922 file, line, func, name);
00923 }
00924 return res;
00925 }
00926 #endif
00927
00928 res = pthread_rwlock_unlock(lock);
00929 ast_remove_lock_info(lock);
00930 return res;
00931 }
00932
00933 #define ast_rwlock_rdlock(a) \
00934 _ast_rwlock_rdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
00935
00936 static inline int _ast_rwlock_rdlock(ast_rwlock_t *lock, const char *name,
00937 const char *file, int line, const char *func)
00938 {
00939 int res;
00940 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00941 int canlog = strcmp(file, "logger.c");
00942
00943 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
00944
00945
00946
00947
00948 res = __ast_rwlock_init(file, line, func, name, lock);
00949 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
00950 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
00951 file, line, func, name);
00952 return res;
00953 }
00954 }
00955 #endif
00956
00957 ast_store_lock_info(AST_RDLOCK, file, line, func, name, lock);
00958 res = pthread_rwlock_rdlock(lock);
00959 if (!res)
00960 ast_mark_lock_acquired(lock);
00961 else
00962 ast_remove_lock_info(lock);
00963 return res;
00964 }
00965
00966 #define ast_rwlock_wrlock(a) \
00967 _ast_rwlock_wrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
00968
00969 static inline int _ast_rwlock_wrlock(ast_rwlock_t *lock, const char *name,
00970 const char *file, int line, const char *func)
00971 {
00972 int res;
00973 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00974 int canlog = strcmp(file, "logger.c");
00975
00976 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
00977
00978
00979
00980
00981 res = __ast_rwlock_init(file, line, func, name, lock);
00982 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
00983 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
00984 file, line, func, name);
00985 return res;
00986 }
00987 }
00988 #endif
00989
00990 ast_store_lock_info(AST_WRLOCK, file, line, func, name, lock);
00991 res = pthread_rwlock_wrlock(lock);
00992 if (!res)
00993 ast_mark_lock_acquired(lock);
00994 else
00995 ast_remove_lock_info(lock);
00996 return res;
00997 }
00998
00999 #define ast_rwlock_timedrdlock(a,b) \
01000 _ast_rwlock_timedrdlock(a, # a, b, __FILE__, __LINE__, __PRETTY_FUNCTION__)
01001
01002 static inline int _ast_rwlock_timedrdlock(ast_rwlock_t *lock, const char *name,
01003 const struct timespec *abs_timeout, const char *file, int line, const char *func)
01004 {
01005 int res;
01006 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
01007 int canlog = strcmp(file, "logger.c");
01008
01009 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
01010
01011
01012
01013
01014 res = __ast_rwlock_init(file, line, func, name, lock);
01015 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
01016 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
01017 file, line, func, name);
01018 return res;
01019 }
01020 }
01021 #endif
01022
01023 ast_store_lock_info(AST_RDLOCK, file, line, func, name, lock);
01024 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
01025 res = pthread_rwlock_timedrdlock(lock, abs_timeout);
01026 #else
01027 do {
01028 struct timeval _start = ast_tvnow(), _diff;
01029 for (;;) {
01030 if (!(res = pthread_rwlock_tryrdlock(&t->lock))) {
01031 break;
01032 }
01033 _diff = ast_tvsub(ast_tvnow(), _start);
01034 if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
01035 break;
01036 }
01037 usleep(1);
01038 }
01039 } while (0);
01040 #endif
01041 if (!res)
01042 ast_mark_lock_acquired(lock);
01043 else
01044 ast_remove_lock_info(lock);
01045 return res;
01046 }
01047
01048 #define ast_rwlock_timedwrlock(a,b) \
01049 _ast_rwlock_timedwrlock(a, # a, b, __FILE__, __LINE__, __PRETTY_FUNCTION__)
01050
01051 static inline int _ast_rwlock_timedwrlock(ast_rwlock_t *lock, const char *name,
01052 const struct timespec *abs_timeout, const char *file, int line, const char *func)
01053 {
01054 int res;
01055 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
01056 int canlog = strcmp(file, "logger.c");
01057
01058 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
01059
01060
01061
01062
01063 res = __ast_rwlock_init(file, line, func, name, lock);
01064 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
01065 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
01066 file, line, func, name);
01067 return res;
01068 }
01069 }
01070 #endif
01071
01072 ast_store_lock_info(AST_WRLOCK, file, line, func, name, lock);
01073 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
01074 res = pthread_rwlock_timedwrlock(lock, abs_timeout);
01075 #else
01076 do {
01077 struct timeval _start = ast_tvnow(), _diff;
01078 for (;;) {
01079 if (!(res = pthread_rwlock_trywrlock(&t->lock))) {
01080 break;
01081 }
01082 _diff = ast_tvsub(ast_tvnow(), _start);
01083 if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
01084 break;
01085 }
01086 usleep(1);
01087 }
01088 } while (0);
01089 #endif
01090 if (!res)
01091 ast_mark_lock_acquired(lock);
01092 else
01093 ast_remove_lock_info(lock);
01094 return res;
01095 }
01096
01097 #define ast_rwlock_tryrdlock(a) \
01098 _ast_rwlock_tryrdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
01099
01100 static inline int _ast_rwlock_tryrdlock(ast_rwlock_t *lock, const char *name,
01101 const char *file, int line, const char *func)
01102 {
01103 int res;
01104 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
01105 int canlog = strcmp(file, "logger.c");
01106
01107 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
01108
01109
01110
01111
01112 res = __ast_rwlock_init(file, line, func, name, lock);
01113 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
01114 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
01115 file, line, func, name);
01116 return res;
01117 }
01118 }
01119 #endif
01120
01121 ast_store_lock_info(AST_RDLOCK, file, line, func, name, lock);
01122 res = pthread_rwlock_tryrdlock(lock);
01123 if (!res)
01124 ast_mark_lock_acquired(lock);
01125 else
01126 ast_remove_lock_info(lock);
01127 return res;
01128 }
01129
01130 #define ast_rwlock_trywrlock(a) \
01131 _ast_rwlock_trywrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
01132
01133 static inline int _ast_rwlock_trywrlock(ast_rwlock_t *lock, const char *name,
01134 const char *file, int line, const char *func)
01135 {
01136 int res;
01137 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
01138 int canlog = strcmp(file, "logger.c");
01139
01140 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
01141
01142
01143
01144
01145 res = __ast_rwlock_init(file, line, func, name, lock);
01146 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
01147 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
01148 file, line, func, name);
01149 return res;
01150 }
01151 }
01152 #endif
01153
01154 ast_store_lock_info(AST_WRLOCK, file, line, func, name, lock);
01155 res = pthread_rwlock_trywrlock(lock);
01156 if (!res)
01157 ast_mark_lock_acquired(lock);
01158 else
01159 ast_remove_lock_info(lock);
01160 return res;
01161 }
01162
01163 #else
01164
01165 static inline int ast_rwlock_init(ast_rwlock_t *prwlock)
01166 {
01167 int res;
01168 pthread_rwlockattr_t attr;
01169
01170 pthread_rwlockattr_init(&attr);
01171
01172 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
01173 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
01174 #endif
01175
01176 res = pthread_rwlock_init(prwlock, &attr);
01177 pthread_rwlockattr_destroy(&attr);
01178 return res;
01179 }
01180
01181 static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
01182 {
01183 return pthread_rwlock_destroy(prwlock);
01184 }
01185
01186 static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
01187 {
01188 return pthread_rwlock_unlock(prwlock);
01189 }
01190
01191 static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
01192 {
01193 return pthread_rwlock_rdlock(prwlock);
01194 }
01195
01196 static inline int ast_rwlock_timedrdlock(ast_rwlock_t *prwlock, const struct timespec *abs_timeout)
01197 {
01198 int res;
01199 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
01200 res = pthread_rwlock_timedrdlock(prwlock, abs_timeout);
01201 #else
01202 struct timeval _start = ast_tvnow(), _diff;
01203 for (;;) {
01204 if (!(res = pthread_rwlock_tryrdlock(prwlock))) {
01205 break;
01206 }
01207 _diff = ast_tvsub(ast_tvnow(), _start);
01208 if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
01209 break;
01210 }
01211 usleep(1);
01212 }
01213 #endif
01214 return res;
01215 }
01216
01217 static inline int ast_rwlock_tryrdlock(ast_rwlock_t *prwlock)
01218 {
01219 return pthread_rwlock_tryrdlock(prwlock);
01220 }
01221
01222 static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
01223 {
01224 return pthread_rwlock_wrlock(prwlock);
01225 }
01226
01227 static inline int ast_rwlock_timedwrlock(ast_rwlock_t *prwlock, const struct timespec *abs_timeout)
01228 {
01229 int res;
01230 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
01231 res = pthread_rwlock_timedwrlock(prwlock, abs_timeout);
01232 #else
01233 do {
01234 struct timeval _start = ast_tvnow(), _diff;
01235 for (;;) {
01236 if (!(res = pthread_rwlock_trywrlock(prwlock))) {
01237 break;
01238 }
01239 _diff = ast_tvsub(ast_tvnow(), _start);
01240 if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
01241 break;
01242 }
01243 usleep(1);
01244 }
01245 } while (0);
01246 #endif
01247 return res;
01248 }
01249
01250 static inline int ast_rwlock_trywrlock(ast_rwlock_t *prwlock)
01251 {
01252 return pthread_rwlock_trywrlock(prwlock);
01253 }
01254 #endif
01255
01256
01257
01258 #ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
01259 #define __AST_RWLOCK_DEFINE(scope, rwlock) \
01260 scope ast_rwlock_t rwlock; \
01261 static void __attribute__((constructor)) init_##rwlock(void) \
01262 { \
01263 ast_rwlock_init(&rwlock); \
01264 } \
01265 static void __attribute__((destructor)) fini_##rwlock(void) \
01266 { \
01267 ast_rwlock_destroy(&rwlock); \
01268 }
01269 #else
01270 #define __AST_RWLOCK_DEFINE(scope, rwlock) \
01271 scope ast_rwlock_t rwlock = AST_RWLOCK_INIT_VALUE
01272 #endif
01273
01274 #define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock)
01275
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285
01286 int ast_atomic_fetchadd_int_slow(volatile int *p, int v);
01287
01288 #include "asterisk/inline_api.h"
01289
01290 #if defined(HAVE_OSX_ATOMICS)
01291 #include "libkern/OSAtomic.h"
01292 #endif
01293
01294
01295
01296
01297
01298
01299 #if defined(HAVE_GCC_ATOMICS)
01300 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
01301 {
01302 return __sync_fetch_and_add(p, v);
01303 })
01304 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
01305 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
01306 {
01307 return OSAtomicAdd32(v, (int32_t *) p) - v;
01308 })
01309 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
01310 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
01311 {
01312 return OSAtomicAdd64(v, (int64_t *) p) - v;
01313 #elif defined (__i386__)
01314 #ifdef sun
01315 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
01316 {
01317 __asm __volatile (
01318 " lock; xaddl %0, %1 ; "
01319 : "+r" (v),
01320 "=m" (*p)
01321 : "m" (*p));
01322 return (v);
01323 })
01324 #else
01325 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
01326 {
01327 __asm __volatile (
01328 " lock xaddl %0, %1 ; "
01329 : "+r" (v),
01330 "=m" (*p)
01331 : "m" (*p));
01332 return (v);
01333 })
01334 #endif
01335 #else
01336 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
01337 {
01338 return ast_atomic_fetchadd_int_slow(p, v);
01339 })
01340 #endif
01341
01342
01343
01344
01345 #if defined(HAVE_GCC_ATOMICS)
01346 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
01347 {
01348 return __sync_sub_and_fetch(p, 1) == 0;
01349 })
01350 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
01351 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
01352 {
01353 return OSAtomicAdd32( -1, (int32_t *) p) == 0;
01354 })
01355 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
01356 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
01357 {
01358 return OSAtomicAdd64( -1, (int64_t *) p) == 0;
01359 #else
01360 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
01361 {
01362 int a = ast_atomic_fetchadd_int(p, -1);
01363 return a == 1;
01364 })
01365 #endif
01366
01367 #ifndef DEBUG_CHANNEL_LOCKS
01368
01369
01370 #define ast_channel_lock(x) ast_mutex_lock(&x->lock)
01371
01372
01373 #define ast_channel_unlock(x) ast_mutex_unlock(&x->lock)
01374
01375
01376 #define ast_channel_trylock(x) ast_mutex_trylock(&x->lock)
01377 #else
01378
01379 struct ast_channel;
01380
01381 #define ast_channel_lock(a) __ast_channel_lock(a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
01382
01383
01384 int __ast_channel_lock(struct ast_channel *chan, const char *file, int lineno, const char *func);
01385
01386 #define ast_channel_unlock(a) __ast_channel_unlock(a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
01387
01388
01389
01390 int __ast_channel_unlock(struct ast_channel *chan, const char *file, int lineno, const char *func);
01391
01392 #define ast_channel_trylock(a) __ast_channel_trylock(a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
01393
01394
01395 int __ast_channel_trylock(struct ast_channel *chan, const char *file, int lineno, const char *func);
01396 #endif
01397
01398 #endif