Asterisk - The Open Source Telephony Project GIT-master-8f1982c
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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 536 of file lock.c.

538{
540}
ast_cond_t cond
Definition: app_sla.c:336
#define pthread_cond_broadcast
Definition: lock.h:640

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

544{
546}
#define pthread_cond_destroy
Definition: lock.h:638

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

526{
527 return pthread_cond_init(cond, cond_attr);
528}
#define pthread_cond_init
Definition: lock.h:637

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

532{
534}
#define pthread_cond_signal
Definition: lock.h:639

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

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

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

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

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:634
#define pthread_mutex_unlock
Definition: lock.h:633
#define pthread_mutex_destroy
Definition: lock.h:636

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:84
#define pthread_mutex_init
Definition: lock.h:635

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 <since>
326 <version>16.29.0</version>
327 <version>18.15.0</version>
328 <version>19.7.0</version>
329 </since>
330 <synopsis>Raised when a probable deadlock has started.
331 Delivery of this event is attempted but not guaranteed,
332 and could fail for example if the manager itself is deadlocked.
333 </synopsis>
334 <syntax>
335 <parameter name="Mutex">
336 <para>The mutex involved in the deadlock.</para>
337 </parameter>
338 </syntax>
339 </managerEventInstance>
340 </managerEvent>
341 ***/
342 manager_event(EVENT_FLAG_SYSTEM, "DeadlockStart",
343 "Mutex: %s\r\n",
344 mutex_name);
345 }
346 }
347 usleep(200);
348 }
349 } while (res == EBUSY);
350 }
351#else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
352#ifdef HAVE_MTX_PROFILE
353 ast_mark(mtx_prof, 1);
354 res = pthread_mutex_trylock(&t->mutex);
355 ast_mark(mtx_prof, 0);
356 if (res)
357#endif
358 res = pthread_mutex_lock(&t->mutex);
359#endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
360
361#ifdef DEBUG_THREADS
362 if (lt && !res) {
363 ast_reentrancy_lock(lt);
364 if (lt->reentrancy < AST_MAX_REENTRANCY) {
365 lt->file[lt->reentrancy] = filename;
366 lt->lineno[lt->reentrancy] = lineno;
367 lt->func[lt->reentrancy] = func;
368 lt->thread_id[lt->reentrancy] = pthread_self();
369 lt->reentrancy++;
370 } else {
371 log_mutex_error(canlog, "%s line %d (%s): '%s' really deep reentrancy!\n",
372 filename, lineno, func, mutex_name);
373 }
374 ast_reentrancy_unlock(lt);
375 ast_mark_lock_acquired(t);
376 } else if (lt) {
377#ifdef HAVE_BKTR
378 if (lt->reentrancy) {
379 ast_reentrancy_lock(lt);
380 bt = &lt->backtrace[lt->reentrancy-1];
381 ast_reentrancy_unlock(lt);
382 } else {
383 bt = NULL;
384 }
385#endif
386 ast_remove_lock_info(t, bt);
387 }
388 if (res) {
389 log_mutex_error(canlog, "%s line %d (%s): Error obtaining mutex: %s\n",
390 filename, lineno, func, strerror(res));
391 DO_THREAD_CRASH;
392 }
393#endif /* DEBUG_THREADS */
394
395 return res;
396}
int64_t ast_mark(int, int start1_stop0)
Definition: astman.c:103
#define ast_bt_get_addresses(bt)
Definition: backtrace.h:38
@ AST_MUTEX
Definition: check_expr.c:36
#define AST_MAX_REENTRANCY
Definition: lock.h:108
#define pthread_mutex_lock
Definition: lock.h:632
#define manager_event(category, event, contents,...)
External routines may send asterisk manager events this way.
Definition: manager.h:254
#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, and ast_lock_track::thread_id.

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

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

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

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

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

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

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

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

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

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

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

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

◆ __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 1142 of file lock.c.

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

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

◆ __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 1224 of file lock.c.

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

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

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

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

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

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

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

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

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

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

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