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