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
00046
00047
00048 #ifndef _ASTERISK_LOCK_H
00049 #define _ASTERISK_LOCK_H
00050
00051 #include <pthread.h>
00052 #include <time.h>
00053 #include <sys/param.h>
00054 #ifdef HAVE_BKTR
00055 #include <execinfo.h>
00056 #endif
00057
00058 #ifndef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
00059 #include "asterisk/time.h"
00060 #endif
00061 #include "asterisk/logger.h"
00062
00063
00064
00065
00066 #ifndef HAVE_MTX_PROFILE
00067 #define __MTX_PROF(a) return pthread_mutex_lock((a))
00068 #else
00069 #define __MTX_PROF(a) do { \
00070 int i; \
00071 \
00072 ast_mark(mtx_prof, 1); \
00073 i = pthread_mutex_trylock((a)); \
00074 ast_mark(mtx_prof, 0); \
00075 if (!i) \
00076 return i; \
00077 else \
00078 return pthread_mutex_lock((a)); \
00079 } while (0)
00080 #endif
00081
00082 #define AST_PTHREADT_NULL (pthread_t) -1
00083 #define AST_PTHREADT_STOP (pthread_t) -2
00084
00085 #if defined(SOLARIS) || defined(BSD)
00086 #define AST_MUTEX_INIT_W_CONSTRUCTORS
00087 #endif
00088
00089
00090
00091 #if defined(HAVE_PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) && defined(HAVE_PTHREAD_MUTEX_RECURSIVE_NP)
00092 #define PTHREAD_MUTEX_INIT_VALUE PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
00093 #define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE_NP
00094 #else
00095 #define PTHREAD_MUTEX_INIT_VALUE PTHREAD_MUTEX_INITIALIZER
00096 #define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE
00097 #endif
00098
00099
00100
00101
00102
00103
00104
00105
00106 #ifdef DEBUG_THREADS
00107
00108 #define __ast_mutex_logger(...) do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0)
00109
00110 #ifdef THREAD_CRASH
00111 #define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
00112 #else
00113 #define DO_THREAD_CRASH do { } while (0)
00114 #endif
00115
00116 #include <errno.h>
00117
00118 #ifdef HAVE_BKTR
00119 #define AST_LOCK_TRACK_INIT_VALUE { { NULL }, { 0 }, 0, { NULL }, { 0 }, {{{ 0 }}}, PTHREAD_MUTEX_INIT_VALUE }
00120
00121 #else
00122 #define AST_LOCK_TRACK_INIT_VALUE { { NULL }, { 0 }, 0, { NULL }, { 0 }, PTHREAD_MUTEX_INIT_VALUE }
00123 #endif
00124
00125 #define AST_MUTEX_INIT_VALUE { AST_LOCK_TRACK_INIT_VALUE, 1, PTHREAD_MUTEX_INIT_VALUE }
00126 #define AST_MUTEX_INIT_VALUE_NOTRACKING { AST_LOCK_TRACK_INIT_VALUE, 0, PTHREAD_MUTEX_INIT_VALUE }
00127
00128 #define AST_MAX_REENTRANCY 10
00129
00130 struct ast_channel;
00131
00132 struct ast_lock_track {
00133 const char *file[AST_MAX_REENTRANCY];
00134 int lineno[AST_MAX_REENTRANCY];
00135 int reentrancy;
00136 const char *func[AST_MAX_REENTRANCY];
00137 pthread_t thread[AST_MAX_REENTRANCY];
00138 #ifdef HAVE_BKTR
00139 struct ast_bt backtrace[AST_MAX_REENTRANCY];
00140 #endif
00141 pthread_mutex_t reentr_mutex;
00142 };
00143
00144 struct ast_mutex_info {
00145
00146 struct ast_lock_track track;
00147 unsigned int tracking:1;
00148 pthread_mutex_t mutex;
00149 };
00150
00151 typedef struct ast_mutex_info ast_mutex_t;
00152
00153 typedef pthread_cond_t ast_cond_t;
00154
00155 enum ast_lock_type {
00156 AST_MUTEX,
00157 AST_RDLOCK,
00158 AST_WRLOCK,
00159 };
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169 #if !defined(LOW_MEMORY)
00170 #ifdef HAVE_BKTR
00171 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
00172 int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt);
00173 #else
00174 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
00175 int line_num, const char *func, const char *lock_name, void *lock_addr);
00176 #endif
00177
00178 #else
00179
00180 #ifdef HAVE_BKTR
00181 #define ast_store_lock_info(I,DONT,CARE,ABOUT,THE,PARAMETERS,BUD)
00182 #else
00183 #define ast_store_lock_info(I,DONT,CARE,ABOUT,THE,PARAMETERS)
00184 #endif
00185 #endif
00186
00187
00188
00189
00190 #if !defined(LOW_MEMORY)
00191 void ast_mark_lock_acquired(void *lock_addr);
00192 #else
00193 #define ast_mark_lock_acquired(ignore)
00194 #endif
00195
00196
00197
00198
00199 #if !defined(LOW_MEMORY)
00200 void ast_mark_lock_failed(void *lock_addr);
00201 #else
00202 #define ast_mark_lock_failed(ignore)
00203 #endif
00204
00205
00206
00207
00208
00209
00210
00211 #if !defined(LOW_MEMORY)
00212 #ifdef HAVE_BKTR
00213 void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt);
00214 #else
00215 void ast_remove_lock_info(void *lock_addr);
00216 #endif
00217 #else
00218 #ifdef HAVE_BKTR
00219 #define ast_remove_lock_info(ignore,me)
00220 #else
00221 #define ast_remove_lock_info(ignore)
00222 #endif
00223 #endif
00224
00225 #ifdef HAVE_BKTR
00226 static inline void __dump_backtrace(struct ast_bt *bt, int canlog)
00227 {
00228 char **strings;
00229
00230 ssize_t i;
00231
00232 strings = backtrace_symbols(bt->addresses, bt->num_frames);
00233
00234 for (i = 0; i < bt->num_frames; i++)
00235 __ast_mutex_logger("%s\n", strings[i]);
00236
00237 free(strings);
00238 }
00239 #endif
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251 void log_show_lock(void *this_lock_addr);
00252
00253
00254
00255
00256
00257
00258
00259 #if !defined(LOW_MEMORY)
00260 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);
00261 #else
00262 #define ast_find_lock_info(a,b,c,d,e,f,g,h) -1
00263 #endif
00264
00265
00266
00267
00268
00269
00270
00271 #define CHANNEL_DEADLOCK_AVOIDANCE(chan) \
00272 do { \
00273 char __filename[80], __func[80], __mutex_name[80]; \
00274 int __lineno; \
00275 int __res = ast_find_lock_info(&chan->lock_dont_use, __filename, sizeof(__filename), &__lineno, __func, sizeof(__func), __mutex_name, sizeof(__mutex_name)); \
00276 ast_channel_unlock(chan); \
00277 usleep(1); \
00278 if (__res < 0) { \
00279 ast_channel_lock(chan); \
00280 } else { \
00281 __ast_pthread_mutex_lock(__filename, __lineno, __func, __mutex_name, &chan->lock_dont_use); \
00282 } \
00283 } while (0)
00284
00285 #define DEADLOCK_AVOIDANCE(lock) \
00286 do { \
00287 char __filename[80], __func[80], __mutex_name[80]; \
00288 int __lineno; \
00289 int __res = ast_find_lock_info(lock, __filename, sizeof(__filename), &__lineno, __func, sizeof(__func), __mutex_name, sizeof(__mutex_name)); \
00290 ast_mutex_unlock(lock); \
00291 usleep(1); \
00292 if (__res < 0) { \
00293 ast_mutex_lock(lock); \
00294 } else { \
00295 __ast_pthread_mutex_lock(__filename, __lineno, __func, __mutex_name, lock); \
00296 } \
00297 } while (0)
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311 #define DLA_UNLOCK(lock) \
00312 do { \
00313 char __filename[80], __func[80], __mutex_name[80]; \
00314 int __lineno; \
00315 int __res = ast_find_lock_info(lock, __filename, sizeof(__filename), &__lineno, __func, sizeof(__func), __mutex_name, sizeof(__mutex_name)); \
00316 ast_mutex_unlock(lock);
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330 #define DLA_LOCK(lock) \
00331 if (__res < 0) { \
00332 ast_mutex_lock(lock); \
00333 } else { \
00334 __ast_pthread_mutex_lock(__filename, __lineno, __func, __mutex_name, lock); \
00335 } \
00336 } while (0)
00337
00338 static inline void ast_reentrancy_lock(struct ast_lock_track *lt)
00339 {
00340 pthread_mutex_lock(<->reentr_mutex);
00341 }
00342
00343 static inline void ast_reentrancy_unlock(struct ast_lock_track *lt)
00344 {
00345 pthread_mutex_unlock(<->reentr_mutex);
00346 }
00347
00348 static inline void ast_reentrancy_init(struct ast_lock_track *lt)
00349 {
00350 int i;
00351 pthread_mutexattr_t reentr_attr;
00352
00353 for (i = 0; i < AST_MAX_REENTRANCY; i++) {
00354 lt->file[i] = NULL;
00355 lt->lineno[i] = 0;
00356 lt->func[i] = NULL;
00357 lt->thread[i] = 0;
00358 #ifdef HAVE_BKTR
00359 memset(<->backtrace[i], 0, sizeof(lt->backtrace[i]));
00360 #endif
00361 }
00362
00363 lt->reentrancy = 0;
00364
00365 pthread_mutexattr_init(&reentr_attr);
00366 pthread_mutexattr_settype(&reentr_attr, AST_MUTEX_KIND);
00367 pthread_mutex_init(<->reentr_mutex, &reentr_attr);
00368 pthread_mutexattr_destroy(&reentr_attr);
00369 }
00370
00371 static inline void delete_reentrancy_cs(struct ast_lock_track *lt)
00372 {
00373 pthread_mutex_destroy(<->reentr_mutex);
00374 }
00375
00376 static inline int __ast_pthread_mutex_init(int tracking, const char *filename, int lineno, const char *func,
00377 const char *mutex_name, ast_mutex_t *t)
00378 {
00379 int res;
00380 pthread_mutexattr_t attr;
00381
00382 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00383
00384 if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00385
00386
00387
00388
00389
00390
00391 return 0;
00392 }
00393
00394 #endif
00395
00396 ast_reentrancy_init(&t->track);
00397 t->tracking = tracking;
00398
00399 pthread_mutexattr_init(&attr);
00400 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
00401
00402 res = pthread_mutex_init(&t->mutex, &attr);
00403 pthread_mutexattr_destroy(&attr);
00404 return res;
00405 }
00406
00407 #define ast_mutex_init(pmutex) __ast_pthread_mutex_init(1, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
00408 #define ast_mutex_init_notracking(pmutex) \
00409 __ast_pthread_mutex_init(0, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
00410
00411 #define ROFFSET ((lt->reentrancy > 0) ? (lt->reentrancy-1) : 0)
00412 static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
00413 const char *mutex_name, ast_mutex_t *t)
00414 {
00415 int res;
00416 struct ast_lock_track *lt;
00417 int canlog = strcmp(filename, "logger.c") & t->tracking;
00418
00419 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00420 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00421
00422
00423
00424
00425
00426
00427 __ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is uninitialized.\n",
00428 filename, lineno, func, mutex_name);
00429 return 0;
00430 }
00431 #endif
00432
00433 lt = &t->track;
00434
00435 res = pthread_mutex_trylock(&t->mutex);
00436 switch (res) {
00437 case 0:
00438 pthread_mutex_unlock(&t->mutex);
00439 break;
00440 case EINVAL:
00441 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
00442 filename, lineno, func, mutex_name);
00443 break;
00444 case EBUSY:
00445 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
00446 filename, lineno, func, mutex_name);
00447 ast_reentrancy_lock(lt);
00448 __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
00449 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
00450 #ifdef HAVE_BKTR
00451 __dump_backtrace(<->backtrace[ROFFSET], canlog);
00452 #endif
00453 ast_reentrancy_unlock(lt);
00454 break;
00455 }
00456
00457
00458 if ((res = pthread_mutex_destroy(&t->mutex))) {
00459 __ast_mutex_logger("%s line %d (%s): Error destroying mutex %s: %s\n",
00460 filename, lineno, func, mutex_name, strerror(res));
00461 }
00462 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
00463 else
00464 t->mutex = PTHREAD_MUTEX_INIT_VALUE;
00465 #endif
00466 ast_reentrancy_lock(lt);
00467 lt->file[0] = filename;
00468 lt->lineno[0] = lineno;
00469 lt->func[0] = func;
00470 lt->reentrancy = 0;
00471 lt->thread[0] = 0;
00472 #ifdef HAVE_BKTR
00473 memset(<->backtrace[0], 0, sizeof(lt->backtrace[0]));
00474 #endif
00475 ast_reentrancy_unlock(lt);
00476 delete_reentrancy_cs(lt);
00477
00478 return res;
00479 }
00480
00481 static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
00482 const char* mutex_name, ast_mutex_t *t)
00483 {
00484 int res;
00485 struct ast_lock_track *lt = &t->track;
00486 int canlog = strcmp(filename, "logger.c") & t->tracking;
00487 #ifdef HAVE_BKTR
00488 struct ast_bt *bt = NULL;
00489 #endif
00490
00491 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
00492 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00493
00494
00495
00496
00497 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
00498 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00499 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
00500 filename, lineno, func, mutex_name);
00501 return res;
00502 }
00503 }
00504 #endif
00505
00506 if (t->tracking) {
00507 #ifdef HAVE_BKTR
00508 ast_reentrancy_lock(lt);
00509 if (lt->reentrancy != AST_MAX_REENTRANCY) {
00510 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
00511 bt = <->backtrace[lt->reentrancy];
00512 }
00513 ast_reentrancy_unlock(lt);
00514 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
00515 #else
00516 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
00517 #endif
00518 }
00519
00520 #ifdef DETECT_DEADLOCKS
00521 {
00522 time_t seconds = time(NULL);
00523 time_t wait_time, reported_wait = 0;
00524 do {
00525 #ifdef HAVE_MTX_PROFILE
00526 ast_mark(mtx_prof, 1);
00527 #endif
00528 res = pthread_mutex_trylock(&t->mutex);
00529 #ifdef HAVE_MTX_PROFILE
00530 ast_mark(mtx_prof, 0);
00531 #endif
00532 if (res == EBUSY) {
00533 wait_time = time(NULL) - seconds;
00534 if (wait_time > reported_wait && (wait_time % 5) == 0) {
00535 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
00536 filename, lineno, func, (int) wait_time, mutex_name);
00537 ast_reentrancy_lock(lt);
00538 #ifdef HAVE_BKTR
00539 __dump_backtrace(<->backtrace[lt->reentrancy], canlog);
00540 #endif
00541 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
00542 lt->file[ROFFSET], lt->lineno[ROFFSET],
00543 lt->func[ROFFSET], mutex_name);
00544 #ifdef HAVE_BKTR
00545 __dump_backtrace(<->backtrace[ROFFSET], canlog);
00546 #endif
00547 ast_reentrancy_unlock(lt);
00548 reported_wait = wait_time;
00549 }
00550 usleep(200);
00551 }
00552 } while (res == EBUSY);
00553 }
00554 #else
00555 #ifdef HAVE_MTX_PROFILE
00556 ast_mark(mtx_prof, 1);
00557 res = pthread_mutex_trylock(&t->mutex);
00558 ast_mark(mtx_prof, 0);
00559 if (res)
00560 #endif
00561 res = pthread_mutex_lock(&t->mutex);
00562 #endif
00563
00564 if (!res) {
00565 ast_reentrancy_lock(lt);
00566 if (lt->reentrancy < AST_MAX_REENTRANCY) {
00567 lt->file[lt->reentrancy] = filename;
00568 lt->lineno[lt->reentrancy] = lineno;
00569 lt->func[lt->reentrancy] = func;
00570 lt->thread[lt->reentrancy] = pthread_self();
00571 lt->reentrancy++;
00572 } else {
00573 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
00574 filename, lineno, func, mutex_name);
00575 }
00576 ast_reentrancy_unlock(lt);
00577 if (t->tracking) {
00578 ast_mark_lock_acquired(t);
00579 }
00580 } else {
00581 #ifdef HAVE_BKTR
00582 if (lt->reentrancy) {
00583 ast_reentrancy_lock(lt);
00584 bt = <->backtrace[lt->reentrancy-1];
00585 ast_reentrancy_unlock(lt);
00586 } else {
00587 bt = NULL;
00588 }
00589 if (t->tracking) {
00590 ast_remove_lock_info(t, bt);
00591 }
00592 #else
00593 if (t->tracking) {
00594 ast_remove_lock_info(t);
00595 }
00596 #endif
00597 __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
00598 filename, lineno, func, strerror(res));
00599 DO_THREAD_CRASH;
00600 }
00601
00602 return res;
00603 }
00604
00605 static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
00606 const char* mutex_name, ast_mutex_t *t)
00607 {
00608 int res;
00609 struct ast_lock_track *lt= &t->track;
00610 int canlog = strcmp(filename, "logger.c") & t->tracking;
00611 #ifdef HAVE_BKTR
00612 struct ast_bt *bt = NULL;
00613 #endif
00614
00615 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
00616 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00617
00618
00619
00620
00621 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
00622 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00623 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
00624 filename, lineno, func, mutex_name);
00625 return res;
00626 }
00627 }
00628 #endif
00629
00630 if (t->tracking) {
00631 #ifdef HAVE_BKTR
00632 ast_reentrancy_lock(lt);
00633 if (lt->reentrancy != AST_MAX_REENTRANCY) {
00634 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
00635 bt = <->backtrace[lt->reentrancy];
00636 }
00637 ast_reentrancy_unlock(lt);
00638 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
00639 #else
00640 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
00641 #endif
00642 }
00643
00644 if (!(res = pthread_mutex_trylock(&t->mutex))) {
00645 ast_reentrancy_lock(lt);
00646 if (lt->reentrancy < AST_MAX_REENTRANCY) {
00647 lt->file[lt->reentrancy] = filename;
00648 lt->lineno[lt->reentrancy] = lineno;
00649 lt->func[lt->reentrancy] = func;
00650 lt->thread[lt->reentrancy] = pthread_self();
00651 lt->reentrancy++;
00652 } else {
00653 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
00654 filename, lineno, func, mutex_name);
00655 }
00656 ast_reentrancy_unlock(lt);
00657 if (t->tracking) {
00658 ast_mark_lock_acquired(t);
00659 }
00660 } else if (t->tracking) {
00661 ast_mark_lock_failed(t);
00662 }
00663
00664 return res;
00665 }
00666
00667 static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
00668 const char *mutex_name, ast_mutex_t *t)
00669 {
00670 int res;
00671 struct ast_lock_track *lt = &t->track;
00672 int canlog = strcmp(filename, "logger.c") & t->tracking;
00673 #ifdef HAVE_BKTR
00674 struct ast_bt *bt = NULL;
00675 #endif
00676
00677 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00678 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00679 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00680 filename, lineno, func, mutex_name);
00681 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
00682 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00683 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
00684 filename, lineno, func, mutex_name);
00685 }
00686 return res;
00687 }
00688 #endif
00689
00690 ast_reentrancy_lock(lt);
00691 if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
00692 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
00693 filename, lineno, func, mutex_name);
00694 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
00695 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
00696 #ifdef HAVE_BKTR
00697 __dump_backtrace(<->backtrace[ROFFSET], canlog);
00698 #endif
00699 DO_THREAD_CRASH;
00700 }
00701
00702 if (--lt->reentrancy < 0) {
00703 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
00704 filename, lineno, func, mutex_name);
00705 lt->reentrancy = 0;
00706 }
00707
00708 if (lt->reentrancy < AST_MAX_REENTRANCY) {
00709 lt->file[lt->reentrancy] = NULL;
00710 lt->lineno[lt->reentrancy] = 0;
00711 lt->func[lt->reentrancy] = NULL;
00712 lt->thread[lt->reentrancy] = 0;
00713 }
00714
00715 #ifdef HAVE_BKTR
00716 if (lt->reentrancy) {
00717 bt = <->backtrace[lt->reentrancy - 1];
00718 }
00719 #endif
00720 ast_reentrancy_unlock(lt);
00721
00722 if (t->tracking) {
00723 #ifdef HAVE_BKTR
00724 ast_remove_lock_info(t, bt);
00725 #else
00726 ast_remove_lock_info(t);
00727 #endif
00728 }
00729
00730 if ((res = pthread_mutex_unlock(&t->mutex))) {
00731 __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n",
00732 filename, lineno, func, strerror(res));
00733 DO_THREAD_CRASH;
00734 }
00735
00736 return res;
00737 }
00738
00739 static inline int __ast_cond_init(const char *filename, int lineno, const char *func,
00740 const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
00741 {
00742 return pthread_cond_init(cond, cond_attr);
00743 }
00744
00745 static inline int __ast_cond_signal(const char *filename, int lineno, const char *func,
00746 const char *cond_name, ast_cond_t *cond)
00747 {
00748 return pthread_cond_signal(cond);
00749 }
00750
00751 static inline int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
00752 const char *cond_name, ast_cond_t *cond)
00753 {
00754 return pthread_cond_broadcast(cond);
00755 }
00756
00757 static inline int __ast_cond_destroy(const char *filename, int lineno, const char *func,
00758 const char *cond_name, ast_cond_t *cond)
00759 {
00760 return pthread_cond_destroy(cond);
00761 }
00762
00763 static inline int __ast_cond_wait(const char *filename, int lineno, const char *func,
00764 const char *cond_name, const char *mutex_name,
00765 ast_cond_t *cond, ast_mutex_t *t)
00766 {
00767 int res;
00768 struct ast_lock_track *lt= &t->track;
00769 int canlog = strcmp(filename, "logger.c") & t->tracking;
00770 #ifdef HAVE_BKTR
00771 struct ast_bt *bt = NULL;
00772 #endif
00773
00774 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00775 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00776 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00777 filename, lineno, func, mutex_name);
00778 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
00779 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00780 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
00781 filename, lineno, func, mutex_name);
00782 }
00783 return res;
00784 }
00785 #endif
00786
00787 ast_reentrancy_lock(lt);
00788 if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
00789 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
00790 filename, lineno, func, mutex_name);
00791 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
00792 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
00793 #ifdef HAVE_BKTR
00794 __dump_backtrace(<->backtrace[ROFFSET], canlog);
00795 #endif
00796 DO_THREAD_CRASH;
00797 }
00798
00799 if (--lt->reentrancy < 0) {
00800 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
00801 filename, lineno, func, mutex_name);
00802 lt->reentrancy = 0;
00803 }
00804
00805 if (lt->reentrancy < AST_MAX_REENTRANCY) {
00806 lt->file[lt->reentrancy] = NULL;
00807 lt->lineno[lt->reentrancy] = 0;
00808 lt->func[lt->reentrancy] = NULL;
00809 lt->thread[lt->reentrancy] = 0;
00810 }
00811
00812 #ifdef HAVE_BKTR
00813 if (lt->reentrancy) {
00814 bt = <->backtrace[lt->reentrancy - 1];
00815 }
00816 #endif
00817 ast_reentrancy_unlock(lt);
00818
00819 if (t->tracking) {
00820 #ifdef HAVE_BKTR
00821 ast_remove_lock_info(t, bt);
00822 #else
00823 ast_remove_lock_info(t);
00824 #endif
00825 }
00826
00827 if ((res = pthread_cond_wait(cond, &t->mutex))) {
00828 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
00829 filename, lineno, func, strerror(res));
00830 DO_THREAD_CRASH;
00831 } else {
00832 ast_reentrancy_lock(lt);
00833 if (lt->reentrancy < AST_MAX_REENTRANCY) {
00834 lt->file[lt->reentrancy] = filename;
00835 lt->lineno[lt->reentrancy] = lineno;
00836 lt->func[lt->reentrancy] = func;
00837 lt->thread[lt->reentrancy] = pthread_self();
00838 #ifdef HAVE_BKTR
00839 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
00840 bt = <->backtrace[lt->reentrancy];
00841 #endif
00842 lt->reentrancy++;
00843 } else {
00844 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
00845 filename, lineno, func, mutex_name);
00846 }
00847 ast_reentrancy_unlock(lt);
00848
00849 if (t->tracking) {
00850 #ifdef HAVE_BKTR
00851 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
00852 #else
00853 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
00854 #endif
00855 }
00856 }
00857
00858 return res;
00859 }
00860
00861 static inline int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
00862 const char *cond_name, const char *mutex_name, ast_cond_t *cond,
00863 ast_mutex_t *t, const struct timespec *abstime)
00864 {
00865 int res;
00866 struct ast_lock_track *lt = &t->track;
00867 int canlog = strcmp(filename, "logger.c") & t->tracking;
00868 #ifdef HAVE_BKTR
00869 struct ast_bt *bt = NULL;
00870 #endif
00871
00872 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00873 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00874 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00875 filename, lineno, func, mutex_name);
00876 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
00877 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00878 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
00879 filename, lineno, func, mutex_name);
00880 }
00881 return res;
00882 }
00883 #endif
00884
00885 ast_reentrancy_lock(lt);
00886 if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
00887 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
00888 filename, lineno, func, mutex_name);
00889 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
00890 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
00891 #ifdef HAVE_BKTR
00892 __dump_backtrace(<->backtrace[ROFFSET], canlog);
00893 #endif
00894 DO_THREAD_CRASH;
00895 }
00896
00897 if (--lt->reentrancy < 0) {
00898 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
00899 filename, lineno, func, mutex_name);
00900 lt->reentrancy = 0;
00901 }
00902
00903 if (lt->reentrancy < AST_MAX_REENTRANCY) {
00904 lt->file[lt->reentrancy] = NULL;
00905 lt->lineno[lt->reentrancy] = 0;
00906 lt->func[lt->reentrancy] = NULL;
00907 lt->thread[lt->reentrancy] = 0;
00908 }
00909 #ifdef HAVE_BKTR
00910 if (lt->reentrancy) {
00911 bt = <->backtrace[lt->reentrancy - 1];
00912 }
00913 #endif
00914 ast_reentrancy_unlock(lt);
00915
00916 if (t->tracking) {
00917 #ifdef HAVE_BKTR
00918 ast_remove_lock_info(t, bt);
00919 #else
00920 ast_remove_lock_info(t);
00921 #endif
00922 }
00923
00924 if ((res = pthread_cond_timedwait(cond, &t->mutex, abstime)) && (res != ETIMEDOUT)) {
00925 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
00926 filename, lineno, func, strerror(res));
00927 DO_THREAD_CRASH;
00928 } else {
00929 ast_reentrancy_lock(lt);
00930 if (lt->reentrancy < AST_MAX_REENTRANCY) {
00931 lt->file[lt->reentrancy] = filename;
00932 lt->lineno[lt->reentrancy] = lineno;
00933 lt->func[lt->reentrancy] = func;
00934 lt->thread[lt->reentrancy] = pthread_self();
00935 #ifdef HAVE_BKTR
00936 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
00937 bt = <->backtrace[lt->reentrancy];
00938 #endif
00939 lt->reentrancy++;
00940 } else {
00941 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
00942 filename, lineno, func, mutex_name);
00943 }
00944 ast_reentrancy_unlock(lt);
00945
00946 if (t->tracking) {
00947 #ifdef HAVE_BKTR
00948 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
00949 #else
00950 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
00951 #endif
00952 }
00953 }
00954
00955 return res;
00956 }
00957
00958 #define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00959 #define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00960 #define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00961 #define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00962 #define ast_cond_init(cond, attr) __ast_cond_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond, attr)
00963 #define ast_cond_destroy(cond) __ast_cond_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
00964 #define ast_cond_signal(cond) __ast_cond_signal(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
00965 #define ast_cond_broadcast(cond) __ast_cond_broadcast(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
00966 #define ast_cond_wait(cond, mutex) __ast_cond_wait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex)
00967 #define ast_cond_timedwait(cond, mutex, time) __ast_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex, time)
00968
00969 struct ast_rwlock_info {
00970
00971 struct ast_lock_track track;
00972 unsigned int tracking:1;
00973 pthread_rwlock_t lock;
00974 };
00975
00976 typedef struct ast_rwlock_info ast_rwlock_t;
00977
00978
00979
00980
00981
00982
00983 #define ast_rwlock_init(rwlock) __ast_rwlock_init(1, __FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)
00984
00985
00986
00987
00988
00989
00990 #define ast_rwlock_init_notracking(rwlock) __ast_rwlock_init(0, __FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)
00991
00992 #define ast_rwlock_destroy(rwlock) __ast_rwlock_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)
00993 #define ast_rwlock_unlock(a) _ast_rwlock_unlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
00994 #define ast_rwlock_rdlock(a) _ast_rwlock_rdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
00995 #define ast_rwlock_wrlock(a) _ast_rwlock_wrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
00996 #define ast_rwlock_tryrdlock(a) _ast_rwlock_tryrdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
00997 #define ast_rwlock_trywrlock(a) _ast_rwlock_trywrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
00998
00999
01000 #ifdef HAVE_PTHREAD_RWLOCK_INITIALIZER
01001 #define __AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
01002 #else
01003 #define __AST_RWLOCK_INIT_VALUE {0}
01004 #endif
01005
01006 #define AST_RWLOCK_INIT_VALUE \
01007 { AST_LOCK_TRACK_INIT_VALUE, 1, __AST_RWLOCK_INIT_VALUE }
01008 #define AST_RWLOCK_INIT_VALUE_NOTRACKING \
01009 { AST_LOCK_TRACK_INIT_VALUE, 0, __AST_RWLOCK_INIT_VALUE }
01010
01011 static inline int __ast_rwlock_init(int tracking, const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
01012 {
01013 int res;
01014 struct ast_lock_track *lt= &t->track;
01015 pthread_rwlockattr_t attr;
01016
01017 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
01018 int canlog = strcmp(filename, "logger.c") & t->tracking;
01019
01020 if (t->lock != ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01021 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
01022 filename, lineno, func, rwlock_name);
01023 return 0;
01024 }
01025 #endif
01026
01027 ast_reentrancy_init(lt);
01028 t->tracking = tracking;
01029 pthread_rwlockattr_init(&attr);
01030
01031 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
01032 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
01033 #endif
01034
01035 res = pthread_rwlock_init(&t->lock, &attr);
01036 pthread_rwlockattr_destroy(&attr);
01037 return res;
01038 }
01039
01040 static inline int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
01041 {
01042 int res;
01043 struct ast_lock_track *lt = &t->track;
01044 int canlog = strcmp(filename, "logger.c") & t->tracking;
01045
01046 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
01047 if (t->lock == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01048 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
01049 filename, lineno, func, rwlock_name);
01050 return 0;
01051 }
01052 #endif
01053
01054 if ((res = pthread_rwlock_destroy(&t->lock))) {
01055 __ast_mutex_logger("%s line %d (%s): Error destroying rwlock %s: %s\n",
01056 filename, lineno, func, rwlock_name, strerror(res));
01057 }
01058 ast_reentrancy_lock(lt);
01059 lt->file[0] = filename;
01060 lt->lineno[0] = lineno;
01061 lt->func[0] = func;
01062 lt->reentrancy = 0;
01063 lt->thread[0] = 0;
01064 #ifdef HAVE_BKTR
01065 memset(<->backtrace[0], 0, sizeof(lt->backtrace[0]));
01066 #endif
01067 ast_reentrancy_unlock(lt);
01068 delete_reentrancy_cs(lt);
01069
01070 return res;
01071 }
01072
01073 static inline int _ast_rwlock_unlock(ast_rwlock_t *t, const char *name,
01074 const char *filename, int line, const char *func)
01075 {
01076 int res;
01077 struct ast_lock_track *lt = &t->track;
01078 int canlog = strcmp(filename, "logger.c") & t->tracking;
01079 #ifdef HAVE_BKTR
01080 struct ast_bt *bt = NULL;
01081 #endif
01082 int lock_found = 0;
01083
01084
01085 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
01086 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01087 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
01088 filename, line, func, name);
01089 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
01090 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01091 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
01092 filename, line, func, name);
01093 }
01094 return res;
01095 }
01096 #endif
01097
01098 ast_reentrancy_lock(lt);
01099 if (lt->reentrancy) {
01100 int i;
01101 pthread_t self = pthread_self();
01102 for (i = lt->reentrancy - 1; i >= 0; --i) {
01103 if (lt->thread[i] == self) {
01104 lock_found = 1;
01105 if (i != lt->reentrancy - 1) {
01106 lt->file[i] = lt->file[lt->reentrancy - 1];
01107 lt->lineno[i] = lt->lineno[lt->reentrancy - 1];
01108 lt->func[i] = lt->func[lt->reentrancy - 1];
01109 lt->thread[i] = lt->thread[lt->reentrancy - 1];
01110 }
01111 #ifdef HAVE_BKTR
01112 bt = <->backtrace[i];
01113 #endif
01114 lt->file[lt->reentrancy - 1] = NULL;
01115 lt->lineno[lt->reentrancy - 1] = 0;
01116 lt->func[lt->reentrancy - 1] = NULL;
01117 lt->thread[lt->reentrancy - 1] = AST_PTHREADT_NULL;
01118 break;
01119 }
01120 }
01121 }
01122
01123 if (lock_found && --lt->reentrancy < 0) {
01124 __ast_mutex_logger("%s line %d (%s): rwlock '%s' freed more times than we've locked!\n",
01125 filename, line, func, name);
01126 lt->reentrancy = 0;
01127 }
01128
01129 ast_reentrancy_unlock(lt);
01130
01131 if (t->tracking) {
01132 #ifdef HAVE_BKTR
01133 ast_remove_lock_info(t, bt);
01134 #else
01135 ast_remove_lock_info(t);
01136 #endif
01137 }
01138
01139 if ((res = pthread_rwlock_unlock(&t->lock))) {
01140 __ast_mutex_logger("%s line %d (%s): Error releasing rwlock: %s\n",
01141 filename, line, func, strerror(res));
01142 DO_THREAD_CRASH;
01143 }
01144
01145 return res;
01146 }
01147
01148 static inline int _ast_rwlock_rdlock(ast_rwlock_t *t, const char *name,
01149 const char *filename, int line, const char *func)
01150 {
01151 int res;
01152 struct ast_lock_track *lt = &t->track;
01153 int canlog = strcmp(filename, "logger.c") & t->tracking;
01154 #ifdef HAVE_BKTR
01155 struct ast_bt *bt = NULL;
01156 #endif
01157
01158 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
01159 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01160
01161
01162
01163
01164 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
01165 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01166 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
01167 filename, line, func, name);
01168 return res;
01169 }
01170 }
01171 #endif
01172
01173 if (t->tracking) {
01174 #ifdef HAVE_BKTR
01175 ast_reentrancy_lock(lt);
01176 if (lt->reentrancy != AST_MAX_REENTRANCY) {
01177 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
01178 bt = <->backtrace[lt->reentrancy];
01179 }
01180 ast_reentrancy_unlock(lt);
01181 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
01182 #else
01183 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t);
01184 #endif
01185 }
01186
01187 #ifdef DETECT_DEADLOCKS
01188 {
01189 time_t seconds = time(NULL);
01190 time_t wait_time, reported_wait = 0;
01191 do {
01192 res = pthread_rwlock_tryrdlock(&t->lock);
01193 if (res == EBUSY) {
01194 wait_time = time(NULL) - seconds;
01195 if (wait_time > reported_wait && (wait_time % 5) == 0) {
01196 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for readlock '%s'?\n",
01197 filename, line, func, (int)wait_time, name);
01198 ast_reentrancy_lock(lt);
01199 #ifdef HAVE_BKTR
01200 __dump_backtrace(<->backtrace[lt->reentrancy], canlog);
01201 #endif
01202 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
01203 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
01204 lt->func[lt->reentrancy-1], name);
01205 #ifdef HAVE_BKTR
01206 __dump_backtrace(<->backtrace[lt->reentrancy-1], canlog);
01207 #endif
01208 ast_reentrancy_unlock(lt);
01209 reported_wait = wait_time;
01210 }
01211 usleep(200);
01212 }
01213 } while (res == EBUSY);
01214 }
01215 #else
01216 res = pthread_rwlock_rdlock(&t->lock);
01217 #endif
01218
01219 if (!res) {
01220 ast_reentrancy_lock(lt);
01221 if (lt->reentrancy < AST_MAX_REENTRANCY) {
01222 lt->file[lt->reentrancy] = filename;
01223 lt->lineno[lt->reentrancy] = line;
01224 lt->func[lt->reentrancy] = func;
01225 lt->thread[lt->reentrancy] = pthread_self();
01226 lt->reentrancy++;
01227 }
01228 ast_reentrancy_unlock(lt);
01229 if (t->tracking) {
01230 ast_mark_lock_acquired(t);
01231 }
01232 } else {
01233 #ifdef HAVE_BKTR
01234 if (lt->reentrancy) {
01235 ast_reentrancy_lock(lt);
01236 bt = <->backtrace[lt->reentrancy-1];
01237 ast_reentrancy_unlock(lt);
01238 } else {
01239 bt = NULL;
01240 }
01241 if (t->tracking) {
01242 ast_remove_lock_info(t, bt);
01243 }
01244 #else
01245 if (t->tracking) {
01246 ast_remove_lock_info(t);
01247 }
01248 #endif
01249 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
01250 filename, line, func, strerror(res));
01251 DO_THREAD_CRASH;
01252 }
01253 return res;
01254 }
01255
01256 static inline int _ast_rwlock_wrlock(ast_rwlock_t *t, const char *name,
01257 const char *filename, int line, const char *func)
01258 {
01259 int res;
01260 struct ast_lock_track *lt = &t->track;
01261 int canlog = strcmp(filename, "logger.c") & t->tracking;
01262 #ifdef HAVE_BKTR
01263 struct ast_bt *bt = NULL;
01264 #endif
01265
01266 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
01267 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01268
01269
01270
01271
01272 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
01273 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01274 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
01275 filename, line, func, name);
01276 return res;
01277 }
01278 }
01279 #endif
01280
01281 if (t->tracking) {
01282 #ifdef HAVE_BKTR
01283 ast_reentrancy_lock(lt);
01284 if (lt->reentrancy != AST_MAX_REENTRANCY) {
01285 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
01286 bt = <->backtrace[lt->reentrancy];
01287 }
01288 ast_reentrancy_unlock(lt);
01289 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
01290 #else
01291 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
01292 #endif
01293 }
01294 #ifdef DETECT_DEADLOCKS
01295 {
01296 time_t seconds = time(NULL);
01297 time_t wait_time, reported_wait = 0;
01298 do {
01299 res = pthread_rwlock_trywrlock(&t->lock);
01300 if (res == EBUSY) {
01301 wait_time = time(NULL) - seconds;
01302 if (wait_time > reported_wait && (wait_time % 5) == 0) {
01303 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for writelock '%s'?\n",
01304 filename, line, func, (int)wait_time, name);
01305 ast_reentrancy_lock(lt);
01306 #ifdef HAVE_BKTR
01307 __dump_backtrace(<->backtrace[lt->reentrancy], canlog);
01308 #endif
01309 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
01310 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
01311 lt->func[lt->reentrancy-1], name);
01312 #ifdef HAVE_BKTR
01313 __dump_backtrace(<->backtrace[lt->reentrancy-1], canlog);
01314 #endif
01315 ast_reentrancy_unlock(lt);
01316 reported_wait = wait_time;
01317 }
01318 usleep(200);
01319 }
01320 } while (res == EBUSY);
01321 }
01322 #else
01323 res = pthread_rwlock_wrlock(&t->lock);
01324 #endif
01325
01326 if (!res) {
01327 ast_reentrancy_lock(lt);
01328 if (lt->reentrancy < AST_MAX_REENTRANCY) {
01329 lt->file[lt->reentrancy] = filename;
01330 lt->lineno[lt->reentrancy] = line;
01331 lt->func[lt->reentrancy] = func;
01332 lt->thread[lt->reentrancy] = pthread_self();
01333 lt->reentrancy++;
01334 }
01335 ast_reentrancy_unlock(lt);
01336 if (t->tracking) {
01337 ast_mark_lock_acquired(t);
01338 }
01339 } else {
01340 #ifdef HAVE_BKTR
01341 if (lt->reentrancy) {
01342 ast_reentrancy_lock(lt);
01343 bt = <->backtrace[lt->reentrancy-1];
01344 ast_reentrancy_unlock(lt);
01345 } else {
01346 bt = NULL;
01347 }
01348 if (t->tracking) {
01349 ast_remove_lock_info(t, bt);
01350 }
01351 #else
01352 if (t->tracking) {
01353 ast_remove_lock_info(t);
01354 }
01355 #endif
01356 __ast_mutex_logger("%s line %d (%s): Error obtaining write lock: %s\n",
01357 filename, line, func, strerror(res));
01358 DO_THREAD_CRASH;
01359 }
01360 return res;
01361 }
01362
01363 #define ast_rwlock_timedrdlock(a, b) \
01364 _ast_rwlock_timedrdlock(a, # a, b, __FILE__, __LINE__, __PRETTY_FUNCTION__)
01365
01366 static inline int _ast_rwlock_timedrdlock(ast_rwlock_t *t, const char *name,
01367 const struct timespec *abs_timeout, const char *filename, int line, const char *func)
01368 {
01369 int res;
01370 struct ast_lock_track *lt = &t->track;
01371 int canlog = strcmp(filename, "logger.c") & t->tracking;
01372 #ifdef HAVE_BKTR
01373 struct ast_bt *bt = NULL;
01374 #endif
01375
01376 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
01377 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01378
01379
01380
01381
01382 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
01383 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01384 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
01385 filename, line, func, name);
01386 return res;
01387 }
01388 }
01389 #endif
01390
01391 if (t->tracking) {
01392 #ifdef HAVE_BKTR
01393 ast_reentrancy_lock(lt);
01394 if (lt->reentrancy != AST_MAX_REENTRANCY) {
01395 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
01396 bt = <->backtrace[lt->reentrancy];
01397 }
01398 ast_reentrancy_unlock(lt);
01399 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
01400 #else
01401 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
01402 #endif
01403 }
01404 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
01405 res = pthread_rwlock_timedrdlock(&t->lock, abs_timeout);
01406 #else
01407 do {
01408 struct timeval _start = ast_tvnow(), _diff;
01409 for (;;) {
01410 if (!(res = pthread_rwlock_tryrdlock(&t->lock))) {
01411 break;
01412 }
01413 _diff = ast_tvsub(ast_tvnow(), _start);
01414 if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
01415 break;
01416 }
01417 usleep(1);
01418 }
01419 } while (0);
01420 #endif
01421 if (!res) {
01422 ast_reentrancy_lock(lt);
01423 if (lt->reentrancy < AST_MAX_REENTRANCY) {
01424 lt->file[lt->reentrancy] = filename;
01425 lt->lineno[lt->reentrancy] = line;
01426 lt->func[lt->reentrancy] = func;
01427 lt->thread[lt->reentrancy] = pthread_self();
01428 lt->reentrancy++;
01429 }
01430 ast_reentrancy_unlock(lt);
01431 if (t->tracking) {
01432 ast_mark_lock_acquired(t);
01433 }
01434 } else {
01435 #ifdef HAVE_BKTR
01436 if (lt->reentrancy) {
01437 ast_reentrancy_lock(lt);
01438 bt = <->backtrace[lt->reentrancy-1];
01439 ast_reentrancy_unlock(lt);
01440 } else {
01441 bt = NULL;
01442 }
01443 if (t->tracking) {
01444 ast_remove_lock_info(t, bt);
01445 }
01446 #else
01447 if (t->tracking) {
01448 ast_remove_lock_info(t);
01449 }
01450 #endif
01451 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
01452 filename, line, func, strerror(res));
01453 DO_THREAD_CRASH;
01454 }
01455 return res;
01456 }
01457
01458 #define ast_rwlock_timedwrlock(a, b) \
01459 _ast_rwlock_timedwrlock(a, # a, b, __FILE__, __LINE__, __PRETTY_FUNCTION__)
01460
01461 static inline int _ast_rwlock_timedwrlock(ast_rwlock_t *t, const char *name,
01462 const struct timespec *abs_timeout, const char *filename, int line, const char *func)
01463 {
01464 int res;
01465 struct ast_lock_track *lt = &t->track;
01466 int canlog = strcmp(filename, "logger.c") & t->tracking;
01467 #ifdef HAVE_BKTR
01468 struct ast_bt *bt = NULL;
01469 #endif
01470
01471 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
01472 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01473
01474
01475
01476
01477 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
01478 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01479 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
01480 filename, line, func, name);
01481 return res;
01482 }
01483 }
01484 #endif
01485
01486 if (t->tracking) {
01487 #ifdef HAVE_BKTR
01488 ast_reentrancy_lock(lt);
01489 if (lt->reentrancy != AST_MAX_REENTRANCY) {
01490 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
01491 bt = <->backtrace[lt->reentrancy];
01492 }
01493 ast_reentrancy_unlock(lt);
01494 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
01495 #else
01496 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
01497 #endif
01498 }
01499 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
01500 res = pthread_rwlock_timedwrlock(&t->lock, abs_timeout);
01501 #else
01502 do {
01503 struct timeval _start = ast_tvnow(), _diff;
01504 for (;;) {
01505 if (!(res = pthread_rwlock_trywrlock(&t->lock))) {
01506 break;
01507 }
01508 _diff = ast_tvsub(ast_tvnow(), _start);
01509 if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
01510 break;
01511 }
01512 usleep(1);
01513 }
01514 } while (0);
01515 #endif
01516 if (!res) {
01517 ast_reentrancy_lock(lt);
01518 if (lt->reentrancy < AST_MAX_REENTRANCY) {
01519 lt->file[lt->reentrancy] = filename;
01520 lt->lineno[lt->reentrancy] = line;
01521 lt->func[lt->reentrancy] = func;
01522 lt->thread[lt->reentrancy] = pthread_self();
01523 lt->reentrancy++;
01524 }
01525 ast_reentrancy_unlock(lt);
01526 if (t->tracking) {
01527 ast_mark_lock_acquired(t);
01528 }
01529 } else {
01530 #ifdef HAVE_BKTR
01531 if (lt->reentrancy) {
01532 ast_reentrancy_lock(lt);
01533 bt = <->backtrace[lt->reentrancy-1];
01534 ast_reentrancy_unlock(lt);
01535 } else {
01536 bt = NULL;
01537 }
01538 if (t->tracking) {
01539 ast_remove_lock_info(t, bt);
01540 }
01541 #else
01542 if (t->tracking) {
01543 ast_remove_lock_info(t);
01544 }
01545 #endif
01546 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
01547 filename, line, func, strerror(res));
01548 DO_THREAD_CRASH;
01549 }
01550 return res;
01551 }
01552
01553 static inline int _ast_rwlock_tryrdlock(ast_rwlock_t *t, const char *name,
01554 const char *filename, int line, const char *func)
01555 {
01556 int res;
01557 struct ast_lock_track *lt = &t->track;
01558 #ifdef HAVE_BKTR
01559 struct ast_bt *bt = NULL;
01560 #endif
01561 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
01562 int canlog = strcmp(filename, "logger.c") & t->tracking;
01563
01564 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01565
01566
01567
01568
01569 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
01570 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01571 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
01572 filename, line, func, name);
01573 return res;
01574 }
01575 }
01576 #endif
01577
01578 if (t->tracking) {
01579 #ifdef HAVE_BKTR
01580 ast_reentrancy_lock(lt);
01581 if (lt->reentrancy != AST_MAX_REENTRANCY) {
01582 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
01583 bt = <->backtrace[lt->reentrancy];
01584 }
01585 ast_reentrancy_unlock(lt);
01586 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
01587 #else
01588 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t);
01589 #endif
01590 }
01591
01592 if (!(res = pthread_rwlock_tryrdlock(&t->lock))) {
01593 ast_reentrancy_lock(lt);
01594 if (lt->reentrancy < AST_MAX_REENTRANCY) {
01595 lt->file[lt->reentrancy] = filename;
01596 lt->lineno[lt->reentrancy] = line;
01597 lt->func[lt->reentrancy] = func;
01598 lt->thread[lt->reentrancy] = pthread_self();
01599 lt->reentrancy++;
01600 }
01601 ast_reentrancy_unlock(lt);
01602 if (t->tracking) {
01603 ast_mark_lock_acquired(t);
01604 }
01605 } else if (t->tracking) {
01606 ast_mark_lock_failed(t);
01607 }
01608 return res;
01609 }
01610
01611 static inline int _ast_rwlock_trywrlock(ast_rwlock_t *t, const char *name,
01612 const char *filename, int line, const char *func)
01613 {
01614 int res;
01615 struct ast_lock_track *lt= &t->track;
01616 #ifdef HAVE_BKTR
01617 struct ast_bt *bt = NULL;
01618 #endif
01619 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
01620 int canlog = strcmp(filename, "logger.c") & t->tracking;
01621
01622 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01623
01624
01625
01626
01627 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
01628 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
01629 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
01630 filename, line, func, name);
01631 return res;
01632 }
01633 }
01634 #endif
01635
01636 if (t->tracking) {
01637 #ifdef HAVE_BKTR
01638 ast_reentrancy_lock(lt);
01639 if (lt->reentrancy != AST_MAX_REENTRANCY) {
01640 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
01641 bt = <->backtrace[lt->reentrancy];
01642 }
01643 ast_reentrancy_unlock(lt);
01644 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
01645 #else
01646 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
01647 #endif
01648 }
01649
01650 if (!(res = pthread_rwlock_trywrlock(&t->lock))) {
01651 ast_reentrancy_lock(lt);
01652 if (lt->reentrancy < AST_MAX_REENTRANCY) {
01653 lt->file[lt->reentrancy] = filename;
01654 lt->lineno[lt->reentrancy] = line;
01655 lt->func[lt->reentrancy] = func;
01656 lt->thread[lt->reentrancy] = pthread_self();
01657 lt->reentrancy++;
01658 }
01659 ast_reentrancy_unlock(lt);
01660 if (t->tracking) {
01661 ast_mark_lock_acquired(t);
01662 }
01663 } else if (t->tracking) {
01664 ast_mark_lock_failed(t);
01665 }
01666 return res;
01667 }
01668
01669 #else
01670
01671 #define CHANNEL_DEADLOCK_AVOIDANCE(chan) \
01672 ast_channel_unlock(chan); \
01673 usleep(1); \
01674 ast_channel_lock(chan);
01675
01676 #define DEADLOCK_AVOIDANCE(lock) \
01677 ast_mutex_unlock(lock); \
01678 usleep(1); \
01679 ast_mutex_lock(lock);
01680
01681 #define DLA_UNLOCK(lock) ast_mutex_unlock(lock)
01682
01683 #define DLA_LOCK(lock) ast_mutex_lock(lock)
01684
01685 typedef pthread_mutex_t ast_mutex_t;
01686
01687 #define AST_MUTEX_INIT_VALUE ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
01688 #define AST_MUTEX_INIT_VALUE_NOTRACKING ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
01689
01690 #define ast_mutex_init_notracking(m) ast_mutex_init(m)
01691
01692 static inline int ast_mutex_init(ast_mutex_t *pmutex)
01693 {
01694 int res;
01695 pthread_mutexattr_t attr;
01696
01697 pthread_mutexattr_init(&attr);
01698 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
01699
01700 res = pthread_mutex_init(pmutex, &attr);
01701 pthread_mutexattr_destroy(&attr);
01702 return res;
01703 }
01704
01705 #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
01706
01707 static inline int ast_mutex_unlock(ast_mutex_t *pmutex)
01708 {
01709 return pthread_mutex_unlock(pmutex);
01710 }
01711
01712 static inline int ast_mutex_destroy(ast_mutex_t *pmutex)
01713 {
01714 return pthread_mutex_destroy(pmutex);
01715 }
01716
01717 static inline int ast_mutex_lock(ast_mutex_t *pmutex)
01718 {
01719 __MTX_PROF(pmutex);
01720 }
01721
01722 static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
01723 {
01724 return pthread_mutex_trylock(pmutex);
01725 }
01726
01727 typedef pthread_cond_t ast_cond_t;
01728
01729 static inline int ast_cond_init(ast_cond_t *cond, pthread_condattr_t *cond_attr)
01730 {
01731 return pthread_cond_init(cond, cond_attr);
01732 }
01733
01734 static inline int ast_cond_signal(ast_cond_t *cond)
01735 {
01736 return pthread_cond_signal(cond);
01737 }
01738
01739 static inline int ast_cond_broadcast(ast_cond_t *cond)
01740 {
01741 return pthread_cond_broadcast(cond);
01742 }
01743
01744 static inline int ast_cond_destroy(ast_cond_t *cond)
01745 {
01746 return pthread_cond_destroy(cond);
01747 }
01748
01749 static inline int ast_cond_wait(ast_cond_t *cond, ast_mutex_t *t)
01750 {
01751 return pthread_cond_wait(cond, t);
01752 }
01753
01754 static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime)
01755 {
01756 return pthread_cond_timedwait(cond, t, abstime);
01757 }
01758
01759
01760 typedef pthread_rwlock_t ast_rwlock_t;
01761
01762 #ifdef HAVE_PTHREAD_RWLOCK_INITIALIZER
01763 #define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
01764 #else
01765 #define AST_RWLOCK_INIT_VALUE { 0 }
01766 #endif
01767
01768 #define ast_rwlock_init_notracking(a) ast_rwlock_init(a)
01769
01770 static inline int ast_rwlock_init(ast_rwlock_t *prwlock)
01771 {
01772 int res;
01773 pthread_rwlockattr_t attr;
01774
01775 pthread_rwlockattr_init(&attr);
01776
01777 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
01778 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
01779 #endif
01780
01781 res = pthread_rwlock_init(prwlock, &attr);
01782 pthread_rwlockattr_destroy(&attr);
01783 return res;
01784 }
01785
01786 static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
01787 {
01788 return pthread_rwlock_destroy(prwlock);
01789 }
01790
01791 static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
01792 {
01793 return pthread_rwlock_unlock(prwlock);
01794 }
01795
01796 static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
01797 {
01798 return pthread_rwlock_rdlock(prwlock);
01799 }
01800
01801 static inline int ast_rwlock_timedrdlock(ast_rwlock_t *prwlock, const struct timespec *abs_timeout)
01802 {
01803 int res;
01804 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
01805 res = pthread_rwlock_timedrdlock(prwlock, abs_timeout);
01806 #else
01807 struct timeval _start = ast_tvnow(), _diff;
01808 for (;;) {
01809 if (!(res = pthread_rwlock_tryrdlock(prwlock))) {
01810 break;
01811 }
01812 _diff = ast_tvsub(ast_tvnow(), _start);
01813 if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
01814 break;
01815 }
01816 usleep(1);
01817 }
01818 #endif
01819 return res;
01820 }
01821
01822 static inline int ast_rwlock_tryrdlock(ast_rwlock_t *prwlock)
01823 {
01824 return pthread_rwlock_tryrdlock(prwlock);
01825 }
01826
01827 static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
01828 {
01829 return pthread_rwlock_wrlock(prwlock);
01830 }
01831
01832 static inline int ast_rwlock_timedwrlock(ast_rwlock_t *prwlock, const struct timespec *abs_timeout)
01833 {
01834 int res;
01835 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
01836 res = pthread_rwlock_timedwrlock(prwlock, abs_timeout);
01837 #else
01838 do {
01839 struct timeval _start = ast_tvnow(), _diff;
01840 for (;;) {
01841 if (!(res = pthread_rwlock_trywrlock(prwlock))) {
01842 break;
01843 }
01844 _diff = ast_tvsub(ast_tvnow(), _start);
01845 if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
01846 break;
01847 }
01848 usleep(1);
01849 }
01850 } while (0);
01851 #endif
01852 return res;
01853 }
01854
01855 static inline int ast_rwlock_trywrlock(ast_rwlock_t *prwlock)
01856 {
01857 return pthread_rwlock_trywrlock(prwlock);
01858 }
01859
01860 #endif
01861
01862 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
01863
01864
01865
01866
01867 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track) \
01868 scope ast_mutex_t mutex = init_val; \
01869 static void __attribute__((constructor)) init_##mutex(void) \
01870 { \
01871 if (track) \
01872 ast_mutex_init(&mutex); \
01873 else \
01874 ast_mutex_init_notracking(&mutex); \
01875 } \
01876 \
01877 static void __attribute__((destructor)) fini_##mutex(void) \
01878 { \
01879 ast_mutex_destroy(&mutex); \
01880 }
01881 #else
01882
01883 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track) scope ast_mutex_t mutex = init_val
01884 #endif
01885
01886 #ifndef __CYGWIN__
01887 #define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
01888 #define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t
01889 #endif
01890 #define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
01891 #define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
01892 #define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
01893 #define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init
01894 #define pthread_mutex_destroy use_ast_mutex_destroy_instead_of_pthread_mutex_destroy
01895 #define pthread_cond_init use_ast_cond_init_instead_of_pthread_cond_init
01896 #define pthread_cond_destroy use_ast_cond_destroy_instead_of_pthread_cond_destroy
01897 #define pthread_cond_signal use_ast_cond_signal_instead_of_pthread_cond_signal
01898 #define pthread_cond_broadcast use_ast_cond_broadcast_instead_of_pthread_cond_broadcast
01899 #define pthread_cond_wait use_ast_cond_wait_instead_of_pthread_cond_wait
01900 #define pthread_cond_timedwait use_ast_cond_timedwait_instead_of_pthread_cond_timedwait
01901
01902 #define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE, 1)
01903 #define AST_MUTEX_DEFINE_STATIC_NOTRACKING(mutex) __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE_NOTRACKING, 0)
01904
01905 #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
01906
01907 #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
01908
01909 #ifndef __linux__
01910 #define pthread_create __use_ast_pthread_create_instead__
01911 #endif
01912
01913
01914
01915 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
01916 #define __AST_RWLOCK_DEFINE(scope, rwlock, init_val, track) \
01917 scope ast_rwlock_t rwlock = init_val; \
01918 static void __attribute__((constructor)) init_##rwlock(void) \
01919 { \
01920 if (track) \
01921 ast_rwlock_init(&rwlock); \
01922 else \
01923 ast_rwlock_init_notracking(&rwlock); \
01924 } \
01925 static void __attribute__((destructor)) fini_##rwlock(void) \
01926 { \
01927 ast_rwlock_destroy(&rwlock); \
01928 }
01929 #else
01930 #define __AST_RWLOCK_DEFINE(scope, rwlock, init_val, track) \
01931 scope ast_rwlock_t rwlock = init_val
01932 #endif
01933
01934 #define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock, AST_RWLOCK_INIT_VALUE, 1)
01935 #define AST_RWLOCK_DEFINE_STATIC_NOTRACKING(rwlock) __AST_RWLOCK_DEFINE(static, rwlock, AST_RWLOCK_INIT_VALUE_NOTRACKING, 0)
01936
01937
01938
01939
01940
01941
01942
01943
01944
01945
01946
01947 int ast_atomic_fetchadd_int_slow(volatile int *p, int v);
01948
01949 #include "asterisk/inline_api.h"
01950
01951 #if defined(HAVE_OSX_ATOMICS)
01952 #include "libkern/OSAtomic.h"
01953 #endif
01954
01955
01956
01957
01958
01959
01960 #if defined(HAVE_GCC_ATOMICS)
01961 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
01962 {
01963 return __sync_fetch_and_add(p, v);
01964 })
01965 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
01966 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
01967 {
01968 return OSAtomicAdd32(v, (int32_t *) p) - v;
01969 })
01970 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
01971 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
01972 {
01973 return OSAtomicAdd64(v, (int64_t *) p) - v;
01974 #elif defined (__i386__) || defined(__x86_64__)
01975 #ifdef sun
01976 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
01977 {
01978 __asm __volatile (
01979 " lock; xaddl %0, %1 ; "
01980 : "+r" (v),
01981 "=m" (*p)
01982 : "m" (*p));
01983 return (v);
01984 })
01985 #else
01986 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
01987 {
01988 __asm __volatile (
01989 " lock xaddl %0, %1 ; "
01990 : "+r" (v),
01991 "=m" (*p)
01992 : "m" (*p));
01993 return (v);
01994 })
01995 #endif
01996 #else
01997 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
01998 {
01999 return ast_atomic_fetchadd_int_slow(p, v);
02000 })
02001 #endif
02002
02003
02004
02005
02006 #if defined(HAVE_GCC_ATOMICS)
02007 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
02008 {
02009 return __sync_sub_and_fetch(p, 1) == 0;
02010 })
02011 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
02012 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
02013 {
02014 return OSAtomicAdd32( -1, (int32_t *) p) == 0;
02015 })
02016 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
02017 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
02018 {
02019 return OSAtomicAdd64( -1, (int64_t *) p) == 0;
02020 #else
02021 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
02022 {
02023 int a = ast_atomic_fetchadd_int(p, -1);
02024 return a == 1;
02025 })
02026 #endif
02027
02028 #ifndef DEBUG_CHANNEL_LOCKS
02029
02030
02031 #define ast_channel_lock(x) ast_mutex_lock(&x->lock_dont_use)
02032
02033
02034 #define ast_channel_unlock(x) ast_mutex_unlock(&x->lock_dont_use)
02035
02036
02037 #define ast_channel_trylock(x) ast_mutex_trylock(&x->lock_dont_use)
02038 #else
02039
02040 #define ast_channel_lock(a) __ast_channel_lock(a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
02041
02042
02043 int __ast_channel_lock(struct ast_channel *chan, const char *file, int lineno, const char *func);
02044
02045 #define ast_channel_unlock(a) __ast_channel_unlock(a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
02046
02047
02048
02049 int __ast_channel_unlock(struct ast_channel *chan, const char *file, int lineno, const char *func);
02050
02051 #define ast_channel_trylock(a) __ast_channel_trylock(a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
02052
02053
02054 int __ast_channel_trylock(struct ast_channel *chan, const char *file, int lineno, const char *func);
02055 #endif
02056
02057 #endif