Asterisk - The Open Source Telephony Project GIT-master-f3e88d3
Functions
lock.c File Reference

General Asterisk locking. More...

#include "asterisk.h"
#include "asterisk/utils.h"
#include "asterisk/lock.h"
#include "asterisk/manager.h"
Include dependency graph for lock.c:

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)
 

Detailed Description

General Asterisk locking.

Definition in file lock.c.

Function Documentation

◆ __ast_cond_broadcast()

int __ast_cond_broadcast ( const char *  filename,
int  lineno,
const char *  func,
const char *  cond_name,
ast_cond_t cond 
)

Definition at line 531 of file lock.c.

533{
535}
ast_cond_t cond
Definition: app_sla.c:330
#define pthread_cond_broadcast
Definition: lock.h:633

References cond, and pthread_cond_broadcast.

◆ __ast_cond_destroy()

int __ast_cond_destroy ( const char *  filename,
int  lineno,
const char *  func,
const char *  cond_name,
ast_cond_t cond 
)

Definition at line 537 of file lock.c.

539{
541}
#define pthread_cond_destroy
Definition: lock.h:631

References cond, and pthread_cond_destroy.

◆ __ast_cond_init()

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 519 of file lock.c.

521{
522 return pthread_cond_init(cond, cond_attr);
523}
#define pthread_cond_init
Definition: lock.h:630

References cond, and pthread_cond_init.

◆ __ast_cond_signal()

int __ast_cond_signal ( const char *  filename,
int  lineno,
const char *  func,
const char *  cond_name,
ast_cond_t cond 
)

Definition at line 525 of file lock.c.

527{
529}
#define pthread_cond_signal
Definition: lock.h:632

References cond, and pthread_cond_signal.

◆ __ast_cond_timedwait()

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 631 of file lock.c.

634{
635 int res;
636
637#ifdef DEBUG_THREADS
638 struct ast_lock_track *lt = NULL;
639 struct ast_lock_track lt_orig;
640 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
641
642#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
643 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
644 log_mutex_error(canlog, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
645 filename, lineno, func, mutex_name);
646 DO_THREAD_CRASH;
647 return EINVAL;
648 }
649#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
650
651 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
652 if (lt) {
653 ast_reentrancy_lock(lt);
654 if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) {
655 log_mutex_error(canlog, "%s line %d (%s): attempted wait using mutex '%s' without owning it!\n",
656 filename, lineno, func, mutex_name);
657 log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
658 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
659#ifdef HAVE_BKTR
660 __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
661#endif
662 DO_THREAD_CRASH;
663 } else if (lt->reentrancy <= 0) {
664 log_mutex_error(canlog, "%s line %d (%s): attempted wait using an unlocked mutex '%s'\n",
665 filename, lineno, func, mutex_name);
666 DO_THREAD_CRASH;
667 }
668
669 /* Waiting on a condition completely suspends a recursive mutex,
670 * even if it's been recursively locked multiple times. Make a
671 * copy of the lock tracking, and reset reentrancy to zero */
672 lt_orig = *lt;
673 lt->reentrancy = 0;
674 ast_reentrancy_unlock(lt);
675
676 ast_suspend_lock_info(t);
677 }
678#endif /* DEBUG_THREADS */
679
680 res = pthread_cond_timedwait(cond, &t->mutex, abstime);
681
682#ifdef DEBUG_THREADS
683 if (res && (res != ETIMEDOUT)) {
684 log_mutex_error(canlog, "%s line %d (%s): Error waiting on condition mutex '%s'\n",
685 filename, lineno, func, strerror(res));
686 DO_THREAD_CRASH;
687 } else if (lt) {
688 restore_lock_tracking(lt, &lt_orig);
689 ast_restore_lock_info(t);
690 }
691#endif /* DEBUG_THREADS */
692
693 return res;
694}
#define ROFFSET
Definition: lock.h:242
#define pthread_mutex_t
Definition: lock.h:622
#define pthread_cond_timedwait
Definition: lock.h:635
#define NULL
Definition: resample.c:96
Lock tracking information.
Definition: lock.h:111
int reentrancy
Definition: lock.h:114
struct ast_bt backtrace[AST_MAX_REENTRANCY]
Definition: lock.h:118
pthread_t thread_id[AST_MAX_REENTRANCY]
Definition: lock.h:116
int lineno[AST_MAX_REENTRANCY]
Definition: lock.h:113
const char * file[AST_MAX_REENTRANCY]
Definition: lock.h:112
const char * func[AST_MAX_REENTRANCY]
Definition: lock.h:115
pthread_mutex_t mutex
Definition: lock.h:136

References ast_lock_track::backtrace, cond, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_mutex_info::mutex, NULL, pthread_cond_timedwait, pthread_mutex_t, ast_lock_track::reentrancy, ROFFSET, and ast_lock_track::thread_id.

◆ __ast_cond_wait()

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 566 of file lock.c.

