ea0be94cc0f795116b0a1f87cdb11ac61b8781aa
[asterisk/asterisk.git] / include / asterisk / lock.h
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, 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  * \brief Asterisk locking-related definitions:
21  * - ast_mutext_t, ast_rwlock_t and related functions;
22  * - atomic arithmetic instructions;
23  * - wrappers for channel locking.
24  *
25  * - See \ref LockDef
26  */
27
28 /*! \page LockDef Asterisk thread locking models
29  *
30  * This file provides different implementation of the functions,
31  * depending on the platform, the use of DEBUG_THREADS, and the way
32  * module-level mutexes are initialized.
33  *
34  *  - \b static: the mutex is assigned the value AST_MUTEX_INIT_VALUE
35  *        this is done at compile time, and is the way used on Linux.
36  *        This method is not applicable to all platforms e.g. when the
37  *        initialization needs that some code is run.
38  *
39  *  - \b through constructors: for each mutex, a constructor function is
40  *        defined, which then runs when the program (or the module)
41  *        starts. The problem with this approach is that there is a
42  *        lot of code duplication (a new block of code is created for
43  *        each mutex). Also, it does not prevent a user from declaring
44  *        a global mutex without going through the wrapper macros,
45  *        so sane programming practices are still required.
46  */
47
48 #ifndef _ASTERISK_LOCK_H
49 #define _ASTERISK_LOCK_H
50
51 #include <pthread.h>
52 #include <time.h>
53 #include <sys/param.h>
54 #ifdef HAVE_BKTR
55 #include <execinfo.h>
56 #endif
57
58 #ifndef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
59 #include "asterisk/time.h"
60 #endif
61
62 #include "asterisk/logger.h"
63
64 /* internal macro to profile mutexes. Only computes the delay on
65  * non-blocking calls.
66  */
67 #ifndef HAVE_MTX_PROFILE
68 #define __MTX_PROF(a)   return pthread_mutex_lock((a))
69 #else
70 #define __MTX_PROF(a)   do {                    \
71         int i;                                  \
72         /* profile only non-blocking events */  \
73         ast_mark(mtx_prof, 1);                  \
74         i = pthread_mutex_trylock((a));         \
75         ast_mark(mtx_prof, 0);                  \
76         if (!i)                                 \
77                 return i;                       \
78         else                                    \
79                 return pthread_mutex_lock((a)); \
80         } while (0)
81 #endif  /* HAVE_MTX_PROFILE */
82
83 #define AST_PTHREADT_NULL (pthread_t) -1
84 #define AST_PTHREADT_STOP (pthread_t) -2
85
86 #if (defined(SOLARIS) || defined(BSD))
87 #define AST_MUTEX_INIT_W_CONSTRUCTORS
88 #endif /* SOLARIS || BSD */
89
90 /* Asterisk REQUIRES recursive (not error checking) mutexes
91    and will not run without them. */
92 #if defined(HAVE_PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) && defined(HAVE_PTHREAD_MUTEX_RECURSIVE_NP)
93 #define PTHREAD_MUTEX_INIT_VALUE        PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
94 #define AST_MUTEX_KIND                  PTHREAD_MUTEX_RECURSIVE_NP
95 #else
96 #define PTHREAD_MUTEX_INIT_VALUE        PTHREAD_MUTEX_INITIALIZER
97 #define AST_MUTEX_KIND                  PTHREAD_MUTEX_RECURSIVE
98 #endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
99
100 /*
101  * Definition of ast_mutex_t, ast_cont_d and related functions with/without debugging
102  * (search for DEBUG_THREADS to find the start/end of the sections).
103  *
104  * The non-debug code contains just wrappers for the corresponding pthread functions.
105  * The debug code tracks usage and tries to identify deadlock situations.
106  */
107 #ifdef DEBUG_THREADS
108
109 #define __ast_mutex_logger(...)  do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0)
110
111 #ifdef THREAD_CRASH
112 #define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
113 #else
114 #define DO_THREAD_CRASH do { } while (0)
115 #endif
116
117 #include <errno.h>
118
119 #ifdef HAVE_BKTR
120 #define AST_LOCK_TRACK_INIT_VALUE { { NULL }, { 0 }, 0, { NULL }, { 0 }, {{{ 0 }}}, PTHREAD_MUTEX_INIT_VALUE }
121
122 #else
123 #define AST_LOCK_TRACK_INIT_VALUE { { NULL }, { 0 }, 0, { NULL }, { 0 }, PTHREAD_MUTEX_INIT_VALUE }
124 #endif
125
126 #define AST_MUTEX_INIT_VALUE { AST_LOCK_TRACK_INIT_VALUE, 1, PTHREAD_MUTEX_INIT_VALUE }
127 #define AST_MUTEX_INIT_VALUE_NOTRACKING { AST_LOCK_TRACK_INIT_VALUE, 0, PTHREAD_MUTEX_INIT_VALUE }
128
129 #define AST_MAX_REENTRANCY 10
130
131 struct ast_channel;
132
133 struct ast_lock_track {
134         const char *file[AST_MAX_REENTRANCY];
135         int lineno[AST_MAX_REENTRANCY];
136         int reentrancy;
137         const char *func[AST_MAX_REENTRANCY];
138         pthread_t thread[AST_MAX_REENTRANCY];
139 #ifdef HAVE_BKTR
140         struct ast_bt backtrace[AST_MAX_REENTRANCY];
141 #endif
142         pthread_mutex_t reentr_mutex;
143 };
144
145 struct ast_mutex_info {
146         /*! Track which thread holds this mutex */
147         struct ast_lock_track track;
148         unsigned int tracking:1;
149         pthread_mutex_t mutex;
150 };
151
152 typedef struct ast_mutex_info ast_mutex_t;
153
154 typedef pthread_cond_t ast_cond_t;
155
156 enum ast_lock_type {
157         AST_MUTEX,
158         AST_RDLOCK,
159         AST_WRLOCK,
160 };
161
162 /*!
163  * \brief Store lock info for the current thread
164  *
165  * This function gets called in ast_mutex_lock() and ast_mutex_trylock() so
166  * that information about this lock can be stored in this thread's
167  * lock info struct.  The lock is marked as pending as the thread is waiting
168  * on the lock.  ast_mark_lock_acquired() will mark it as held by this thread.
169  */
170 #if !defined(LOW_MEMORY)
171 #ifdef HAVE_BKTR
172 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
173         int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt);
174 #else
175 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
176         int line_num, const char *func, const char *lock_name, void *lock_addr);
177 #endif /* HAVE_BKTR */
178
179 #else
180
181 #ifdef HAVE_BKTR
182 #define ast_store_lock_info(I,DONT,CARE,ABOUT,THE,PARAMETERS,BUD)
183 #else
184 #define ast_store_lock_info(I,DONT,CARE,ABOUT,THE,PARAMETERS)
185 #endif /* HAVE_BKTR */
186 #endif /* !defined(LOW_MEMORY) */
187
188 /*!
189  * \brief Mark the last lock as acquired
190  */
191 #if !defined(LOW_MEMORY)
192 void ast_mark_lock_acquired(void *lock_addr);
193 #else
194 #define ast_mark_lock_acquired(ignore)
195 #endif
196
197 /*!
198  * \brief Mark the last lock as failed (trylock)
199  */
200 #if !defined(LOW_MEMORY)
201 void ast_mark_lock_failed(void *lock_addr);
202 #else
203 #define ast_mark_lock_failed(ignore)
204 #endif
205
206 /*!
207  * \brief remove lock info for the current thread
208  *
209  * this gets called by ast_mutex_unlock so that information on the lock can
210  * be removed from the current thread's lock info struct.
211  */
212 #if !defined(LOW_MEMORY)
213 #ifdef HAVE_BKTR
214 void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt);
215 #else
216 void ast_remove_lock_info(void *lock_addr);
217 #endif /* HAVE_BKTR */
218 #else
219 #ifdef HAVE_BKTR
220 #define ast_remove_lock_info(ignore,me)
221 #else
222 #define ast_remove_lock_info(ignore)
223 #endif /* HAVE_BKTR */
224 #endif /* !defined(LOW_MEMORY) */
225
226 #ifdef HAVE_BKTR
227 static inline void __dump_backtrace(struct ast_bt *bt, int canlog)
228 {
229         char **strings;
230
231         ssize_t i;
232
233         strings = backtrace_symbols(bt->addresses, bt->num_frames);
234
235         for (i = 0; i < bt->num_frames; i++)
236                 __ast_mutex_logger("%s\n", strings[i]);
237
238         free(strings);
239 }
240 #endif
241
242 /*!
243  * \brief log info for the current lock with ast_log().
244  *
245  * this function would be mostly for debug. If you come across a lock
246  * that is unexpectedly but momentarily locked, and you wonder who
247  * are fighting with for the lock, this routine could be called, IF
248  * you have the thread debugging stuff turned on.
249  * \param this_lock_addr lock address to return lock information
250  * \since 1.6.1
251  */
252 void log_show_lock(void *this_lock_addr);
253
254 /*!
255  * \brief retrieve lock info for the specified mutex
256  *
257  * this gets called during deadlock avoidance, so that the information may
258  * be preserved as to what location originally acquired the lock.
259  */
260 #if !defined(LOW_MEMORY)
261 int ast_find_lock_info(void *lock_addr, char *filename, size_t filename_size, int *lineno, char *func, size_t func_size, char *mutex_name, size_t mutex_name_size);
262 #else
263 #define ast_find_lock_info(a,b,c,d,e,f,g,h) -1
264 #endif
265
266 /*!
267  * \brief Unlock a lock briefly
268  *
269  * used during deadlock avoidance, to preserve the original location where
270  * a lock was originally acquired.
271  */
272 #define CHANNEL_DEADLOCK_AVOIDANCE(chan) \
273         do { \
274                 char __filename[80], __func[80], __mutex_name[80]; \
275                 int __lineno; \
276                 int __res = ast_find_lock_info(ao2_object_get_lockaddr(chan), __filename, sizeof(__filename), &__lineno, __func, sizeof(__func), __mutex_name, sizeof(__mutex_name)); \
277                 ast_channel_unlock(chan); \
278                 usleep(1); \
279                 if (__res < 0) { /* Shouldn't ever happen, but just in case... */ \
280                         ast_channel_lock(chan); \
281                 } else { \
282                         __ao2_lock(chan, __filename, __func, __lineno, __mutex_name); \
283                 } \
284         } while (0)
285
286 #define DEADLOCK_AVOIDANCE(lock) \
287         do { \
288                 char __filename[80], __func[80], __mutex_name[80]; \
289                 int __lineno; \
290                 int __res = ast_find_lock_info(lock, __filename, sizeof(__filename), &__lineno, __func, sizeof(__func), __mutex_name, sizeof(__mutex_name)); \
291                 ast_mutex_unlock(lock); \
292                 usleep(1); \
293                 if (__res < 0) { /* Shouldn't ever happen, but just in case... */ \
294                         ast_mutex_lock(lock); \
295                 } else { \
296                         __ast_pthread_mutex_lock(__filename, __lineno, __func, __mutex_name, lock); \
297                 } \
298         } while (0)
299
300 /*!
301  * \brief Deadlock avoidance unlock
302  *
303  * In certain deadlock avoidance scenarios, there is more than one lock to be
304  * unlocked and relocked.  Therefore, this pair of macros is provided for that
305  * purpose.  Note that every DLA_UNLOCK _MUST_ be paired with a matching
306  * DLA_LOCK.  The intent of this pair of macros is to be used around another
307  * set of deadlock avoidance code, mainly CHANNEL_DEADLOCK_AVOIDANCE, as the
308  * locking order specifies that we may safely lock a channel, followed by its
309  * pvt, with no worries about a deadlock.  In any other scenario, this macro
310  * may not be safe to use.
311  */
312 #define DLA_UNLOCK(lock) \
313         do { \
314                 char __filename[80], __func[80], __mutex_name[80]; \
315                 int __lineno; \
316                 int __res = ast_find_lock_info(lock, __filename, sizeof(__filename), &__lineno, __func, sizeof(__func), __mutex_name, sizeof(__mutex_name)); \
317                 ast_mutex_unlock(lock);
318
319 /*!
320  * \brief Deadlock avoidance lock
321  *
322  * In certain deadlock avoidance scenarios, there is more than one lock to be
323  * unlocked and relocked.  Therefore, this pair of macros is provided for that
324  * purpose.  Note that every DLA_UNLOCK _MUST_ be paired with a matching
325  * DLA_LOCK.  The intent of this pair of macros is to be used around another
326  * set of deadlock avoidance code, mainly CHANNEL_DEADLOCK_AVOIDANCE, as the
327  * locking order specifies that we may safely lock a channel, followed by its
328  * pvt, with no worries about a deadlock.  In any other scenario, this macro
329  * may not be safe to use.
330  */
331 #define DLA_LOCK(lock) \
332                 if (__res < 0) { /* Shouldn't ever happen, but just in case... */ \
333                         ast_mutex_lock(lock); \
334                 } else { \
335                         __ast_pthread_mutex_lock(__filename, __lineno, __func, __mutex_name, lock); \
336                 } \
337         } while (0)
338
339 static inline void ast_reentrancy_lock(struct ast_lock_track *lt)
340 {
341         pthread_mutex_lock(&lt->reentr_mutex);
342 }
343
344 static inline void ast_reentrancy_unlock(struct ast_lock_track *lt)
345 {
346         pthread_mutex_unlock(&lt->reentr_mutex);
347 }
348
349 static inline void ast_reentrancy_init(struct ast_lock_track *lt)
350 {
351         int i;
352         pthread_mutexattr_t reentr_attr;
353
354         for (i = 0; i < AST_MAX_REENTRANCY; i++) {
355                 lt->file[i] = NULL;
356                 lt->lineno[i] = 0;
357                 lt->func[i] = NULL;
358                 lt->thread[i] = 0;
359 #ifdef HAVE_BKTR
360                 memset(&lt->backtrace[i], 0, sizeof(lt->backtrace[i]));
361 #endif
362         }
363
364         lt->reentrancy = 0;
365
366         pthread_mutexattr_init(&reentr_attr);
367         pthread_mutexattr_settype(&reentr_attr, AST_MUTEX_KIND);
368         pthread_mutex_init(&lt->reentr_mutex, &reentr_attr);
369         pthread_mutexattr_destroy(&reentr_attr);
370 }
371
372 static inline void delete_reentrancy_cs(struct ast_lock_track *lt)
373 {
374         pthread_mutex_destroy(&lt->reentr_mutex);
375 }
376
377 static inline int __ast_pthread_mutex_init(int tracking, const char *filename, int lineno, const char *func,
378                                                 const char *mutex_name, ast_mutex_t *t)
379 {
380         int res;
381         pthread_mutexattr_t  attr;
382
383 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
384
385         if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
386 /*
387                 int canlog = strcmp(filename, "logger.c") & track;
388                 __ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is already initialized.\n",
389                                    filename, lineno, func, mutex_name);
390                 DO_THREAD_CRASH;
391 */
392                 return 0;
393         }
394
395 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
396
397         ast_reentrancy_init(&t->track);
398         t->tracking = tracking;
399
400         pthread_mutexattr_init(&attr);
401         pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
402
403         res = pthread_mutex_init(&t->mutex, &attr);
404         pthread_mutexattr_destroy(&attr);
405         return res;
406 }
407
408 #define ast_mutex_init(pmutex) __ast_pthread_mutex_init(1, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
409 #define ast_mutex_init_notracking(pmutex) \
410         __ast_pthread_mutex_init(0, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
411
412 #define ROFFSET ((lt->reentrancy > 0) ? (lt->reentrancy-1) : 0)
413 static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
414                                                 const char *mutex_name, ast_mutex_t *t)
415 {
416         int res;
417         struct ast_lock_track *lt;
418         int canlog = strcmp(filename, "logger.c") & t->tracking;
419
420 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
421         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
422                 /* Don't try to uninitialize non initialized mutex
423                  * This may no effect on linux
424                  * And always ganerate core on *BSD with
425                  * linked libpthread
426                  * This not error condition if the mutex created on the fly.
427                  */
428                 __ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is uninitialized.\n",
429                                    filename, lineno, func, mutex_name);
430                 return 0;
431         }
432 #endif
433
434         lt = &t->track;
435
436         res = pthread_mutex_trylock(&t->mutex);
437         switch (res) {
438         case 0:
439                 pthread_mutex_unlock(&t->mutex);
440                 break;
441         case EINVAL:
442                 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
443                                   filename, lineno, func, mutex_name);
444                 break;
445         case EBUSY:
446                 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
447                                    filename, lineno, func, mutex_name);
448                 ast_reentrancy_lock(lt);
449                 __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
450                             lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
451 #ifdef HAVE_BKTR
452                 __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
453 #endif
454                 ast_reentrancy_unlock(lt);
455                 break;
456         }
457
458
459         if ((res = pthread_mutex_destroy(&t->mutex))) {
460                 __ast_mutex_logger("%s line %d (%s): Error destroying mutex %s: %s\n",
461                                    filename, lineno, func, mutex_name, strerror(res));
462         }
463         ast_reentrancy_lock(lt);
464         lt->file[0] = filename;
465         lt->lineno[0] = lineno;
466         lt->func[0] = func;
467         lt->reentrancy = 0;
468         lt->thread[0] = 0;
469 #ifdef HAVE_BKTR
470         memset(&lt->backtrace[0], 0, sizeof(lt->backtrace[0]));
471 #endif
472         ast_reentrancy_unlock(lt);
473         delete_reentrancy_cs(lt);
474
475         return res;
476 }
477
478 static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
479                                            const char* mutex_name, ast_mutex_t *t)
480 {
481         int res;
482         struct ast_lock_track *lt = &t->track;
483         int canlog = strcmp(filename, "logger.c") & t->tracking;
484 #ifdef HAVE_BKTR
485         struct ast_bt *bt = NULL;
486 #endif
487
488 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
489         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
490                 /* Don't warn abount uninitialized mutex.
491                  * Simple try to initialize it.
492                  * May be not needed in linux system.
493                  */
494                 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
495                 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
496                         __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
497                                          filename, lineno, func, mutex_name);
498                         return res;
499                 }
500         }
501 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
502
503         if (t->tracking) {
504 #ifdef HAVE_BKTR
505                 ast_reentrancy_lock(lt);
506                 if (lt->reentrancy != AST_MAX_REENTRANCY) {
507                         ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
508                         bt = &lt->backtrace[lt->reentrancy];
509                 }
510                 ast_reentrancy_unlock(lt);
511                 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
512 #else
513                 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
514 #endif
515         }
516
517 #ifdef DETECT_DEADLOCKS
518         {
519                 time_t seconds = time(NULL);
520                 time_t wait_time, reported_wait = 0;
521                 do {
522 #ifdef  HAVE_MTX_PROFILE
523                         ast_mark(mtx_prof, 1);
524 #endif
525                         res = pthread_mutex_trylock(&t->mutex);
526 #ifdef  HAVE_MTX_PROFILE
527                         ast_mark(mtx_prof, 0);
528 #endif
529                         if (res == EBUSY) {
530                                 wait_time = time(NULL) - seconds;
531                                 if (wait_time > reported_wait && (wait_time % 5) == 0) {
532                                         __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
533                                                            filename, lineno, func, (int) wait_time, mutex_name);
534                                         ast_reentrancy_lock(lt);
535 #ifdef HAVE_BKTR
536                                         __dump_backtrace(&lt->backtrace[lt->reentrancy], canlog);
537 #endif
538                                         __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
539                                                            lt->file[ROFFSET], lt->lineno[ROFFSET],
540                                                            lt->func[ROFFSET], mutex_name);
541 #ifdef HAVE_BKTR
542                                         __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
543 #endif
544                                         ast_reentrancy_unlock(lt);
545                                         reported_wait = wait_time;
546                                 }
547                                 usleep(200);
548                         }
549                 } while (res == EBUSY);
550         }
551 #else
552 #ifdef  HAVE_MTX_PROFILE
553         ast_mark(mtx_prof, 1);
554         res = pthread_mutex_trylock(&t->mutex);
555         ast_mark(mtx_prof, 0);
556         if (res)
557 #endif
558         res = pthread_mutex_lock(&t->mutex);
559 #endif /* DETECT_DEADLOCKS */
560
561         if (!res) {
562                 ast_reentrancy_lock(lt);
563                 if (lt->reentrancy < AST_MAX_REENTRANCY) {
564                         lt->file[lt->reentrancy] = filename;
565                         lt->lineno[lt->reentrancy] = lineno;
566                         lt->func[lt->reentrancy] = func;
567                         lt->thread[lt->reentrancy] = pthread_self();
568                         lt->reentrancy++;
569                 } else {
570                         __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
571                                                            filename, lineno, func, mutex_name);
572                 }
573                 ast_reentrancy_unlock(lt);
574                 if (t->tracking) {
575                         ast_mark_lock_acquired(t);
576                 }
577         } else {
578 #ifdef HAVE_BKTR
579                 if (lt->reentrancy) {
580                         ast_reentrancy_lock(lt);
581                         bt = &lt->backtrace[lt->reentrancy-1];
582                         ast_reentrancy_unlock(lt);
583                 } else {
584                         bt = NULL;
585                 }
586                 if (t->tracking) {
587                         ast_remove_lock_info(t, bt);
588                 }
589 #else
590                 if (t->tracking) {
591                         ast_remove_lock_info(t);
592                 }
593 #endif
594                 __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
595                                    filename, lineno, func, strerror(res));
596                 DO_THREAD_CRASH;
597         }
598
599         return res;
600 }
601
602 static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
603                                               const char* mutex_name, ast_mutex_t *t)
604 {
605         int res;
606         struct ast_lock_track *lt= &t->track;
607         int canlog = strcmp(filename, "logger.c") & t->tracking;
608 #ifdef HAVE_BKTR
609         struct ast_bt *bt = NULL;
610 #endif
611
612 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
613         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
614                 /* Don't warn abount uninitialized mutex.
615                  * Simple try to initialize it.
616                  * May be not needed in linux system.
617                  */
618                 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
619                 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
620                         __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
621                                          filename, lineno, func, mutex_name);
622                         return res;
623                 }
624         }
625 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
626
627         if (t->tracking) {
628 #ifdef HAVE_BKTR
629                 ast_reentrancy_lock(lt);
630                 if (lt->reentrancy != AST_MAX_REENTRANCY) {
631                         ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
632                         bt = &lt->backtrace[lt->reentrancy];
633                 }
634                 ast_reentrancy_unlock(lt);
635                 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
636 #else
637                 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
638 #endif
639         }
640
641         if (!(res = pthread_mutex_trylock(&t->mutex))) {
642                 ast_reentrancy_lock(lt);
643                 if (lt->reentrancy < AST_MAX_REENTRANCY) {
644                         lt->file[lt->reentrancy] = filename;
645                         lt->lineno[lt->reentrancy] = lineno;
646                         lt->func[lt->reentrancy] = func;
647                         lt->thread[lt->reentrancy] = pthread_self();
648                         lt->reentrancy++;
649                 } else {
650                         __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
651                                            filename, lineno, func, mutex_name);
652                 }
653                 ast_reentrancy_unlock(lt);
654                 if (t->tracking) {
655                         ast_mark_lock_acquired(t);
656                 }
657         } else if (t->tracking) {
658                 ast_mark_lock_failed(t);
659         }
660
661         return res;
662 }
663
664 static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
665                                              const char *mutex_name, ast_mutex_t *t)
666 {
667         int res;
668         struct ast_lock_track *lt = &t->track;
669         int canlog = strcmp(filename, "logger.c") & t->tracking;
670 #ifdef HAVE_BKTR
671         struct ast_bt *bt = NULL;
672 #endif
673
674 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
675         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
676                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
677                                    filename, lineno, func, mutex_name);
678                 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
679                 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
680                         __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
681                                          filename, lineno, func, mutex_name);
682                 }
683                 return res;
684         }
685 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
686
687         ast_reentrancy_lock(lt);
688         if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
689                 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
690                                    filename, lineno, func, mutex_name);
691                 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
692                                    lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
693 #ifdef HAVE_BKTR
694                 __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
695 #endif
696                 DO_THREAD_CRASH;
697         }
698
699         if (--lt->reentrancy < 0) {
700                 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
701                                    filename, lineno, func, mutex_name);
702                 lt->reentrancy = 0;
703         }
704
705         if (lt->reentrancy < AST_MAX_REENTRANCY) {
706                 lt->file[lt->reentrancy] = NULL;
707                 lt->lineno[lt->reentrancy] = 0;
708                 lt->func[lt->reentrancy] = NULL;
709                 lt->thread[lt->reentrancy] = 0;
710         }
711
712 #ifdef HAVE_BKTR
713         if (lt->reentrancy) {
714                 bt = &lt->backtrace[lt->reentrancy - 1];
715         }
716 #endif
717         ast_reentrancy_unlock(lt);
718
719         if (t->tracking) {
720 #ifdef HAVE_BKTR
721                 ast_remove_lock_info(t, bt);
722 #else
723                 ast_remove_lock_info(t);
724 #endif
725         }
726
727         if ((res = pthread_mutex_unlock(&t->mutex))) {
728                 __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n",
729                                    filename, lineno, func, strerror(res));
730                 DO_THREAD_CRASH;
731         }
732
733         return res;
734 }
735
736 static inline int __ast_cond_init(const char *filename, int lineno, const char *func,
737                                   const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
738 {
739         return pthread_cond_init(cond, cond_attr);
740 }
741
742 static inline int __ast_cond_signal(const char *filename, int lineno, const char *func,
743                                     const char *cond_name, ast_cond_t *cond)
744 {
745         return pthread_cond_signal(cond);
746 }
747
748 static inline int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
749                                        const char *cond_name, ast_cond_t *cond)
750 {
751         return pthread_cond_broadcast(cond);
752 }
753
754 static inline int __ast_cond_destroy(const char *filename, int lineno, const char *func,
755                                      const char *cond_name, ast_cond_t *cond)
756 {
757         return pthread_cond_destroy(cond);
758 }
759
760 static inline int __ast_cond_wait(const char *filename, int lineno, const char *func,
761                                   const char *cond_name, const char *mutex_name,
762                                   ast_cond_t *cond, ast_mutex_t *t)
763 {
764         int res;
765         struct ast_lock_track *lt= &t->track;
766         int canlog = strcmp(filename, "logger.c") & t->tracking;
767 #ifdef HAVE_BKTR
768         struct ast_bt *bt = NULL;
769 #endif
770
771 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
772         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
773                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
774                                    filename, lineno, func, mutex_name);
775                 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
776                 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
777                         __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
778                                          filename, lineno, func, mutex_name);
779                 }
780                 return res;
781         }
782 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
783
784         ast_reentrancy_lock(lt);
785         if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
786                 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
787                                    filename, lineno, func, mutex_name);
788                 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
789                                    lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
790 #ifdef HAVE_BKTR
791                 __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
792 #endif
793                 DO_THREAD_CRASH;
794         }
795
796         if (--lt->reentrancy < 0) {
797                 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
798                                    filename, lineno, func, mutex_name);
799                 lt->reentrancy = 0;
800         }
801
802         if (lt->reentrancy < AST_MAX_REENTRANCY) {
803                 lt->file[lt->reentrancy] = NULL;
804                 lt->lineno[lt->reentrancy] = 0;
805                 lt->func[lt->reentrancy] = NULL;
806                 lt->thread[lt->reentrancy] = 0;
807         }
808
809 #ifdef HAVE_BKTR
810         if (lt->reentrancy) {
811                 bt = &lt->backtrace[lt->reentrancy - 1];
812         }
813 #endif
814         ast_reentrancy_unlock(lt);
815
816         if (t->tracking) {
817 #ifdef HAVE_BKTR
818                 ast_remove_lock_info(t, bt);
819 #else
820                 ast_remove_lock_info(t);
821 #endif
822         }
823
824         if ((res = pthread_cond_wait(cond, &t->mutex))) {
825                 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
826                                    filename, lineno, func, strerror(res));
827                 DO_THREAD_CRASH;
828         } else {
829                 ast_reentrancy_lock(lt);
830                 if (lt->reentrancy < AST_MAX_REENTRANCY) {
831                         lt->file[lt->reentrancy] = filename;
832                         lt->lineno[lt->reentrancy] = lineno;
833                         lt->func[lt->reentrancy] = func;
834                         lt->thread[lt->reentrancy] = pthread_self();
835 #ifdef HAVE_BKTR
836                         ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
837                         bt = &lt->backtrace[lt->reentrancy];
838 #endif
839                         lt->reentrancy++;
840                 } else {
841                         __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
842                                                            filename, lineno, func, mutex_name);
843                 }
844                 ast_reentrancy_unlock(lt);
845
846                 if (t->tracking) {
847 #ifdef HAVE_BKTR
848                         ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
849 #else
850                         ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
851 #endif
852                 }
853         }
854
855         return res;
856 }
857
858 static inline int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
859                                        const char *cond_name, const char *mutex_name, ast_cond_t *cond,
860                                        ast_mutex_t *t, const struct timespec *abstime)
861 {
862         int res;
863         struct ast_lock_track *lt = &t->track;
864         int canlog = strcmp(filename, "logger.c") & t->tracking;
865 #ifdef HAVE_BKTR
866         struct ast_bt *bt = NULL;
867 #endif
868
869 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
870         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
871                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
872                                    filename, lineno, func, mutex_name);
873                 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
874                 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
875                         __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
876                                          filename, lineno, func, mutex_name);
877                 }
878                 return res;
879         }
880 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
881
882         ast_reentrancy_lock(lt);
883         if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
884                 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
885                                    filename, lineno, func, mutex_name);
886                 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
887                                    lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
888 #ifdef HAVE_BKTR
889                 __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
890 #endif
891                 DO_THREAD_CRASH;
892         }
893
894         if (--lt->reentrancy < 0) {
895                 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
896                                    filename, lineno, func, mutex_name);
897                 lt->reentrancy = 0;
898         }
899
900         if (lt->reentrancy < AST_MAX_REENTRANCY) {
901                 lt->file[lt->reentrancy] = NULL;
902                 lt->lineno[lt->reentrancy] = 0;
903                 lt->func[lt->reentrancy] = NULL;
904                 lt->thread[lt->reentrancy] = 0;
905         }
906 #ifdef HAVE_BKTR
907         if (lt->reentrancy) {
908                 bt = &lt->backtrace[lt->reentrancy - 1];
909         }
910 #endif
911         ast_reentrancy_unlock(lt);
912
913         if (t->tracking) {
914 #ifdef HAVE_BKTR
915                 ast_remove_lock_info(t, bt);
916 #else
917                 ast_remove_lock_info(t);
918 #endif
919         }
920
921         if ((res = pthread_cond_timedwait(cond, &t->mutex, abstime)) && (res != ETIMEDOUT)) {
922                 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
923                                    filename, lineno, func, strerror(res));
924                 DO_THREAD_CRASH;
925         } else {
926                 ast_reentrancy_lock(lt);
927                 if (lt->reentrancy < AST_MAX_REENTRANCY) {
928                         lt->file[lt->reentrancy] = filename;
929                         lt->lineno[lt->reentrancy] = lineno;
930                         lt->func[lt->reentrancy] = func;
931                         lt->thread[lt->reentrancy] = pthread_self();
932 #ifdef HAVE_BKTR
933                         ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
934                         bt = &lt->backtrace[lt->reentrancy];
935 #endif
936                         lt->reentrancy++;
937                 } else {
938                         __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
939                                                            filename, lineno, func, mutex_name);
940                 }
941                 ast_reentrancy_unlock(lt);
942
943                 if (t->tracking) {
944 #ifdef HAVE_BKTR
945                         ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
946 #else
947                         ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
948 #endif
949                 }
950         }
951
952         return res;
953 }
954
955 #define ast_mutex_destroy(a)                    __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
956 #define ast_mutex_lock(a)                       __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
957 #define ast_mutex_unlock(a)                     __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
958 #define ast_mutex_trylock(a)                    __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
959 #define ast_cond_init(cond, attr)               __ast_cond_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond, attr)
960 #define ast_cond_destroy(cond)                  __ast_cond_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
961 #define ast_cond_signal(cond)                   __ast_cond_signal(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
962 #define ast_cond_broadcast(cond)                __ast_cond_broadcast(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
963 #define ast_cond_wait(cond, mutex)              __ast_cond_wait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex)
964 #define ast_cond_timedwait(cond, mutex, time)   __ast_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex, time)
965
966 struct ast_rwlock_info {
967         /*! Track which thread holds this lock */
968         struct ast_lock_track track;
969         unsigned int tracking:1;
970         pthread_rwlock_t lock;
971 };
972
973 typedef struct ast_rwlock_info ast_rwlock_t;
974
975 /*!
976  * \brief wrapper for rwlock with tracking enabled
977  * \return 0 on success, non zero for error
978  * \since 1.6.1
979  */
980 #define ast_rwlock_init(rwlock) __ast_rwlock_init(1, __FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)
981
982 /*!
983  * \brief wrapper for ast_rwlock_init with tracking disabled
984  * \return 0 on success, non zero for error
985  * \since 1.6.1
986  */
987 #define ast_rwlock_init_notracking(rwlock) __ast_rwlock_init(0, __FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)
988
989 #define ast_rwlock_destroy(rwlock)      __ast_rwlock_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)
990 #define ast_rwlock_unlock(a)            _ast_rwlock_unlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
991 #define ast_rwlock_rdlock(a)            _ast_rwlock_rdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
992 #define ast_rwlock_wrlock(a)            _ast_rwlock_wrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
993 #define ast_rwlock_tryrdlock(a)         _ast_rwlock_tryrdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
994 #define ast_rwlock_trywrlock(a) _ast_rwlock_trywrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
995
996
997 #ifdef HAVE_PTHREAD_RWLOCK_INITIALIZER
998 #define __AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
999 #else  /* HAVE_PTHREAD_RWLOCK_INITIALIZER */
1000 #define __AST_RWLOCK_INIT_VALUE {0}
1001 #endif /* HAVE_PTHREAD_RWLOCK_INITIALIZER */
1002
1003 #define AST_RWLOCK_INIT_VALUE \
1004         { AST_LOCK_TRACK_INIT_VALUE, 1, __AST_RWLOCK_INIT_VALUE }
1005 #define AST_RWLOCK_INIT_VALUE_NOTRACKING \
1006         { AST_LOCK_TRACK_INIT_VALUE, 0, __AST_RWLOCK_INIT_VALUE }
1007
1008 static inline int __ast_rwlock_init(int tracking, const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
1009 {
1010         int res;
1011         struct ast_lock_track *lt= &t->track;
1012         pthread_rwlockattr_t attr;
1013
1014 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1015         int canlog = strcmp(filename, "logger.c") & t->tracking;
1016
1017         if (t->lock != ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1018                 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
1019                                 filename, lineno, func, rwlock_name);
1020                 return 0;
1021         }
1022 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1023
1024         ast_reentrancy_init(lt);
1025         t->tracking = tracking;
1026         pthread_rwlockattr_init(&attr);
1027
1028 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
1029         pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
1030 #endif
1031
1032         res = pthread_rwlock_init(&t->lock, &attr);
1033         pthread_rwlockattr_destroy(&attr);
1034         return res;
1035 }
1036
1037 static inline int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
1038 {
1039         int res;
1040         struct ast_lock_track *lt = &t->track;
1041         int canlog = strcmp(filename, "logger.c") & t->tracking;
1042
1043 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1044         if (t->lock == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1045                 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
1046                                    filename, lineno, func, rwlock_name);
1047                 return 0;
1048         }
1049 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1050
1051         if ((res = pthread_rwlock_destroy(&t->lock))) {
1052                 __ast_mutex_logger("%s line %d (%s): Error destroying rwlock %s: %s\n",
1053                                 filename, lineno, func, rwlock_name, strerror(res));
1054         }
1055         ast_reentrancy_lock(lt);
1056         lt->file[0] = filename;
1057         lt->lineno[0] = lineno;
1058         lt->func[0] = func;
1059         lt->reentrancy = 0;
1060         lt->thread[0] = 0;
1061 #ifdef HAVE_BKTR
1062         memset(&lt->backtrace[0], 0, sizeof(lt->backtrace[0]));
1063 #endif
1064         ast_reentrancy_unlock(lt);
1065         delete_reentrancy_cs(lt);
1066
1067         return res;
1068 }
1069
1070 static inline int _ast_rwlock_unlock(ast_rwlock_t *t, const char *name,
1071         const char *filename, int line, const char *func)
1072 {
1073         int res;
1074         struct ast_lock_track *lt = &t->track;
1075         int canlog = strcmp(filename, "logger.c") & t->tracking;
1076 #ifdef HAVE_BKTR
1077         struct ast_bt *bt = NULL;
1078 #endif
1079         int lock_found = 0;
1080
1081
1082 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1083         if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1084                 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
1085                                    filename, line, func, name);
1086                 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1087                 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1088                         __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1089                                         filename, line, func, name);
1090                 }
1091                 return res;
1092         }
1093 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1094
1095         ast_reentrancy_lock(lt);
1096         if (lt->reentrancy) {
1097                 int i;
1098                 pthread_t self = pthread_self();
1099                 for (i = lt->reentrancy - 1; i >= 0; --i) {
1100                         if (lt->thread[i] == self) {
1101                                 lock_found = 1;
1102                                 if (i != lt->reentrancy - 1) {
1103                                         lt->file[i] = lt->file[lt->reentrancy - 1];
1104                                         lt->lineno[i] = lt->lineno[lt->reentrancy - 1];
1105                                         lt->func[i] = lt->func[lt->reentrancy - 1];
1106                                         lt->thread[i] = lt->thread[lt->reentrancy - 1];
1107                                 }
1108 #ifdef HAVE_BKTR
1109                                 bt = &lt->backtrace[i];
1110 #endif
1111                                 lt->file[lt->reentrancy - 1] = NULL;
1112                                 lt->lineno[lt->reentrancy - 1] = 0;
1113                                 lt->func[lt->reentrancy - 1] = NULL;
1114                                 lt->thread[lt->reentrancy - 1] = AST_PTHREADT_NULL;
1115                                 break;
1116                         }
1117                 }
1118         }
1119
1120         if (lock_found && --lt->reentrancy < 0) {
1121                 __ast_mutex_logger("%s line %d (%s): rwlock '%s' freed more times than we've locked!\n",
1122                                 filename, line, func, name);
1123                 lt->reentrancy = 0;
1124         }
1125
1126         ast_reentrancy_unlock(lt);
1127
1128         if (t->tracking) {
1129 #ifdef HAVE_BKTR
1130                 ast_remove_lock_info(t, bt);
1131 #else
1132                 ast_remove_lock_info(t);
1133 #endif
1134         }
1135
1136         if ((res = pthread_rwlock_unlock(&t->lock))) {
1137                 __ast_mutex_logger("%s line %d (%s): Error releasing rwlock: %s\n",
1138                                 filename, line, func, strerror(res));
1139                 DO_THREAD_CRASH;
1140         }
1141
1142         return res;
1143 }
1144
1145 static inline int _ast_rwlock_rdlock(ast_rwlock_t *t, const char *name,
1146         const char *filename, int line, const char *func)
1147 {
1148         int res;
1149         struct ast_lock_track *lt = &t->track;
1150         int canlog = strcmp(filename, "logger.c") & t->tracking;
1151 #ifdef HAVE_BKTR
1152         struct ast_bt *bt = NULL;
1153 #endif
1154
1155 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1156         if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1157                  /* Don't warn abount uninitialized lock.
1158                   * Simple try to initialize it.
1159                   * May be not needed in linux system.
1160                   */
1161                 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1162                 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1163                         __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1164                                         filename, line, func, name);
1165                         return res;
1166                 }
1167         }
1168 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1169
1170         if (t->tracking) {
1171 #ifdef HAVE_BKTR
1172                 ast_reentrancy_lock(lt);
1173                 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1174                         ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
1175                         bt = &lt->backtrace[lt->reentrancy];
1176                 }
1177                 ast_reentrancy_unlock(lt);
1178                 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
1179 #else
1180                 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t);
1181 #endif
1182         }
1183
1184 #ifdef DETECT_DEADLOCKS
1185         {
1186                 time_t seconds = time(NULL);
1187                 time_t wait_time, reported_wait = 0;
1188                 do {
1189                         res = pthread_rwlock_tryrdlock(&t->lock);
1190                         if (res == EBUSY) {
1191                                 wait_time = time(NULL) - seconds;
1192                                 if (wait_time > reported_wait && (wait_time % 5) == 0) {
1193                                         __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for readlock '%s'?\n",
1194                                                 filename, line, func, (int)wait_time, name);
1195                                         ast_reentrancy_lock(lt);
1196 #ifdef HAVE_BKTR
1197                                         __dump_backtrace(&lt->backtrace[lt->reentrancy], canlog);
1198 #endif
1199                                         __ast_mutex_logger("%s line %d (%s): '%s' was locked  here.\n",
1200                                                         lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
1201                                                         lt->func[lt->reentrancy-1], name);
1202 #ifdef HAVE_BKTR
1203                                         __dump_backtrace(&lt->backtrace[lt->reentrancy-1], canlog);
1204 #endif
1205                                         ast_reentrancy_unlock(lt);
1206                                         reported_wait = wait_time;
1207                                 }
1208                                 usleep(200);
1209                         }
1210                 } while (res == EBUSY);
1211         }
1212 #else /* !DETECT_DEADLOCKS */
1213         res = pthread_rwlock_rdlock(&t->lock);
1214 #endif /* !DETECT_DEADLOCKS */
1215
1216         if (!res) {
1217                 ast_reentrancy_lock(lt);
1218                 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1219                         lt->file[lt->reentrancy] = filename;
1220                         lt->lineno[lt->reentrancy] = line;
1221                         lt->func[lt->reentrancy] = func;
1222                         lt->thread[lt->reentrancy] = pthread_self();
1223                         lt->reentrancy++;
1224                 }
1225                 ast_reentrancy_unlock(lt);
1226                 if (t->tracking) {
1227                         ast_mark_lock_acquired(t);
1228                 }
1229         } else {
1230 #ifdef HAVE_BKTR
1231                 if (lt->reentrancy) {
1232                         ast_reentrancy_lock(lt);
1233                         bt = &lt->backtrace[lt->reentrancy-1];
1234                         ast_reentrancy_unlock(lt);
1235                 } else {
1236                         bt = NULL;
1237                 }
1238                 if (t->tracking) {
1239                         ast_remove_lock_info(t, bt);
1240                 }
1241 #else
1242                 if (t->tracking) {
1243                         ast_remove_lock_info(t);
1244                 }
1245 #endif
1246                 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
1247                                 filename, line, func, strerror(res));
1248                 DO_THREAD_CRASH;
1249         }
1250         return res;
1251 }
1252
1253 static inline int _ast_rwlock_wrlock(ast_rwlock_t *t, const char *name,
1254         const char *filename, int line, const char *func)
1255 {
1256         int res;
1257         struct ast_lock_track *lt = &t->track;
1258         int canlog = strcmp(filename, "logger.c") & t->tracking;
1259 #ifdef HAVE_BKTR
1260         struct ast_bt *bt = NULL;
1261 #endif
1262
1263 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1264         if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1265                  /* Don't warn abount uninitialized lock.
1266                   * Simple try to initialize it.
1267                   * May be not needed in linux system.
1268                   */
1269                 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1270                 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1271                         __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1272                                         filename, line, func, name);
1273                         return res;
1274                 }
1275         }
1276 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1277
1278         if (t->tracking) {
1279 #ifdef HAVE_BKTR
1280                 ast_reentrancy_lock(lt);
1281                 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1282                         ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
1283                         bt = &lt->backtrace[lt->reentrancy];
1284                 }
1285                 ast_reentrancy_unlock(lt);
1286                 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1287 #else
1288                 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1289 #endif
1290         }
1291 #ifdef DETECT_DEADLOCKS
1292         {
1293                 time_t seconds = time(NULL);
1294                 time_t wait_time, reported_wait = 0;
1295                 do {
1296                         res = pthread_rwlock_trywrlock(&t->lock);
1297                         if (res == EBUSY) {
1298                                 wait_time = time(NULL) - seconds;
1299                                 if (wait_time > reported_wait && (wait_time % 5) == 0) {
1300                                         __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for writelock '%s'?\n",
1301                                                 filename, line, func, (int)wait_time, name);
1302                                         ast_reentrancy_lock(lt);
1303 #ifdef HAVE_BKTR
1304                                         __dump_backtrace(&lt->backtrace[lt->reentrancy], canlog);
1305 #endif
1306                                         __ast_mutex_logger("%s line %d (%s): '%s' was locked  here.\n",
1307                                                         lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
1308                                                         lt->func[lt->reentrancy-1], name);
1309 #ifdef HAVE_BKTR
1310                                         __dump_backtrace(&lt->backtrace[lt->reentrancy-1], canlog);
1311 #endif
1312                                         ast_reentrancy_unlock(lt);
1313                                         reported_wait = wait_time;
1314                                 }
1315                                 usleep(200);
1316                         }
1317                 } while (res == EBUSY);
1318         }
1319 #else /* !DETECT_DEADLOCKS */
1320         res = pthread_rwlock_wrlock(&t->lock);
1321 #endif /* !DETECT_DEADLOCKS */
1322
1323         if (!res) {
1324                 ast_reentrancy_lock(lt);
1325                 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1326                         lt->file[lt->reentrancy] = filename;
1327                         lt->lineno[lt->reentrancy] = line;
1328                         lt->func[lt->reentrancy] = func;
1329                         lt->thread[lt->reentrancy] = pthread_self();
1330                         lt->reentrancy++;
1331                 }
1332                 ast_reentrancy_unlock(lt);
1333                 if (t->tracking) {
1334                         ast_mark_lock_acquired(t);
1335                 }
1336         } else {
1337 #ifdef HAVE_BKTR
1338                 if (lt->reentrancy) {
1339                         ast_reentrancy_lock(lt);
1340                         bt = &lt->backtrace[lt->reentrancy-1];
1341                         ast_reentrancy_unlock(lt);
1342                 } else {
1343                         bt = NULL;
1344                 }
1345                 if (t->tracking) {
1346                         ast_remove_lock_info(t, bt);
1347                 }
1348 #else
1349                 if (t->tracking) {
1350                         ast_remove_lock_info(t);
1351                 }
1352 #endif
1353                 __ast_mutex_logger("%s line %d (%s): Error obtaining write lock: %s\n",
1354                                 filename, line, func, strerror(res));
1355                 DO_THREAD_CRASH;
1356         }
1357         return res;
1358 }
1359
1360 #define ast_rwlock_timedrdlock(a, b) \
1361         _ast_rwlock_timedrdlock(a, # a, b, __FILE__, __LINE__, __PRETTY_FUNCTION__)
1362
1363 static inline int _ast_rwlock_timedrdlock(ast_rwlock_t *t, const char *name,
1364         const struct timespec *abs_timeout, const char *filename, int line, const char *func)
1365 {
1366         int res;
1367         struct ast_lock_track *lt = &t->track;
1368         int canlog = strcmp(filename, "logger.c") & t->tracking;
1369 #ifdef HAVE_BKTR
1370         struct ast_bt *bt = NULL;
1371 #endif
1372
1373 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1374         if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1375                  /* Don't warn abount uninitialized lock.
1376                   * Simple try to initialize it.
1377                   * May be not needed in linux system.
1378                   */
1379                 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1380                 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1381                         __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1382                                         filename, line, func, name);
1383                         return res;
1384                 }
1385         }
1386 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1387
1388         if (t->tracking) {
1389 #ifdef HAVE_BKTR
1390                 ast_reentrancy_lock(lt);
1391                 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1392                         ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
1393                         bt = &lt->backtrace[lt->reentrancy];
1394                 }
1395                 ast_reentrancy_unlock(lt);
1396                 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1397 #else
1398                 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1399 #endif
1400         }
1401 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1402         res = pthread_rwlock_timedrdlock(&t->lock, abs_timeout);
1403 #else
1404         do {
1405                 struct timeval _start = ast_tvnow(), _diff;
1406                 for (;;) {
1407                         if (!(res = pthread_rwlock_tryrdlock(&t->lock))) {
1408                                 break;
1409                         }
1410                         _diff = ast_tvsub(ast_tvnow(), _start);
1411                         if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1412                                 break;
1413                         }
1414                         usleep(1);
1415                 }
1416         } while (0);
1417 #endif
1418         if (!res) {
1419                 ast_reentrancy_lock(lt);
1420                 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1421                         lt->file[lt->reentrancy] = filename;
1422                         lt->lineno[lt->reentrancy] = line;
1423                         lt->func[lt->reentrancy] = func;
1424                         lt->thread[lt->reentrancy] = pthread_self();
1425                         lt->reentrancy++;
1426                 }
1427                 ast_reentrancy_unlock(lt);
1428                 if (t->tracking) {
1429                         ast_mark_lock_acquired(t);
1430                 }
1431         } else {
1432 #ifdef HAVE_BKTR
1433                 if (lt->reentrancy) {
1434                         ast_reentrancy_lock(lt);
1435                         bt = &lt->backtrace[lt->reentrancy-1];
1436                         ast_reentrancy_unlock(lt);
1437                 } else {
1438                         bt = NULL;
1439                 }
1440                 if (t->tracking) {
1441                         ast_remove_lock_info(t, bt);
1442                 }
1443 #else
1444                 if (t->tracking) {
1445                         ast_remove_lock_info(t);
1446                 }
1447 #endif
1448                 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
1449                                 filename, line, func, strerror(res));
1450                 DO_THREAD_CRASH;
1451         }
1452         return res;
1453 }
1454
1455 #define ast_rwlock_timedwrlock(a, b) \
1456         _ast_rwlock_timedwrlock(a, # a, b, __FILE__, __LINE__, __PRETTY_FUNCTION__)
1457
1458 static inline int _ast_rwlock_timedwrlock(ast_rwlock_t *t, const char *name,
1459         const struct timespec *abs_timeout, const char *filename, int line, const char *func)
1460 {
1461         int res;
1462         struct ast_lock_track *lt = &t->track;
1463         int canlog = strcmp(filename, "logger.c") & t->tracking;
1464 #ifdef HAVE_BKTR
1465         struct ast_bt *bt = NULL;
1466 #endif
1467
1468 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1469         if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1470                  /* Don't warn abount uninitialized lock.
1471                   * Simple try to initialize it.
1472                   * May be not needed in linux system.
1473                   */
1474                 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1475                 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1476                         __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1477                                         filename, line, func, name);
1478                         return res;
1479                 }
1480         }
1481 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1482
1483         if (t->tracking) {
1484 #ifdef HAVE_BKTR
1485                 ast_reentrancy_lock(lt);
1486                 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1487                         ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
1488                         bt = &lt->backtrace[lt->reentrancy];
1489                 }
1490                 ast_reentrancy_unlock(lt);
1491                 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1492 #else
1493                 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1494 #endif
1495         }
1496 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1497         res = pthread_rwlock_timedwrlock(&t->lock, abs_timeout);
1498 #else
1499         do {
1500                 struct timeval _start = ast_tvnow(), _diff;
1501                 for (;;) {
1502                         if (!(res = pthread_rwlock_trywrlock(&t->lock))) {
1503                                 break;
1504                         }
1505                         _diff = ast_tvsub(ast_tvnow(), _start);
1506                         if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1507                                 break;
1508                         }
1509                         usleep(1);
1510                 }
1511         } while (0);
1512 #endif
1513         if (!res) {
1514                 ast_reentrancy_lock(lt);
1515                 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1516                         lt->file[lt->reentrancy] = filename;
1517                         lt->lineno[lt->reentrancy] = line;
1518                         lt->func[lt->reentrancy] = func;
1519                         lt->thread[lt->reentrancy] = pthread_self();
1520                         lt->reentrancy++;
1521                 }
1522                 ast_reentrancy_unlock(lt);
1523                 if (t->tracking) {
1524                         ast_mark_lock_acquired(t);
1525                 }
1526         } else {
1527 #ifdef HAVE_BKTR
1528                 if (lt->reentrancy) {
1529                         ast_reentrancy_lock(lt);
1530                         bt = &lt->backtrace[lt->reentrancy-1];
1531                         ast_reentrancy_unlock(lt);
1532                 } else {
1533                         bt = NULL;
1534                 }
1535                 if (t->tracking) {
1536                         ast_remove_lock_info(t, bt);
1537                 }
1538 #else
1539                 if (t->tracking) {
1540                         ast_remove_lock_info(t);
1541                 }
1542 #endif
1543                 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
1544                                 filename, line, func, strerror(res));
1545                 DO_THREAD_CRASH;
1546         }
1547         return res;
1548 }
1549
1550 static inline int _ast_rwlock_tryrdlock(ast_rwlock_t *t, const char *name,
1551         const char *filename, int line, const char *func)
1552 {
1553         int res;
1554         struct ast_lock_track *lt = &t->track;
1555 #ifdef HAVE_BKTR
1556         struct ast_bt *bt = NULL;
1557 #endif
1558 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1559         int canlog = strcmp(filename, "logger.c") & t->tracking;
1560
1561         if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1562                  /* Don't warn abount uninitialized lock.
1563                   * Simple try to initialize it.
1564                   * May be not needed in linux system.
1565                   */
1566                 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1567                 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1568                         __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1569                                         filename, line, func, name);
1570                         return res;
1571                 }
1572         }
1573 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1574
1575         if (t->tracking) {
1576 #ifdef HAVE_BKTR
1577                 ast_reentrancy_lock(lt);
1578                 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1579                         ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
1580                         bt = &lt->backtrace[lt->reentrancy];
1581                 }
1582                 ast_reentrancy_unlock(lt);
1583                 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
1584 #else
1585                 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t);
1586 #endif
1587         }
1588
1589         if (!(res = pthread_rwlock_tryrdlock(&t->lock))) {
1590                 ast_reentrancy_lock(lt);
1591                 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1592                         lt->file[lt->reentrancy] = filename;
1593                         lt->lineno[lt->reentrancy] = line;
1594                         lt->func[lt->reentrancy] = func;
1595                         lt->thread[lt->reentrancy] = pthread_self();
1596                         lt->reentrancy++;
1597                 }
1598                 ast_reentrancy_unlock(lt);
1599                 if (t->tracking) {
1600                         ast_mark_lock_acquired(t);
1601                 }
1602         } else if (t->tracking) {
1603                 ast_mark_lock_failed(t);
1604         }
1605         return res;
1606 }
1607
1608 static inline int _ast_rwlock_trywrlock(ast_rwlock_t *t, const char *name,
1609         const char *filename, int line, const char *func)
1610 {
1611         int res;
1612         struct ast_lock_track *lt= &t->track;
1613 #ifdef HAVE_BKTR
1614         struct ast_bt *bt = NULL;
1615 #endif
1616 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1617         int canlog = strcmp(filename, "logger.c") & t->tracking;
1618
1619         if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1620                  /* Don't warn abount uninitialized lock.
1621                   * Simple try to initialize it.
1622                   * May be not needed in linux system.
1623                   */
1624                 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1625                 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1626                         __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1627                                         filename, line, func, name);
1628                         return res;
1629                 }
1630         }
1631 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1632
1633         if (t->tracking) {
1634 #ifdef HAVE_BKTR
1635                 ast_reentrancy_lock(lt);
1636                 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1637                         ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
1638                         bt = &lt->backtrace[lt->reentrancy];
1639                 }
1640                 ast_reentrancy_unlock(lt);
1641                 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1642 #else
1643                 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1644 #endif
1645         }
1646
1647         if (!(res = pthread_rwlock_trywrlock(&t->lock))) {
1648                 ast_reentrancy_lock(lt);
1649                 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1650                         lt->file[lt->reentrancy] = filename;
1651                         lt->lineno[lt->reentrancy] = line;
1652                         lt->func[lt->reentrancy] = func;
1653                         lt->thread[lt->reentrancy] = pthread_self();
1654                         lt->reentrancy++;
1655                 }
1656                 ast_reentrancy_unlock(lt);
1657                 if (t->tracking) {
1658                         ast_mark_lock_acquired(t);
1659                 }
1660         } else if (t->tracking) {
1661                 ast_mark_lock_failed(t);
1662         }
1663         return res;
1664 }
1665
1666 #else /* !DEBUG_THREADS */
1667
1668 #define CHANNEL_DEADLOCK_AVOIDANCE(chan) \
1669         ast_channel_unlock(chan); \
1670         usleep(1); \
1671         ast_channel_lock(chan);
1672
1673 #define DEADLOCK_AVOIDANCE(lock) \
1674         ast_mutex_unlock(lock); \
1675         usleep(1); \
1676         ast_mutex_lock(lock);
1677
1678 #define DLA_UNLOCK(lock)        ast_mutex_unlock(lock)
1679
1680 #define DLA_LOCK(lock)  ast_mutex_lock(lock)
1681
1682 typedef pthread_mutex_t ast_mutex_t;
1683
1684 #define AST_MUTEX_INIT_VALUE                    ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
1685 #define AST_MUTEX_INIT_VALUE_NOTRACKING         ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
1686
1687 #define ast_mutex_init_notracking(m)            ast_mutex_init(m)
1688
1689 static inline int ast_mutex_init(ast_mutex_t *pmutex)
1690 {
1691         int res;
1692         pthread_mutexattr_t attr;
1693
1694         pthread_mutexattr_init(&attr);
1695         pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
1696
1697         res = pthread_mutex_init(pmutex, &attr);
1698         pthread_mutexattr_destroy(&attr);
1699         return res;
1700 }
1701
1702 #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
1703
1704 static inline int ast_mutex_unlock(ast_mutex_t *pmutex)
1705 {
1706         return pthread_mutex_unlock(pmutex);
1707 }
1708
1709 static inline int ast_mutex_destroy(ast_mutex_t *pmutex)
1710 {
1711         return pthread_mutex_destroy(pmutex);
1712 }
1713
1714 static inline int ast_mutex_lock(ast_mutex_t *pmutex)
1715 {
1716         __MTX_PROF(pmutex);
1717 }
1718
1719 static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
1720 {
1721         return pthread_mutex_trylock(pmutex);
1722 }
1723
1724 typedef pthread_cond_t ast_cond_t;
1725
1726 static inline int ast_cond_init(ast_cond_t *cond, pthread_condattr_t *cond_attr)
1727 {
1728         return pthread_cond_init(cond, cond_attr);
1729 }
1730
1731 static inline int ast_cond_signal(ast_cond_t *cond)
1732 {
1733         return pthread_cond_signal(cond);
1734 }
1735
1736 static inline int ast_cond_broadcast(ast_cond_t *cond)
1737 {
1738         return pthread_cond_broadcast(cond);
1739 }
1740
1741 static inline int ast_cond_destroy(ast_cond_t *cond)
1742 {
1743         return pthread_cond_destroy(cond);
1744 }
1745
1746 static inline int ast_cond_wait(ast_cond_t *cond, ast_mutex_t *t)
1747 {
1748         return pthread_cond_wait(cond, t);
1749 }
1750
1751 static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime)
1752 {
1753         return pthread_cond_timedwait(cond, t, abstime);
1754 }
1755
1756
1757 typedef pthread_rwlock_t ast_rwlock_t;
1758
1759 #ifdef HAVE_PTHREAD_RWLOCK_INITIALIZER
1760 #define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
1761 #else
1762 #define AST_RWLOCK_INIT_VALUE { 0 }
1763 #endif
1764
1765 #define ast_rwlock_init_notracking(a) ast_rwlock_init(a)
1766
1767 static inline int ast_rwlock_init(ast_rwlock_t *prwlock)
1768 {
1769         int res;
1770         pthread_rwlockattr_t attr;
1771
1772         pthread_rwlockattr_init(&attr);
1773
1774 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
1775         pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
1776 #endif
1777
1778         res = pthread_rwlock_init(prwlock, &attr);
1779         pthread_rwlockattr_destroy(&attr);
1780         return res;
1781 }
1782
1783 static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
1784 {
1785         return pthread_rwlock_destroy(prwlock);
1786 }
1787
1788 static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
1789 {
1790         return pthread_rwlock_unlock(prwlock);
1791 }
1792
1793 static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
1794 {
1795         return pthread_rwlock_rdlock(prwlock);
1796 }
1797
1798 static inline int ast_rwlock_timedrdlock(ast_rwlock_t *prwlock, const struct timespec *abs_timeout)
1799 {
1800         int res;
1801 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1802         res = pthread_rwlock_timedrdlock(prwlock, abs_timeout);
1803 #else
1804         struct timeval _start = ast_tvnow(), _diff;
1805         for (;;) {
1806                 if (!(res = pthread_rwlock_tryrdlock(prwlock))) {
1807                         break;
1808                 }
1809                 _diff = ast_tvsub(ast_tvnow(), _start);
1810                 if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1811                         break;
1812                 }
1813                 usleep(1);
1814         }
1815 #endif
1816         return res;
1817 }
1818
1819 static inline int ast_rwlock_tryrdlock(ast_rwlock_t *prwlock)
1820 {
1821         return pthread_rwlock_tryrdlock(prwlock);
1822 }
1823
1824 static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
1825 {
1826         return pthread_rwlock_wrlock(prwlock);
1827 }
1828
1829 static inline int ast_rwlock_timedwrlock(ast_rwlock_t *prwlock, const struct timespec *abs_timeout)
1830 {
1831         int res;
1832 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1833         res = pthread_rwlock_timedwrlock(prwlock, abs_timeout);
1834 #else
1835         do {
1836                 struct timeval _start = ast_tvnow(), _diff;
1837                 for (;;) {
1838                         if (!(res = pthread_rwlock_trywrlock(prwlock))) {
1839                                 break;
1840                         }
1841                         _diff = ast_tvsub(ast_tvnow(), _start);
1842                         if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1843                                 break;
1844                         }
1845                         usleep(1);
1846                 }
1847         } while (0);
1848 #endif
1849         return res;
1850 }
1851
1852 static inline int ast_rwlock_trywrlock(ast_rwlock_t *prwlock)
1853 {
1854         return pthread_rwlock_trywrlock(prwlock);
1855 }
1856
1857 #endif /* !DEBUG_THREADS */
1858
1859 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
1860 /*
1861  * If AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope constructors
1862  * and destructors to create/destroy global mutexes.
1863  */
1864 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track)       \
1865         scope ast_mutex_t mutex = init_val;                     \
1866 static void  __attribute__((constructor)) init_##mutex(void)    \
1867 {                                                               \
1868         if (track)                                              \
1869                 ast_mutex_init(&mutex);                         \
1870         else                                                    \
1871                 ast_mutex_init_notracking(&mutex);              \
1872 }                                                               \
1873                                                                 \
1874 static void  __attribute__((destructor)) fini_##mutex(void)     \
1875 {                                                               \
1876         ast_mutex_destroy(&mutex);                              \
1877 }
1878 #else /* !AST_MUTEX_INIT_W_CONSTRUCTORS */
1879 /* By default, use static initialization of mutexes. */
1880 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track)       scope ast_mutex_t mutex = init_val
1881 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1882
1883 #ifndef __CYGWIN__      /* temporary disabled for cygwin */
1884 #define pthread_mutex_t         use_ast_mutex_t_instead_of_pthread_mutex_t
1885 #define pthread_cond_t          use_ast_cond_t_instead_of_pthread_cond_t
1886 #endif
1887 #define pthread_mutex_lock      use_ast_mutex_lock_instead_of_pthread_mutex_lock
1888 #define pthread_mutex_unlock    use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
1889 #define pthread_mutex_trylock   use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
1890 #define pthread_mutex_init      use_ast_mutex_init_instead_of_pthread_mutex_init
1891 #define pthread_mutex_destroy   use_ast_mutex_destroy_instead_of_pthread_mutex_destroy
1892 #define pthread_cond_init       use_ast_cond_init_instead_of_pthread_cond_init
1893 #define pthread_cond_destroy    use_ast_cond_destroy_instead_of_pthread_cond_destroy
1894 #define pthread_cond_signal     use_ast_cond_signal_instead_of_pthread_cond_signal
1895 #define pthread_cond_broadcast  use_ast_cond_broadcast_instead_of_pthread_cond_broadcast
1896 #define pthread_cond_wait       use_ast_cond_wait_instead_of_pthread_cond_wait
1897 #define pthread_cond_timedwait  use_ast_cond_timedwait_instead_of_pthread_cond_timedwait
1898
1899 #define AST_MUTEX_DEFINE_STATIC(mutex)                  __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE, 1)
1900 #define AST_MUTEX_DEFINE_STATIC_NOTRACKING(mutex)       __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE_NOTRACKING, 0)
1901
1902 #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
1903
1904 #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
1905
1906 #ifndef __linux__
1907 #define pthread_create __use_ast_pthread_create_instead__
1908 #endif
1909
1910 /* Statically declared read/write locks */
1911
1912 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
1913 #define __AST_RWLOCK_DEFINE(scope, rwlock, init_val, track) \
1914         scope ast_rwlock_t rwlock = init_val; \
1915 static void  __attribute__((constructor)) init_##rwlock(void) \
1916 { \
1917         if (track) \
1918                 ast_rwlock_init(&rwlock); \
1919         else \
1920                 ast_rwlock_init_notracking(&rwlock); \
1921 } \
1922 static void  __attribute__((destructor)) fini_##rwlock(void) \
1923 { \
1924         ast_rwlock_destroy(&rwlock); \
1925 }
1926 #else
1927 #define __AST_RWLOCK_DEFINE(scope, rwlock, init_val, track) \
1928         scope ast_rwlock_t rwlock = init_val
1929 #endif
1930
1931 #define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock, AST_RWLOCK_INIT_VALUE, 1)
1932 #define AST_RWLOCK_DEFINE_STATIC_NOTRACKING(rwlock) __AST_RWLOCK_DEFINE(static, rwlock, AST_RWLOCK_INIT_VALUE_NOTRACKING, 0)
1933
1934 /*
1935  * Support for atomic instructions.
1936  * For platforms that have it, use the native cpu instruction to
1937  * implement them. For other platforms, resort to a 'slow' version
1938  * (defined in utils.c) that protects the atomic instruction with
1939  * a single lock.
1940  * The slow versions is always available, for testing purposes,
1941  * as ast_atomic_fetchadd_int_slow()
1942  */
1943
1944 int ast_atomic_fetchadd_int_slow(volatile int *p, int v);
1945
1946 #include "asterisk/inline_api.h"
1947
1948 #if defined(HAVE_OSX_ATOMICS)
1949 #include "libkern/OSAtomic.h"
1950 #endif
1951
1952 /*! \brief Atomically add v to *p and return * the previous value of *p.
1953  * This can be used to handle reference counts, and the return value
1954  * can be used to generate unique identifiers.
1955  */
1956
1957 #if defined(HAVE_GCC_ATOMICS)
1958 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1959 {
1960         return __sync_fetch_and_add(p, v);
1961 })
1962 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
1963 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1964 {
1965         return OSAtomicAdd32(v, (int32_t *) p) - v;
1966 })
1967 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
1968 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1969 {
1970         return OSAtomicAdd64(v, (int64_t *) p) - v;
1971 #elif defined (__i386__) || defined(__x86_64__)
1972 #ifdef sun
1973 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1974 {
1975         __asm __volatile (
1976         "       lock;  xaddl   %0, %1 ;        "
1977         : "+r" (v),                     /* 0 (result) */
1978           "=m" (*p)                     /* 1 */
1979         : "m" (*p));                    /* 2 */
1980         return (v);
1981 })
1982 #else /* ifndef sun */
1983 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1984 {
1985         __asm __volatile (
1986         "       lock   xaddl   %0, %1 ;        "
1987         : "+r" (v),                     /* 0 (result) */
1988           "=m" (*p)                     /* 1 */
1989         : "m" (*p));                    /* 2 */
1990         return (v);
1991 })
1992 #endif
1993 #else   /* low performance version in utils.c */
1994 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1995 {
1996         return ast_atomic_fetchadd_int_slow(p, v);
1997 })
1998 #endif
1999
2000 /*! \brief decrement *p by 1 and return true if the variable has reached 0.
2001  * Useful e.g. to check if a refcount has reached 0.
2002  */
2003 #if defined(HAVE_GCC_ATOMICS)
2004 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
2005 {
2006         return __sync_sub_and_fetch(p, 1) == 0;
2007 })
2008 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
2009 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
2010 {
2011         return OSAtomicAdd32( -1, (int32_t *) p) == 0;
2012 })
2013 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
2014 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
2015 {
2016         return OSAtomicAdd64( -1, (int64_t *) p) == 0;
2017 #else
2018 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
2019 {
2020         int a = ast_atomic_fetchadd_int(p, -1);
2021         return a == 1; /* true if the value is 0 now (so it was 1 previously) */
2022 })
2023 #endif
2024
2025 #endif /* _ASTERISK_LOCK_H */