Asterisk - The Open Source Telephony Project GIT-master-266378a
Loading...
Searching...
No Matches
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 549 of file lock.c.

551{
553}
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 555 of file lock.c.

557{
559}
#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 537 of file lock.c.

539{
540 return pthread_cond_init(cond, cond_attr);
541}
#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 543 of file lock.c.

545{
547}
#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 649 of file lock.c.

652{
653 int res;
654
655#ifdef DEBUG_THREADS
656 struct ast_lock_track *lt = NULL;
657 struct ast_lock_track lt_orig;
658 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
659
660#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
661 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
662 log_mutex_error(canlog, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
663 filename, lineno, func, mutex_name);
664 DO_THREAD_CRASH;
665 return EINVAL;
666 }
667#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
668
669 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
670 if (lt) {
671 ast_reentrancy_lock(lt);
672 if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) {
673 log_mutex_error(canlog, "%s line %d (%s): attempted wait using mutex '%s' without owning it!\n",
674 filename, lineno, func, mutex_name);
675 log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
676 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
677#ifdef HAVE_BKTR
678 __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
679#endif
680 DO_THREAD_CRASH;
681 } else if (lt->reentrancy <= 0) {
682 log_mutex_error(canlog, "%s line %d (%s): attempted wait using an unlocked mutex '%s'\n",
683 filename, lineno, func, mutex_name);
684 DO_THREAD_CRASH;
685 }
686
687 /* Waiting on a condition completely suspends a recursive mutex,
688 * even if it's been recursively locked multiple times. Make a
689 * copy of the lock tracking, and reset reentrancy to zero */
690 lt_orig = *lt;
691 lt->reentrancy = 0;
692 ast_reentrancy_unlock(lt);
693
694 ast_suspend_lock_info(t);
695 }
696#endif /* DEBUG_THREADS */
697
698 res = pthread_cond_timedwait(cond, &t->mutex, abstime);
699
700#ifdef DEBUG_THREADS
701 if (res && (res != ETIMEDOUT)) {
702 log_mutex_error(canlog, "%s line %d (%s): Error waiting on condition mutex '%s'\n",
703 filename, lineno, func, strerror(res));
704 DO_THREAD_CRASH;
705 } else if (lt) {
706 restore_lock_tracking(lt, &lt_orig);
707 ast_restore_lock_info(t);
708 }
709#endif /* DEBUG_THREADS */
710
711 return res;
712}
#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 584 of file lock.c.

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

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#ifndef DEBUG_THREADS
513 /*
514 * An unlock failure (e.g. EPERM) means the mutex may stay locked.
515 * The strcmp only runs when the unlock failed, so there is no
516 * performance impact on normal unlocks. It avoids recursion if the
517 * logger's own mutex fails to unlock.
518 */
519 if (res && strcmp(filename, "logger.c")) {
520 ast_log(LOG_ERROR, "Failed to unlock mutex '%s' at %s:%d (%s): %s\n",
521 mutex_name, filename, lineno, func, strerror(res));
522 }
523#endif
524
525#ifdef DEBUG_THREADS
526 if (res) {
527 log_mutex_error(canlog, "%s line %d (%s): Error releasing mutex: %s\n",
528 filename, lineno, func, strerror(res));
529 DO_THREAD_CRASH;
530 }
531#endif /* DEBUG_THREADS */
532
533 return res;
534}
#define ast_log
Definition astobj2.c:42
#define LOG_ERROR

References ast_log, AST_MAX_REENTRANCY, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, LOG_ERROR, 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 748 of file lock.c.

749{
750 int res;
751
752#ifdef DEBUG_THREADS
753 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 1);
754 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
755
756#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
757 if (t->lock == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
758 log_mutex_error(canlog, "%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
759 filename, lineno, func, rwlock_name);
760 DO_THREAD_CRASH;
761 res = EINVAL;
762 goto lt_cleanup;
763 }
764#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
765#endif /* DEBUG_THREADS */
766
767 res = pthread_rwlock_destroy(&t->lock);
768
769#ifdef DEBUG_THREADS
770 if (res) {
771 log_mutex_error(canlog, "%s line %d (%s): Error destroying rwlock %s: %s\n",
772 filename, lineno, func, rwlock_name, strerror(res));
773 }
774#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
775lt_cleanup:
776#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
777 if (lt) {
778 ast_reentrancy_lock(lt);
779 lt->file[0] = filename;
780 lt->lineno[0] = lineno;
781 lt->func[0] = func;
782 lt->reentrancy = 0;
783 lt->thread_id[0] = 0;
784#ifdef HAVE_BKTR
785 memset(&lt->backtrace[0], 0, sizeof(lt->backtrace[0]));
786#endif
787 ast_reentrancy_unlock(lt);
788 delete_reentrancy_cs(&t->track);
789 }
790#endif /* DEBUG_THREADS */
791
792 return res;
793}
#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 714 of file lock.c.

716{
717 int res;
718 pthread_rwlockattr_t attr;
719
720#if defined(DEBUG_THREADS) && defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && \
721 defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
722 if (t->lock != ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
723 int canlog = tracking && strcmp(filename, "logger.c");
724
725 log_mutex_error(canlog, "%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
726 filename, lineno, func, rwlock_name);
727 DO_THREAD_CRASH;
728 return EBUSY;
729 }
730#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
731
732#if defined(DEBUG_THREADS) || defined(DETECT_DEADLOCKS)
733 t->track = NULL;
734 t->flags.tracking = tracking;
735 t->flags.setup = 0;
736#endif /* DEBUG_THREADS */
737
738 pthread_rwlockattr_init(&attr);
739#ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
740 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
741#endif
742 res = pthread_rwlock_init(&t->lock, &attr);
743 pthread_rwlockattr_destroy(&attr);
744
745 return res;
746}

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

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

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

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

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