569{
570 int res;
571
572#ifdef DEBUG_THREADS
573 struct ast_lock_track *lt = NULL;
574 struct ast_lock_track lt_orig;
575 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
576
577#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
578 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
579 log_mutex_error(canlog, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
580 filename, lineno, func, mutex_name);
581 DO_THREAD_CRASH;
582 return EINVAL;
583 }
584#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
585
586 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
587 if (lt) {
588 ast_reentrancy_lock(lt);
589 if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) {
590 log_mutex_error(canlog, "%s line %d (%s): attempted wait using mutex '%s' without owning it!\n",
591 filename, lineno, func, mutex_name);
592 log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
593 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
594#ifdef HAVE_BKTR
595 __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
596#endif
597 DO_THREAD_CRASH;
598 } else if (lt->reentrancy <= 0) {
599 log_mutex_error(canlog, "%s line %d (%s): attempted wait using an unlocked mutex '%s'\n",
600 filename, lineno, func, mutex_name);
601 DO_THREAD_CRASH;
602 }
603
604 /* Waiting on a condition completely suspends a recursive mutex,
605 * even if it's been recursively locked multiple times. Make a
606 * copy of the lock tracking, and reset reentrancy to zero */
607 lt_orig = *lt;
608 lt->reentrancy = 0;
609 ast_reentrancy_unlock(lt);
610
611 ast_suspend_lock_info(t);
612 }
613#endif /* DEBUG_THREADS */
614
615 res = pthread_cond_wait(cond, &t->mutex);
616
617#ifdef DEBUG_THREADS
618 if (res) {
619 log_mutex_error(canlog, "%s line %d (%s): Error waiting on condition mutex '%s'\n",
620 filename, lineno, func, strerror(res));
621 DO_THREAD_CRASH;
622 } else if (lt) {
623 restore_lock_tracking(lt, &lt_orig);
624 ast_restore_lock_info(t);
625 }
626#endif /* DEBUG_THREADS */
627
628 return res;
629}
#define pthread_cond_wait
Definition: lock.h:634

References ast_lock_track::backtrace, cond, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_mutex_info::mutex, NULL, pthread_cond_wait, pthread_mutex_t, ast_lock_track::reentrancy, ROFFSET, and ast_lock_track::thread_id.

◆ __ast_pthread_mutex_destroy()

int __ast_pthread_mutex_destroy ( const char *  filename,
int  lineno,
const char *  func,
const char *  mutex_name,
ast_mutex_t t 
)

Definition at line 177 of file lock.c.

179{
180 int res;
181
182#ifdef DEBUG_THREADS
183 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 1);
184 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
185
186#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
187 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
188 /* Don't try to uninitialize an uninitialized mutex
189 * This may have no effect on linux
190 * but it always generates a core on *BSD when
191 * linked with libpthread.
192 * This is not an error condition if the mutex is created on the fly.
193 */
194 log_mutex_error(canlog, "%s line %d (%s): NOTICE: mutex '%s' is uninitialized.\n",
195 filename, lineno, func, mutex_name);
196 DO_THREAD_CRASH;
197 res = EINVAL;
198 goto lt_cleanup;
199 }
200#endif
201
202 res = pthread_mutex_trylock(&t->mutex);
203 switch (res) {
204 case 0:
206 break;
207 case EINVAL:
208 log_mutex_error(canlog, "%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
209 filename, lineno, func, mutex_name);
210 break;
211 case EBUSY:
212 log_mutex_error(canlog, "%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
213 filename, lineno, func, mutex_name);
214 if (lt) {
215 ast_reentrancy_lock(lt);
216 log_mutex_error(canlog, "%s line %d (%s): Error: '%s' was locked here.\n",
217 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
218#ifdef HAVE_BKTR
219 __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
220#endif
221 ast_reentrancy_unlock(lt);
222 }
223 break;
224 }
225#endif /* DEBUG_THREADS */
226
227 res = pthread_mutex_destroy(&t->mutex);
228
229#ifdef DEBUG_THREADS
230 if (res) {
231 log_mutex_error(canlog, "%s line %d (%s): Error destroying mutex %s: %s\n",
232 filename, lineno, func, mutex_name, strerror(res));
233 }
234#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
235lt_cleanup:
236#endif
237 if (lt) {
238 ast_reentrancy_lock(lt);
239 lt->file[0] = filename;
240 lt->lineno[0] = lineno;
241 lt->func[0] = func;
242 lt->reentrancy = 0;
243 lt->thread_id[0] = 0;
244#ifdef HAVE_BKTR
245 memset(&lt->backtrace[0], 0, sizeof(lt->backtrace[0]));
246#endif
247 ast_reentrancy_unlock(lt);
248 delete_reentrancy_cs(&t->track);
249 }
250#endif /* DEBUG_THREADS */
251
252 return res;
253}
#define pthread_mutex_trylock
Definition: lock.h:627
#define pthread_mutex_unlock
Definition: lock.h:626
#define pthread_mutex_destroy
Definition: lock.h:629

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, and ast_lock_track::thread_id.

◆ __ast_pthread_mutex_init()

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 145 of file lock.c.

147{
148 int res;
149 pthread_mutexattr_t attr;
150
151#if defined(DEBUG_THREADS) && defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && \
152 defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
153 if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
154 int canlog = tracking && strcmp(filename, "logger.c");
155
156 log_mutex_error(canlog, "%s line %d (%s): NOTICE: mutex '%s' is already initialized.\n",
157 filename, lineno, func, mutex_name);
158 DO_THREAD_CRASH;
159 return EBUSY;
160 }
161#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
162
163#if defined(DEBUG_THREADS) || defined(DETECT_DEADLOCKS)
164 t->track = NULL;
165 t->flags.tracking = tracking;
166 t->flags.setup = 0;
167#endif /* DEBUG_THREADS */
168
169 pthread_mutexattr_init(&attr);
170 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
171 res = pthread_mutex_init(&t->mutex, &attr);
172 pthread_mutexattr_destroy(&attr);
173
174 return res;
175}
#define AST_MUTEX_KIND
Definition: lock.h:77
#define pthread_mutex_init
Definition: lock.h:628

References AST_MUTEX_KIND, ast_lock_track::func, ast_lock_track::lineno, ast_mutex_info::mutex, NULL, pthread_mutex_init, and pthread_mutex_t.

◆ __ast_pthread_mutex_lock()

int __ast_pthread_mutex_lock ( const char *  filename,
int  lineno,
const char *  func,
const char *  mutex_name,
ast_mutex_t t 
)

Definition at line 255 of file lock.c.

