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