Asterisk - The Open Source Telephony Project GIT-master-8924258
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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#ifdef DEBUG_THREADS
513 if (res) {
514 log_mutex_error(canlog, "%s line %d (%s): Error releasing mutex: %s\n",
515 filename, lineno, func, strerror(res));
516 DO_THREAD_CRASH;
517 }
518#endif /* DEBUG_THREADS */
519
520 return res;
521}
522
523
524int __ast_cond_init(const char *filename, int lineno, const char *func,
525 const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
526{
527 return pthread_cond_init(cond, cond_attr);
528}
529
530int __ast_cond_signal(const char *filename, int lineno, const char *func,
531 const char *cond_name, ast_cond_t *cond)
532{
534}
535
536int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
537 const char *cond_name, ast_cond_t *cond)
538{
540}
541
542int __ast_cond_destroy(const char *filename, int lineno, const char *func,
543 const char *cond_name, ast_cond_t *cond)
544{
546}
547
548#ifdef DEBUG_THREADS
549static void restore_lock_tracking(struct ast_lock_track *lt, struct ast_lock_track *lt_saved)
550{
551 ast_reentrancy_lock(lt);
552
553 /*
554 * The following code must match the struct ast_lock_track
555 * definition with the explicit exception of the reentr_mutex
556 * member.
557 */
558 memcpy(lt->file, lt_saved->file, sizeof(lt->file));
559 memcpy(lt->lineno, lt_saved->lineno, sizeof(lt->lineno));
560 lt->reentrancy = lt_saved->reentrancy;
561 memcpy(lt->func, lt_saved->func, sizeof(lt->func));
562 memcpy(lt->thread_id, lt_saved->thread_id, sizeof(lt->thread_id));
563#ifdef HAVE_BKTR
564 memcpy(lt->backtrace, lt_saved->backtrace, sizeof(lt->backtrace));
565#endif
566
567 ast_reentrancy_unlock(lt);
568}
569#endif /* DEBUG_THREADS */
570
571int __ast_cond_wait(const char *filename, int lineno, const char *func,
572 const char *cond_name, const char *mutex_name,
574{
575 int res;
576
577#ifdef DEBUG_THREADS
578 struct ast_lock_track *lt = NULL;
579 struct ast_lock_track lt_orig;
580 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
581
582#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
583 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
584 log_mutex_error(canlog, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
585 filename, lineno, func, mutex_name);
586 DO_THREAD_CRASH;
587 return EINVAL;
588 }
589#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
590
591 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
592 if (lt) {
593 ast_reentrancy_lock(lt);
594 if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) {
595 log_mutex_error(canlog, "%s line %d (%s): attempted wait using mutex '%s' without owning it!\n",
596 filename, lineno, func, mutex_name);
597 log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
598 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
599#ifdef HAVE_BKTR
600 __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
601#endif
602 DO_THREAD_CRASH;
603 } else if (lt->reentrancy <= 0) {
604 log_mutex_error(canlog, "%s line %d (%s): attempted wait using an unlocked mutex '%s'\n",
605 filename, lineno, func, mutex_name);
606 DO_THREAD_CRASH;
607 }
608
609 /* Waiting on a condition completely suspends a recursive mutex,
610 * even if it's been recursively locked multiple times. Make a
611 * copy of the lock tracking, and reset reentrancy to zero */
612 lt_orig = *lt;
613 lt->reentrancy = 0;
614 ast_reentrancy_unlock(lt);
615
616 ast_suspend_lock_info(t);
617 }
618#endif /* DEBUG_THREADS */
619
620 res = pthread_cond_wait(cond, &t->mutex);
621
622#ifdef DEBUG_THREADS
623 if (res) {
624 log_mutex_error(canlog, "%s line %d (%s): Error waiting on condition mutex '%s'\n",
625 filename, lineno, func, strerror(res));
626 DO_THREAD_CRASH;
627 } else if (lt) {
628 restore_lock_tracking(lt, &lt_orig);
629 ast_restore_lock_info(t);
630 }
631#endif /* DEBUG_THREADS */
632
633 return res;
634}
635
636int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
637 const char *cond_name, const char *mutex_name, ast_cond_t *cond,
638 ast_mutex_t *t, const struct timespec *abstime)
639{
640 int res;
641
642#ifdef DEBUG_THREADS
643 struct ast_lock_track *lt = NULL;
644 struct ast_lock_track lt_orig;
645 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
646
647#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
648 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
649 log_mutex_error(canlog, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
650 filename, lineno, func, mutex_name);
651 DO_THREAD_CRASH;
652 return EINVAL;
653 }
654#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
655
656 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
657 if (lt) {
658 ast_reentrancy_lock(lt);
659 if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) {
660 log_mutex_error(canlog, "%s line %d (%s): attempted wait using mutex '%s' without owning it!\n",
661 filename, lineno, func, mutex_name);
662 log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
663 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
664#ifdef HAVE_BKTR
665 __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
666#endif
667 DO_THREAD_CRASH;
668 } else if (lt->reentrancy <= 0) {
669 log_mutex_error(canlog, "%s line %d (%s): attempted wait using an unlocked mutex '%s'\n",
670 filename, lineno, func, mutex_name);
671 DO_THREAD_CRASH;
672 }
673
674 /* Waiting on a condition completely suspends a recursive mutex,
675 * even if it's been recursively locked multiple times. Make a
676 * copy of the lock tracking, and reset reentrancy to zero */
677 lt_orig = *lt;
678 lt->reentrancy = 0;
679 ast_reentrancy_unlock(lt);
680
681 ast_suspend_lock_info(t);
682 }
683#endif /* DEBUG_THREADS */
684
685 res = pthread_cond_timedwait(cond, &t->mutex, abstime);
686
687#ifdef DEBUG_THREADS
688 if (res && (res != ETIMEDOUT)) {
689 log_mutex_error(canlog, "%s line %d (%s): Error waiting on condition mutex '%s'\n",
690 filename, lineno, func, strerror(res));
691 DO_THREAD_CRASH;
692 } else if (lt) {
693 restore_lock_tracking(lt, &lt_orig);
694 ast_restore_lock_info(t);
695 }
696#endif /* DEBUG_THREADS */
697
698 return res;
699}
700
701int __ast_rwlock_init(int tracking, const char *filename, int lineno, \
702 const char *func, const char *rwlock_name, ast_rwlock_t *t)
703{
704 int res;
705 pthread_rwlockattr_t attr;
706
707#if defined(DEBUG_THREADS) && defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && \
708 defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
709 if (t->lock != ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
710 int canlog = tracking && strcmp(filename, "logger.c");
711
712 log_mutex_error(canlog, "%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
713 filename, lineno, func, rwlock_name);
714 DO_THREAD_CRASH;
715 return EBUSY;
716 }
717#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
718
719#if defined(DEBUG_THREADS) || defined(DETECT_DEADLOCKS)
720 t->track = NULL;
721 t->flags.tracking = tracking;
722 t->flags.setup = 0;
723#endif /* DEBUG_THREADS */
724
725 pthread_rwlockattr_init(&attr);
726#ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
727 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
728#endif
729 res = pthread_rwlock_init(&t->lock, &attr);
730 pthread_rwlockattr_destroy(&attr);
731
732 return res;
733}
734
735int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
736{
737 int res;
738
739#ifdef DEBUG_THREADS
740 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 1);
741 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
742
743#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
744 if (t->lock == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
745 log_mutex_error(canlog, "%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
746 filename, lineno, func, rwlock_name);
747 DO_THREAD_CRASH;
748 res = EINVAL;
749 goto lt_cleanup;
750 }
751#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
752#endif /* DEBUG_THREADS */
753
754 res = pthread_rwlock_destroy(&t->lock);
755
756#ifdef DEBUG_THREADS
757 if (res) {
758 log_mutex_error(canlog, "%s line %d (%s): Error destroying rwlock %s: %s\n",
759 filename, lineno, func, rwlock_name, strerror(res));
760 }
761#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
762lt_cleanup:
763#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
764 if (lt) {
765 ast_reentrancy_lock(lt);
766 lt->file[0] = filename;
767 lt->lineno[0] = lineno;
768 lt->func[0] = func;
769 lt->reentrancy = 0;
770 lt->thread_id[0] = 0;
771#ifdef HAVE_BKTR
772 memset(&lt->backtrace[0], 0, sizeof(lt->backtrace[0]));
773#endif
774 ast_reentrancy_unlock(lt);
775 delete_reentrancy_cs(&t->track);
776 }
777#endif /* DEBUG_THREADS */
778
779 return res;
780}
781
782int __ast_rwlock_unlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
783{
784 int res;
785
786#ifdef DEBUG_THREADS
787 struct ast_lock_track *lt = NULL;
788 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
789 struct ast_bt *bt = NULL;
790 int lock_found = 0;
791
792#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
793 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
794 log_mutex_error(canlog, "%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
795 filename, line, func, name);
796 DO_THREAD_CRASH;
797 return EINVAL;
798 }
799#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
800
801 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
802 if (lt) {
803 ast_reentrancy_lock(lt);
804 if (lt->reentrancy) {
805 int i;
806 pthread_t self = pthread_self();
807 for (i = lt->reentrancy - 1; i >= 0; --i) {
808 if (lt->thread_id[i] == self) {
809 lock_found = 1;
810 if (i != lt->reentrancy - 1) {
811 lt->file[i] = lt->file[lt->reentrancy - 1];
812 lt->lineno[i] = lt->lineno[lt->reentrancy - 1];
813 lt->func[i] = lt->func[lt->reentrancy - 1];
814 lt->thread_id[i] = lt->thread_id[lt->reentrancy - 1];
815 }
816#ifdef HAVE_BKTR
817 bt = &lt->backtrace[i];
818#endif
819 lt->file[lt->reentrancy - 1] = NULL;
820 lt->lineno[lt->reentrancy - 1] = 0;
821 lt->func[lt->reentrancy - 1] = NULL;
823 break;
824 }
825 }
826 }
827
828 if (lock_found && --lt->reentrancy < 0) {
829 log_mutex_error(canlog, "%s line %d (%s): rwlock '%s' freed more times than we've locked!\n",
830 filename, line, func, name);
831 lt->reentrancy = 0;
832 }
833
834 ast_reentrancy_unlock(lt);
835
836 ast_remove_lock_info(t, bt);
837 }
838#endif /* DEBUG_THREADS */
839
840 res = pthread_rwlock_unlock(&t->lock);
841
842#ifdef DEBUG_THREADS
843 if (res) {
844 log_mutex_error(canlog, "%s line %d (%s): Error releasing rwlock: %s\n",
845 filename, line, func, strerror(res));
846 DO_THREAD_CRASH;
847 }
848#endif /* DEBUG_THREADS */
849
850 return res;
851}
852
853int __ast_rwlock_rdlock(const char *filename, int line, const char *func,
854 ast_rwlock_t *t, const char *name)
855{
856 int res;
857
858#if defined(DEBUG_THREADS) || defined(DETECT_DEADLOCKS)
859 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
860#endif
861
862#ifdef DEBUG_THREADS
863 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
864 struct ast_bt *bt = NULL;
865
866 if (lt) {
867#ifdef HAVE_BKTR
868 struct ast_bt tmp;
869
870 /* The implementation of backtrace() may have its own locks.
871 * Capture the backtrace outside of the reentrancy lock to
872 * avoid deadlocks. See ASTERISK-22455. */
874
875 ast_reentrancy_lock(lt);
876 if (lt->reentrancy < AST_MAX_REENTRANCY) {
877 lt->backtrace[lt->reentrancy] = tmp;
878 bt = &lt->backtrace[lt->reentrancy];
879 }
880 ast_reentrancy_unlock(lt);
881#endif
882 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
883 }
884#endif /* DEBUG_THREADS */
885
886#if defined(DETECT_DEADLOCKS)
887 {
888 time_t seconds = time(NULL);
889 time_t wait_time, reported_wait = 0;
890 do {
891 res = pthread_rwlock_tryrdlock(&t->lock);
892 if (res == EBUSY) {
893 wait_time = time(NULL) - seconds;
894 if (wait_time > reported_wait && (wait_time % 5) == 0) {
895 log_mutex_error(canlog, "%s line %d (%s): Deadlock? waited %d sec for readlock '%s'?\n",
896 filename, line, func, (int)wait_time, name);
897#ifdef DEBUG_THREADS
898 if (lt) {
899 ast_reentrancy_lock(lt);
900#ifdef HAVE_BKTR
901 __dump_backtrace(&lt->backtrace[lt->reentrancy], canlog);
902#endif
903 log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
904 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
905 lt->func[lt->reentrancy-1], name);
906#ifdef HAVE_BKTR
907 __dump_backtrace(&lt->backtrace[lt->reentrancy-1], canlog);
908#endif
909 ast_reentrancy_unlock(lt);
910 }
911#endif
912 reported_wait = wait_time;
913 }
914 usleep(200);
915 }
916 } while (res == EBUSY);
917 }
918#else /* !DETECT_DEADLOCKS */
919 res = pthread_rwlock_rdlock(&t->lock);
920#endif /* !DETECT_DEADLOCKS */
921
922#ifdef DEBUG_THREADS
923 if (!res && lt) {
924 ast_reentrancy_lock(lt);
925 if (lt->reentrancy < AST_MAX_REENTRANCY) {
926 lt->file[lt->reentrancy] = filename;
927 lt->lineno[lt->reentrancy] = line;
928 lt->func[lt->reentrancy] = func;
929 lt->thread_id[lt->reentrancy] = pthread_self();
930 lt->reentrancy++;
931 }
932 ast_reentrancy_unlock(lt);
933 ast_mark_lock_acquired(t);
934 } else if (lt) {
935#ifdef HAVE_BKTR
936 if (lt->reentrancy) {
937 ast_reentrancy_lock(lt);
938 bt = &lt->backtrace[lt->reentrancy-1];
939 ast_reentrancy_unlock(lt);
940 } else {
941 bt = NULL;
942 }
943#endif
944 ast_remove_lock_info(t, bt);
945 }
946
947 if (res) {
948 log_mutex_error(canlog, "%s line %d (%s): Error obtaining read lock: %s\n",
949 filename, line, func, strerror(res));
950 DO_THREAD_CRASH;
951 }
952#endif /* DEBUG_THREADS */
953
954 return res;
955}
956
957int __ast_rwlock_wrlock(const char *filename, int line, const char *func, \
958 ast_rwlock_t *t, const char *name)
959{
960 int res;
961
962#if defined(DEBUG_THREADS) || defined(DETECT_DEADLOCKS)
963 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
964#endif
965
966#ifdef DEBUG_THREADS
967 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
968 struct ast_bt *bt = NULL;
969
970 if (lt) {
971#ifdef HAVE_BKTR
972 struct ast_bt tmp;
973
974 /* The implementation of backtrace() may have its own locks.
975 * Capture the backtrace outside of the reentrancy lock to
976 * avoid deadlocks. See ASTERISK-22455. */
978
979 ast_reentrancy_lock(lt);
980 if (lt->reentrancy < AST_MAX_REENTRANCY) {
981 lt->backtrace[lt->reentrancy] = tmp;
982 bt = &lt->backtrace[lt->reentrancy];
983 }
984 ast_reentrancy_unlock(lt);
985#endif
986 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
987 }
988#endif /* DEBUG_THREADS */
989
990#ifdef DETECT_DEADLOCKS
991 {
992 time_t seconds = time(NULL);
993 time_t wait_time, reported_wait = 0;
994 do {
995 res = pthread_rwlock_trywrlock(&t->lock);
996 if (res == EBUSY) {
997 wait_time = time(NULL) - seconds;
998 if (wait_time > reported_wait && (wait_time % 5) == 0) {
999 log_mutex_error(canlog, "%s line %d (%s): Deadlock? waited %d sec for writelock '%s'?\n",
1000 filename, line, func, (int)wait_time, name);
1001#ifdef DEBUG_THREADS
1002 if (lt) {
1003 ast_reentrancy_lock(lt);
1004#ifdef HAVE_BKTR
1005 __dump_backtrace(&lt->backtrace[lt->reentrancy], canlog);
1006#endif
1007 log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
1008 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
1009 lt->func[lt->reentrancy-1], name);
1010#ifdef HAVE_BKTR
1011 __dump_backtrace(&lt->backtrace[lt->reentrancy-1], canlog);
1012#endif
1013 ast_reentrancy_unlock(lt);
1014 }
1015#endif
1016 reported_wait = wait_time;
1017 }
1018 usleep(200);
1019 }
1020 } while (res == EBUSY);
1021 }
1022#else /* !DETECT_DEADLOCKS */
1023 res = pthread_rwlock_wrlock(&t->lock);
1024#endif /* !DETECT_DEADLOCKS */
1025
1026#ifdef DEBUG_THREADS
1027 if (!res && lt) {
1028 ast_reentrancy_lock(lt);
1029 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1030 lt->file[lt->reentrancy] = filename;
1031 lt->lineno[lt->reentrancy] = line;
1032 lt->func[lt->reentrancy] = func;
1033 lt->thread_id[lt->reentrancy] = pthread_self();
1034 lt->reentrancy++;
1035 }
1036 ast_reentrancy_unlock(lt);
1037 ast_mark_lock_acquired(t);
1038 } else if (lt) {
1039#ifdef HAVE_BKTR
1040 if (lt->reentrancy) {
1041 ast_reentrancy_lock(lt);
1042 bt = &lt->backtrace[lt->reentrancy-1];
1043 ast_reentrancy_unlock(lt);
1044 } else {
1045 bt = NULL;
1046 }
1047#endif
1048 ast_remove_lock_info(t, bt);
1049 }
1050 if (res) {
1051 log_mutex_error(canlog, "%s line %d (%s): Error obtaining write lock: %s\n",
1052 filename, line, func, strerror(res));
1053 DO_THREAD_CRASH;
1054 }
1055#endif /* DEBUG_THREADS */
1056
1057 return res;
1058}
1059
1060int __ast_rwlock_timedrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name,
1061 const struct timespec *abs_timeout)
1062{
1063 int res;
1064
1065#ifdef DEBUG_THREADS
1066 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1067 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
1068 struct ast_bt *bt = NULL;
1069
1070 if (lt) {
1071#ifdef HAVE_BKTR
1072 struct ast_bt tmp;
1073
1074 /* The implementation of backtrace() may have its own locks.
1075 * Capture the backtrace outside of the reentrancy lock to
1076 * avoid deadlocks. See ASTERISK-22455. */
1078
1079 ast_reentrancy_lock(lt);
1080 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1081 lt->backtrace[lt->reentrancy] = tmp;
1082 bt = &lt->backtrace[lt->reentrancy];
1083 }
1084 ast_reentrancy_unlock(lt);
1085#endif
1086 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1087 }
1088#endif /* DEBUG_THREADS */
1089
1090#ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1091 res = pthread_rwlock_timedrdlock(&t->lock, abs_timeout);
1092#else
1093 do {
1094 struct timeval _now;
1095 for (;;) {
1096 if (!(res = pthread_rwlock_tryrdlock(&t->lock))) {
1097 break;
1098 }
1099 _now = ast_tvnow();
1100 if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1101 break;
1102 }
1103 usleep(1);
1104 }
1105 } while (0);
1106#endif
1107
1108#ifdef DEBUG_THREADS
1109 if (!res && lt) {
1110 ast_reentrancy_lock(lt);
1111 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1112 lt->file[lt->reentrancy] = filename;
1113 lt->lineno[lt->reentrancy] = line;
1114 lt->func[lt->reentrancy] = func;
1115 lt->thread_id[lt->reentrancy] = pthread_self();
1116 lt->reentrancy++;
1117 }
1118 ast_reentrancy_unlock(lt);
1119 ast_mark_lock_acquired(t);
1120 } else if (lt) {
1121#ifdef HAVE_BKTR
1122 if (lt->reentrancy) {
1123 ast_reentrancy_lock(lt);
1124 bt = &lt->backtrace[lt->reentrancy-1];
1125 ast_reentrancy_unlock(lt);
1126 } else {
1127 bt = NULL;
1128 }
1129#endif
1130 ast_remove_lock_info(t, bt);
1131 }
1132 if (res) {
1133 log_mutex_error(canlog, "%s line %d (%s): Error obtaining read lock: %s\n",
1134 filename, line, func, strerror(res));
1135 DO_THREAD_CRASH;
1136 }
1137#endif /* DEBUG_THREADS */
1138
1139 return res;
1140}
1141
1142int __ast_rwlock_timedwrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name,
1143 const struct timespec *abs_timeout)
1144{
1145 int res;
1146
1147#ifdef DEBUG_THREADS
1148 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1149 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
1150 struct ast_bt *bt = NULL;
1151
1152 if (lt) {
1153#ifdef HAVE_BKTR
1154 struct ast_bt tmp;
1155
1156 /* The implementation of backtrace() may have its own locks.
1157 * Capture the backtrace outside of the reentrancy lock to
1158 * avoid deadlocks. See ASTERISK-22455. */
1160
1161 ast_reentrancy_lock(lt);
1162 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1163 lt->backtrace[lt->reentrancy] = tmp;
1164 bt = &lt->backtrace[lt->reentrancy];
1165 }
1166 ast_reentrancy_unlock(lt);
1167#endif
1168 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1169 }
1170#endif /* DEBUG_THREADS */
1171
1172#ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1173 res = pthread_rwlock_timedwrlock(&t->lock, abs_timeout);
1174#else
1175 do {
1176 struct timeval _now;
1177 for (;;) {
1178 if (!(res = pthread_rwlock_trywrlock(&t->lock))) {
1179 break;
1180 }
1181 _now = ast_tvnow();
1182 if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1183 break;
1184 }
1185 usleep(1);
1186 }
1187 } while (0);
1188#endif
1189
1190#ifdef DEBUG_THREADS
1191 if (!res && lt) {
1192 ast_reentrancy_lock(lt);
1193 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1194 lt->file[lt->reentrancy] = filename;
1195 lt->lineno[lt->reentrancy] = line;
1196 lt->func[lt->reentrancy] = func;
1197 lt->thread_id[lt->reentrancy] = pthread_self();
1198 lt->reentrancy++;
1199 }
1200 ast_reentrancy_unlock(lt);
1201 ast_mark_lock_acquired(t);
1202 } else if (lt) {
1203#ifdef HAVE_BKTR
1204 if (lt->reentrancy) {
1205 ast_reentrancy_lock(lt);
1206 bt = &lt->backtrace[lt->reentrancy-1];
1207 ast_reentrancy_unlock(lt);
1208 } else {
1209 bt = NULL;
1210 }
1211#endif
1212 ast_remove_lock_info(t, bt);
1213 }
1214 if (res) {
1215 log_mutex_error(canlog, "%s line %d (%s): Error obtaining read lock: %s\n",
1216 filename, line, func, strerror(res));
1217 DO_THREAD_CRASH;
1218 }
1219#endif /* DEBUG_THREADS */
1220
1221 return res;
1222}
1223
1224int __ast_rwlock_tryrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
1225{
1226 int res;
1227
1228#ifdef DEBUG_THREADS
1229 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1230 struct ast_bt *bt = NULL;
1231
1232 if (lt) {
1233#ifdef HAVE_BKTR
1234 struct ast_bt tmp;
1235
1236 /* The implementation of backtrace() may have its own locks.
1237 * Capture the backtrace outside of the reentrancy lock to
1238 * avoid deadlocks. See ASTERISK-22455. */
1240
1241 ast_reentrancy_lock(lt);
1242 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1243 lt->backtrace[lt->reentrancy] = tmp;
1244 bt = &lt->backtrace[lt->reentrancy];
1245 }
1246 ast_reentrancy_unlock(lt);
1247#endif
1248 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
1249 }
1250#endif /* DEBUG_THREADS */
1251
1252 res = pthread_rwlock_tryrdlock(&t->lock);
1253
1254#ifdef DEBUG_THREADS
1255 if (!res && lt) {
1256 ast_reentrancy_lock(lt);
1257 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1258 lt->file[lt->reentrancy] = filename;
1259 lt->lineno[lt->reentrancy] = line;
1260 lt->func[lt->reentrancy] = func;
1261 lt->thread_id[lt->reentrancy] = pthread_self();
1262 lt->reentrancy++;
1263 }
1264 ast_reentrancy_unlock(lt);
1265 ast_mark_lock_acquired(t);
1266 } else if (lt) {
1268 }
1269#endif /* DEBUG_THREADS */
1270
1271 return res;
1272}
1273
1274int __ast_rwlock_trywrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
1275{
1276 int res;
1277
1278#ifdef DEBUG_THREADS
1279 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1280 struct ast_bt *bt = NULL;
1281
1282 if (lt) {
1283#ifdef HAVE_BKTR
1284 struct ast_bt tmp;
1285
1286 /* The implementation of backtrace() may have its own locks.
1287 * Capture the backtrace outside of the reentrancy lock to
1288 * avoid deadlocks. See ASTERISK-22455. */
1290
1291 ast_reentrancy_lock(lt);
1292 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1293 lt->backtrace[lt->reentrancy] = tmp;
1294 bt = &lt->backtrace[lt->reentrancy];
1295 }
1296 ast_reentrancy_unlock(lt);
1297#endif
1298 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1299 }
1300#endif /* DEBUG_THREADS */
1301
1302 res = pthread_rwlock_trywrlock(&t->lock);
1303
1304#ifdef DEBUG_THREADS
1305 if (!res && lt) {
1306 ast_reentrancy_lock(lt);
1307 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1308 lt->file[lt->reentrancy] = filename;
1309 lt->lineno[lt->reentrancy] = line;
1310 lt->func[lt->reentrancy] = func;
1311 lt->thread_id[lt->reentrancy] = pthread_self();
1312 lt->reentrancy++;
1313 }
1314 ast_reentrancy_unlock(lt);
1315 ast_mark_lock_acquired(t);
1316 } else if (lt) {
1318 }
1319#endif /* DEBUG_THREADS */
1320
1321 return res;
1322}
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_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: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:1060
int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
Definition: lock.c:735
int __ast_rwlock_rdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
Definition: lock.c:853
int __ast_cond_broadcast(const char *filename, int lineno, const char *func, const char *cond_name, ast_cond_t *cond)
Definition: lock.c:536
int __ast_rwlock_tryrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
Definition: lock.c:1224
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:701
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:1142
int __ast_rwlock_unlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
Definition: lock.c:782
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:524
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:571
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:636
int __ast_cond_signal(const char *filename, int lineno, const char *func, const char *cond_name, ast_cond_t *cond)
Definition: lock.c:530
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:1274
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:542
int __ast_rwlock_wrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
Definition: lock.c:957
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:105
#define __AST_RWLOCK_INIT_VALUE
Definition: lock.h:88
#define ROFFSET
Definition: lock.h:246
#define pthread_cond_broadcast
Definition: lock.h:637
#define pthread_mutex_trylock
Definition: lock.h:631
#define AST_PTHREADT_NULL
Definition: lock.h:70
#define pthread_mutex_lock
Definition: lock.h:629
#define pthread_mutex_t
Definition: lock.h:626
#define AST_MUTEX_KIND
Definition: lock.h:81
pthread_cond_t ast_cond_t
Definition: lock.h:182
#define pthread_mutex_unlock
Definition: lock.h:630
#define pthread_mutex_destroy
Definition: lock.h:633
#define pthread_cond_destroy
Definition: lock.h:635
#define pthread_cond_signal
Definition: lock.h:636
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:524
#define pthread_mutex_init
Definition: lock.h:632
#define pthread_cond_init
Definition: lock.h:634
#define pthread_cond_timedwait
Definition: lock.h:639
#define pthread_cond_wait
Definition: lock.h:638
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:254
#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:131
unsigned int tracking
Definition: lock.h:129
Lock tracking information.
Definition: lock.h:115
int reentrancy
Definition: lock.h:118
struct ast_bt backtrace[AST_MAX_REENTRANCY]
Definition: lock.h:122
pthread_t thread_id[AST_MAX_REENTRANCY]
Definition: lock.h:120
int lineno[AST_MAX_REENTRANCY]
Definition: lock.h:117
pthread_mutex_t reentr_mutex
Definition: lock.h:124
const char * file[AST_MAX_REENTRANCY]
Definition: lock.h:116
const char * func[AST_MAX_REENTRANCY]
Definition: lock.h:119
Structure for mutex and tracking information.
Definition: lock.h:139
pthread_mutex_t mutex
Definition: lock.h:140
Structure for rwlock and tracking information.
Definition: lock.h:161
pthread_rwlock_t lock
Definition: lock.h:162
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
Utility functions.