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