257{
258 int res;
259
260#if defined(DETECT_DEADLOCKS) || defined(DEBUG_THREADS)
261 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
262#endif
263
264#ifdef DEBUG_THREADS
265 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
266 struct ast_bt *bt = NULL;
267
268 if (lt) {
269#ifdef HAVE_BKTR
270 struct ast_bt tmp;
271
272 /* The implementation of backtrace() may have its own locks.
273 * Capture the backtrace outside of the reentrancy lock to
274 * avoid deadlocks. See ASTERISK-22455. */
276
277 ast_reentrancy_lock(lt);
278 if (lt->reentrancy < AST_MAX_REENTRANCY) {
279 lt->backtrace[lt->reentrancy] = tmp;
280 bt = &lt->backtrace[lt->reentrancy];
281 }
282 ast_reentrancy_unlock(lt);
283#endif
284 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
285 }
286#endif /* DEBUG_THREADS */
287
288#if defined(DETECT_DEADLOCKS)
289 {
290 time_t seconds = time(NULL);
291 time_t wait_time, reported_wait = 0;
292 do {
293#ifdef HAVE_MTX_PROFILE
294 ast_mark(mtx_prof, 1);
295#endif
296 res = pthread_mutex_trylock(&t->mutex);
297#ifdef HAVE_MTX_PROFILE
298 ast_mark(mtx_prof, 0);
299#endif
300 if (res == EBUSY) {
301 wait_time = time(NULL) - seconds;
302 if (wait_time > reported_wait && (wait_time % 5) == 0) {
303 log_mutex_error(canlog, "%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
304 filename, lineno, func, (int) wait_time, mutex_name);
305#ifdef DEBUG_THREADS
306 if (lt) {
307 ast_reentrancy_lock(lt);
308#ifdef HAVE_BKTR
309 __dump_backtrace(&lt->backtrace[lt->reentrancy], canlog);
310#endif
311 log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
312 lt->file[ROFFSET], lt->lineno[ROFFSET],
313 lt->func[ROFFSET], mutex_name);
314#ifdef HAVE_BKTR
315 __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
316#endif
317 ast_reentrancy_unlock(lt);
318 }
319#endif
320 reported_wait = wait_time;
321 if ((int) wait_time < 10) { /* Only emit an event when a deadlock starts, not every 5 seconds */
322 /*** DOCUMENTATION
323 <managerEvent language="en_US" name="DeadlockStart">
324 <managerEventInstance class="EVENT_FLAG_SYSTEM">
325 <synopsis>Raised when a probable deadlock has started.
326 Delivery of this event is attempted but not guaranteed,
327 and could fail for example if the manager itself is deadlocked.
328 </synopsis>
329 <syntax>
330 <parameter name="Mutex">
331 <para>The mutex involved in the deadlock.</para>
332 </parameter>
333 </syntax>
334 </managerEventInstance>
335 </managerEvent>
336 ***/
337 manager_event(EVENT_FLAG_SYSTEM, "DeadlockStart",
338 "Mutex: %s\r\n",
339 mutex_name);
340 }
341 }
342 usleep(200);
343 }
344 } while (res == EBUSY);
345 }
346#else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
347#ifdef HAVE_MTX_PROFILE
348 ast_mark(mtx_prof, 1);
349 res = pthread_mutex_trylock(&t->mutex);
350 ast_mark(mtx_prof, 0);
351 if (res)
352#endif
353 res = pthread_mutex_lock(&t->mutex);
354#endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
355
356#ifdef DEBUG_THREADS
357 if (lt && !res) {
358 ast_reentrancy_lock(lt);
359 if (lt->reentrancy < AST_MAX_REENTRANCY) {
360 lt->file[lt->reentrancy] = filename;
361 lt->lineno[lt->reentrancy] = lineno;
362 lt->func[lt->reentrancy] = func;
363 lt->thread_id[lt->reentrancy] = pthread_self();
364 lt->reentrancy++;
365 } else {
366 log_mutex_error(canlog, "%s line %d (%s): '%s' really deep reentrancy!\n",
367 filename, lineno, func, mutex_name);
368 }
369 ast_reentrancy_unlock(lt);
370 ast_mark_lock_acquired(t);
371 } else if (lt) {
372#ifdef HAVE_BKTR
373 if (lt->reentrancy) {
374 ast_reentrancy_lock(lt);
375 bt = &lt->backtrace[lt->reentrancy-1];
376 ast_reentrancy_unlock(lt);
377 } else {
378 bt = NULL;
379 }
380#endif
381 ast_remove_lock_info(t, bt);
382 }
383 if (res) {
384 log_mutex_error(canlog, "%s line %d (%s): Error obtaining mutex: %s\n",
385 filename, lineno, func, strerror(res));
386 DO_THREAD_CRASH;
387 }
388#endif /* DEBUG_THREADS */
389
390 return res;
391}
int64_t ast_mark(int, int start1_stop0)
Definition: astman.c:103
#define ast_bt_get_addresses(bt)
Definition: backtrace.h:38
static int tmp()
Definition: bt_open.c:389
@ AST_MUTEX
Definition: check_expr.c:36
#define AST_MAX_REENTRANCY
Definition: lock.h:101
#define pthread_mutex_lock
Definition: lock.h:625
#define manager_event(category, event, contents,...)
External routines may send asterisk manager events this way.
Definition: manager.h:253
#define EVENT_FLAG_SYSTEM
Definition: manager.h:75
A structure to hold backtrace information. This structure provides an easy means to store backtrace i...
Definition: backtrace.h:50

References ast_bt_get_addresses, ast_mark(), AST_MAX_REENTRANCY, AST_MUTEX, ast_lock_track::backtrace, EVENT_FLAG_SYSTEM, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, manager_event, ast_mutex_info::mutex, NULL, pthread_mutex_lock, pthread_mutex_trylock, ast_lock_track::reentrancy, ROFFSET, ast_lock_track::thread_id, and tmp().

