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