Merge "pjproject_bundled: Replace earlier reverts with official fixes."
[asterisk/asterisk.git] / main / lock.c
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 */
32 static int mtx_prof = -1;
33 static 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
42 /* Allow direct use of pthread_mutex_* / pthread_cond_* */
43 #undef pthread_mutex_init
44 #undef pthread_mutex_destroy
45 #undef pthread_mutex_lock
46 #undef pthread_mutex_trylock
47 #undef pthread_mutex_t
48 #undef pthread_mutex_unlock
49 #undef pthread_cond_init
50 #undef pthread_cond_signal
51 #undef pthread_cond_broadcast
52 #undef pthread_cond_destroy
53 #undef pthread_cond_wait
54 #undef pthread_cond_timedwait
55
56 #if defined(DEBUG_THREADS)
57 #define log_mutex_error(canlog, ...) \
58         do { \
59                 if (canlog) { \
60                         ast_log(LOG_ERROR, __VA_ARGS__); \
61                 } else { \
62                         fprintf(stderr, __VA_ARGS__); \
63                 } \
64         } while (0)
65 #endif
66
67 #if defined(DEBUG_THREADS) && defined(HAVE_BKTR)
68 static void __dump_backtrace(struct ast_bt *bt, int canlog)
69 {
70         char **strings;
71         ssize_t i;
72
73         strings = backtrace_symbols(bt->addresses, bt->num_frames);
74
75         for (i = 0; i < bt->num_frames; i++) {
76                 log_mutex_error(canlog, "%s\n", strings[i]);
77         }
78
79         ast_std_free(strings);
80 }
81 #endif  /* defined(DEBUG_THREADS) && defined(HAVE_BKTR) */
82
83 #ifdef DEBUG_THREADS
84 AST_MUTEX_DEFINE_STATIC(reentrancy_lock);
85
86 static inline struct ast_lock_track *ast_get_reentrancy(struct ast_lock_track **plt,
87         struct ast_lock_track_flags *flags, int no_setup)
88 {
89         pthread_mutexattr_t reentr_attr;
90         struct ast_lock_track *lt;
91
92         if (!flags->tracking || flags->setup) {
93                 return *plt;
94         }
95
96         pthread_mutex_lock(&reentrancy_lock.mutex);
97
98         if (*plt) {
99                 pthread_mutex_unlock(&reentrancy_lock.mutex);
100                 return *plt;
101         }
102
103         if (no_setup) {
104                 pthread_mutex_unlock(&reentrancy_lock.mutex);
105                 return NULL;
106         }
107
108         lt = *plt = ast_std_calloc(1, sizeof(*lt));
109         if (!lt) {
110                 fprintf(stderr, "%s: Failed to allocate lock tracking\n", __func__);
111 #if defined(DO_CRASH) || defined(THREAD_CRASH)
112                 abort();
113 #else
114                 pthread_mutex_unlock(&reentrancy_lock.mutex);
115                 return NULL;
116 #endif
117         }
118
119         pthread_mutexattr_init(&reentr_attr);
120         pthread_mutexattr_settype(&reentr_attr, AST_MUTEX_KIND);
121         pthread_mutex_init(&lt->reentr_mutex, &reentr_attr);
122         pthread_mutexattr_destroy(&reentr_attr);
123
124         flags->setup = 1;
125         pthread_mutex_unlock(&reentrancy_lock.mutex);
126         return lt;
127 }
128
129 static inline void delete_reentrancy_cs(struct ast_lock_track **plt)
130 {
131         struct ast_lock_track *lt;
132
133         if (*plt) {
134                 lt = *plt;
135                 *plt = NULL;
136
137                 pthread_mutex_destroy(&lt->reentr_mutex);
138                 ast_std_free(lt);
139         }
140 }
141
142 #endif /* DEBUG_THREADS */
143
144 int __ast_pthread_mutex_init(int tracking, const char *filename, int lineno, const char *func,
145                                                 const char *mutex_name, ast_mutex_t *t)
146 {
147         int res;
148         pthread_mutexattr_t  attr;
149
150 #ifdef DEBUG_THREADS
151 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
152         if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
153                 int canlog = tracking && strcmp(filename, "logger.c");
154
155                 log_mutex_error(canlog, "%s line %d (%s): NOTICE: mutex '%s' is already initialized.\n",
156                                    filename, lineno, func, mutex_name);
157                 DO_THREAD_CRASH;
158                 return EBUSY;
159         }
160 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
161
162         t->track = NULL;
163         t->flags.tracking = tracking;
164         t->flags.setup = 0;
165 #endif /* DEBUG_THREADS */
166
167         pthread_mutexattr_init(&attr);
168         pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
169         res = pthread_mutex_init(&t->mutex, &attr);
170         pthread_mutexattr_destroy(&attr);
171
172         return res;
173 }
174
175 int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
176                                                 const char *mutex_name, ast_mutex_t *t)
177 {
178         int res;
179
180 #ifdef DEBUG_THREADS
181         struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 1);
182         int canlog = t->flags.tracking && strcmp(filename, "logger.c");
183
184 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
185         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
186                 /* Don't try to uninitialize an uninitialized mutex
187                  * This may have no effect on linux
188                  * but it always generates a core on *BSD when
189                  * linked with libpthread.
190                  * This is not an error condition if the mutex is created on the fly.
191                  */
192                 log_mutex_error(canlog, "%s line %d (%s): NOTICE: mutex '%s' is uninitialized.\n",
193                                    filename, lineno, func, mutex_name);
194                 DO_THREAD_CRASH;
195                 res = EINVAL;
196                 goto lt_cleanup;
197         }
198 #endif
199
200         res = pthread_mutex_trylock(&t->mutex);
201         switch (res) {
202         case 0:
203                 pthread_mutex_unlock(&t->mutex);
204                 break;
205         case EINVAL:
206                 log_mutex_error(canlog, "%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
207                                   filename, lineno, func, mutex_name);
208                 break;
209         case EBUSY:
210                 log_mutex_error(canlog, "%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
211                                    filename, lineno, func, mutex_name);
212                 if (lt) {
213                         ast_reentrancy_lock(lt);
214                         log_mutex_error(canlog, "%s line %d (%s): Error: '%s' was locked here.\n",
215                                     lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
216 #ifdef HAVE_BKTR
217                         __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
218 #endif
219                         ast_reentrancy_unlock(lt);
220                 }
221                 break;
222         }
223 #endif /* DEBUG_THREADS */
224
225         res = pthread_mutex_destroy(&t->mutex);
226
227 #ifdef DEBUG_THREADS
228         if (res) {
229                 log_mutex_error(canlog, "%s line %d (%s): Error destroying mutex %s: %s\n",
230                                    filename, lineno, func, mutex_name, strerror(res));
231         }
232 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
233 lt_cleanup:
234 #endif
235         if (lt) {
236                 ast_reentrancy_lock(lt);
237                 lt->file[0] = filename;
238                 lt->lineno[0] = lineno;
239                 lt->func[0] = func;
240                 lt->reentrancy = 0;
241                 lt->thread_id[0] = 0;
242 #ifdef HAVE_BKTR
243                 memset(&lt->backtrace[0], 0, sizeof(lt->backtrace[0]));
244 #endif
245                 ast_reentrancy_unlock(lt);
246                 delete_reentrancy_cs(&t->track);
247         }
248 #endif /* DEBUG_THREADS */
249
250         return res;
251 }
252
253 int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
254                                 const char* mutex_name, ast_mutex_t *t)
255 {
256         int res;
257
258 #ifdef DEBUG_THREADS
259         struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
260         int canlog = t->flags.tracking && strcmp(filename, "logger.c");
261         struct ast_bt *bt = NULL;
262
263         if (lt) {
264 #ifdef HAVE_BKTR
265                 struct ast_bt tmp;
266
267                 /* The implementation of backtrace() may have its own locks.
268                  * Capture the backtrace outside of the reentrancy lock to
269                  * avoid deadlocks. See ASTERISK-22455. */
270                 ast_bt_get_addresses(&tmp);
271
272                 ast_reentrancy_lock(lt);
273                 if (lt->reentrancy < AST_MAX_REENTRANCY) {
274                         lt->backtrace[lt->reentrancy] = tmp;
275                         bt = &lt->backtrace[lt->reentrancy];
276                 }
277                 ast_reentrancy_unlock(lt);
278 #endif
279                 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
280         }
281 #endif /* DEBUG_THREADS */
282
283 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
284         {
285                 time_t seconds = time(NULL);
286                 time_t wait_time, reported_wait = 0;
287                 do {
288 #ifdef  HAVE_MTX_PROFILE
289                         ast_mark(mtx_prof, 1);
290 #endif
291                         res = pthread_mutex_trylock(&t->mutex);
292 #ifdef  HAVE_MTX_PROFILE
293                         ast_mark(mtx_prof, 0);
294 #endif
295                         if (res == EBUSY) {
296                                 wait_time = time(NULL) - seconds;
297                                 if (wait_time > reported_wait && (wait_time % 5) == 0) {
298                                         log_mutex_error(canlog, "%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
299                                                            filename, lineno, func, (int) wait_time, mutex_name);
300                                         if (lt) {
301                                                 ast_reentrancy_lock(lt);
302 #ifdef HAVE_BKTR
303                                                 __dump_backtrace(&lt->backtrace[lt->reentrancy], canlog);
304 #endif
305                                                 log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
306                                                                    lt->file[ROFFSET], lt->lineno[ROFFSET],
307                                                                    lt->func[ROFFSET], mutex_name);
308 #ifdef HAVE_BKTR
309                                                 __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
310 #endif
311                                                 ast_reentrancy_unlock(lt);
312                                         }
313                                         reported_wait = wait_time;
314                                 }
315                                 usleep(200);
316                         }
317                 } while (res == EBUSY);
318         }
319 #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
320 #ifdef  HAVE_MTX_PROFILE
321         ast_mark(mtx_prof, 1);
322         res = pthread_mutex_trylock(&t->mutex);
323         ast_mark(mtx_prof, 0);
324         if (res)
325 #endif
326         res = pthread_mutex_lock(&t->mutex);
327 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
328
329 #ifdef DEBUG_THREADS
330         if (lt && !res) {
331                 ast_reentrancy_lock(lt);
332                 if (lt->reentrancy < AST_MAX_REENTRANCY) {
333                         lt->file[lt->reentrancy] = filename;
334                         lt->lineno[lt->reentrancy] = lineno;
335                         lt->func[lt->reentrancy] = func;
336                         lt->thread_id[lt->reentrancy] = pthread_self();
337                         lt->reentrancy++;
338                 } else {
339                         log_mutex_error(canlog, "%s line %d (%s): '%s' really deep reentrancy!\n",
340                                                            filename, lineno, func, mutex_name);
341                 }
342                 ast_reentrancy_unlock(lt);
343                 ast_mark_lock_acquired(t);
344         } else if (lt) {
345 #ifdef HAVE_BKTR
346                 if (lt->reentrancy) {
347                         ast_reentrancy_lock(lt);
348                         bt = &lt->backtrace[lt->reentrancy-1];
349                         ast_reentrancy_unlock(lt);
350                 } else {
351                         bt = NULL;
352                 }
353 #endif
354                 ast_remove_lock_info(t, bt);
355         }
356         if (res) {
357                 log_mutex_error(canlog, "%s line %d (%s): Error obtaining mutex: %s\n",
358                                    filename, lineno, func, strerror(res));
359                 DO_THREAD_CRASH;
360         }
361 #endif /* DEBUG_THREADS */
362
363         return res;
364 }
365
366 int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
367                                 const char* mutex_name, ast_mutex_t *t)
368 {
369         int res;
370
371 #ifdef DEBUG_THREADS
372         struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
373         int canlog = t->flags.tracking && strcmp(filename, "logger.c");
374         struct ast_bt *bt = NULL;
375
376         if (lt) {
377 #ifdef HAVE_BKTR
378                 struct ast_bt tmp;
379
380                 /* The implementation of backtrace() may have its own locks.
381                  * Capture the backtrace outside of the reentrancy lock to
382                  * avoid deadlocks. See ASTERISK-22455. */
383                 ast_bt_get_addresses(&tmp);
384
385                 ast_reentrancy_lock(lt);
386                 if (lt->reentrancy < AST_MAX_REENTRANCY) {
387                         lt->backtrace[lt->reentrancy] = tmp;
388                         bt = &lt->backtrace[lt->reentrancy];
389                 }
390                 ast_reentrancy_unlock(lt);
391 #endif
392                 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
393         }
394 #endif /* DEBUG_THREADS */
395
396         res = pthread_mutex_trylock(&t->mutex);
397
398 #ifdef DEBUG_THREADS
399         if (lt && !res) {
400                 ast_reentrancy_lock(lt);
401                 if (lt->reentrancy < AST_MAX_REENTRANCY) {
402                         lt->file[lt->reentrancy] = filename;
403                         lt->lineno[lt->reentrancy] = lineno;
404                         lt->func[lt->reentrancy] = func;
405                         lt->thread_id[lt->reentrancy] = pthread_self();
406                         lt->reentrancy++;
407                 } else {
408                         log_mutex_error(canlog, "%s line %d (%s): '%s' really deep reentrancy!\n",
409                                            filename, lineno, func, mutex_name);
410                 }
411                 ast_reentrancy_unlock(lt);
412                 ast_mark_lock_acquired(t);
413         } else if (lt) {
414                 ast_mark_lock_failed(t);
415         }
416 #endif /* DEBUG_THREADS */
417
418         return res;
419 }
420
421 int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
422                                              const char *mutex_name, ast_mutex_t *t)
423 {
424         int res;
425
426 #ifdef DEBUG_THREADS
427         struct ast_lock_track *lt = NULL;
428         int canlog = t->flags.tracking && strcmp(filename, "logger.c");
429         struct ast_bt *bt = NULL;
430
431 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
432         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
433                 log_mutex_error(canlog, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
434                                    filename, lineno, func, mutex_name);
435                 DO_THREAD_CRASH;
436                 return EINVAL;
437         }
438 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
439
440         lt = ast_get_reentrancy(&t->track, &t->flags, 0);
441         if (lt) {
442                 ast_reentrancy_lock(lt);
443                 if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) {
444                         log_mutex_error(canlog, "%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
445                                            filename, lineno, func, mutex_name);
446                         log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
447                                            lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
448 #ifdef HAVE_BKTR
449                         __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
450 #endif
451                         DO_THREAD_CRASH;
452                 }
453
454                 if (--lt->reentrancy < 0) {
455                         log_mutex_error(canlog, "%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
456                                            filename, lineno, func, mutex_name);
457                         lt->reentrancy = 0;
458                 }
459
460                 if (lt->reentrancy < AST_MAX_REENTRANCY) {
461                         lt->file[lt->reentrancy] = NULL;
462                         lt->lineno[lt->reentrancy] = 0;
463                         lt->func[lt->reentrancy] = NULL;
464                         lt->thread_id[lt->reentrancy] = 0;
465                 }
466
467 #ifdef HAVE_BKTR
468                 if (lt->reentrancy) {
469                         bt = &lt->backtrace[lt->reentrancy - 1];
470                 }
471 #endif
472                 ast_reentrancy_unlock(lt);
473
474                 ast_remove_lock_info(t, bt);
475         }
476 #endif /* DEBUG_THREADS */
477
478         res = pthread_mutex_unlock(&t->mutex);
479
480 #ifdef DEBUG_THREADS
481         if (res) {
482                 log_mutex_error(canlog, "%s line %d (%s): Error releasing mutex: %s\n",
483                                    filename, lineno, func, strerror(res));
484                 DO_THREAD_CRASH;
485         }
486 #endif /* DEBUG_THREADS */
487
488         return res;
489 }
490
491
492 int __ast_cond_init(const char *filename, int lineno, const char *func,
493                                   const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
494 {
495         return pthread_cond_init(cond, cond_attr);
496 }
497
498 int __ast_cond_signal(const char *filename, int lineno, const char *func,
499                                     const char *cond_name, ast_cond_t *cond)
500 {
501         return pthread_cond_signal(cond);
502 }
503
504 int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
505                                        const char *cond_name, ast_cond_t *cond)
506 {
507         return pthread_cond_broadcast(cond);
508 }
509
510 int __ast_cond_destroy(const char *filename, int lineno, const char *func,
511                                      const char *cond_name, ast_cond_t *cond)
512 {
513         return pthread_cond_destroy(cond);
514 }
515
516 #ifdef DEBUG_THREADS
517 static void restore_lock_tracking(struct ast_lock_track *lt, struct ast_lock_track *lt_saved)
518 {
519         ast_reentrancy_lock(lt);
520
521         /*
522          * The following code must match the struct ast_lock_track
523          * definition with the explicit exception of the reentr_mutex
524          * member.
525          */
526         memcpy(lt->file, lt_saved->file, sizeof(lt->file));
527         memcpy(lt->lineno, lt_saved->lineno, sizeof(lt->lineno));
528         lt->reentrancy = lt_saved->reentrancy;
529         memcpy(lt->func, lt_saved->func, sizeof(lt->func));
530         memcpy(lt->thread_id, lt_saved->thread_id, sizeof(lt->thread_id));
531 #ifdef HAVE_BKTR
532         memcpy(lt->backtrace, lt_saved->backtrace, sizeof(lt->backtrace));
533 #endif
534
535         ast_reentrancy_unlock(lt);
536 }
537 #endif /* DEBUG_THREADS */
538
539 int __ast_cond_wait(const char *filename, int lineno, const char *func,
540                                   const char *cond_name, const char *mutex_name,
541                                   ast_cond_t *cond, ast_mutex_t *t)
542 {
543         int res;
544
545 #ifdef DEBUG_THREADS
546         struct ast_lock_track *lt = NULL;
547         struct ast_lock_track lt_orig;
548         int canlog = t->flags.tracking && strcmp(filename, "logger.c");
549
550 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
551         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
552                 log_mutex_error(canlog, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
553                                    filename, lineno, func, mutex_name);
554                 DO_THREAD_CRASH;
555                 return EINVAL;
556         }
557 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
558
559         lt = ast_get_reentrancy(&t->track, &t->flags, 0);
560         if (lt) {
561                 ast_reentrancy_lock(lt);
562                 if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) {
563                         log_mutex_error(canlog, "%s line %d (%s): attempted wait using mutex '%s' without owning it!\n",
564                                            filename, lineno, func, mutex_name);
565                         log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
566                                            lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
567 #ifdef HAVE_BKTR
568                         __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
569 #endif
570                         DO_THREAD_CRASH;
571                 } else if (lt->reentrancy <= 0) {
572                         log_mutex_error(canlog, "%s line %d (%s): attempted wait using an unlocked mutex '%s'\n",
573                                            filename, lineno, func, mutex_name);
574                         DO_THREAD_CRASH;
575                 }
576
577                 /* Waiting on a condition completely suspends a recursive mutex,
578                  * even if it's been recursively locked multiple times. Make a
579                  * copy of the lock tracking, and reset reentrancy to zero */
580                 lt_orig = *lt;
581                 lt->reentrancy = 0;
582                 ast_reentrancy_unlock(lt);
583
584                 ast_suspend_lock_info(t);
585         }
586 #endif /* DEBUG_THREADS */
587
588         res = pthread_cond_wait(cond, &t->mutex);
589
590 #ifdef DEBUG_THREADS
591         if (res) {
592                 log_mutex_error(canlog, "%s line %d (%s): Error waiting on condition mutex '%s'\n",
593                                    filename, lineno, func, strerror(res));
594                 DO_THREAD_CRASH;
595         } else if (lt) {
596                 restore_lock_tracking(lt, &lt_orig);
597                 ast_restore_lock_info(t);
598         }
599 #endif /* DEBUG_THREADS */
600
601         return res;
602 }
603
604 int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
605                                        const char *cond_name, const char *mutex_name, ast_cond_t *cond,
606                                        ast_mutex_t *t, const struct timespec *abstime)
607 {
608         int res;
609
610 #ifdef DEBUG_THREADS
611         struct ast_lock_track *lt = NULL;
612         struct ast_lock_track lt_orig;
613         int canlog = t->flags.tracking && strcmp(filename, "logger.c");
614
615 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
616         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
617                 log_mutex_error(canlog, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
618                                    filename, lineno, func, mutex_name);
619                 DO_THREAD_CRASH;
620                 return EINVAL;
621         }
622 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
623
624         lt = ast_get_reentrancy(&t->track, &t->flags, 0);
625         if (lt) {
626                 ast_reentrancy_lock(lt);
627                 if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) {
628                         log_mutex_error(canlog, "%s line %d (%s): attempted wait using mutex '%s' without owning it!\n",
629                                            filename, lineno, func, mutex_name);
630                         log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
631                                            lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
632 #ifdef HAVE_BKTR
633                         __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
634 #endif
635                         DO_THREAD_CRASH;
636                 } else if (lt->reentrancy <= 0) {
637                         log_mutex_error(canlog, "%s line %d (%s): attempted wait using an unlocked mutex '%s'\n",
638                                            filename, lineno, func, mutex_name);
639                         DO_THREAD_CRASH;
640                 }
641
642                 /* Waiting on a condition completely suspends a recursive mutex,
643                  * even if it's been recursively locked multiple times. Make a
644                  * copy of the lock tracking, and reset reentrancy to zero */
645                 lt_orig = *lt;
646                 lt->reentrancy = 0;
647                 ast_reentrancy_unlock(lt);
648
649                 ast_suspend_lock_info(t);
650         }
651 #endif /* DEBUG_THREADS */
652
653         res = pthread_cond_timedwait(cond, &t->mutex, abstime);
654
655 #ifdef DEBUG_THREADS
656         if (res && (res != ETIMEDOUT)) {
657                 log_mutex_error(canlog, "%s line %d (%s): Error waiting on condition mutex '%s'\n",
658                                    filename, lineno, func, strerror(res));
659                 DO_THREAD_CRASH;
660         } else if (lt) {
661                 restore_lock_tracking(lt, &lt_orig);
662                 ast_restore_lock_info(t);
663         }
664 #endif /* DEBUG_THREADS */
665
666         return res;
667 }
668
669 int __ast_rwlock_init(int tracking, const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
670 {
671         int res;
672         pthread_rwlockattr_t attr;
673
674 #ifdef DEBUG_THREADS
675 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
676         if (t->lock != ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
677                 int canlog = tracking && strcmp(filename, "logger.c");
678
679                 log_mutex_error(canlog, "%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
680                                 filename, lineno, func, rwlock_name);
681                 DO_THREAD_CRASH;
682                 return EBUSY;
683         }
684 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
685
686         t->track = NULL;
687         t->flags.tracking = tracking;
688         t->flags.setup = 0;
689 #endif /* DEBUG_THREADS */
690
691         pthread_rwlockattr_init(&attr);
692 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
693         pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
694 #endif
695         res = pthread_rwlock_init(&t->lock, &attr);
696         pthread_rwlockattr_destroy(&attr);
697
698         return res;
699 }
700
701 int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
702 {
703         int res;
704
705 #ifdef DEBUG_THREADS
706         struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 1);
707         int canlog = t->flags.tracking && strcmp(filename, "logger.c");
708
709 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
710         if (t->lock == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
711                 log_mutex_error(canlog, "%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
712                                    filename, lineno, func, rwlock_name);
713                 DO_THREAD_CRASH;
714                 res = EINVAL;
715                 goto lt_cleanup;
716         }
717 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
718 #endif /* DEBUG_THREADS */
719
720         res = pthread_rwlock_destroy(&t->lock);
721
722 #ifdef DEBUG_THREADS
723         if (res) {
724                 log_mutex_error(canlog, "%s line %d (%s): Error destroying rwlock %s: %s\n",
725                                 filename, lineno, func, rwlock_name, strerror(res));
726         }
727 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
728 lt_cleanup:
729 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
730         if (lt) {
731                 ast_reentrancy_lock(lt);
732                 lt->file[0] = filename;
733                 lt->lineno[0] = lineno;
734                 lt->func[0] = func;
735                 lt->reentrancy = 0;
736                 lt->thread_id[0] = 0;
737 #ifdef HAVE_BKTR
738                 memset(&lt->backtrace[0], 0, sizeof(lt->backtrace[0]));
739 #endif
740                 ast_reentrancy_unlock(lt);
741                 delete_reentrancy_cs(&t->track);
742         }
743 #endif /* DEBUG_THREADS */
744
745         return res;
746 }
747
748 int __ast_rwlock_unlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
749 {
750         int res;
751
752 #ifdef DEBUG_THREADS
753         struct ast_lock_track *lt = NULL;
754         int canlog = t->flags.tracking && strcmp(filename, "logger.c");
755         struct ast_bt *bt = NULL;
756         int lock_found = 0;
757
758 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
759         if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
760                 log_mutex_error(canlog, "%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
761                                    filename, line, func, name);
762                 DO_THREAD_CRASH;
763                 return EINVAL;
764         }
765 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
766
767         lt = ast_get_reentrancy(&t->track, &t->flags, 0);
768         if (lt) {
769                 ast_reentrancy_lock(lt);
770                 if (lt->reentrancy) {
771                         int i;
772                         pthread_t self = pthread_self();
773                         for (i = lt->reentrancy - 1; i >= 0; --i) {
774                                 if (lt->thread_id[i] == self) {
775                                         lock_found = 1;
776                                         if (i != lt->reentrancy - 1) {
777                                                 lt->file[i] = lt->file[lt->reentrancy - 1];
778                                                 lt->lineno[i] = lt->lineno[lt->reentrancy - 1];
779                                                 lt->func[i] = lt->func[lt->reentrancy - 1];
780                                                 lt->thread_id[i] = lt->thread_id[lt->reentrancy - 1];
781                                         }
782 #ifdef HAVE_BKTR
783                                         bt = &lt->backtrace[i];
784 #endif
785                                         lt->file[lt->reentrancy - 1] = NULL;
786                                         lt->lineno[lt->reentrancy - 1] = 0;
787                                         lt->func[lt->reentrancy - 1] = NULL;
788                                         lt->thread_id[lt->reentrancy - 1] = AST_PTHREADT_NULL;
789                                         break;
790                                 }
791                         }
792                 }
793
794                 if (lock_found && --lt->reentrancy < 0) {
795                         log_mutex_error(canlog, "%s line %d (%s): rwlock '%s' freed more times than we've locked!\n",
796                                         filename, line, func, name);
797                         lt->reentrancy = 0;
798                 }
799
800                 ast_reentrancy_unlock(lt);
801
802                 ast_remove_lock_info(t, bt);
803         }
804 #endif /* DEBUG_THREADS */
805
806         res = pthread_rwlock_unlock(&t->lock);
807
808 #ifdef DEBUG_THREADS
809         if (res) {
810                 log_mutex_error(canlog, "%s line %d (%s): Error releasing rwlock: %s\n",
811                                 filename, line, func, strerror(res));
812                 DO_THREAD_CRASH;
813         }
814 #endif /* DEBUG_THREADS */
815
816         return res;
817 }
818
819 int __ast_rwlock_rdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
820 {
821         int res;
822
823 #ifdef DEBUG_THREADS
824         struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
825         int canlog = t->flags.tracking && strcmp(filename, "logger.c");
826         struct ast_bt *bt = NULL;
827
828         if (lt) {
829 #ifdef HAVE_BKTR
830                 struct ast_bt tmp;
831
832                 /* The implementation of backtrace() may have its own locks.
833                  * Capture the backtrace outside of the reentrancy lock to
834                  * avoid deadlocks. See ASTERISK-22455. */
835                 ast_bt_get_addresses(&tmp);
836
837                 ast_reentrancy_lock(lt);
838                 if (lt->reentrancy < AST_MAX_REENTRANCY) {
839                         lt->backtrace[lt->reentrancy] = tmp;
840                         bt = &lt->backtrace[lt->reentrancy];
841                 }
842                 ast_reentrancy_unlock(lt);
843 #endif
844                 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
845         }
846 #endif /* DEBUG_THREADS */
847
848 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
849         {
850                 time_t seconds = time(NULL);
851                 time_t wait_time, reported_wait = 0;
852                 do {
853                         res = pthread_rwlock_tryrdlock(&t->lock);
854                         if (res == EBUSY) {
855                                 wait_time = time(NULL) - seconds;
856                                 if (wait_time > reported_wait && (wait_time % 5) == 0) {
857                                         log_mutex_error(canlog, "%s line %d (%s): Deadlock? waited %d sec for readlock '%s'?\n",
858                                                 filename, line, func, (int)wait_time, name);
859                                         if (lt) {
860                                                 ast_reentrancy_lock(lt);
861 #ifdef HAVE_BKTR
862                                                 __dump_backtrace(&lt->backtrace[lt->reentrancy], canlog);
863 #endif
864                                                 log_mutex_error(canlog, "%s line %d (%s): '%s' was locked  here.\n",
865                                                                 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
866                                                                 lt->func[lt->reentrancy-1], name);
867 #ifdef HAVE_BKTR
868                                                 __dump_backtrace(&lt->backtrace[lt->reentrancy-1], canlog);
869 #endif
870                                                 ast_reentrancy_unlock(lt);
871                                         }
872                                         reported_wait = wait_time;
873                                 }
874                                 usleep(200);
875                         }
876                 } while (res == EBUSY);
877         }
878 #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
879         res = pthread_rwlock_rdlock(&t->lock);
880 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
881
882 #ifdef DEBUG_THREADS
883         if (!res && lt) {
884                 ast_reentrancy_lock(lt);
885                 if (lt->reentrancy < AST_MAX_REENTRANCY) {
886                         lt->file[lt->reentrancy] = filename;
887                         lt->lineno[lt->reentrancy] = line;
888                         lt->func[lt->reentrancy] = func;
889                         lt->thread_id[lt->reentrancy] = pthread_self();
890                         lt->reentrancy++;
891                 }
892                 ast_reentrancy_unlock(lt);
893                 ast_mark_lock_acquired(t);
894         } else if (lt) {
895 #ifdef HAVE_BKTR
896                 if (lt->reentrancy) {
897                         ast_reentrancy_lock(lt);
898                         bt = &lt->backtrace[lt->reentrancy-1];
899                         ast_reentrancy_unlock(lt);
900                 } else {
901                         bt = NULL;
902                 }
903 #endif
904                 ast_remove_lock_info(t, bt);
905         }
906
907         if (res) {
908                 log_mutex_error(canlog, "%s line %d (%s): Error obtaining read lock: %s\n",
909                                 filename, line, func, strerror(res));
910                 DO_THREAD_CRASH;
911         }
912 #endif /* DEBUG_THREADS */
913
914         return res;
915 }
916
917 int __ast_rwlock_wrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
918 {
919         int res;
920
921 #ifdef DEBUG_THREADS
922         struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
923         int canlog = t->flags.tracking && strcmp(filename, "logger.c");
924         struct ast_bt *bt = NULL;
925
926         if (lt) {
927 #ifdef HAVE_BKTR
928                 struct ast_bt tmp;
929
930                 /* The implementation of backtrace() may have its own locks.
931                  * Capture the backtrace outside of the reentrancy lock to
932                  * avoid deadlocks. See ASTERISK-22455. */
933                 ast_bt_get_addresses(&tmp);
934
935                 ast_reentrancy_lock(lt);
936                 if (lt->reentrancy < AST_MAX_REENTRANCY) {
937                         lt->backtrace[lt->reentrancy] = tmp;
938                         bt = &lt->backtrace[lt->reentrancy];
939                 }
940                 ast_reentrancy_unlock(lt);
941 #endif
942                 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
943         }
944 #endif /* DEBUG_THREADS */
945
946 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
947         {
948                 time_t seconds = time(NULL);
949                 time_t wait_time, reported_wait = 0;
950                 do {
951                         res = pthread_rwlock_trywrlock(&t->lock);
952                         if (res == EBUSY) {
953                                 wait_time = time(NULL) - seconds;
954                                 if (wait_time > reported_wait && (wait_time % 5) == 0) {
955                                         log_mutex_error(canlog, "%s line %d (%s): Deadlock? waited %d sec for writelock '%s'?\n",
956                                                 filename, line, func, (int)wait_time, name);
957                                         if (lt) {
958                                                 ast_reentrancy_lock(lt);
959 #ifdef HAVE_BKTR
960                                                 __dump_backtrace(&lt->backtrace[lt->reentrancy], canlog);
961 #endif
962                                                 log_mutex_error(canlog, "%s line %d (%s): '%s' was locked  here.\n",
963                                                                 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
964                                                                 lt->func[lt->reentrancy-1], name);
965 #ifdef HAVE_BKTR
966                                                 __dump_backtrace(&lt->backtrace[lt->reentrancy-1], canlog);
967 #endif
968                                                 ast_reentrancy_unlock(lt);
969                                         }
970                                         reported_wait = wait_time;
971                                 }
972                                 usleep(200);
973                         }
974                 } while (res == EBUSY);
975         }
976 #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
977         res = pthread_rwlock_wrlock(&t->lock);
978 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
979
980 #ifdef DEBUG_THREADS
981         if (!res && lt) {
982                 ast_reentrancy_lock(lt);
983                 if (lt->reentrancy < AST_MAX_REENTRANCY) {
984                         lt->file[lt->reentrancy] = filename;
985                         lt->lineno[lt->reentrancy] = line;
986                         lt->func[lt->reentrancy] = func;
987                         lt->thread_id[lt->reentrancy] = pthread_self();
988                         lt->reentrancy++;
989                 }
990                 ast_reentrancy_unlock(lt);
991                 ast_mark_lock_acquired(t);
992         } else if (lt) {
993 #ifdef HAVE_BKTR
994                 if (lt->reentrancy) {
995                         ast_reentrancy_lock(lt);
996                         bt = &lt->backtrace[lt->reentrancy-1];
997                         ast_reentrancy_unlock(lt);
998                 } else {
999                         bt = NULL;
1000                 }
1001 #endif
1002                 ast_remove_lock_info(t, bt);
1003         }
1004         if (res) {
1005                 log_mutex_error(canlog, "%s line %d (%s): Error obtaining write lock: %s\n",
1006                                 filename, line, func, strerror(res));
1007                 DO_THREAD_CRASH;
1008         }
1009 #endif /* DEBUG_THREADS */
1010
1011         return res;
1012 }
1013
1014 int __ast_rwlock_timedrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name,
1015         const struct timespec *abs_timeout)
1016 {
1017         int res;
1018
1019 #ifdef DEBUG_THREADS
1020         struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1021         int canlog = t->flags.tracking && strcmp(filename, "logger.c");
1022         struct ast_bt *bt = NULL;
1023
1024         if (lt) {
1025 #ifdef HAVE_BKTR
1026                 struct ast_bt tmp;
1027
1028                 /* The implementation of backtrace() may have its own locks.
1029                  * Capture the backtrace outside of the reentrancy lock to
1030                  * avoid deadlocks. See ASTERISK-22455. */
1031                 ast_bt_get_addresses(&tmp);
1032
1033                 ast_reentrancy_lock(lt);
1034                 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1035                         lt->backtrace[lt->reentrancy] = tmp;
1036                         bt = &lt->backtrace[lt->reentrancy];
1037                 }
1038                 ast_reentrancy_unlock(lt);
1039 #endif
1040                 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1041         }
1042 #endif /* DEBUG_THREADS */
1043
1044 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1045         res = pthread_rwlock_timedrdlock(&t->lock, abs_timeout);
1046 #else
1047         do {
1048                 struct timeval _now;
1049                 for (;;) {
1050                         if (!(res = pthread_rwlock_tryrdlock(&t->lock))) {
1051                                 break;
1052                         }
1053                         _now = ast_tvnow();
1054                         if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1055                                 break;
1056                         }
1057                         usleep(1);
1058                 }
1059         } while (0);
1060 #endif
1061
1062 #ifdef DEBUG_THREADS
1063         if (!res && lt) {
1064                 ast_reentrancy_lock(lt);
1065                 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1066                         lt->file[lt->reentrancy] = filename;
1067                         lt->lineno[lt->reentrancy] = line;
1068                         lt->func[lt->reentrancy] = func;
1069                         lt->thread_id[lt->reentrancy] = pthread_self();
1070                         lt->reentrancy++;
1071                 }
1072                 ast_reentrancy_unlock(lt);
1073                 ast_mark_lock_acquired(t);
1074         } else if (lt) {
1075 #ifdef HAVE_BKTR
1076                 if (lt->reentrancy) {
1077                         ast_reentrancy_lock(lt);
1078                         bt = &lt->backtrace[lt->reentrancy-1];
1079                         ast_reentrancy_unlock(lt);
1080                 } else {
1081                         bt = NULL;
1082                 }
1083 #endif
1084                 ast_remove_lock_info(t, bt);
1085         }
1086         if (res) {
1087                 log_mutex_error(canlog, "%s line %d (%s): Error obtaining read lock: %s\n",
1088                                 filename, line, func, strerror(res));
1089                 DO_THREAD_CRASH;
1090         }
1091 #endif /* DEBUG_THREADS */
1092
1093         return res;
1094 }
1095
1096 int __ast_rwlock_timedwrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name,
1097         const struct timespec *abs_timeout)
1098 {
1099         int res;
1100
1101 #ifdef DEBUG_THREADS
1102         struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1103         int canlog = t->flags.tracking && strcmp(filename, "logger.c");
1104         struct ast_bt *bt = NULL;
1105
1106         if (lt) {
1107 #ifdef HAVE_BKTR
1108                 struct ast_bt tmp;
1109
1110                 /* The implementation of backtrace() may have its own locks.
1111                  * Capture the backtrace outside of the reentrancy lock to
1112                  * avoid deadlocks. See ASTERISK-22455. */
1113                 ast_bt_get_addresses(&tmp);
1114
1115                 ast_reentrancy_lock(lt);
1116                 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1117                         lt->backtrace[lt->reentrancy] = tmp;
1118                         bt = &lt->backtrace[lt->reentrancy];
1119                 }
1120                 ast_reentrancy_unlock(lt);
1121 #endif
1122                 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1123         }
1124 #endif /* DEBUG_THREADS */
1125
1126 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1127         res = pthread_rwlock_timedwrlock(&t->lock, abs_timeout);
1128 #else
1129         do {
1130                 struct timeval _now;
1131                 for (;;) {
1132                         if (!(res = pthread_rwlock_trywrlock(&t->lock))) {
1133                                 break;
1134                         }
1135                         _now = ast_tvnow();
1136                         if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1137                                 break;
1138                         }
1139                         usleep(1);
1140                 }
1141         } while (0);
1142 #endif
1143
1144 #ifdef DEBUG_THREADS
1145         if (!res && lt) {
1146                 ast_reentrancy_lock(lt);
1147                 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1148                         lt->file[lt->reentrancy] = filename;
1149                         lt->lineno[lt->reentrancy] = line;
1150                         lt->func[lt->reentrancy] = func;
1151                         lt->thread_id[lt->reentrancy] = pthread_self();
1152                         lt->reentrancy++;
1153                 }
1154                 ast_reentrancy_unlock(lt);
1155                 ast_mark_lock_acquired(t);
1156         } else if (lt) {
1157 #ifdef HAVE_BKTR
1158                 if (lt->reentrancy) {
1159                         ast_reentrancy_lock(lt);
1160                         bt = &lt->backtrace[lt->reentrancy-1];
1161                         ast_reentrancy_unlock(lt);
1162                 } else {
1163                         bt = NULL;
1164                 }
1165 #endif
1166                 ast_remove_lock_info(t, bt);
1167         }
1168         if (res) {
1169                 log_mutex_error(canlog, "%s line %d (%s): Error obtaining read lock: %s\n",
1170                                 filename, line, func, strerror(res));
1171                 DO_THREAD_CRASH;
1172         }
1173 #endif /* DEBUG_THREADS */
1174
1175         return res;
1176 }
1177
1178 int __ast_rwlock_tryrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
1179 {
1180         int res;
1181
1182 #ifdef DEBUG_THREADS
1183         struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1184         struct ast_bt *bt = NULL;
1185
1186         if (lt) {
1187 #ifdef HAVE_BKTR
1188                 struct ast_bt tmp;
1189
1190                 /* The implementation of backtrace() may have its own locks.
1191                  * Capture the backtrace outside of the reentrancy lock to
1192                  * avoid deadlocks. See ASTERISK-22455. */
1193                 ast_bt_get_addresses(&tmp);
1194
1195                 ast_reentrancy_lock(lt);
1196                 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1197                         lt->backtrace[lt->reentrancy] = tmp;
1198                         bt = &lt->backtrace[lt->reentrancy];
1199                 }
1200                 ast_reentrancy_unlock(lt);
1201 #endif
1202                 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
1203         }
1204 #endif /* DEBUG_THREADS */
1205
1206         res = pthread_rwlock_tryrdlock(&t->lock);
1207
1208 #ifdef DEBUG_THREADS
1209         if (!res && lt) {
1210                 ast_reentrancy_lock(lt);
1211                 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1212                         lt->file[lt->reentrancy] = filename;
1213                         lt->lineno[lt->reentrancy] = line;
1214                         lt->func[lt->reentrancy] = func;
1215                         lt->thread_id[lt->reentrancy] = pthread_self();
1216                         lt->reentrancy++;
1217                 }
1218                 ast_reentrancy_unlock(lt);
1219                 ast_mark_lock_acquired(t);
1220         } else if (lt) {
1221                 ast_mark_lock_failed(t);
1222         }
1223 #endif /* DEBUG_THREADS */
1224
1225         return res;
1226 }
1227
1228 int __ast_rwlock_trywrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
1229 {
1230         int res;
1231
1232 #ifdef DEBUG_THREADS
1233         struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1234         struct ast_bt *bt = NULL;
1235
1236         if (lt) {
1237 #ifdef HAVE_BKTR
1238                 struct ast_bt tmp;
1239
1240                 /* The implementation of backtrace() may have its own locks.
1241                  * Capture the backtrace outside of the reentrancy lock to
1242                  * avoid deadlocks. See ASTERISK-22455. */
1243                 ast_bt_get_addresses(&tmp);
1244
1245                 ast_reentrancy_lock(lt);
1246                 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1247                         lt->backtrace[lt->reentrancy] = tmp;
1248                         bt = &lt->backtrace[lt->reentrancy];
1249                 }
1250                 ast_reentrancy_unlock(lt);
1251 #endif
1252                 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1253         }
1254 #endif /* DEBUG_THREADS */
1255
1256         res = pthread_rwlock_trywrlock(&t->lock);
1257
1258 #ifdef DEBUG_THREADS
1259         if (!res && lt) {
1260                 ast_reentrancy_lock(lt);
1261                 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1262                         lt->file[lt->reentrancy] = filename;
1263                         lt->lineno[lt->reentrancy] = line;
1264                         lt->func[lt->reentrancy] = func;
1265                         lt->thread_id[lt->reentrancy] = pthread_self();
1266                         lt->reentrancy++;
1267                 }
1268                 ast_reentrancy_unlock(lt);
1269                 ast_mark_lock_acquired(t);
1270         } else if (lt) {
1271                 ast_mark_lock_failed(t);
1272         }
1273 #endif /* DEBUG_THREADS */
1274
1275         return res;
1276 }