Referenced by __ao2_lock().

◆ __ast_pthread_mutex_trylock()

int __ast_pthread_mutex_trylock ( const char *  filename,
int  lineno,
const char *  func,
const char *  mutex_name,
ast_mutex_t t 
)

Definition at line 393 of file lock.c.

395{
396 int res;
397
398#ifdef DEBUG_THREADS
399 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
400 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
401 struct ast_bt *bt = NULL;
402
403 if (lt) {
404#ifdef HAVE_BKTR
405 struct ast_bt tmp;
406
407 /* The implementation of backtrace() may have its own locks.
408 * Capture the backtrace outside of the reentrancy lock to
409 * avoid deadlocks. See ASTERISK-22455. */
411
412 ast_reentrancy_lock(lt);
413 if (lt->reentrancy < AST_MAX_REENTRANCY) {
414 lt->backtrace[lt->reentrancy] = tmp;
415 bt = &lt->backtrace[lt->reentrancy];
416 }
417 ast_reentrancy_unlock(lt);
418#endif
419 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
420 }
421#endif /* DEBUG_THREADS */
422
423 res = pthread_mutex_trylock(&t->mutex);
424
425#ifdef DEBUG_THREADS
426 if (lt && !res) {
427 ast_reentrancy_lock(lt);
428 if (lt->reentrancy < AST_MAX_REENTRANCY) {
429 lt->file[lt->reentrancy] = filename;
430 lt->lineno[lt->reentrancy] = lineno;
431 lt->func[lt->reentrancy] = func;
432 lt->thread_id[lt->reentrancy] = pthread_self();
433 lt->reentrancy++;
434 } else {
435 log_mutex_error(canlog, "%s line %d (%s): '%s' really deep reentrancy!\n",
436 filename, lineno, func, mutex_name);
437 }
438 ast_reentrancy_unlock(lt);
439 ast_mark_lock_acquired(t);
440 } else if (lt) {
442 }
443#endif /* DEBUG_THREADS */
444
445 return res;
446}
void ast_mark_lock_failed(void *lock_addr)
Definition: extconf.c:2313

References ast_bt_get_addresses, ast_mark_lock_failed(), AST_MAX_REENTRANCY, AST_MUTEX, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_mutex_info::mutex, NULL, pthread_mutex_trylock, ast_lock_track::reentrancy, ast_lock_track::thread_id, and tmp().

Referenced by __ao2_trylock().

◆ __ast_pthread_mutex_unlock()

int __ast_pthread_mutex_unlock ( const char *  filename,
int  lineno,
const char *  func,
const char *  mutex_name,
ast_mutex_t t 
)

Definition at line 448 of file lock.c.

450{
451 int res;
452
453#ifdef DEBUG_THREADS
454 struct ast_lock_track *lt = NULL;
455 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
456 struct ast_bt *bt = NULL;
457
458#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
459 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
460 log_mutex_error(canlog, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
461 filename, lineno, func, mutex_name);
462 DO_THREAD_CRASH;
463 return EINVAL;
464 }
465#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
466
467 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
468 if (lt) {
469 ast_reentrancy_lock(lt);
470 if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) {
471 log_mutex_error(canlog, "%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
472 filename, lineno, func, mutex_name);
473 log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
474 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
475#ifdef HAVE_BKTR
476 __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
477#endif
478 DO_THREAD_CRASH;
479 }
480
481 if (--lt->reentrancy < 0) {
482 log_mutex_error(canlog, "%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
483 filename, lineno, func, mutex_name);
484 lt->reentrancy = 0;
485 }
486
487 if (lt->reentrancy < AST_MAX_REENTRANCY) {
488 lt->file[lt->reentrancy] = NULL;
489 lt->lineno[lt->reentrancy] = 0;
490 lt->func[lt->reentrancy] = NULL;
491 lt->thread_id[lt->reentrancy] = 0;
492 }
493
494#ifdef HAVE_BKTR
495 if (lt->reentrancy) {
496 bt = &lt->backtrace[lt->reentrancy - 1];
497 }
498#endif
499 ast_reentrancy_unlock(lt);
500
501 ast_remove_lock_info(t, bt);
502 }
503#endif /* DEBUG_THREADS */
504
505 res = pthread_mutex_unlock(&t->mutex);
506
507#ifdef DEBUG_THREADS
508 if (res) {
509 log_mutex_error(canlog, "%s line %d (%s): Error releasing mutex: %s\n",
510 filename, lineno, func, strerror(res));
511 DO_THREAD_CRASH;
512 }
513#endif /* DEBUG_THREADS */
514
515 return res;
516}

References AST_MAX_REENTRANCY, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_mutex_info::mutex, NULL, pthread_mutex_t, pthread_mutex_unlock, ast_lock_track::reentrancy, ROFFSET, and ast_lock_track::thread_id.

Referenced by __ao2_unlock().

◆ __ast_rwlock_destroy()

int __ast_rwlock_destroy ( const char *  filename,
int  lineno,
const char *  func,
const char *  rwlock_name,
ast_rwlock_t t 
)

Definition at line 730 of file lock.c.

