Asterisk - The Open Source Telephony Project GIT-master-266378a
Loading...
Searching...
No Matches
lock.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2010, Digium, Inc.
5 *
6 * Mark Spencer <markster@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*! \file
20 *
21 * \brief General Asterisk locking.
22 */
23
24/*** MODULEINFO
25 <support_level>core</support_level>
26 ***/
27
28#include "asterisk.h"
29
30#ifdef HAVE_MTX_PROFILE
31/* profile mutex */
32static int mtx_prof = -1;
33static void __attribute__((constructor)) __mtx_init(void)
34{
35 mtx_prof = ast_add_profile("mtx_lock_" __FILE__, 0);
36}
37#endif
38
39#include "asterisk/utils.h"
40#include "asterisk/lock.h"
41#include "asterisk/manager.h"
42
43/* Allow direct use of pthread_mutex_* / pthread_cond_* */
44#undef pthread_mutex_init
45#undef pthread_mutex_destroy
46#undef pthread_mutex_lock
47#undef pthread_mutex_trylock
48#undef pthread_mutex_t
49#undef pthread_mutex_unlock
50#undef pthread_cond_init
51#undef pthread_cond_signal
52#undef pthread_cond_broadcast
53#undef pthread_cond_destroy
54#undef pthread_cond_wait
55#undef pthread_cond_timedwait
56
57#if defined(DEBUG_THREADS) || defined(DETECT_DEADLOCKS)
58#define log_mutex_error(canlog, ...) \
59 do { \
60 if (canlog) { \
61 ast_log(LOG_ERROR, __VA_ARGS__); \
62 } else { \
63 fprintf(stderr, __VA_ARGS__); \
64 } \
65 } while (0)
66#endif
67
68#if defined(DEBUG_THREADS) && defined(HAVE_BKTR)
69static void __dump_backtrace(struct ast_bt *bt, int canlog)
70{
71 char **strings;
72 ssize_t i;
73
74 strings = backtrace_symbols(bt->addresses, bt->num_frames);
75
76 for (i = 0; i < bt->num_frames; i++) {
77 log_mutex_error(canlog, "%s\n", strings[i]);
78 }
79
80 ast_std_free(strings);
81}
82#endif /* defined(DEBUG_THREADS) && defined(HAVE_BKTR) */
83
84#ifdef DEBUG_THREADS
85AST_MUTEX_DEFINE_STATIC(reentrancy_lock);
86
87static inline struct ast_lock_track *ast_get_reentrancy(struct ast_lock_track **plt,
88 struct ast_lock_track_flags *flags, int no_setup)
89{
90 pthread_mutexattr_t reentr_attr;
91 struct ast_lock_track *lt;
92
93 if (!flags->tracking || flags->setup) {
94 return *plt;
95 }
96
97 pthread_mutex_lock(&reentrancy_lock.mutex);
98
99 if (*plt) {
100 pthread_mutex_unlock(&reentrancy_lock.mutex);
101 return *plt;
102 }
103
104 if (no_setup) {
105 pthread_mutex_unlock(&reentrancy_lock.mutex);
106 return NULL;
107 }
108
109 lt = *plt = ast_std_calloc(1, sizeof(*lt));
110 if (!lt) {
111 fprintf(stderr, "%s: Failed to allocate lock tracking\n", __func__);
112#if defined(DO_CRASH) || defined(THREAD_CRASH)
113 abort();
114#else
115 pthread_mutex_unlock(&reentrancy_lock.mutex);
116 return NULL;
117#endif
118 }
119
120 pthread_mutexattr_init(&reentr_attr);
121 pthread_mutexattr_settype(&reentr_attr, AST_MUTEX_KIND);
122 pthread_mutex_init(&lt->reentr_mutex, &reentr_attr);
123 pthread_mutexattr_destroy(&reentr_attr);
124
125 flags->setup = 1;
126 pthread_mutex_unlock(&reentrancy_lock.mutex);
127 return lt;
128}
129
130static inline void delete_reentrancy_cs(struct ast_lock_track **plt)
131{
132 struct ast_lock_track *lt;
133
134 if (*plt) {
135 lt = *plt;
136 *plt = NULL;
137
139 ast_std_free(lt);
140 }
141}
142
143#endif /* DEBUG_THREADS */
144
145int __ast_pthread_mutex_init(int tracking, const char *filename, int lineno, const char *func,
146 const char *mutex_name, ast_mutex_t *t)
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}
176
177int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
178 const char *mutex_name, ast_mutex_t *t)
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}
254
255int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
256 const char* mutex_name, ast_mutex_t *t)
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}
397
398int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
399 const char* mutex_name, ast_mutex_t *t)
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}
452
453int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
454 const char *mutex_name, ast_mutex_t *t)
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}
535
536
537int __ast_cond_init(const char *filename, int lineno, const char *func,
538 const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
539{
540 return pthread_cond_init(cond, cond_attr);
541}
542
543int __ast_cond_signal(const char *filename, int lineno, const char *func,
544 const char *cond_name, ast_cond_t *cond)
545{
547}
548
549int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
550 const char *cond_name, ast_cond_t *cond)
551{
553}
554
555int __ast_cond_destroy(const char *filename, int lineno, const char *func,
556 const char *cond_name, ast_cond_t *cond)
557{
559}
560
561#ifdef DEBUG_THREADS
562static void restore_lock_tracking(struct ast_lock_track *lt, struct ast_lock_track *lt_saved)
563{
564 ast_reentrancy_lock(lt);
565
566 /*
567 * The following code must match the struct ast_lock_track
568 * definition with the explicit exception of the reentr_mutex
569 * member.
570 */
571 memcpy(lt->file, lt_saved->file, sizeof(lt->file));
572 memcpy(lt->lineno, lt_saved->lineno, sizeof(lt->lineno));
573 lt->reentrancy = lt_saved->reentrancy;
574 memcpy(lt->func, lt_saved->func, sizeof(lt->func));
575 memcpy(lt->thread_id, lt_saved->thread_id, sizeof(lt->thread_id));
576#ifdef HAVE_BKTR
577 memcpy(lt->backtrace, lt_saved->backtrace, sizeof(lt->backtrace));
578#endif
579
580 ast_reentrancy_unlock(lt);
581}
582#endif /* DEBUG_THREADS */
583
584int __ast_cond_wait(const char *filename, int lineno, const char *func,
585 const char *cond_name, const char *mutex_name,
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}
648
649int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
650 const char *cond_name, const char *mutex_name, ast_cond_t *cond,
651 ast_mutex_t *t, const struct timespec *abstime)
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}
713
714int __ast_rwlock_init(int tracking, const char *filename, int lineno, \
715 const char *func, const char *rwlock_name, ast_rwlock_t *t)
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}
747
748int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
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}
794
795int __ast_rwlock_unlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
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}
865
866int __ast_rwlock_rdlock(const char *filename, int line, const char *func,
867 ast_rwlock_t *t, const char *name)
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}
969
970int __ast_rwlock_wrlock(const char *filename, int line, const char *func, \
971 ast_rwlock_t *t, const char *name)
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}
1072
1073int __ast_rwlock_timedrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name,
1074 const struct timespec *abs_timeout)
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}
1154
1155int __ast_rwlock_timedwrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name,
1156 const struct timespec *abs_timeout)
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}
1236
1237int __ast_rwlock_tryrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
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}
1286
1287int __ast_rwlock_trywrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
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}
ast_cond_t cond
Definition app_sla.c:336
Asterisk main include file. File version handling, generic pbx functions.
int ast_add_profile(const char *, uint64_t scale)
support for event profiling
Definition astman.c:92
int64_t ast_mark(int, int start1_stop0)
Definition astman.c:103
void ast_std_free(void *ptr)
Definition astmm.c:1734
void * ast_std_calloc(size_t nmemb, size_t size) attribute_malloc
Definition astmm.c:1724
#define ast_log
Definition astobj2.c:42
#define ast_bt_get_addresses(bt)
Definition backtrace.h:38
@ AST_RDLOCK
Definition check_expr.c:37
@ AST_WRLOCK
Definition check_expr.c:38
@ AST_MUTEX
Definition check_expr.c:36
void ast_mark_lock_failed(void *lock_addr)
Definition extconf.c:2309
static const char name[]
Definition format_mp3.c:68
#define LOG_ERROR
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 lock.c:1073
int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
Definition lock.c:748
int __ast_rwlock_rdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
Definition lock.c:866
int __ast_cond_broadcast(const char *filename, int lineno, const char *func, const char *cond_name, ast_cond_t *cond)
Definition lock.c:549
int __ast_rwlock_tryrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
Definition lock.c:1237
int __ast_rwlock_init(int tracking, const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
Definition lock.c:714
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 lock.c:1155
int __ast_rwlock_unlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
Definition lock.c:795
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 lock.c:537
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 lock.c:584
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 lock.c:649
int __ast_cond_signal(const char *filename, int lineno, const char *func, const char *cond_name, ast_cond_t *cond)
Definition lock.c:543
int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
Definition lock.c:255
int __ast_pthread_mutex_init(int tracking, const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
Definition lock.c:145
int __ast_rwlock_trywrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
Definition lock.c:1287
int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
Definition lock.c:398
int __ast_cond_destroy(const char *filename, int lineno, const char *func, const char *cond_name, ast_cond_t *cond)
Definition lock.c:555
int __ast_rwlock_wrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
Definition lock.c:970
int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
Definition lock.c:177
int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
Definition lock.c:453
Asterisk locking-related definitions:
#define AST_MAX_REENTRANCY
Definition lock.h:108
#define __AST_RWLOCK_INIT_VALUE
Definition lock.h:91
#define ROFFSET
Definition lock.h:249
#define pthread_cond_broadcast
Definition lock.h:640
#define pthread_mutex_trylock
Definition lock.h:634
#define AST_PTHREADT_NULL
Definition lock.h:73
#define pthread_mutex_lock
Definition lock.h:632
#define pthread_mutex_t
Definition lock.h:629
#define AST_MUTEX_KIND
Definition lock.h:84
pthread_cond_t ast_cond_t
Definition lock.h:185
#define pthread_mutex_unlock
Definition lock.h:633
#define pthread_mutex_destroy
Definition lock.h:636
#define pthread_cond_destroy
Definition lock.h:638
#define pthread_cond_signal
Definition lock.h:639
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition lock.h:527
#define pthread_mutex_init
Definition lock.h:635
#define pthread_cond_init
Definition lock.h:637
#define pthread_cond_timedwait
Definition lock.h:642
#define pthread_cond_wait
Definition lock.h:641
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#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
#define NULL
Definition resample.c:96
A structure to hold backtrace information. This structure provides an easy means to store backtrace i...
Definition backtrace.h:50
void * addresses[AST_MAX_BT_FRAMES]
Definition backtrace.h:52
int num_frames
Definition backtrace.h:54
volatile unsigned int setup
Definition lock.h:134
unsigned int tracking
Definition lock.h:132
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
pthread_mutex_t reentr_mutex
Definition lock.h:127
const char * file[AST_MAX_REENTRANCY]
Definition lock.h:119
const char * func[AST_MAX_REENTRANCY]
Definition lock.h:122
Structure for mutex and tracking information.
Definition lock.h:142
pthread_mutex_t mutex
Definition lock.h:143
Structure for rwlock and tracking information.
Definition lock.h:164
pthread_rwlock_t lock
Definition lock.h:165
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159
Utility functions.