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