731{
732 int res;
733
734#ifdef DEBUG_THREADS
735 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 1);
736 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
737
738#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
739 if (t->lock == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
740 log_mutex_error(canlog, "%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
741 filename, lineno, func, rwlock_name);
742 DO_THREAD_CRASH;
743 res = EINVAL;
744 goto lt_cleanup;
745 }
746#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
747#endif /* DEBUG_THREADS */
748
749 res = pthread_rwlock_destroy(&t->lock);
750
751#ifdef DEBUG_THREADS
752 if (res) {
753 log_mutex_error(canlog, "%s line %d (%s): Error destroying rwlock %s: %s\n",
754 filename, lineno, func, rwlock_name, strerror(res));
755 }
756#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
757lt_cleanup:
758#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
759 if (lt) {
760 ast_reentrancy_lock(lt);
761 lt->file[0] = filename;
762 lt->lineno[0] = lineno;
763 lt->func[0] = func;
764 lt->reentrancy = 0;
765 lt->thread_id[0] = 0;
766#ifdef HAVE_BKTR
767 memset(&lt->backtrace[0], 0, sizeof(lt->backtrace[0]));
768#endif
769 ast_reentrancy_unlock(lt);
770 delete_reentrancy_cs(&t->track);
771 }
772#endif /* DEBUG_THREADS */
773
774 return res;
775}
#define __AST_RWLOCK_INIT_VALUE
Definition: lock.h:84
pthread_rwlock_t lock
Definition: lock.h:158

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, and ast_lock_track::thread_id.

◆ __ast_rwlock_init()

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 696 of file lock.c.

698{
699 int res;
700 pthread_rwlockattr_t attr;
701
702#if defined(DEBUG_THREADS) && defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && \
703 defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
704 if (t->lock != ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
705 int canlog = tracking && strcmp(filename, "logger.c");
706
707 log_mutex_error(canlog, "%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
708 filename, lineno, func, rwlock_name);
709 DO_THREAD_CRASH;
710 return EBUSY;
711 }
712#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
713
714#if defined(DEBUG_THREADS) || defined(DETECT_DEADLOCKS)
715 t->track = NULL;
716 t->flags.tracking = tracking;
717 t->flags.setup = 0;
718#endif /* DEBUG_THREADS */
719
720 pthread_rwlockattr_init(&attr);
721#ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
722 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
723#endif
724 res = pthread_rwlock_init(&t->lock, &attr);
725 pthread_rwlockattr_destroy(&attr);
726
727 return res;
728}

References __AST_RWLOCK_INIT_VALUE, ast_lock_track::func, ast_lock_track::lineno, ast_rwlock_info::lock, and NULL.

◆ __ast_rwlock_rdlock()

int __ast_rwlock_rdlock ( const char *  filename,
int  line,
const char *  func,
ast_rwlock_t t,
const char *  name 
)

Definition at line 848 of file lock.c.

850{
851 int res;
852
853#if defined(DEBUG_THREADS) || defined(DETECT_DEADLOCKS)
854 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
855#endif
856
857#ifdef DEBUG_THREADS
858 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
859 struct ast_bt *bt = NULL;
860
861 if (lt) {
862#ifdef HAVE_BKTR
863 struct ast_bt tmp;
864
865 /* The implementation of backtrace() may have its own locks.
866 * Capture the backtrace outside of the reentrancy lock to
867 * avoid deadlocks. See ASTERISK-22455. */
869
870 ast_reentrancy_lock(lt);
871 if (lt->reentrancy < AST_MAX_REENTRANCY) {
872 lt->backtrace[lt->reentrancy] = tmp;
873 bt = &lt->backtrace[lt->reentrancy];
874 }
875 ast_reentrancy_unlock(lt);
876#endif
877 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
878 }
879#endif /* DEBUG_THREADS */
880
881#if defined(DETECT_DEADLOCKS)
882 {
883 time_t seconds = time(NULL);
884 time_t wait_time, reported_wait = 0;
885 do {
886 res = pthread_rwlock_tryrdlock(&t->lock);
887 if (res == EBUSY) {
888 wait_time = time(NULL) - seconds;
889 if (wait_time > reported_wait && (wait_time % 5) == 0) {
890 log_mutex_error(canlog, "%s line %d (%s): Deadlock? waited %d sec for readlock '%s'?\n",
891 filename, line, func, (int)wait_time, name);
892#ifdef DEBUG_THREADS
893 if (lt) {
894 ast_reentrancy_lock(lt);
895#ifdef HAVE_BKTR
896 __dump_backtrace(&lt->backtrace[lt->reentrancy], canlog);
897#endif
898 log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
899 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
900 lt->func[lt->reentrancy-1], name);
901#ifdef HAVE_BKTR
902 __dump_backtrace(&lt->backtrace[lt->reentrancy-1], canlog);
903#endif
904 ast_reentrancy_unlock(lt);
905 }
906#endif
907 reported_wait = wait_time;
908 }
909 usleep(200);
910 }
911 } while (res == EBUSY);
912 }
913#else /* !DETECT_DEADLOCKS */
914 res = pthread_rwlock_rdlock(&t->lock);
915#endif /* !DETECT_DEADLOCKS */
916
917#ifdef DEBUG_THREADS
918 if (!res && lt) {
919 ast_reentrancy_lock(lt);
920 if (lt->reentrancy < AST_MAX_REENTRANCY) {
921 lt->file[lt->reentrancy] = filename;
922 lt->lineno[lt->reentrancy] = line;
923 lt->func[lt->reentrancy] = func;
924 lt->thread_id[lt->reentrancy] = pthread_self();
925 lt->reentrancy++;
926 }
927 ast_reentrancy_unlock(lt);
928 ast_mark_lock_acquired(t);
929 } else if (lt) {
930#ifdef HAVE_BKTR
931 if (lt->reentrancy) {
932 ast_reentrancy_lock(lt);
933 bt = &lt->backtrace[lt->reentrancy-1];
934 ast_reentrancy_unlock(lt);
935 } else {
936 bt = NULL;
937 }
938#endif
939 ast_remove_lock_info(t, bt);
940 }
941
942 if (res) {
943 log_mutex_error(canlog, "%s line %d (%s): Error obtaining read lock: %s\n",
944 filename, line, func, strerror(res));
945 DO_THREAD_CRASH;
946 }
947#endif /* DEBUG_THREADS */
948
949 return res;
950}
@ AST_RDLOCK
Definition: check_expr.c:37
static const char name[]
Definition: format_mp3.c:68

