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