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