References ast_bt_get_addresses, AST_MAX_REENTRANCY, AST_RDLOCK, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_rwlock_info::lock, name, NULL, ast_lock_track::reentrancy, ast_lock_track::thread_id, and tmp().

Referenced by __ao2_global_obj_ref(), __ao2_lock(), and __ast_heap_rdlock().

◆ __ast_rwlock_timedrdlock()

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 1055 of file lock.c.

1057{
1058 int res;
1059
1060#ifdef DEBUG_THREADS
1061 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1062 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
1063 struct ast_bt *bt = NULL;
1064
1065 if (lt) {
1066#ifdef HAVE_BKTR
1067 struct ast_bt tmp;
1068
1069 /* The implementation of backtrace() may have its own locks.
1070 * Capture the backtrace outside of the reentrancy lock to
1071 * avoid deadlocks. See ASTERISK-22455. */
1073
1074 ast_reentrancy_lock(lt);
1075 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1076 lt->backtrace[lt->reentrancy] = tmp;
1077 bt = &lt->backtrace[lt->reentrancy];
1078 }
1079 ast_reentrancy_unlock(lt);
1080#endif
1081 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1082 }
1083#endif /* DEBUG_THREADS */
1084
1085#ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1086 res = pthread_rwlock_timedrdlock(&t->lock, abs_timeout);
1087#else
1088 do {
1089 struct timeval _now;
1090 for (;;) {
1091 if (!(res = pthread_rwlock_tryrdlock(&t->lock))) {
1092 break;
1093 }
1094 _now = ast_tvnow();
1095 if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1096 break;
1097 }
1098 usleep(1);
1099 }
1100 } while (0);
1101#endif
1102
1103#ifdef DEBUG_THREADS
1104 if (!res && lt) {
1105 ast_reentrancy_lock(lt);
1106 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1107 lt->file[lt->reentrancy] = filename;
1108 lt->lineno[lt->reentrancy] = line;
1109 lt->func[lt->reentrancy] = func;
1110 lt->thread_id[lt->reentrancy] = pthread_self();
1111 lt->reentrancy++;
1112 }
1113 ast_reentrancy_unlock(lt);
1114 ast_mark_lock_acquired(t);
1115 } else if (lt) {
1116#ifdef HAVE_BKTR
1117 if (lt->reentrancy) {
1118 ast_reentrancy_lock(lt);
1119 bt = &lt->backtrace[lt->reentrancy-1];
1120 ast_reentrancy_unlock(lt);
1121 } else {
1122 bt = NULL;
1123 }
1124#endif
1125 ast_remove_lock_info(t, bt);
1126 }
1127 if (res) {
1128 log_mutex_error(canlog, "%s line %d (%s): Error obtaining read lock: %s\n",
1129 filename, line, func, strerror(res));
1130 DO_THREAD_CRASH;
1131 }
1132#endif /* DEBUG_THREADS */
1133
1134 return res;
1135}
@ AST_WRLOCK
Definition: check_expr.c:38
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159

References ast_bt_get_addresses, AST_MAX_REENTRANCY, ast_tvnow(), AST_WRLOCK, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_rwlock_info::lock, name, NULL, ast_lock_track::reentrancy, ast_lock_track::thread_id, and tmp().

◆ __ast_rwlock_timedwrlock()

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 1137 of file lock.c.

1139{
1140 int res;
1141
1142#ifdef DEBUG_THREADS
1143 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1144 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
1145 struct ast_bt *bt = NULL;
1146
1147 if (lt) {
1148#ifdef HAVE_BKTR
1149 struct ast_bt tmp;
1150
1151 /* The implementation of backtrace() may have its own locks.
1152 * Capture the backtrace outside of the reentrancy lock to
1153 * avoid deadlocks. See ASTERISK-22455. */
1155
1156 ast_reentrancy_lock(lt);
1157 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1158 lt->backtrace[lt->reentrancy] = tmp;
1159 bt = &lt->backtrace[lt->reentrancy];
1160 }
1161 ast_reentrancy_unlock(lt);
1162#endif
1163 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1164 }
1165#endif /* DEBUG_THREADS */
1166
1167#ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1168 res = pthread_rwlock_timedwrlock(&t->lock, abs_timeout);
1169#else
1170 do {
1171 struct timeval _now;
1172 for (;;) {
1173 if (!(res = pthread_rwlock_trywrlock(&t->lock))) {
1174 break;
1175 }
1176 _now = ast_tvnow();
1177 if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1178 break;
1179 }
1180 usleep(1);
1181 }
1182 } while (0);
1183#endif
1184
1185#ifdef DEBUG_THREADS
1186 if (!res && lt) {
1187 ast_reentrancy_lock(lt);
1188 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1189 lt->file[lt->reentrancy] = filename;
1190 lt->lineno[lt->reentrancy] = line;
1191 lt->func[lt->reentrancy] = func;
1192 lt->thread_id[lt->reentrancy] = pthread_self();
1193 lt->reentrancy++;
1194 }
1195 ast_reentrancy_unlock(lt);
1196 ast_mark_lock_acquired(t);
1197 } else if (lt) {
1198#ifdef HAVE_BKTR
1199 if (lt->reentrancy) {
1200 ast_reentrancy_lock(lt);
1201 bt = &lt->backtrace[lt->reentrancy-1];
1202 ast_reentrancy_unlock(lt);
1203 } else {
1204 bt = NULL;
1205 }
1206#endif
1207 ast_remove_lock_info(t, bt);
1208 }
1209 if (res) {
1210 log_mutex_error(canlog, "%s line %d (%s): Error obtaining read lock: %s\n",
1211 filename, line, func, strerror(res));
1212 DO_THREAD_CRASH;
1213 }
1214#endif /* DEBUG_THREADS */
1215
1216 return res;
1217}

