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