1238{
1239 int res;
1240
1241#ifdef DEBUG_THREADS
1242 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1243 struct ast_bt *bt = NULL;
1244
1245 if (lt) {
1246#ifdef HAVE_BKTR
1247 struct ast_bt tmp;
1248
1249 /* The implementation of backtrace() may have its own locks.
1250 * Capture the backtrace outside of the reentrancy lock to
1251 * avoid deadlocks. See ASTERISK-22455. */
1253
1254 ast_reentrancy_lock(lt);
1255 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1256 lt->backtrace[lt->reentrancy] = tmp;
1257 bt = &lt->backtrace[lt->reentrancy];
1258 }
1259 ast_reentrancy_unlock(lt);
1260#endif
1261 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
1262 }
1263#endif /* DEBUG_THREADS */
1264
1265 res = pthread_rwlock_tryrdlock(&t->lock);
1266
1267#ifdef DEBUG_THREADS
1268 if (!res && lt) {
1269 ast_reentrancy_lock(lt);
1270 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1271 lt->file[lt->reentrancy] = filename;
1272 lt->lineno[lt->reentrancy] = line;
1273 lt->func[lt->reentrancy] = func;
1274 lt->thread_id[lt->reentrancy] = pthread_self();
1275 lt->reentrancy++;
1276 }
1277 ast_reentrancy_unlock(lt);
1278 ast_mark_lock_acquired(t);
1279 } else if (lt) {
1281 }
1282#endif /* DEBUG_THREADS */
1283
1284 return res;
1285}

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

1288{
1289 int res;
1290
1291#ifdef DEBUG_THREADS
1292 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1293 struct ast_bt *bt = NULL;
1294
1295 if (lt) {
1296#ifdef HAVE_BKTR
1297 struct ast_bt tmp;
1298
1299 /* The implementation of backtrace() may have its own locks.
1300 * Capture the backtrace outside of the reentrancy lock to
1301 * avoid deadlocks. See ASTERISK-22455. */
1303
1304 ast_reentrancy_lock(lt);
1305 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1306 lt->backtrace[lt->reentrancy] = tmp;
1307 bt = &lt->backtrace[lt->reentrancy];
1308 }
1309 ast_reentrancy_unlock(lt);
1310#endif
1311 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1312 }
1313#endif /* DEBUG_THREADS */
1314
1315 res = pthread_rwlock_trywrlock(&t->lock);
1316
1317#ifdef DEBUG_THREADS
1318 if (!res && lt) {
1319 ast_reentrancy_lock(lt);
1320 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1321 lt->file[lt->reentrancy] = filename;
1322 lt->lineno[lt->reentrancy] = line;
1323 lt->func[lt->reentrancy] = func;
1324 lt->thread_id[lt->reentrancy] = pthread_self();
1325 lt->reentrancy++;
1326 }
1327 ast_reentrancy_unlock(lt);
1328 ast_mark_lock_acquired(t);
1329 } else if (lt) {
1331 }
1332#endif /* DEBUG_THREADS */
1333
1334 return res;
1335}

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

796{
797 int res;
798
799#ifdef DEBUG_THREADS
800 struct ast_lock_track *lt = NULL;
801 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
802 struct ast_bt *bt = NULL;
803 int lock_found = 0;
804
805#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
806 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
807 log_mutex_error(canlog, "%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
808 filename, line, func, name);
809 DO_THREAD_CRASH;
810 return EINVAL;
811 }
812#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
813
814 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
815 if (lt) {
816 ast_reentrancy_lock(lt);
817 if (lt->reentrancy) {
818 int i;
819 pthread_t self = pthread_self();
820 for (i = lt->reentrancy - 1; i >= 0; --i) {
821 if (lt->thread_id[i] == self) {
822 lock_found = 1;
823 if (i != lt->reentrancy - 1) {
824 lt->file[i] = lt->file[lt->reentrancy - 1];
825 lt->lineno[i] = lt->lineno[lt->reentrancy - 1];
826 lt->func[i] = lt->func[lt->reentrancy - 1];
827 lt->thread_id[i] = lt->thread_id[lt->reentrancy - 1];
828 }
829#ifdef HAVE_BKTR
830 bt = &lt->backtrace[i];
831#endif
832 lt->file[lt->reentrancy - 1] = NULL;
833 lt->lineno[lt->reentrancy - 1] = 0;
834 lt->func[lt->reentrancy - 1] = NULL;
836 break;
837 }
838 }
839 }
840
841 if (lock_found && --lt->reentrancy < 0) {
842 log_mutex_error(canlog, "%s line %d (%s): rwlock '%s' freed more times than we've locked!\n",
843 filename, line, func, name);
844 lt->reentrancy = 0;
845 }
846
847 ast_reentrancy_unlock(lt);
848
849 ast_remove_lock_info(t, bt);
850 }
851#endif /* DEBUG_THREADS */
852
853 res = pthread_rwlock_unlock(&t->lock);
854
855#ifdef DEBUG_THREADS
856 if (res) {
857 log_mutex_error(canlog, "%s line %d (%s): Error releasing rwlock: %s\n",
858 filename, line, func, strerror(res));
859 DO_THREAD_CRASH;
860 }
861#endif /* DEBUG_THREADS */
862
863 return res;
864}
#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 970 of file lock.c.

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

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().