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