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