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