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