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 #ifndef _ASTERISK_LOCK_H
00046 #define _ASTERISK_LOCK_H
00047
00048 #include <pthread.h>
00049 #include <netdb.h>
00050 #include <time.h>
00051 #include <sys/param.h>
00052
00053 #include "asterisk/logger.h"
00054
00055
00056
00057
00058 #ifndef HAVE_MTX_PROFILE
00059 #define __MTX_PROF(a) return pthread_mutex_lock((a))
00060 #else
00061 #define __MTX_PROF(a) do { \
00062 int i; \
00063 \
00064 ast_mark(mtx_prof, 1); \
00065 i = pthread_mutex_trylock((a)); \
00066 ast_mark(mtx_prof, 0); \
00067 if (!i) \
00068 return i; \
00069 else \
00070 return pthread_mutex_lock((a)); \
00071 } while (0)
00072 #endif
00073
00074 #define AST_PTHREADT_NULL (pthread_t) -1
00075 #define AST_PTHREADT_STOP (pthread_t) -2
00076
00077 #if defined(SOLARIS) || defined(BSD)
00078 #define AST_MUTEX_INIT_W_CONSTRUCTORS
00079 #endif
00080
00081
00082
00083 #if defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
00084 #define PTHREAD_MUTEX_INIT_VALUE PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
00085 #define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE_NP
00086 #else
00087 #define PTHREAD_MUTEX_INIT_VALUE PTHREAD_MUTEX_INITIALIZER
00088 #define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE
00089 #endif
00090
00091 #ifdef DEBUG_THREADS
00092
00093 #define __ast_mutex_logger(...) do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0)
00094
00095 #ifdef THREAD_CRASH
00096 #define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
00097 #else
00098 #define DO_THREAD_CRASH do { } while (0)
00099 #endif
00100
00101 #include <errno.h>
00102 #include <string.h>
00103 #include <stdio.h>
00104 #include <unistd.h>
00105
00106 #define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, 1, { NULL }, { 0 }, 0, { NULL }, { 0 }, PTHREAD_MUTEX_INIT_VALUE }
00107 #define AST_MUTEX_INIT_VALUE_NOTRACKING \
00108 { PTHREAD_MUTEX_INIT_VALUE, 0, { NULL }, { 0 }, 0, { NULL }, { 0 }, PTHREAD_MUTEX_INIT_VALUE }
00109
00110 #define AST_MAX_REENTRANCY 10
00111
00112 struct ast_mutex_info {
00113 pthread_mutex_t mutex;
00114
00115 unsigned int track:1;
00116 const char *file[AST_MAX_REENTRANCY];
00117 int lineno[AST_MAX_REENTRANCY];
00118 int reentrancy;
00119 const char *func[AST_MAX_REENTRANCY];
00120 pthread_t thread[AST_MAX_REENTRANCY];
00121 pthread_mutex_t reentr_mutex;
00122 };
00123
00124 typedef struct ast_mutex_info ast_mutex_t;
00125
00126 typedef pthread_cond_t ast_cond_t;
00127
00128 static pthread_mutex_t empty_mutex;
00129
00130 enum ast_lock_type {
00131 AST_MUTEX,
00132 AST_RDLOCK,
00133 AST_WRLOCK,
00134 };
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
00145 int line_num, const char *func, const char *lock_name, void *lock_addr);
00146
00147
00148
00149
00150 void ast_mark_lock_acquired(void);
00151
00152
00153
00154
00155 void ast_mark_lock_failed(void);
00156
00157
00158
00159
00160
00161
00162
00163 void ast_remove_lock_info(void *lock_addr);
00164
00165 static void __attribute__((constructor)) init_empty_mutex(void)
00166 {
00167 memset(&empty_mutex, 0, sizeof(empty_mutex));
00168 }
00169
00170 static inline void ast_reentrancy_lock(ast_mutex_t *p_ast_mutex)
00171 {
00172 pthread_mutex_lock(&p_ast_mutex->reentr_mutex);
00173 }
00174
00175 static inline void ast_reentrancy_unlock(ast_mutex_t *p_ast_mutex)
00176 {
00177 pthread_mutex_unlock(&p_ast_mutex->reentr_mutex);
00178 }
00179
00180 static inline void ast_reentrancy_init(ast_mutex_t *p_ast_mutex)
00181 {
00182 int i;
00183 pthread_mutexattr_t reentr_attr;
00184
00185 for (i = 0; i < AST_MAX_REENTRANCY; i++) {
00186 p_ast_mutex->file[i] = NULL;
00187 p_ast_mutex->lineno[i] = 0;
00188 p_ast_mutex->func[i] = NULL;
00189 p_ast_mutex->thread[i] = 0;
00190 }
00191
00192 p_ast_mutex->reentrancy = 0;
00193
00194 pthread_mutexattr_init(&reentr_attr);
00195 pthread_mutexattr_settype(&reentr_attr, AST_MUTEX_KIND);
00196 pthread_mutex_init(&p_ast_mutex->reentr_mutex, &reentr_attr);
00197 pthread_mutexattr_destroy(&reentr_attr);
00198 }
00199
00200 static inline void delete_reentrancy_cs(ast_mutex_t * p_ast_mutex)
00201 {
00202 pthread_mutex_destroy(&p_ast_mutex->reentr_mutex);
00203 }
00204
00205 static inline int __ast_pthread_mutex_init(int track, const char *filename, int lineno, const char *func,
00206 const char *mutex_name, ast_mutex_t *t)
00207 {
00208 int res;
00209 pthread_mutexattr_t attr;
00210
00211 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00212
00213 if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00214
00215
00216
00217
00218
00219
00220 return 0;
00221 }
00222
00223 #endif
00224
00225 ast_reentrancy_init(t);
00226 t->track = track;
00227
00228 pthread_mutexattr_init(&attr);
00229 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
00230
00231 res = pthread_mutex_init(&t->mutex, &attr);
00232 pthread_mutexattr_destroy(&attr);
00233 return res;
00234 }
00235
00236 #define ast_mutex_init(pmutex) __ast_pthread_mutex_init(1, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
00237 #define ast_mutex_init_notracking(pmutex) \
00238 __ast_pthread_mutex_init(0, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
00239
00240 static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
00241 const char *mutex_name, ast_mutex_t *t)
00242 {
00243 int res;
00244 int canlog = strcmp(filename, "logger.c") & t->track;
00245
00246 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00247 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00248
00249
00250
00251
00252
00253
00254 __ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is uninitialized.\n",
00255 filename, lineno, func, mutex_name);
00256 return 0;
00257 }
00258 #endif
00259
00260 res = pthread_mutex_trylock(&t->mutex);
00261 switch (res) {
00262 case 0:
00263 pthread_mutex_unlock(&t->mutex);
00264 break;
00265 case EINVAL:
00266 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
00267 filename, lineno, func, mutex_name);
00268 break;
00269 case EBUSY:
00270 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
00271 filename, lineno, func, mutex_name);
00272 ast_reentrancy_lock(t);
00273 __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
00274 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
00275 ast_reentrancy_unlock(t);
00276 break;
00277 }
00278
00279 if ((res = pthread_mutex_destroy(&t->mutex)))
00280 __ast_mutex_logger("%s line %d (%s): Error destroying mutex %s: %s\n",
00281 filename, lineno, func, mutex_name, strerror(res));
00282 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
00283 else
00284 t->mutex = PTHREAD_MUTEX_INIT_VALUE;
00285 #endif
00286 ast_reentrancy_lock(t);
00287 t->file[0] = filename;
00288 t->lineno[0] = lineno;
00289 t->func[0] = func;
00290 t->reentrancy = 0;
00291 t->thread[0] = 0;
00292 ast_reentrancy_unlock(t);
00293 delete_reentrancy_cs(t);
00294
00295 return res;
00296 }
00297
00298 static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
00299 const char* mutex_name, ast_mutex_t *t)
00300 {
00301 int res;
00302 int canlog = strcmp(filename, "logger.c") & t->track;
00303
00304 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
00305 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00306
00307
00308
00309
00310 res = __ast_pthread_mutex_init(t->track, 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->track)
00320 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
00321
00322 #ifdef DETECT_DEADLOCKS
00323 {
00324 time_t seconds = time(NULL);
00325 time_t wait_time, reported_wait = 0;
00326 do {
00327 #ifdef HAVE_MTX_PROFILE
00328 ast_mark(mtx_prof, 1);
00329 #endif
00330 res = pthread_mutex_trylock(&t->mutex);
00331 #ifdef HAVE_MTX_PROFILE
00332 ast_mark(mtx_prof, 0);
00333 #endif
00334 if (res == EBUSY) {
00335 wait_time = time(NULL) - seconds;
00336 if (wait_time > reported_wait && (wait_time % 5) == 0) {
00337 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
00338 filename, lineno, func, (int) wait_time, mutex_name);
00339 ast_reentrancy_lock(t);
00340 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
00341 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1],
00342 t->func[t->reentrancy-1], mutex_name);
00343 ast_reentrancy_unlock(t);
00344 reported_wait = wait_time;
00345 }
00346 usleep(200);
00347 }
00348 } while (res == EBUSY);
00349 }
00350 #else
00351 #ifdef HAVE_MTX_PROFILE
00352 ast_mark(mtx_prof, 1);
00353 res = pthread_mutex_trylock(&t->mutex);
00354 ast_mark(mtx_prof, 0);
00355 if (res)
00356 #endif
00357 res = pthread_mutex_lock(&t->mutex);
00358 #endif
00359
00360 if (!res) {
00361 ast_reentrancy_lock(t);
00362 if (t->reentrancy < AST_MAX_REENTRANCY) {
00363 t->file[t->reentrancy] = filename;
00364 t->lineno[t->reentrancy] = lineno;
00365 t->func[t->reentrancy] = func;
00366 t->thread[t->reentrancy] = pthread_self();
00367 t->reentrancy++;
00368 } else {
00369 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
00370 filename, lineno, func, mutex_name);
00371 }
00372 ast_reentrancy_unlock(t);
00373 if (t->track)
00374 ast_mark_lock_acquired();
00375 } else {
00376 if (t->track)
00377 ast_remove_lock_info(&t->mutex);
00378 __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
00379 filename, lineno, func, strerror(res));
00380 DO_THREAD_CRASH;
00381 }
00382
00383 return res;
00384 }
00385
00386 static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
00387 const char* mutex_name, ast_mutex_t *t)
00388 {
00389 int res;
00390 int canlog = strcmp(filename, "logger.c") & t->track;
00391
00392 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
00393 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00394
00395
00396
00397
00398 res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
00399 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00400 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
00401 filename, lineno, func, mutex_name);
00402 return res;
00403 }
00404 }
00405 #endif
00406
00407 if (t->track)
00408 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
00409
00410 if (!(res = pthread_mutex_trylock(&t->mutex))) {
00411 ast_reentrancy_lock(t);
00412 if (t->reentrancy < AST_MAX_REENTRANCY) {
00413 t->file[t->reentrancy] = filename;
00414 t->lineno[t->reentrancy] = lineno;
00415 t->func[t->reentrancy] = func;
00416 t->thread[t->reentrancy] = pthread_self();
00417 t->reentrancy++;
00418 } else {
00419 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
00420 filename, lineno, func, mutex_name);
00421 }
00422 ast_reentrancy_unlock(t);
00423 if (t->track)
00424 ast_mark_lock_acquired();
00425 } else if (t->track) {
00426 ast_mark_lock_failed();
00427 }
00428
00429 return res;
00430 }
00431
00432 static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
00433 const char *mutex_name, ast_mutex_t *t)
00434 {
00435 int res;
00436 int canlog = strcmp(filename, "logger.c") & t->track;
00437
00438 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00439 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00440 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00441 filename, lineno, func, mutex_name);
00442 res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
00443 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00444 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
00445 filename, lineno, func, mutex_name);
00446 }
00447 return res;
00448 }
00449 #endif
00450
00451 ast_reentrancy_lock(t);
00452 if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
00453 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
00454 filename, lineno, func, mutex_name);
00455 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
00456 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
00457 DO_THREAD_CRASH;
00458 }
00459
00460 if (--t->reentrancy < 0) {
00461 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
00462 filename, lineno, func, mutex_name);
00463 t->reentrancy = 0;
00464 }
00465
00466 if (t->reentrancy < AST_MAX_REENTRANCY) {
00467 t->file[t->reentrancy] = NULL;
00468 t->lineno[t->reentrancy] = 0;
00469 t->func[t->reentrancy] = NULL;
00470 t->thread[t->reentrancy] = 0;
00471 }
00472 ast_reentrancy_unlock(t);
00473
00474 if (t->track)
00475 ast_remove_lock_info(&t->mutex);
00476
00477 if ((res = pthread_mutex_unlock(&t->mutex))) {
00478 __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n",
00479 filename, lineno, func, strerror(res));
00480 DO_THREAD_CRASH;
00481 }
00482
00483 return res;
00484 }
00485
00486 static inline int __ast_cond_init(const char *filename, int lineno, const char *func,
00487 const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
00488 {
00489 return pthread_cond_init(cond, cond_attr);
00490 }
00491
00492 static inline int __ast_cond_signal(const char *filename, int lineno, const char *func,
00493 const char *cond_name, ast_cond_t *cond)
00494 {
00495 return pthread_cond_signal(cond);
00496 }
00497
00498 static inline int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
00499 const char *cond_name, ast_cond_t *cond)
00500 {
00501 return pthread_cond_broadcast(cond);
00502 }
00503
00504 static inline int __ast_cond_destroy(const char *filename, int lineno, const char *func,
00505 const char *cond_name, ast_cond_t *cond)
00506 {
00507 return pthread_cond_destroy(cond);
00508 }
00509
00510 static inline int __ast_cond_wait(const char *filename, int lineno, const char *func,
00511 const char *cond_name, const char *mutex_name,
00512 ast_cond_t *cond, ast_mutex_t *t)
00513 {
00514 int res;
00515 int canlog = strcmp(filename, "logger.c") & t->track;
00516
00517 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00518 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00519 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00520 filename, lineno, func, mutex_name);
00521 res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
00522 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00523 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
00524 filename, lineno, func, mutex_name);
00525 }
00526 return res;
00527 }
00528 #endif
00529
00530 ast_reentrancy_lock(t);
00531 if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
00532 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
00533 filename, lineno, func, mutex_name);
00534 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
00535 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
00536 DO_THREAD_CRASH;
00537 }
00538
00539 if (--t->reentrancy < 0) {
00540 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
00541 filename, lineno, func, mutex_name);
00542 t->reentrancy = 0;
00543 }
00544
00545 if (t->reentrancy < AST_MAX_REENTRANCY) {
00546 t->file[t->reentrancy] = NULL;
00547 t->lineno[t->reentrancy] = 0;
00548 t->func[t->reentrancy] = NULL;
00549 t->thread[t->reentrancy] = 0;
00550 }
00551 ast_reentrancy_unlock(t);
00552
00553 if (t->track)
00554 ast_remove_lock_info(&t->mutex);
00555
00556 if ((res = pthread_cond_wait(cond, &t->mutex))) {
00557 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
00558 filename, lineno, func, strerror(res));
00559 DO_THREAD_CRASH;
00560 } else {
00561 ast_reentrancy_lock(t);
00562 if (t->reentrancy < AST_MAX_REENTRANCY) {
00563 t->file[t->reentrancy] = filename;
00564 t->lineno[t->reentrancy] = lineno;
00565 t->func[t->reentrancy] = func;
00566 t->thread[t->reentrancy] = pthread_self();
00567 t->reentrancy++;
00568 } else {
00569 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
00570 filename, lineno, func, mutex_name);
00571 }
00572 ast_reentrancy_unlock(t);
00573
00574 if (t->track)
00575 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
00576 }
00577
00578 return res;
00579 }
00580
00581 static inline int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
00582 const char *cond_name, const char *mutex_name, ast_cond_t *cond,
00583 ast_mutex_t *t, const struct timespec *abstime)
00584 {
00585 int res;
00586 int canlog = strcmp(filename, "logger.c") & t->track;
00587
00588 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00589 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00590 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
00591 filename, lineno, func, mutex_name);
00592 res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
00593 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
00594 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
00595 filename, lineno, func, mutex_name);
00596 }
00597 return res;
00598 }
00599 #endif
00600
00601 ast_reentrancy_lock(t);
00602 if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
00603 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
00604 filename, lineno, func, mutex_name);
00605 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
00606 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
00607 DO_THREAD_CRASH;
00608 }
00609
00610 if (--t->reentrancy < 0) {
00611 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
00612 filename, lineno, func, mutex_name);
00613 t->reentrancy = 0;
00614 }
00615
00616 if (t->reentrancy < AST_MAX_REENTRANCY) {
00617 t->file[t->reentrancy] = NULL;
00618 t->lineno[t->reentrancy] = 0;
00619 t->func[t->reentrancy] = NULL;
00620 t->thread[t->reentrancy] = 0;
00621 }
00622 ast_reentrancy_unlock(t);
00623
00624 if (t->track)
00625 ast_remove_lock_info(&t->mutex);
00626
00627 if ((res = pthread_cond_timedwait(cond, &t->mutex, abstime)) && (res != ETIMEDOUT)) {
00628 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
00629 filename, lineno, func, strerror(res));
00630 DO_THREAD_CRASH;
00631 } else {
00632 ast_reentrancy_lock(t);
00633 if (t->reentrancy < AST_MAX_REENTRANCY) {
00634 t->file[t->reentrancy] = filename;
00635 t->lineno[t->reentrancy] = lineno;
00636 t->func[t->reentrancy] = func;
00637 t->thread[t->reentrancy] = pthread_self();
00638 t->reentrancy++;
00639 } else {
00640 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
00641 filename, lineno, func, mutex_name);
00642 }
00643 ast_reentrancy_unlock(t);
00644
00645 if (t->track)
00646 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
00647 }
00648
00649 return res;
00650 }
00651
00652 #define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00653 #define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00654 #define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00655 #define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
00656 #define ast_cond_init(cond, attr) __ast_cond_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond, attr)
00657 #define ast_cond_destroy(cond) __ast_cond_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
00658 #define ast_cond_signal(cond) __ast_cond_signal(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
00659 #define ast_cond_broadcast(cond) __ast_cond_broadcast(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
00660 #define ast_cond_wait(cond, mutex) __ast_cond_wait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex)
00661 #define ast_cond_timedwait(cond, mutex, time) __ast_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex, time)
00662
00663 #else
00664
00665
00666 typedef pthread_mutex_t ast_mutex_t;
00667
00668 #define AST_MUTEX_INIT_VALUE ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
00669 #define AST_MUTEX_INIT_VALUE_NOTRACKING \
00670 ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
00671
00672 #define ast_mutex_init_notracking(m) ast_mutex_init(m)
00673
00674 static inline int ast_mutex_init(ast_mutex_t *pmutex)
00675 {
00676 int res;
00677 pthread_mutexattr_t attr;
00678
00679 pthread_mutexattr_init(&attr);
00680 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
00681
00682 res = pthread_mutex_init(pmutex, &attr);
00683 pthread_mutexattr_destroy(&attr);
00684 return res;
00685 }
00686
00687 #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
00688
00689 static inline int ast_mutex_unlock(ast_mutex_t *pmutex)
00690 {
00691 return pthread_mutex_unlock(pmutex);
00692 }
00693
00694 static inline int ast_mutex_destroy(ast_mutex_t *pmutex)
00695 {
00696 return pthread_mutex_destroy(pmutex);
00697 }
00698
00699 static inline int ast_mutex_lock(ast_mutex_t *pmutex)
00700 {
00701 __MTX_PROF(pmutex);
00702 }
00703
00704 static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
00705 {
00706 return pthread_mutex_trylock(pmutex);
00707 }
00708
00709 typedef pthread_cond_t ast_cond_t;
00710
00711 static inline int ast_cond_init(ast_cond_t *cond, pthread_condattr_t *cond_attr)
00712 {
00713 return pthread_cond_init(cond, cond_attr);
00714 }
00715
00716 static inline int ast_cond_signal(ast_cond_t *cond)
00717 {
00718 return pthread_cond_signal(cond);
00719 }
00720
00721 static inline int ast_cond_broadcast(ast_cond_t *cond)
00722 {
00723 return pthread_cond_broadcast(cond);
00724 }
00725
00726 static inline int ast_cond_destroy(ast_cond_t *cond)
00727 {
00728 return pthread_cond_destroy(cond);
00729 }
00730
00731 static inline int ast_cond_wait(ast_cond_t *cond, ast_mutex_t *t)
00732 {
00733 return pthread_cond_wait(cond, t);
00734 }
00735
00736 static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime)
00737 {
00738 return pthread_cond_timedwait(cond, t, abstime);
00739 }
00740
00741 #endif
00742
00743 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
00744
00745
00746 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track) \
00747 scope ast_mutex_t mutex = init_val; \
00748 static void __attribute__ ((constructor)) init_##mutex(void) \
00749 { \
00750 if (track) \
00751 ast_mutex_init(&mutex); \
00752 else \
00753 ast_mutex_init_notracking(&mutex); \
00754 } \
00755 static void __attribute__ ((destructor)) fini_##mutex(void) \
00756 { \
00757 ast_mutex_destroy(&mutex); \
00758 }
00759 #else
00760
00761 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track) \
00762 scope ast_mutex_t mutex = init_val
00763 #endif
00764
00765 #define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
00766 #define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
00767 #define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
00768 #define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
00769 #define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init
00770 #define pthread_mutex_destroy use_ast_mutex_destroy_instead_of_pthread_mutex_destroy
00771 #define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t
00772 #define pthread_cond_init use_ast_cond_init_instead_of_pthread_cond_init
00773 #define pthread_cond_destroy use_ast_cond_destroy_instead_of_pthread_cond_destroy
00774 #define pthread_cond_signal use_ast_cond_signal_instead_of_pthread_cond_signal
00775 #define pthread_cond_broadcast use_ast_cond_broadcast_instead_of_pthread_cond_broadcast
00776 #define pthread_cond_wait use_ast_cond_wait_instead_of_pthread_cond_wait
00777 #define pthread_cond_timedwait use_ast_cond_timedwait_instead_of_pthread_cond_timedwait
00778
00779 #define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE, 1)
00780 #define AST_MUTEX_DEFINE_STATIC_NOTRACKING(mutex) __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE_NOTRACKING, 0)
00781
00782 #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
00783
00784 #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
00785
00786 #ifndef __linux__
00787 #define pthread_create __use_ast_pthread_create_instead__
00788 #endif
00789
00790 typedef pthread_rwlock_t ast_rwlock_t;
00791
00792 #ifdef HAVE_PTHREAD_RWLOCK_INITIALIZER
00793 #define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
00794 #else
00795 #define AST_RWLOCK_INIT_VALUE NULL
00796 #endif
00797
00798 #ifdef DEBUG_THREADS
00799
00800 #define ast_rwlock_init(rwlock) __ast_rwlock_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)
00801
00802
00803 static inline int __ast_rwlock_init(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *prwlock)
00804 {
00805 int res;
00806 pthread_rwlockattr_t attr;
00807 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00808 int canlog = strcmp(filename, "logger.c");
00809
00810 if (*prwlock != ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
00811 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
00812 filename, lineno, func, rwlock_name);
00813 return 0;
00814 }
00815 #endif
00816 pthread_rwlockattr_init(&attr);
00817
00818 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
00819 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
00820 #endif
00821
00822 res = pthread_rwlock_init(prwlock, &attr);
00823 pthread_rwlockattr_destroy(&attr);
00824 return res;
00825 }
00826
00827 #define ast_rwlock_destroy(rwlock) __ast_rwlock_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)
00828
00829 static inline int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *prwlock)
00830 {
00831 int res;
00832 int canlog = strcmp(filename, "logger.c");
00833
00834 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00835 if (*prwlock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
00836 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
00837 filename, lineno, func, rwlock_name);
00838 return 0;
00839 }
00840 #endif
00841
00842 if ((res = pthread_rwlock_destroy(prwlock)))
00843 __ast_mutex_logger("%s line %d (%s): Error destroying rwlock %s: %s\n",
00844 filename, lineno, func, rwlock_name, strerror(res));
00845
00846 return res;
00847 }
00848
00849 #define ast_rwlock_unlock(a) \
00850 _ast_rwlock_unlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
00851
00852 static inline int _ast_rwlock_unlock(ast_rwlock_t *lock, const char *name,
00853 const char *file, int line, const char *func)
00854 {
00855 int res;
00856 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00857 int canlog = strcmp(file, "logger.c");
00858
00859 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
00860 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
00861 file, line, func, name);
00862 res = __ast_rwlock_init(file, line, func, name, lock);
00863 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
00864 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
00865 file, line, func, name);
00866 }
00867 return res;
00868 }
00869 #endif
00870
00871 res = pthread_rwlock_unlock(lock);
00872 ast_remove_lock_info(lock);
00873 return res;
00874 }
00875
00876 #define ast_rwlock_rdlock(a) \
00877 _ast_rwlock_rdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
00878
00879 static inline int _ast_rwlock_rdlock(ast_rwlock_t *lock, const char *name,
00880 const char *file, int line, const char *func)
00881 {
00882 int res;
00883 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00884 int canlog = strcmp(file, "logger.c");
00885
00886 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
00887
00888
00889
00890
00891 res = __ast_rwlock_init(file, line, func, name, lock);
00892 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
00893 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
00894 file, line, func, name);
00895 return res;
00896 }
00897 }
00898 #endif
00899
00900 ast_store_lock_info(AST_RDLOCK, file, line, func, name, lock);
00901 res = pthread_rwlock_rdlock(lock);
00902 if (!res)
00903 ast_mark_lock_acquired();
00904 else
00905 ast_remove_lock_info(lock);
00906 return res;
00907 }
00908
00909 #define ast_rwlock_wrlock(a) \
00910 _ast_rwlock_wrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
00911
00912 static inline int _ast_rwlock_wrlock(ast_rwlock_t *lock, const char *name,
00913 const char *file, int line, const char *func)
00914 {
00915 int res;
00916 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00917 int canlog = strcmp(file, "logger.c");
00918
00919 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
00920
00921
00922
00923
00924 res = __ast_rwlock_init(file, line, func, name, lock);
00925 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
00926 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
00927 file, line, func, name);
00928 return res;
00929 }
00930 }
00931 #endif
00932
00933 ast_store_lock_info(AST_WRLOCK, file, line, func, name, lock);
00934 res = pthread_rwlock_wrlock(lock);
00935 if (!res)
00936 ast_mark_lock_acquired();
00937 else
00938 ast_remove_lock_info(lock);
00939 return res;
00940 }
00941
00942 #define ast_rwlock_tryrdlock(a) \
00943 _ast_rwlock_tryrdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
00944
00945 static inline int _ast_rwlock_tryrdlock(ast_rwlock_t *lock, const char *name,
00946 const char *file, int line, const char *func)
00947 {
00948 int res;
00949 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00950 int canlog = strcmp(file, "logger.c");
00951
00952 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
00953
00954
00955
00956
00957 res = __ast_rwlock_init(file, line, func, name, lock);
00958 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
00959 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
00960 file, line, func, name);
00961 return res;
00962 }
00963 }
00964 #endif
00965
00966 ast_store_lock_info(AST_RDLOCK, file, line, func, name, lock);
00967 res = pthread_rwlock_tryrdlock(lock);
00968 if (!res)
00969 ast_mark_lock_acquired();
00970 else
00971 ast_remove_lock_info(lock);
00972 return res;
00973 }
00974
00975 #define ast_rwlock_trywrlock(a) \
00976 _ast_rwlock_trywrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
00977
00978 static inline int _ast_rwlock_trywrlock(ast_rwlock_t *lock, const char *name,
00979 const char *file, int line, const char *func)
00980 {
00981 int res;
00982 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00983 int canlog = strcmp(file, "logger.c");
00984
00985 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
00986
00987
00988
00989
00990 res = __ast_rwlock_init(file, line, func, name, lock);
00991 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
00992 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
00993 file, line, func, name);
00994 return res;
00995 }
00996 }
00997 #endif
00998
00999 ast_store_lock_info(AST_WRLOCK, file, line, func, name, lock);
01000 res = pthread_rwlock_trywrlock(lock);
01001 if (!res)
01002 ast_mark_lock_acquired();
01003 else
01004 ast_remove_lock_info(lock);
01005 return res;
01006 }
01007
01008 #else
01009
01010 static inline int ast_rwlock_init(ast_rwlock_t *prwlock)
01011 {
01012 int res;
01013 pthread_rwlockattr_t attr;
01014
01015 pthread_rwlockattr_init(&attr);
01016
01017 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
01018 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
01019 #endif
01020
01021 res = pthread_rwlock_init(prwlock, &attr);
01022 pthread_rwlockattr_destroy(&attr);
01023 return res;
01024 }
01025
01026 static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
01027 {
01028 return pthread_rwlock_destroy(prwlock);
01029 }
01030
01031 static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
01032 {
01033 return pthread_rwlock_unlock(prwlock);
01034 }
01035
01036 static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
01037 {
01038 return pthread_rwlock_rdlock(prwlock);
01039 }
01040
01041 static inline int ast_rwlock_tryrdlock(ast_rwlock_t *prwlock)
01042 {
01043 return pthread_rwlock_tryrdlock(prwlock);
01044 }
01045
01046 static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
01047 {
01048 return pthread_rwlock_wrlock(prwlock);
01049 }
01050
01051 static inline int ast_rwlock_trywrlock(ast_rwlock_t *prwlock)
01052 {
01053 return pthread_rwlock_trywrlock(prwlock);
01054 }
01055 #endif
01056
01057
01058
01059 #ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
01060 #define __AST_RWLOCK_DEFINE(scope, rwlock) \
01061 scope ast_rwlock_t rwlock; \
01062 static void __attribute__ ((constructor)) init_##rwlock(void) \
01063 { \
01064 ast_rwlock_init(&rwlock); \
01065 } \
01066 static void __attribute__ ((destructor)) fini_##rwlock(void) \
01067 { \
01068 ast_rwlock_destroy(&rwlock); \
01069 }
01070 #else
01071 #define __AST_RWLOCK_DEFINE(scope, rwlock) \
01072 scope ast_rwlock_t rwlock = AST_RWLOCK_INIT_VALUE
01073 #endif
01074
01075 #define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock)
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087 int ast_atomic_fetchadd_int_slow(volatile int *p, int v);
01088
01089 #include "asterisk/inline_api.h"
01090
01091 #if defined(HAVE_OSX_ATOMICS)
01092 #include "libkern/OSAtomic.h"
01093 #endif
01094
01095
01096
01097
01098
01099
01100 #if defined(HAVE_GCC_ATOMICS)
01101 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
01102 {
01103 return __sync_fetch_and_add(p, v);
01104 })
01105 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
01106 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
01107 {
01108 return OSAtomicAdd32(v, (int32_t *) p) - v;
01109 })
01110 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
01111 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
01112 {
01113 return OSAtomicAdd64(v, (int64_t *) p) - v;
01114 #elif defined (__i386__)
01115 #ifdef sun
01116 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
01117 {
01118 __asm __volatile (
01119 " lock; xaddl %0, %1 ; "
01120 : "+r" (v),
01121 "=m" (*p)
01122 : "m" (*p));
01123 return (v);
01124 })
01125 #else
01126 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
01127 {
01128 __asm __volatile (
01129 " lock xaddl %0, %1 ; "
01130 : "+r" (v),
01131 "=m" (*p)
01132 : "m" (*p));
01133 return (v);
01134 })
01135 #endif
01136 #else
01137 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
01138 {
01139 return ast_atomic_fetchadd_int_slow(p, v);
01140 })
01141 #endif
01142
01143
01144
01145
01146 #if defined(HAVE_GCC_ATOMICS)
01147 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
01148 {
01149 return __sync_sub_and_fetch(p, 1) == 0;
01150 })
01151 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
01152 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
01153 {
01154 return OSAtomicAdd32( -1, (int32_t *) p) == 0;
01155 })
01156 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
01157 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
01158 {
01159 return OSAtomicAdd64( -1, (int64_t *) p) == 0;
01160 #else
01161 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
01162 {
01163 int a = ast_atomic_fetchadd_int(p, -1);
01164 return a == 1;
01165 })
01166 #endif
01167
01168 #ifndef DEBUG_CHANNEL_LOCKS
01169
01170
01171 #define ast_channel_lock(x) ast_mutex_lock(&x->lock)
01172
01173
01174 #define ast_channel_unlock(x) ast_mutex_unlock(&x->lock)
01175
01176
01177 #define ast_channel_trylock(x) ast_mutex_trylock(&x->lock)
01178 #else
01179
01180 struct ast_channel;
01181
01182
01183
01184 int ast_channel_lock(struct ast_channel *chan);
01185
01186
01187
01188
01189 int ast_channel_unlock(struct ast_channel *chan);
01190
01191
01192
01193 int ast_channel_trylock(struct ast_channel *chan);
01194 #endif
01195
01196 #endif