Asterisk - The Open Source Telephony Project GIT-master-0644429
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 <synopsis>Raised when a probable deadlock has started.
326 Delivery of this event is attempted but not guaranteed,
327 and could fail for example if the manager itself is deadlocked.
328 </synopsis>
329 <syntax>
330 <parameter name="Mutex">
331 <para>The mutex involved in the deadlock.</para>
332 </parameter>
333 </syntax>
334 </managerEventInstance>
335 </managerEvent>
336 ***/
337 manager_event(EVENT_FLAG_SYSTEM, "DeadlockStart",
338 "Mutex: %s\r\n",
339 mutex_name);
340 }
341 }
342 usleep(200);
343 }
344 } while (res == EBUSY);
345 }
346#else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
347#ifdef HAVE_MTX_PROFILE
348 ast_mark(mtx_prof, 1);
349 res = pthread_mutex_trylock(&t->mutex);
350 ast_mark(mtx_prof, 0);
351 if (res)
352#endif
353 res = pthread_mutex_lock(&t->mutex);
354#endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
355
356#ifdef DEBUG_THREADS
357 if (lt && !res) {
358 ast_reentrancy_lock(lt);
359 if (lt->reentrancy < AST_MAX_REENTRANCY) {
360 lt->file[lt->reentrancy] = filename;
361 lt->lineno[lt->reentrancy] = lineno;
362 lt->func[lt->reentrancy] = func;
363 lt->thread_id[lt->reentrancy] = pthread_self();
364 lt->reentrancy++;
365 } else {
366 log_mutex_error(canlog, "%s line %d (%s): '%s' really deep reentrancy!\n",
367 filename, lineno, func, mutex_name);
368 }
369 ast_reentrancy_unlock(lt);
370 ast_mark_lock_acquired(t);
371 } else if (lt) {
372#ifdef HAVE_BKTR
373 if (lt->reentrancy) {
374 ast_reentrancy_lock(lt);
375 bt = &lt->backtrace[lt->reentrancy-1];
376 ast_reentrancy_unlock(lt);
377 } else {
378 bt = NULL;
379 }
380#endif
381 ast_remove_lock_info(t, bt);
382 }
383 if (res) {
384 log_mutex_error(canlog, "%s line %d (%s): Error obtaining mutex: %s\n",
385 filename, lineno, func, strerror(res));
386 DO_THREAD_CRASH;
387 }
388#endif /* DEBUG_THREADS */
389
390 return res;
391}
392
393int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
394 const char* mutex_name, ast_mutex_t *t)
395{
396 int res;
397
398#ifdef DEBUG_THREADS
399 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
400 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
401 struct ast_bt *bt = NULL;
402
403 if (lt) {
404#ifdef HAVE_BKTR
405 struct ast_bt tmp;
406
407 /* The implementation of backtrace() may have its own locks.
408 * Capture the backtrace outside of the reentrancy lock to
409 * avoid deadlocks. See ASTERISK-22455. */
411
412 ast_reentrancy_lock(lt);
413 if (lt->reentrancy < AST_MAX_REENTRANCY) {
414 lt->backtrace[lt->reentrancy] = tmp;
415 bt = &lt->backtrace[lt->reentrancy];
416 }
417 ast_reentrancy_unlock(lt);
418#endif
419 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
420 }
421#endif /* DEBUG_THREADS */
422
423 res = pthread_mutex_trylock(&t->mutex);
424
425#ifdef DEBUG_THREADS
426 if (lt && !res) {
427 ast_reentrancy_lock(lt);
428 if (lt->reentrancy < AST_MAX_REENTRANCY) {
429 lt->file[lt->reentrancy] = filename;
430 lt->lineno[lt->reentrancy] = lineno;
431 lt->func[lt->reentrancy] = func;
432 lt->thread_id[lt->reentrancy] = pthread_self();
433 lt->reentrancy++;
434 } else {
435 log_mutex_error(canlog, "%s line %d (%s): '%s' really deep reentrancy!\n",
436 filename, lineno, func, mutex_name);
437 }
438 ast_reentrancy_unlock(lt);
439 ast_mark_lock_acquired(t);
440 } else if (lt) {
442 }
443#endif /* DEBUG_THREADS */
444
445 return res;
446}
447
448int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
449 const char *mutex_name, ast_mutex_t *t)
450{
451 int res;
452
453#ifdef DEBUG_THREADS
454 struct ast_lock_track *lt = NULL;
455 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
456 struct ast_bt *bt = NULL;
457
458#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
459 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
460 log_mutex_error(canlog, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
461 filename, lineno, func, mutex_name);
462 DO_THREAD_CRASH;
463 return EINVAL;
464 }
465#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
466
467 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
468 if (lt) {
469 ast_reentrancy_lock(lt);
470 if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) {
471 log_mutex_error(canlog, "%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
472 filename, lineno, func, mutex_name);
473 log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
474 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
475#ifdef HAVE_BKTR
476 __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
477#endif
478 DO_THREAD_CRASH;
479 }
480
481 if (--lt->reentrancy < 0) {
482 log_mutex_error(canlog, "%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
483 filename, lineno, func, mutex_name);
484 lt->reentrancy = 0;
485 }
486
487 if (lt->reentrancy < AST_MAX_REENTRANCY) {
488 lt->file[lt->reentrancy] = NULL;
489 lt->lineno[lt->reentrancy] = 0;
490 lt->func[lt->reentrancy] = NULL;
491 lt->thread_id[lt->reentrancy] = 0;
492 }
493
494#ifdef HAVE_BKTR
495 if (lt->reentrancy) {
496 bt = &lt->backtrace[lt->reentrancy - 1];
497 }
498#endif
499 ast_reentrancy_unlock(lt);
500
501 ast_remove_lock_info(t, bt);
502 }
503#endif /* DEBUG_THREADS */
504
505 res = pthread_mutex_unlock(&t->mutex);
506
507#ifdef DEBUG_THREADS
508 if (res) {
509 log_mutex_error(canlog, "%s line %d (%s): Error releasing mutex: %s\n",
510 filename, lineno, func, strerror(res));
511 DO_THREAD_CRASH;
512 }
513#endif /* DEBUG_THREADS */
514
515 return res;
516}
517
518
519int __ast_cond_init(const char *filename, int lineno, const char *func,
520 const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
521{
522 return pthread_cond_init(cond, cond_attr);
523}
524
525int __ast_cond_signal(const char *filename, int lineno, const char *func,
526 const char *cond_name, ast_cond_t *cond)
527{
529}
530
531int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
532 const char *cond_name, ast_cond_t *cond)
533{
535}
536
537int __ast_cond_destroy(const char *filename, int lineno, const char *func,
538 const char *cond_name, ast_cond_t *cond)
539{
541}
542
543#ifdef DEBUG_THREADS
544static void restore_lock_tracking(struct ast_lock_track *lt, struct ast_lock_track *lt_saved)
545{
546 ast_reentrancy_lock(lt);
547
548 /*
549 * The following code must match the struct ast_lock_track
550 * definition with the explicit exception of the reentr_mutex
551 * member.
552 */
553 memcpy(lt->file, lt_saved->file, sizeof(lt->file));
554 memcpy(lt->lineno, lt_saved->lineno, sizeof(lt->lineno));
555 lt->reentrancy = lt_saved->reentrancy;
556 memcpy(lt->func, lt_saved->func, sizeof(lt->func));
557 memcpy(lt->thread_id, lt_saved->thread_id, sizeof(lt->thread_id));
558#ifdef HAVE_BKTR
559 memcpy(lt->backtrace, lt_saved->backtrace, sizeof(lt->backtrace));
560#endif
561
562 ast_reentrancy_unlock(lt);
563}
564#endif /* DEBUG_THREADS */
565
566int __ast_cond_wait(const char *filename, int lineno, const char *func,
567 const char *cond_name, const char *mutex_name,
569{
570 int res;
571
572#ifdef DEBUG_THREADS
573 struct ast_lock_track *lt = NULL;
574 struct ast_lock_track lt_orig;
575 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
576
577#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
578 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
579 log_mutex_error(canlog, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
580 filename, lineno, func, mutex_name);
581 DO_THREAD_CRASH;
582 return EINVAL;
583 }
584#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
585
586 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
587 if (lt) {
588 ast_reentrancy_lock(lt);
589 if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) {
590 log_mutex_error(canlog, "%s line %d (%s): attempted wait using mutex '%s' without owning it!\n",
591 filename, lineno, func, mutex_name);
592 log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
593 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
594#ifdef HAVE_BKTR
595 __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
596#endif
597 DO_THREAD_CRASH;
598 } else if (lt->reentrancy <= 0) {
599 log_mutex_error(canlog, "%s line %d (%s): attempted wait using an unlocked mutex '%s'\n",
600 filename, lineno, func, mutex_name);
601 DO_THREAD_CRASH;
602 }
603
604 /* Waiting on a condition completely suspends a recursive mutex,
605 * even if it's been recursively locked multiple times. Make a
606 * copy of the lock tracking, and reset reentrancy to zero */
607 lt_orig = *lt;
608 lt->reentrancy = 0;
609 ast_reentrancy_unlock(lt);
610
611 ast_suspend_lock_info(t);
612 }
613#endif /* DEBUG_THREADS */
614
615 res = pthread_cond_wait(cond, &t->mutex);
616
617#ifdef DEBUG_THREADS
618 if (res) {
619 log_mutex_error(canlog, "%s line %d (%s): Error waiting on condition mutex '%s'\n",
620 filename, lineno, func, strerror(res));
621 DO_THREAD_CRASH;
622 } else if (lt) {
623 restore_lock_tracking(lt, &lt_orig);
624 ast_restore_lock_info(t);
625 }
626#endif /* DEBUG_THREADS */
627
628 return res;
629}
630
631int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
632 const char *cond_name, const char *mutex_name, ast_cond_t *cond,
633 ast_mutex_t *t, const struct timespec *abstime)
634{
635 int res;
636
637#ifdef DEBUG_THREADS
638 struct ast_lock_track *lt = NULL;
639 struct ast_lock_track lt_orig;
640 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
641
642#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
643 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
644 log_mutex_error(canlog, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
645 filename, lineno, func, mutex_name);
646 DO_THREAD_CRASH;
647 return EINVAL;
648 }
649#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
650
651 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
652 if (lt) {
653 ast_reentrancy_lock(lt);
654 if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) {
655 log_mutex_error(canlog, "%s line %d (%s): attempted wait using mutex '%s' without owning it!\n",
656 filename, lineno, func, mutex_name);
657 log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
658 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
659#ifdef HAVE_BKTR
660 __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
661#endif
662 DO_THREAD_CRASH;
663 } else if (lt->reentrancy <= 0) {
664 log_mutex_error(canlog, "%s line %d (%s): attempted wait using an unlocked mutex '%s'\n",
665 filename, lineno, func, mutex_name);
666 DO_THREAD_CRASH;
667 }
668
669 /* Waiting on a condition completely suspends a recursive mutex,
670 * even if it's been recursively locked multiple times. Make a
671 * copy of the lock tracking, and reset reentrancy to zero */
672 lt_orig = *lt;
673 lt->reentrancy = 0;
674 ast_reentrancy_unlock(lt);
675
676 ast_suspend_lock_info(t);
677 }
678#endif /* DEBUG_THREADS */
679
680 res = pthread_cond_timedwait(cond, &t->mutex, abstime);
681
682#ifdef DEBUG_THREADS
683 if (res && (res != ETIMEDOUT)) {
684 log_mutex_error(canlog, "%s line %d (%s): Error waiting on condition mutex '%s'\n",
685 filename, lineno, func, strerror(res));
686 DO_THREAD_CRASH;
687 } else if (lt) {
688 restore_lock_tracking(lt, &lt_orig);
689 ast_restore_lock_info(t);
690 }
691#endif /* DEBUG_THREADS */
692
693 return res;
694}
695
696int __ast_rwlock_init(int tracking, const char *filename, int lineno, \
697 const char *func, const char *rwlock_name, ast_rwlock_t *t)
698{
699 int res;
700 pthread_rwlockattr_t attr;
701
702#if defined(DEBUG_THREADS) && defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && \
703 defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
704 if (t->lock != ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
705 int canlog = tracking && strcmp(filename, "logger.c");
706
707 log_mutex_error(canlog, "%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
708 filename, lineno, func, rwlock_name);
709 DO_THREAD_CRASH;
710 return EBUSY;
711 }
712#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
713
714#if defined(DEBUG_THREADS) || defined(DETECT_DEADLOCKS)
715 t->track = NULL;
716 t->flags.tracking = tracking;
717 t->flags.setup = 0;
718#endif /* DEBUG_THREADS */
719
720 pthread_rwlockattr_init(&attr);
721#ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
722 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
723#endif
724 res = pthread_rwlock_init(&t->lock, &attr);
725 pthread_rwlockattr_destroy(&attr);
726
727 return res;
728}
729
730int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
731{
732 int res;
733
734#ifdef DEBUG_THREADS
735 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 1);
736 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
737
738#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
739 if (t->lock == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
740 log_mutex_error(canlog, "%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
741 filename, lineno, func, rwlock_name);
742 DO_THREAD_CRASH;
743 res = EINVAL;
744 goto lt_cleanup;
745 }
746#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
747#endif /* DEBUG_THREADS */
748
749 res = pthread_rwlock_destroy(&t->lock);
750
751#ifdef DEBUG_THREADS
752 if (res) {
753 log_mutex_error(canlog, "%s line %d (%s): Error destroying rwlock %s: %s\n",
754 filename, lineno, func, rwlock_name, strerror(res));
755 }
756#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
757lt_cleanup:
758#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
759 if (lt) {
760 ast_reentrancy_lock(lt);
761 lt->file[0] = filename;
762 lt->lineno[0] = lineno;
763 lt->func[0] = func;
764 lt->reentrancy = 0;
765 lt->thread_id[0] = 0;
766#ifdef HAVE_BKTR
767 memset(&lt->backtrace[0], 0, sizeof(lt->backtrace[0]));
768#endif
769 ast_reentrancy_unlock(lt);
770 delete_reentrancy_cs(&t->track);
771 }
772#endif /* DEBUG_THREADS */
773
774 return res;
775}
776
777int __ast_rwlock_unlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
778{
779 int res;
780
781#ifdef DEBUG_THREADS
782 struct ast_lock_track *lt = NULL;
783 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
784 struct ast_bt *bt = NULL;
785 int lock_found = 0;
786
787#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
788 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
789 log_mutex_error(canlog, "%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
790 filename, line, func, name);
791 DO_THREAD_CRASH;
792 return EINVAL;
793 }
794#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
795
796 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
797 if (lt) {
798 ast_reentrancy_lock(lt);
799 if (lt->reentrancy) {
800 int i;
801 pthread_t self = pthread_self();
802 for (i = lt->reentrancy - 1; i >= 0; --i) {
803 if (lt->thread_id[i] == self) {
804 lock_found = 1;
805 if (i != lt->reentrancy - 1) {
806 lt->file[i] = lt->file[lt->reentrancy - 1];
807 lt->lineno[i] = lt->lineno[lt->reentrancy - 1];
808 lt->func[i] = lt->func[lt->reentrancy - 1];
809 lt->thread_id[i] = lt->thread_id[lt->reentrancy - 1];
810 }
811#ifdef HAVE_BKTR
812 bt = &lt->backtrace[i];
813#endif
814 lt->file[lt->reentrancy - 1] = NULL;
815 lt->lineno[lt->reentrancy - 1] = 0;
816 lt->func[lt->reentrancy - 1] = NULL;
818 break;
819 }
820 }
821 }
822
823 if (lock_found && --lt->reentrancy < 0) {
824 log_mutex_error(canlog, "%s line %d (%s): rwlock '%s' freed more times than we've locked!\n",
825 filename, line, func, name);
826 lt->reentrancy = 0;
827 }
828
829 ast_reentrancy_unlock(lt);
830
831 ast_remove_lock_info(t, bt);
832 }
833#endif /* DEBUG_THREADS */
834
835 res = pthread_rwlock_unlock(&t->lock);
836
837#ifdef DEBUG_THREADS
838 if (res) {
839 log_mutex_error(canlog, "%s line %d (%s): Error releasing rwlock: %s\n",
840 filename, line, func, strerror(res));
841 DO_THREAD_CRASH;
842 }
843#endif /* DEBUG_THREADS */
844
845 return res;
846}
847
848int __ast_rwlock_rdlock(const char *filename, int line, const char *func,
849 ast_rwlock_t *t, const char *name)
850{
851 int res;
852
853#if defined(DEBUG_THREADS) || defined(DETECT_DEADLOCKS)
854 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
855#endif
856
857#ifdef DEBUG_THREADS
858 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
859 struct ast_bt *bt = NULL;
860
861 if (lt) {
862#ifdef HAVE_BKTR
863 struct ast_bt tmp;
864
865 /* The implementation of backtrace() may have its own locks.
866 * Capture the backtrace outside of the reentrancy lock to
867 * avoid deadlocks. See ASTERISK-22455. */
869
870 ast_reentrancy_lock(lt);
871 if (lt->reentrancy < AST_MAX_REENTRANCY) {
872 lt->backtrace[lt->reentrancy] = tmp;
873 bt = &lt->backtrace[lt->reentrancy];
874 }
875 ast_reentrancy_unlock(lt);
876#endif
877 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
878 }
879#endif /* DEBUG_THREADS */
880
881#if defined(DETECT_DEADLOCKS)
882 {
883 time_t seconds = time(NULL);
884 time_t wait_time, reported_wait = 0;
885 do {
886 res = pthread_rwlock_tryrdlock(&t->lock);
887 if (res == EBUSY) {
888 wait_time = time(NULL) - seconds;
889 if (wait_time > reported_wait && (wait_time % 5) == 0) {
890 log_mutex_error(canlog, "%s line %d (%s): Deadlock? waited %d sec for readlock '%s'?\n",
891 filename, line, func, (int)wait_time, name);
892#ifdef DEBUG_THREADS
893 if (lt) {
894 ast_reentrancy_lock(lt);
895#ifdef HAVE_BKTR
896 __dump_backtrace(&lt->backtrace[lt->reentrancy], canlog);
897#endif
898 log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
899 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
900 lt->func[lt->reentrancy-1], name);
901#ifdef HAVE_BKTR
902 __dump_backtrace(&lt->backtrace[lt->reentrancy-1], canlog);
903#endif
904 ast_reentrancy_unlock(lt);
905 }
906#endif
907 reported_wait = wait_time;
908 }
909 usleep(200);
910 }
911 } while (res == EBUSY);
912 }
913#else /* !DETECT_DEADLOCKS */
914 res = pthread_rwlock_rdlock(&t->lock);
915#endif /* !DETECT_DEADLOCKS */
916
917#ifdef DEBUG_THREADS
918 if (!res && lt) {
919 ast_reentrancy_lock(lt);
920 if (lt->reentrancy < AST_MAX_REENTRANCY) {
921 lt->file[lt->reentrancy] = filename;
922 lt->lineno[lt->reentrancy] = line;
923 lt->func[lt->reentrancy] = func;
924 lt->thread_id[lt->reentrancy] = pthread_self();
925 lt->reentrancy++;
926 }
927 ast_reentrancy_unlock(lt);
928 ast_mark_lock_acquired(t);
929 } else if (lt) {
930#ifdef HAVE_BKTR
931 if (lt->reentrancy) {
932 ast_reentrancy_lock(lt);
933 bt = &lt->backtrace[lt->reentrancy-1];
934 ast_reentrancy_unlock(lt);
935 } else {
936 bt = NULL;
937 }
938#endif
939 ast_remove_lock_info(t, bt);
940 }
941
942 if (res) {
943 log_mutex_error(canlog, "%s line %d (%s): Error obtaining read lock: %s\n",
944 filename, line, func, strerror(res));
945 DO_THREAD_CRASH;
946 }
947#endif /* DEBUG_THREADS */
948
949 return res;
950}
951
952int __ast_rwlock_wrlock(const char *filename, int line, const char *func, \
953 ast_rwlock_t *t, const char *name)
954{
955 int res;
956
957#if defined(DEBUG_THREADS) || defined(DETECT_DEADLOCKS)
958 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
959#endif
960
961#ifdef DEBUG_THREADS
962 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
963 struct ast_bt *bt = NULL;
964
965 if (lt) {
966#ifdef HAVE_BKTR
967 struct ast_bt tmp;
968
969 /* The implementation of backtrace() may have its own locks.
970 * Capture the backtrace outside of the reentrancy lock to
971 * avoid deadlocks. See ASTERISK-22455. */
973
974 ast_reentrancy_lock(lt);
975 if (lt->reentrancy < AST_MAX_REENTRANCY) {
976 lt->backtrace[lt->reentrancy] = tmp;
977 bt = &lt->backtrace[lt->reentrancy];
978 }
979 ast_reentrancy_unlock(lt);
980#endif
981 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
982 }
983#endif /* DEBUG_THREADS */
984
985#ifdef DETECT_DEADLOCKS
986 {
987 time_t seconds = time(NULL);
988 time_t wait_time, reported_wait = 0;
989 do {
990 res = pthread_rwlock_trywrlock(&t->lock);
991 if (res == EBUSY) {
992 wait_time = time(NULL) - seconds;
993 if (wait_time > reported_wait && (wait_time % 5) == 0) {
994 log_mutex_error(canlog, "%s line %d (%s): Deadlock? waited %d sec for writelock '%s'?\n",
995 filename, line, func, (int)wait_time, name);
996#ifdef DEBUG_THREADS
997 if (lt) {
998 ast_reentrancy_lock(lt);
999#ifdef HAVE_BKTR
1000 __dump_backtrace(&lt->backtrace[lt->reentrancy], canlog);
1001#endif
1002 log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
1003 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
1004 lt->func[lt->reentrancy-1], name);
1005#ifdef HAVE_BKTR
1006 __dump_backtrace(&lt->backtrace[lt->reentrancy-1], canlog);
1007#endif
1008 ast_reentrancy_unlock(lt);
1009 }
1010#endif
1011 reported_wait = wait_time;
1012 }
1013 usleep(200);
1014 }
1015 } while (res == EBUSY);
1016 }
1017#else /* !DETECT_DEADLOCKS */
1018 res = pthread_rwlock_wrlock(&t->lock);
1019#endif /* !DETECT_DEADLOCKS */
1020
1021#ifdef DEBUG_THREADS
1022 if (!res && lt) {
1023 ast_reentrancy_lock(lt);
1024 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1025 lt->file[lt->reentrancy] = filename;
1026 lt->lineno[lt->reentrancy] = line;
1027 lt->func[lt->reentrancy] = func;
1028 lt->thread_id[lt->reentrancy] = pthread_self();
1029 lt->reentrancy++;
1030 }
1031 ast_reentrancy_unlock(lt);
1032 ast_mark_lock_acquired(t);
1033 } else if (lt) {
1034#ifdef HAVE_BKTR
1035 if (lt->reentrancy) {
1036 ast_reentrancy_lock(lt);
1037 bt = &lt->backtrace[lt->reentrancy-1];
1038 ast_reentrancy_unlock(lt);
1039 } else {
1040 bt = NULL;
1041 }
1042#endif
1043 ast_remove_lock_info(t, bt);
1044 }
1045 if (res) {
1046 log_mutex_error(canlog, "%s line %d (%s): Error obtaining write lock: %s\n",
1047 filename, line, func, strerror(res));
1048 DO_THREAD_CRASH;
1049 }
1050#endif /* DEBUG_THREADS */
1051
1052 return res;
1053}
1054
1055int __ast_rwlock_timedrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name,
1056 const struct timespec *abs_timeout)
1057{
1058 int res;
1059
1060#ifdef DEBUG_THREADS
1061 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1062 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
1063 struct ast_bt *bt = NULL;
1064
1065 if (lt) {
1066#ifdef HAVE_BKTR
1067 struct ast_bt tmp;
1068
1069 /* The implementation of backtrace() may have its own locks.
1070 * Capture the backtrace outside of the reentrancy lock to
1071 * avoid deadlocks. See ASTERISK-22455. */
1073
1074 ast_reentrancy_lock(lt);
1075 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1076 lt->backtrace[lt->reentrancy] = tmp;
1077 bt = &lt->backtrace[lt->reentrancy];
1078 }
1079 ast_reentrancy_unlock(lt);
1080#endif
1081 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1082 }
1083#endif /* DEBUG_THREADS */
1084
1085#ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1086 res = pthread_rwlock_timedrdlock(&t->lock, abs_timeout);
1087#else
1088 do {
1089 struct timeval _now;
1090 for (;;) {
1091 if (!(res = pthread_rwlock_tryrdlock(&t->lock))) {
1092 break;
1093 }
1094 _now = ast_tvnow();
1095 if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1096 break;
1097 }
1098 usleep(1);
1099 }
1100 } while (0);
1101#endif
1102
1103#ifdef DEBUG_THREADS
1104 if (!res && lt) {
1105 ast_reentrancy_lock(lt);
1106 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1107 lt->file[lt->reentrancy] = filename;
1108 lt->lineno[lt->reentrancy] = line;
1109 lt->func[lt->reentrancy] = func;
1110 lt->thread_id[lt->reentrancy] = pthread_self();
1111 lt->reentrancy++;
1112 }
1113 ast_reentrancy_unlock(lt);
1114 ast_mark_lock_acquired(t);
1115 } else if (lt) {
1116#ifdef HAVE_BKTR
1117 if (lt->reentrancy) {
1118 ast_reentrancy_lock(lt);
1119 bt = &lt->backtrace[lt->reentrancy-1];
1120 ast_reentrancy_unlock(lt);
1121 } else {
1122 bt = NULL;
1123 }
1124#endif
1125 ast_remove_lock_info(t, bt);
1126 }
1127 if (res) {
1128 log_mutex_error(canlog, "%s line %d (%s): Error obtaining read lock: %s\n",
1129 filename, line, func, strerror(res));
1130 DO_THREAD_CRASH;
1131 }
1132#endif /* DEBUG_THREADS */
1133
1134 return res;
1135}
1136
1137int __ast_rwlock_timedwrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name,
1138 const struct timespec *abs_timeout)
1139{
1140 int res;
1141
1142#ifdef DEBUG_THREADS
1143 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1144 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
1145 struct ast_bt *bt = NULL;
1146
1147 if (lt) {
1148#ifdef HAVE_BKTR
1149 struct ast_bt tmp;
1150
1151 /* The implementation of backtrace() may have its own locks.
1152 * Capture the backtrace outside of the reentrancy lock to
1153 * avoid deadlocks. See ASTERISK-22455. */
1155
1156 ast_reentrancy_lock(lt);
1157 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1158 lt->backtrace[lt->reentrancy] = tmp;
1159 bt = &lt->backtrace[lt->reentrancy];
1160 }
1161 ast_reentrancy_unlock(lt);
1162#endif
1163 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1164 }
1165#endif /* DEBUG_THREADS */
1166
1167#ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1168 res = pthread_rwlock_timedwrlock(&t->lock, abs_timeout);
1169#else
1170 do {
1171 struct timeval _now;
1172 for (;;) {
1173 if (!(res = pthread_rwlock_trywrlock(&t->lock))) {
1174 break;
1175 }
1176 _now = ast_tvnow();
1177 if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1178 break;
1179 }
1180 usleep(1);
1181 }
1182 } while (0);
1183#endif
1184
1185#ifdef DEBUG_THREADS
1186 if (!res && lt) {
1187 ast_reentrancy_lock(lt);
1188 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1189 lt->file[lt->reentrancy] = filename;
1190 lt->lineno[lt->reentrancy] = line;
1191 lt->func[lt->reentrancy] = func;
1192 lt->thread_id[lt->reentrancy] = pthread_self();
1193 lt->reentrancy++;
1194 }
1195 ast_reentrancy_unlock(lt);
1196 ast_mark_lock_acquired(t);
1197 } else if (lt) {
1198#ifdef HAVE_BKTR
1199 if (lt->reentrancy) {
1200 ast_reentrancy_lock(lt);
1201 bt = &lt->backtrace[lt->reentrancy-1];
1202 ast_reentrancy_unlock(lt);
1203 } else {
1204 bt = NULL;
1205 }
1206#endif
1207 ast_remove_lock_info(t, bt);
1208 }
1209 if (res) {
1210 log_mutex_error(canlog, "%s line %d (%s): Error obtaining read lock: %s\n",
1211 filename, line, func, strerror(res));
1212 DO_THREAD_CRASH;
1213 }
1214#endif /* DEBUG_THREADS */
1215
1216 return res;
1217}
1218
1219int __ast_rwlock_tryrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
1220{
1221 int res;
1222
1223#ifdef DEBUG_THREADS
1224 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1225 struct ast_bt *bt = NULL;
1226
1227 if (lt) {
1228#ifdef HAVE_BKTR
1229 struct ast_bt tmp;
1230
1231 /* The implementation of backtrace() may have its own locks.
1232 * Capture the backtrace outside of the reentrancy lock to
1233 * avoid deadlocks. See ASTERISK-22455. */
1235
1236 ast_reentrancy_lock(lt);
1237 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1238 lt->backtrace[lt->reentrancy] = tmp;
1239 bt = &lt->backtrace[lt->reentrancy];
1240 }
1241 ast_reentrancy_unlock(lt);
1242#endif
1243 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
1244 }
1245#endif /* DEBUG_THREADS */
1246
1247 res = pthread_rwlock_tryrdlock(&t->lock);
1248
1249#ifdef DEBUG_THREADS
1250 if (!res && lt) {
1251 ast_reentrancy_lock(lt);
1252 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1253 lt->file[lt->reentrancy] = filename;
1254 lt->lineno[lt->reentrancy] = line;
1255 lt->func[lt->reentrancy] = func;
1256 lt->thread_id[lt->reentrancy] = pthread_self();
1257 lt->reentrancy++;
1258 }
1259 ast_reentrancy_unlock(lt);
1260 ast_mark_lock_acquired(t);
1261 } else if (lt) {
1263 }
1264#endif /* DEBUG_THREADS */
1265
1266 return res;
1267}
1268
1269int __ast_rwlock_trywrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
1270{
1271 int res;
1272
1273#ifdef DEBUG_THREADS
1274 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1275 struct ast_bt *bt = NULL;
1276
1277 if (lt) {
1278#ifdef HAVE_BKTR
1279 struct ast_bt tmp;
1280
1281 /* The implementation of backtrace() may have its own locks.
1282 * Capture the backtrace outside of the reentrancy lock to
1283 * avoid deadlocks. See ASTERISK-22455. */
1285
1286 ast_reentrancy_lock(lt);
1287 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1288 lt->backtrace[lt->reentrancy] = tmp;
1289 bt = &lt->backtrace[lt->reentrancy];
1290 }
1291 ast_reentrancy_unlock(lt);
1292#endif
1293 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1294 }
1295#endif /* DEBUG_THREADS */
1296
1297 res = pthread_rwlock_trywrlock(&t->lock);
1298
1299#ifdef DEBUG_THREADS
1300 if (!res && lt) {
1301 ast_reentrancy_lock(lt);
1302 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1303 lt->file[lt->reentrancy] = filename;
1304 lt->lineno[lt->reentrancy] = line;
1305 lt->func[lt->reentrancy] = func;
1306 lt->thread_id[lt->reentrancy] = pthread_self();
1307 lt->reentrancy++;
1308 }
1309 ast_reentrancy_unlock(lt);
1310 ast_mark_lock_acquired(t);
1311 } else if (lt) {
1313 }
1314#endif /* DEBUG_THREADS */
1315
1316 return res;
1317}
ast_cond_t cond
Definition: app_sla.c:330
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_bt_get_addresses(bt)
Definition: backtrace.h:38
static int tmp()
Definition: bt_open.c:389
@ 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:2313
static const char name[]
Definition: format_mp3.c:68
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:1055
int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
Definition: lock.c:730
int __ast_rwlock_rdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
Definition: lock.c:848
int __ast_cond_broadcast(const char *filename, int lineno, const char *func, const char *cond_name, ast_cond_t *cond)
Definition: lock.c:531
int __ast_rwlock_tryrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
Definition: lock.c:1219
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:696
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:1137
int __ast_rwlock_unlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
Definition: lock.c:777
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:519
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:566
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:631
int __ast_cond_signal(const char *filename, int lineno, const char *func, const char *cond_name, ast_cond_t *cond)
Definition: lock.c:525
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:1269
int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
Definition: lock.c:393
int __ast_cond_destroy(const char *filename, int lineno, const char *func, const char *cond_name, ast_cond_t *cond)
Definition: lock.c:537
int __ast_rwlock_wrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
Definition: lock.c:952
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:448
Asterisk locking-related definitions:
#define AST_MAX_REENTRANCY
Definition: lock.h:101
#define __AST_RWLOCK_INIT_VALUE
Definition: lock.h:84
#define ROFFSET
Definition: lock.h:242
#define pthread_cond_broadcast
Definition: lock.h:633
#define pthread_mutex_trylock
Definition: lock.h:627
#define AST_PTHREADT_NULL
Definition: lock.h:66
#define pthread_mutex_lock
Definition: lock.h:625
#define pthread_mutex_t
Definition: lock.h:622
#define AST_MUTEX_KIND
Definition: lock.h:77
pthread_cond_t ast_cond_t
Definition: lock.h:178
#define pthread_mutex_unlock
Definition: lock.h:626
#define pthread_mutex_destroy
Definition: lock.h:629
#define pthread_cond_destroy
Definition: lock.h:631
#define pthread_cond_signal
Definition: lock.h:632
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:520
#define pthread_mutex_init
Definition: lock.h:628
#define pthread_cond_init
Definition: lock.h:630
#define pthread_cond_timedwait
Definition: lock.h:635
#define pthread_cond_wait
Definition: lock.h:634
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:253
#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:127
unsigned int tracking
Definition: lock.h:125
Lock tracking information.
Definition: lock.h:111
int reentrancy
Definition: lock.h:114
struct ast_bt backtrace[AST_MAX_REENTRANCY]
Definition: lock.h:118
pthread_t thread_id[AST_MAX_REENTRANCY]
Definition: lock.h:116
int lineno[AST_MAX_REENTRANCY]
Definition: lock.h:113
pthread_mutex_t reentr_mutex
Definition: lock.h:120
const char * file[AST_MAX_REENTRANCY]
Definition: lock.h:112
const char * func[AST_MAX_REENTRANCY]
Definition: lock.h:115
Structure for mutex and tracking information.
Definition: lock.h:135
pthread_mutex_t mutex
Definition: lock.h:136
Structure for rwlock and tracking information.
Definition: lock.h:157
pthread_rwlock_t lock
Definition: lock.h:158
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
Utility functions.