References ast_bt_get_addresses, AST_MAX_REENTRANCY, ast_tvnow(), AST_WRLOCK, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_rwlock_info::lock, name, NULL, ast_lock_track::reentrancy, ast_lock_track::thread_id, and tmp().

◆ __ast_rwlock_tryrdlock()

int __ast_rwlock_tryrdlock ( const char *  filename,
int  line,
const char *  func,
ast_rwlock_t t,
const char *  name 
)

Definition at line 1219 of file lock.c.

1220{
1221 int res;
1222
1223#ifdef DEBUG_THREADS
1224 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1225 struct ast_bt *bt = NULL;
1226
1227 if (lt) {
1228#ifdef HAVE_BKTR
1229 struct ast_bt tmp;
1230
1231 /* The implementation of backtrace() may have its own locks.
1232 * Capture the backtrace outside of the reentrancy lock to
1233 * avoid deadlocks. See ASTERISK-22455. */
1235
1236 ast_reentrancy_lock(lt);
1237 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1238 lt->backtrace[lt->reentrancy] = tmp;
1239 bt = &lt->backtrace[lt->reentrancy];
1240 }
1241 ast_reentrancy_unlock(lt);
1242#endif
1243 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
1244 }
1245#endif /* DEBUG_THREADS */
1246
1247 res = pthread_rwlock_tryrdlock(&t->lock);
1248
1249#ifdef DEBUG_THREADS
1250 if (!res && lt) {
1251 ast_reentrancy_lock(lt);
1252 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1253 lt->file[lt->reentrancy] = filename;
1254 lt->lineno[lt->reentrancy] = line;
1255 lt->func[lt->reentrancy] = func;
1256 lt->thread_id[lt->reentrancy] = pthread_self();
1257 lt->reentrancy++;
1258 }
1259 ast_reentrancy_unlock(lt);
1260 ast_mark_lock_acquired(t);
1261 } else if (lt) {
1263 }
1264#endif /* DEBUG_THREADS */
1265
1266 return res;
1267}

References ast_bt_get_addresses, ast_mark_lock_failed(), AST_MAX_REENTRANCY, AST_RDLOCK, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_rwlock_info::lock, name, NULL, ast_lock_track::reentrancy, ast_lock_track::thread_id, and tmp().

Referenced by __ao2_trylock().

◆ __ast_rwlock_trywrlock()

int __ast_rwlock_trywrlock ( const char *  filename,
int  line,
const char *  func,
ast_rwlock_t t,
const char *  name 
)

Definition at line 1269 of file lock.c.

1270{
1271 int res;
1272
1273#ifdef DEBUG_THREADS
1274 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1275 struct ast_bt *bt = NULL;
1276
1277 if (lt) {
1278#ifdef HAVE_BKTR
1279 struct ast_bt tmp;
1280
1281 /* The implementation of backtrace() may have its own locks.
1282 * Capture the backtrace outside of the reentrancy lock to
1283 * avoid deadlocks. See ASTERISK-22455. */
1285
1286 ast_reentrancy_lock(lt);
1287 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1288 lt->backtrace[lt->reentrancy] = tmp;
1289 bt = &lt->backtrace[lt->reentrancy];
1290 }
1291 ast_reentrancy_unlock(lt);
1292#endif
1293 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1294 }
1295#endif /* DEBUG_THREADS */
1296
1297 res = pthread_rwlock_trywrlock(&t->lock);
1298
1299#ifdef DEBUG_THREADS
1300 if (!res && lt) {
1301 ast_reentrancy_lock(lt);
1302 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1303 lt->file[lt->reentrancy] = filename;
1304 lt->lineno[lt->reentrancy] = line;
1305 lt->func[lt->reentrancy] = func;
1306 lt->thread_id[lt->reentrancy] = pthread_self();
1307 lt->reentrancy++;
1308 }
1309 ast_reentrancy_unlock(lt);
1310 ast_mark_lock_acquired(t);
1311 } else if (lt) {
1313 }
1314#endif /* DEBUG_THREADS */
1315
1316 return res;
1317}

References ast_bt_get_addresses, ast_mark_lock_failed(), AST_MAX_REENTRANCY, AST_WRLOCK, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_rwlock_info::lock, name, NULL, ast_lock_track::reentrancy, ast_lock_track::thread_id, and tmp().

Referenced by __ao2_trylock().

◆ __ast_rwlock_unlock()

int __ast_rwlock_unlock ( const char *  filename,
int  line,
const char *  func,
ast_rwlock_t t,
const char *  name 
)

Definition at line 777 of file lock.c.

