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