778{
779 int res;
780
781#ifdef DEBUG_THREADS
782 struct ast_lock_track *lt = NULL;
783 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
784 struct ast_bt *bt = NULL;
785 int lock_found = 0;
786
787#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
788 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
789 log_mutex_error(canlog, "%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
790 filename, line, func, name);
791 DO_THREAD_CRASH;
792 return EINVAL;
793 }
794#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
795
796 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
797 if (lt) {
798 ast_reentrancy_lock(lt);
799 if (lt->reentrancy) {
800 int i;
801 pthread_t self = pthread_self();
802 for (i = lt->reentrancy - 1; i >= 0; --i) {
803 if (lt->thread_id[i] == self) {
804 lock_found = 1;
805 if (i != lt->reentrancy - 1) {
806 lt->file[i] = lt->file[lt->reentrancy - 1];
807 lt->lineno[i] = lt->lineno[lt->reentrancy - 1];
808 lt->func[i] = lt->func[lt->reentrancy - 1];
809 lt->thread_id[i] = lt->thread_id[lt->reentrancy - 1];
810 }
811#ifdef HAVE_BKTR
812 bt = &lt->backtrace[i];
813#endif
814 lt->file[lt->reentrancy - 1] = NULL;
815 lt->lineno[lt->reentrancy - 1] = 0;
816 lt->func[lt->reentrancy - 1] = NULL;
818 break;
819 }
820 }
821 }
822
823 if (lock_found && --lt->reentrancy < 0) {
824 log_mutex_error(canlog, "%s line %d (%s): rwlock '%s' freed more times than we've locked!\n",
825 filename, line, func, name);
826 lt->reentrancy = 0;
827 }
828
829 ast_reentrancy_unlock(lt);
830
831 ast_remove_lock_info(t, bt);
832 }
833#endif /* DEBUG_THREADS */
834
835 res = pthread_rwlock_unlock(&t->lock);
836
837#ifdef DEBUG_THREADS
838 if (res) {
839 log_mutex_error(canlog, "%s line %d (%s): Error releasing rwlock: %s\n",
840 filename, line, func, strerror(res));
841 DO_THREAD_CRASH;
842 }
843#endif /* DEBUG_THREADS */
844
845 return res;
846}
#define AST_PTHREADT_NULL
Definition: lock.h:66

References __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, name, NULL, ast_lock_track::reentrancy, and ast_lock_track::thread_id.

Referenced by __ao2_global_obj_ref(), __ao2_global_obj_replace(), __ao2_unlock(), and __ast_heap_unlock().

◆ __ast_rwlock_wrlock()

int __ast_rwlock_wrlock ( const char *  filename,
int  line,
const char *  func,
ast_rwlock_t t,
const char *  name 
)

Definition at line 952 of file lock.c.

954{
955 int res;
956
957#if defined(DEBUG_THREADS) || defined(DETECT_DEADLOCKS)
958 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
959#endif
960
961#ifdef DEBUG_THREADS
962 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
963 struct ast_bt *bt = NULL;
964
965 if (lt) {
966#ifdef HAVE_BKTR
967 struct ast_bt tmp;
968
969 /* The implementation of backtrace() may have its own locks.
970 * Capture the backtrace outside of the reentrancy lock to
971 * avoid deadlocks. See ASTERISK-22455. */
973
974 ast_reentrancy_lock(lt);
975 if (lt->reentrancy < AST_MAX_REENTRANCY) {
976 lt->backtrace[lt->reentrancy] = tmp;
977 bt = &lt->backtrace[lt->reentrancy];
978 }
979 ast_reentrancy_unlock(lt);
980#endif
981 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
982 }
983#endif /* DEBUG_THREADS */
984
985#ifdef DETECT_DEADLOCKS
986 {
987 time_t seconds = time(NULL);
988 time_t wait_time, reported_wait = 0;
989 do {
990 res = pthread_rwlock_trywrlock(&t->lock);
991 if (res == EBUSY) {
992 wait_time = time(NULL) - seconds;
993 if (wait_time > reported_wait && (wait_time % 5) == 0) {
994 log_mutex_error(canlog, "%s line %d (%s): Deadlock? waited %d sec for writelock '%s'?\n",
995 filename, line, func, (int)wait_time, name);
996#ifdef DEBUG_THREADS
997 if (lt) {
998 ast_reentrancy_lock(lt);
999#ifdef HAVE_BKTR
1000 __dump_backtrace(&lt->backtrace[lt->reentrancy], canlog);
1001#endif
1002 log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
1003 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
1004 lt->func[lt->reentrancy-1], name);
1005#ifdef HAVE_BKTR
1006 __dump_backtrace(&lt->backtrace[lt->reentrancy-1], canlog);
1007#endif
1008 ast_reentrancy_unlock(lt);
1009 }
1010#endif
1011 reported_wait = wait_time;
1012 }
1013 usleep(200);
1014 }
1015 } while (res == EBUSY);
1016 }
1017#else /* !DETECT_DEADLOCKS */
1018 res = pthread_rwlock_wrlock(&t->lock);
1019#endif /* !DETECT_DEADLOCKS */
1020
1021#ifdef DEBUG_THREADS
1022 if (!res && lt) {
1023 ast_reentrancy_lock(lt);
1024 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1025 lt->file[lt->reentrancy] = filename;
1026 lt->lineno[lt->reentrancy] = line;
1027 lt->func[lt->reentrancy] = func;
1028 lt->thread_id[lt->reentrancy] = pthread_self();
1029 lt->reentrancy++;
1030 }
1031 ast_reentrancy_unlock(lt);
1032 ast_mark_lock_acquired(t);
1033 } else if (lt) {
1034#ifdef HAVE_BKTR
1035 if (lt->reentrancy) {
1036 ast_reentrancy_lock(lt);
1037 bt = &lt->backtrace[lt->reentrancy-1];
1038 ast_reentrancy_unlock(lt);
1039 } else {
1040 bt = NULL;
1041 }
1042#endif
1043 ast_remove_lock_info(t, bt);
1044 }
1045 if (res) {
1046 log_mutex_error(canlog, "%s line %d (%s): Error obtaining write lock: %s\n",
1047 filename, line, func, strerror(res));
1048 DO_THREAD_CRASH;
1049 }
1050#endif /* DEBUG_THREADS */
1051
1052 return res;
1053}

References ast_bt_get_addresses, AST_MAX_REENTRANCY, AST_WRLOCK, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_rwlock_info::lock, name, NULL, ast_lock_track::reentrancy, ast_lock_track::thread_id, and tmp().

Referenced by __ao2_global_obj_replace(), __ao2_lock(), and __ast_heap_wrlock().