5d6ef43bba73045239ae02d1aae39f34776239ef
[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
54 #include "asterisk/logger.h"
55
56 /* internal macro to profile mutexes. Only computes the delay on
57  * non-blocking calls.
58  */
59 #ifndef HAVE_MTX_PROFILE
60 #define __MTX_PROF(a)   return pthread_mutex_lock((a))
61 #else
62 #define __MTX_PROF(a)   do {                    \
63         int i;                                  \
64         /* profile only non-blocking events */  \
65         ast_mark(mtx_prof, 1);                  \
66         i = pthread_mutex_trylock((a));         \
67         ast_mark(mtx_prof, 0);                  \
68         if (!i)                                 \
69                 return i;                       \
70         else                                    \
71                 return pthread_mutex_lock((a)); \
72         } while (0)
73 #endif  /* HAVE_MTX_PROFILE */
74
75 #define AST_PTHREADT_NULL (pthread_t) -1
76 #define AST_PTHREADT_STOP (pthread_t) -2
77
78 #if defined(SOLARIS) || defined(BSD)
79 #define AST_MUTEX_INIT_W_CONSTRUCTORS
80 #endif /* SOLARIS || BSD */
81
82 /* Asterisk REQUIRES recursive (not error checking) mutexes
83    and will not run without them. */
84 #if defined(HAVE_PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) && defined(HAVE_PTHREAD_MUTEX_RECURSIVE_NP)
85 #define PTHREAD_MUTEX_INIT_VALUE        PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
86 #define AST_MUTEX_KIND                  PTHREAD_MUTEX_RECURSIVE_NP
87 #else
88 #define PTHREAD_MUTEX_INIT_VALUE        PTHREAD_MUTEX_INITIALIZER
89 #define AST_MUTEX_KIND                  PTHREAD_MUTEX_RECURSIVE
90 #endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
91
92 /*
93  * Definition of ast_mutex_t, ast_cont_d and related functions with/without debugging
94  * (search for DEBUG_THREADS to find the start/end of the sections).
95  *
96  * The non-debug code contains just wrappers for the corresponding pthread functions.
97  * The debug code tracks usage and tries to identify deadlock situations.
98  */
99 #ifdef DEBUG_THREADS
100
101 #define __ast_mutex_logger(...)  do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0)
102
103 #ifdef THREAD_CRASH
104 #define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
105 #else
106 #define DO_THREAD_CRASH do { } while (0)
107 #endif
108
109 #include <errno.h>
110
111 #define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, 1, { NULL }, { 0 }, 0, { NULL }, { 0 }, PTHREAD_MUTEX_INIT_VALUE }
112 #define AST_MUTEX_INIT_VALUE_NOTRACKING \
113                              { PTHREAD_MUTEX_INIT_VALUE, 0, { NULL }, { 0 }, 0, { NULL }, { 0 }, PTHREAD_MUTEX_INIT_VALUE }
114
115 #define AST_MAX_REENTRANCY 10
116
117 struct ast_channel;
118
119 struct ast_mutex_info {
120         pthread_mutex_t mutex;
121         /*! Track which thread holds this lock */
122         unsigned int track:1;
123         const char *file[AST_MAX_REENTRANCY];
124         int lineno[AST_MAX_REENTRANCY];
125         int reentrancy;
126         const char *func[AST_MAX_REENTRANCY];
127         pthread_t thread[AST_MAX_REENTRANCY];
128         pthread_mutex_t reentr_mutex;
129 };
130
131 typedef struct ast_mutex_info ast_mutex_t;
132
133 typedef pthread_cond_t ast_cond_t;
134
135 static pthread_mutex_t empty_mutex;
136
137 enum ast_lock_type {
138         AST_MUTEX,
139         AST_RDLOCK,
140         AST_WRLOCK,
141 };
142
143 /*!
144  * \brief Store lock info for the current thread
145  *
146  * This function gets called in ast_mutex_lock() and ast_mutex_trylock() so
147  * that information about this lock can be stored in this thread's
148  * lock info struct.  The lock is marked as pending as the thread is waiting
149  * on the lock.  ast_mark_lock_acquired() will mark it as held by this thread.
150  */
151 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
152         int line_num, const char *func, const char *lock_name, void *lock_addr);
153
154 /*!
155  * \brief Mark the last lock as acquired
156  */
157 void ast_mark_lock_acquired(void *lock_addr);
158
159 /*!
160  * \brief Mark the last lock as failed (trylock)
161  */
162 void ast_mark_lock_failed(void *lock_addr);
163
164 /*!
165  * \brief remove lock info for the current thread
166  *
167  * this gets called by ast_mutex_unlock so that information on the lock can
168  * be removed from the current thread's lock info struct.
169  */
170 void ast_remove_lock_info(void *lock_addr);
171
172 static void __attribute__((constructor)) init_empty_mutex(void)
173 {
174         memset(&empty_mutex, 0, sizeof(empty_mutex));
175 }
176
177 static inline void ast_reentrancy_lock(ast_mutex_t *p_ast_mutex)
178 {
179         pthread_mutex_lock(&p_ast_mutex->reentr_mutex);
180 }
181
182 static inline void ast_reentrancy_unlock(ast_mutex_t *p_ast_mutex)
183 {
184         pthread_mutex_unlock(&p_ast_mutex->reentr_mutex);
185 }
186
187 static inline void ast_reentrancy_init(ast_mutex_t *p_ast_mutex)
188 {
189         int i;
190         pthread_mutexattr_t reentr_attr;
191
192         for (i = 0; i < AST_MAX_REENTRANCY; i++) {
193                 p_ast_mutex->file[i] = NULL;
194                 p_ast_mutex->lineno[i] = 0;
195                 p_ast_mutex->func[i] = NULL;
196                 p_ast_mutex->thread[i] = 0;
197         }
198
199         p_ast_mutex->reentrancy = 0;
200
201         pthread_mutexattr_init(&reentr_attr);
202         pthread_mutexattr_settype(&reentr_attr, AST_MUTEX_KIND);
203         pthread_mutex_init(&p_ast_mutex->reentr_mutex, &reentr_attr);
204         pthread_mutexattr_destroy(&reentr_attr);
205 }
206
207 static inline void delete_reentrancy_cs(ast_mutex_t * p_ast_mutex)
208 {
209         pthread_mutex_destroy(&p_ast_mutex->reentr_mutex);
210 }
211
212 static inline int __ast_pthread_mutex_init(int track, const char *filename, int lineno, const char *func,
213                                                 const char *mutex_name, ast_mutex_t *t) 
214 {
215         int res;
216         pthread_mutexattr_t  attr;
217
218 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
219
220         if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
221 /*
222                 int canlog = strcmp(filename, "logger.c") & track;
223                 __ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is already initialized.\n",
224                                    filename, lineno, func, mutex_name);
225                 DO_THREAD_CRASH;
226 */
227                 return 0;
228         }
229
230 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
231
232         ast_reentrancy_init(t);
233         t->track = track;
234
235         pthread_mutexattr_init(&attr);
236         pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
237
238         res = pthread_mutex_init(&t->mutex, &attr);
239         pthread_mutexattr_destroy(&attr);
240         return res;
241 }
242
243 #define ast_mutex_init(pmutex) __ast_pthread_mutex_init(1, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
244 #define ast_mutex_init_notracking(pmutex) \
245         __ast_pthread_mutex_init(0, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
246
247 static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
248                                                 const char *mutex_name, ast_mutex_t *t)
249 {
250         int res;
251         int canlog = strcmp(filename, "logger.c") & t->track;
252
253 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
254         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
255                 /* Don't try to uninitialize non initialized mutex
256                  * This may no effect on linux
257                  * And always ganerate core on *BSD with 
258                  * linked libpthread
259                  * This not error condition if the mutex created on the fly.
260                  */
261                 __ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is uninitialized.\n",
262                                    filename, lineno, func, mutex_name);
263                 return 0;
264         }
265 #endif
266
267         res = pthread_mutex_trylock(&t->mutex);
268         switch (res) {
269         case 0:
270                 pthread_mutex_unlock(&t->mutex);
271                 break;
272         case EINVAL:
273                 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
274                                   filename, lineno, func, mutex_name);
275                 break;
276         case EBUSY:
277                 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
278                                    filename, lineno, func, mutex_name);
279                 ast_reentrancy_lock(t);
280                 __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
281                             t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
282                 ast_reentrancy_unlock(t);
283                 break;
284         }
285
286         if ((res = pthread_mutex_destroy(&t->mutex)))
287                 __ast_mutex_logger("%s line %d (%s): Error destroying mutex %s: %s\n",
288                                    filename, lineno, func, mutex_name, strerror(res));
289 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
290         else
291                 t->mutex = PTHREAD_MUTEX_INIT_VALUE;
292 #endif
293         ast_reentrancy_lock(t);
294         t->file[0] = filename;
295         t->lineno[0] = lineno;
296         t->func[0] = func;
297         t->reentrancy = 0;
298         t->thread[0] = 0;
299         ast_reentrancy_unlock(t);
300         delete_reentrancy_cs(t);
301
302         return res;
303 }
304
305 static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
306                                            const char* mutex_name, ast_mutex_t *t)
307 {
308         int res;
309         int canlog = strcmp(filename, "logger.c") & t->track;
310
311 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
312         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
313                 /* Don't warn abount uninitialized mutex.
314                  * Simple try to initialize it.
315                  * May be not needed in linux system.
316                  */
317                 res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
318                 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
319                         __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
320                                          filename, lineno, func, mutex_name);
321                         return res;
322                 }               
323         }
324 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
325
326         if (t->track)
327                 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
328
329 #ifdef DETECT_DEADLOCKS
330         {
331                 time_t seconds = time(NULL);
332                 time_t wait_time, reported_wait = 0;
333                 do {
334 #ifdef  HAVE_MTX_PROFILE
335                         ast_mark(mtx_prof, 1);
336 #endif
337                         res = pthread_mutex_trylock(&t->mutex);
338 #ifdef  HAVE_MTX_PROFILE
339                         ast_mark(mtx_prof, 0);
340 #endif
341                         if (res == EBUSY) {
342                                 wait_time = time(NULL) - seconds;
343                                 if (wait_time > reported_wait && (wait_time % 5) == 0) {
344                                         __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
345                                                            filename, lineno, func, (int) wait_time, mutex_name);
346                                         ast_reentrancy_lock(t);
347                                         __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
348                                                            t->file[t->reentrancy-1], t->lineno[t->reentrancy-1],
349                                                            t->func[t->reentrancy-1], mutex_name);
350                                         ast_reentrancy_unlock(t);
351                                         reported_wait = wait_time;
352                                 }
353                                 usleep(200);
354                         }
355                 } while (res == EBUSY);
356         }
357 #else
358 #ifdef  HAVE_MTX_PROFILE
359         ast_mark(mtx_prof, 1);
360         res = pthread_mutex_trylock(&t->mutex);
361         ast_mark(mtx_prof, 0);
362         if (res)
363 #endif
364         res = pthread_mutex_lock(&t->mutex);
365 #endif /* DETECT_DEADLOCKS */
366
367         if (!res) {
368                 ast_reentrancy_lock(t);
369                 if (t->reentrancy < AST_MAX_REENTRANCY) {
370                         t->file[t->reentrancy] = filename;
371                         t->lineno[t->reentrancy] = lineno;
372                         t->func[t->reentrancy] = func;
373                         t->thread[t->reentrancy] = pthread_self();
374                         t->reentrancy++;
375                 } else {
376                         __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
377                                                            filename, lineno, func, mutex_name);
378                 }
379                 ast_reentrancy_unlock(t);
380                 if (t->track)
381                         ast_mark_lock_acquired(&t->mutex);
382         } else {
383                 if (t->track)
384                         ast_remove_lock_info(&t->mutex);
385                 __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
386                                    filename, lineno, func, strerror(res));
387                 DO_THREAD_CRASH;
388         }
389
390         return res;
391 }
392
393 static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
394                                               const char* mutex_name, ast_mutex_t *t)
395 {
396         int res;
397         int canlog = strcmp(filename, "logger.c") & t->track;
398
399 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
400         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
401                 /* Don't warn abount uninitialized mutex.
402                  * Simple try to initialize it.
403                  * May be not needed in linux system.
404                  */
405                 res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
406                 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
407                         __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
408                                          filename, lineno, func, mutex_name);
409                         return res;
410                 }               
411         }
412 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
413
414         if (t->track)
415                 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
416
417         if (!(res = pthread_mutex_trylock(&t->mutex))) {
418                 ast_reentrancy_lock(t);
419                 if (t->reentrancy < AST_MAX_REENTRANCY) {
420                         t->file[t->reentrancy] = filename;
421                         t->lineno[t->reentrancy] = lineno;
422                         t->func[t->reentrancy] = func;
423                         t->thread[t->reentrancy] = pthread_self();
424                         t->reentrancy++;
425                 } else {
426                         __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
427                                            filename, lineno, func, mutex_name);
428                 }
429                 ast_reentrancy_unlock(t);
430                 if (t->track)
431                         ast_mark_lock_acquired(&t->mutex);
432         } else if (t->track) {
433                 ast_mark_lock_failed(&t->mutex);
434         }
435
436         return res;
437 }
438
439 static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
440                                              const char *mutex_name, ast_mutex_t *t)
441 {
442         int res;
443         int canlog = strcmp(filename, "logger.c") & t->track;
444
445 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
446         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
447                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
448                                    filename, lineno, func, mutex_name);
449                 res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
450                 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
451                         __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
452                                          filename, lineno, func, mutex_name);
453                 }
454                 return res;
455         }
456 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
457
458         ast_reentrancy_lock(t);
459         if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
460                 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
461                                    filename, lineno, func, mutex_name);
462                 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
463                                    t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
464                 DO_THREAD_CRASH;
465         }
466
467         if (--t->reentrancy < 0) {
468                 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
469                                    filename, lineno, func, mutex_name);
470                 t->reentrancy = 0;
471         }
472
473         if (t->reentrancy < AST_MAX_REENTRANCY) {
474                 t->file[t->reentrancy] = NULL;
475                 t->lineno[t->reentrancy] = 0;
476                 t->func[t->reentrancy] = NULL;
477                 t->thread[t->reentrancy] = 0;
478         }
479         ast_reentrancy_unlock(t);
480
481         if (t->track)
482                 ast_remove_lock_info(&t->mutex);
483
484         if ((res = pthread_mutex_unlock(&t->mutex))) {
485                 __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n", 
486                                    filename, lineno, func, strerror(res));
487                 DO_THREAD_CRASH;
488         }
489
490         return res;
491 }
492
493 static inline int __ast_cond_init(const char *filename, int lineno, const char *func,
494                                   const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
495 {
496         return pthread_cond_init(cond, cond_attr);
497 }
498
499 static inline int __ast_cond_signal(const char *filename, int lineno, const char *func,
500                                     const char *cond_name, ast_cond_t *cond)
501 {
502         return pthread_cond_signal(cond);
503 }
504
505 static inline int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
506                                        const char *cond_name, ast_cond_t *cond)
507 {
508         return pthread_cond_broadcast(cond);
509 }
510
511 static inline int __ast_cond_destroy(const char *filename, int lineno, const char *func,
512                                      const char *cond_name, ast_cond_t *cond)
513 {
514         return pthread_cond_destroy(cond);
515 }
516
517 static inline int __ast_cond_wait(const char *filename, int lineno, const char *func,
518                                   const char *cond_name, const char *mutex_name,
519                                   ast_cond_t *cond, ast_mutex_t *t)
520 {
521         int res;
522         int canlog = strcmp(filename, "logger.c") & t->track;
523
524 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
525         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
526                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
527                                    filename, lineno, func, mutex_name);
528                 res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
529                 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
530                         __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
531                                          filename, lineno, func, mutex_name);
532                 }
533                 return res;
534         }
535 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
536
537         ast_reentrancy_lock(t);
538         if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
539                 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
540                                    filename, lineno, func, mutex_name);
541                 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
542                                    t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
543                 DO_THREAD_CRASH;
544         }
545
546         if (--t->reentrancy < 0) {
547                 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
548                                    filename, lineno, func, mutex_name);
549                 t->reentrancy = 0;
550         }
551
552         if (t->reentrancy < AST_MAX_REENTRANCY) {
553                 t->file[t->reentrancy] = NULL;
554                 t->lineno[t->reentrancy] = 0;
555                 t->func[t->reentrancy] = NULL;
556                 t->thread[t->reentrancy] = 0;
557         }
558         ast_reentrancy_unlock(t);
559
560         if (t->track)
561                 ast_remove_lock_info(&t->mutex);
562
563         if ((res = pthread_cond_wait(cond, &t->mutex))) {
564                 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n", 
565                                    filename, lineno, func, strerror(res));
566                 DO_THREAD_CRASH;
567         } else {
568                 ast_reentrancy_lock(t);
569                 if (t->reentrancy < AST_MAX_REENTRANCY) {
570                         t->file[t->reentrancy] = filename;
571                         t->lineno[t->reentrancy] = lineno;
572                         t->func[t->reentrancy] = func;
573                         t->thread[t->reentrancy] = pthread_self();
574                         t->reentrancy++;
575                 } else {
576                         __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
577                                                            filename, lineno, func, mutex_name);
578                 }
579                 ast_reentrancy_unlock(t);
580
581                 if (t->track)
582                         ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
583         }
584
585         return res;
586 }
587
588 static inline int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
589                                        const char *cond_name, const char *mutex_name, ast_cond_t *cond,
590                                        ast_mutex_t *t, const struct timespec *abstime)
591 {
592         int res;
593         int canlog = strcmp(filename, "logger.c") & t->track;
594
595 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
596         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
597                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
598                                    filename, lineno, func, mutex_name);
599                 res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
600                 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
601                         __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
602                                          filename, lineno, func, mutex_name);
603                 }
604                 return res;
605         }
606 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
607
608         ast_reentrancy_lock(t);
609         if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
610                 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
611                                    filename, lineno, func, mutex_name);
612                 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
613                                    t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
614                 DO_THREAD_CRASH;
615         }
616
617         if (--t->reentrancy < 0) {
618                 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
619                                    filename, lineno, func, mutex_name);
620                 t->reentrancy = 0;
621         }
622
623         if (t->reentrancy < AST_MAX_REENTRANCY) {
624                 t->file[t->reentrancy] = NULL;
625                 t->lineno[t->reentrancy] = 0;
626                 t->func[t->reentrancy] = NULL;
627                 t->thread[t->reentrancy] = 0;
628         }
629         ast_reentrancy_unlock(t);
630
631         if (t->track)
632                 ast_remove_lock_info(&t->mutex);
633
634         if ((res = pthread_cond_timedwait(cond, &t->mutex, abstime)) && (res != ETIMEDOUT)) {
635                 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n", 
636                                    filename, lineno, func, strerror(res));
637                 DO_THREAD_CRASH;
638         } else {
639                 ast_reentrancy_lock(t);
640                 if (t->reentrancy < AST_MAX_REENTRANCY) {
641                         t->file[t->reentrancy] = filename;
642                         t->lineno[t->reentrancy] = lineno;
643                         t->func[t->reentrancy] = func;
644                         t->thread[t->reentrancy] = pthread_self();
645                         t->reentrancy++;
646                 } else {
647                         __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
648                                                            filename, lineno, func, mutex_name);
649                 }
650                 ast_reentrancy_unlock(t);
651
652                 if (t->track)
653                         ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
654         }
655
656         return res;
657 }
658
659 #define ast_mutex_destroy(a)                    __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
660 #define ast_mutex_lock(a)                       __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
661 #define ast_mutex_unlock(a)                     __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
662 #define ast_mutex_trylock(a)                    __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
663 #define ast_cond_init(cond, attr)               __ast_cond_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond, attr)
664 #define ast_cond_destroy(cond)                  __ast_cond_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
665 #define ast_cond_signal(cond)                   __ast_cond_signal(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
666 #define ast_cond_broadcast(cond)                __ast_cond_broadcast(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
667 #define ast_cond_wait(cond, mutex)              __ast_cond_wait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex)
668 #define ast_cond_timedwait(cond, mutex, time)   __ast_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex, time)
669
670 #else /* !DEBUG_THREADS */
671
672
673 typedef pthread_mutex_t ast_mutex_t;
674
675 #define AST_MUTEX_INIT_VALUE                    ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
676 #define AST_MUTEX_INIT_VALUE_NOTRACKING         ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
677
678 #define ast_mutex_init_notracking(m)            ast_mutex_init(m)
679
680 static inline int ast_mutex_init(ast_mutex_t *pmutex)
681 {
682         int res;
683         pthread_mutexattr_t attr;
684
685         pthread_mutexattr_init(&attr);
686         pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
687
688         res = pthread_mutex_init(pmutex, &attr);
689         pthread_mutexattr_destroy(&attr);
690         return res;
691 }
692
693 #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
694
695 static inline int ast_mutex_unlock(ast_mutex_t *pmutex)
696 {
697         return pthread_mutex_unlock(pmutex);
698 }
699
700 static inline int ast_mutex_destroy(ast_mutex_t *pmutex)
701 {
702         return pthread_mutex_destroy(pmutex);
703 }
704
705 static inline int ast_mutex_lock(ast_mutex_t *pmutex)
706 {
707         __MTX_PROF(pmutex);
708 }
709
710 static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
711 {
712         return pthread_mutex_trylock(pmutex);
713 }
714
715 typedef pthread_cond_t ast_cond_t;
716
717 static inline int ast_cond_init(ast_cond_t *cond, pthread_condattr_t *cond_attr)
718 {
719         return pthread_cond_init(cond, cond_attr);
720 }
721
722 static inline int ast_cond_signal(ast_cond_t *cond)
723 {
724         return pthread_cond_signal(cond);
725 }
726
727 static inline int ast_cond_broadcast(ast_cond_t *cond)
728 {
729         return pthread_cond_broadcast(cond);
730 }
731
732 static inline int ast_cond_destroy(ast_cond_t *cond)
733 {
734         return pthread_cond_destroy(cond);
735 }
736
737 static inline int ast_cond_wait(ast_cond_t *cond, ast_mutex_t *t)
738 {
739         return pthread_cond_wait(cond, t);
740 }
741
742 static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime)
743 {
744         return pthread_cond_timedwait(cond, t, abstime);
745 }
746
747 #endif /* !DEBUG_THREADS */
748
749 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
750 /*
751  * If AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope constructors
752  * and destructors to create/destroy global mutexes.
753  */
754 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track)       \
755         scope ast_mutex_t mutex = init_val;                     \
756 static void  __attribute__ ((constructor)) init_##mutex(void)   \
757 {                                                               \
758         if (track)                                              \
759                 ast_mutex_init(&mutex);                         \
760         else                                                    \
761                 ast_mutex_init_notracking(&mutex);              \
762 }                                                               \
763                                                                 \
764 static void  __attribute__ ((destructor)) fini_##mutex(void)    \
765 {                                                               \
766         ast_mutex_destroy(&mutex);                              \
767 }
768 #else /* !AST_MUTEX_INIT_W_CONSTRUCTORS */
769 /* By default, use static initialization of mutexes. */ 
770 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track)       scope ast_mutex_t mutex = init_val
771 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
772
773 #ifndef __CYGWIN__      /* temporary disabled for cygwin */
774 #define pthread_mutex_t         use_ast_mutex_t_instead_of_pthread_mutex_t
775 #define pthread_cond_t          use_ast_cond_t_instead_of_pthread_cond_t
776 #endif
777 #define pthread_mutex_lock      use_ast_mutex_lock_instead_of_pthread_mutex_lock
778 #define pthread_mutex_unlock    use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
779 #define pthread_mutex_trylock   use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
780 #define pthread_mutex_init      use_ast_mutex_init_instead_of_pthread_mutex_init
781 #define pthread_mutex_destroy   use_ast_mutex_destroy_instead_of_pthread_mutex_destroy
782 #define pthread_cond_init       use_ast_cond_init_instead_of_pthread_cond_init
783 #define pthread_cond_destroy    use_ast_cond_destroy_instead_of_pthread_cond_destroy
784 #define pthread_cond_signal     use_ast_cond_signal_instead_of_pthread_cond_signal
785 #define pthread_cond_broadcast  use_ast_cond_broadcast_instead_of_pthread_cond_broadcast
786 #define pthread_cond_wait       use_ast_cond_wait_instead_of_pthread_cond_wait
787 #define pthread_cond_timedwait  use_ast_cond_timedwait_instead_of_pthread_cond_timedwait
788
789 #define AST_MUTEX_DEFINE_STATIC(mutex)                  __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE, 1)
790 #define AST_MUTEX_DEFINE_STATIC_NOTRACKING(mutex)       __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE_NOTRACKING, 0)
791
792 #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
793
794 #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
795
796 #ifndef __linux__
797 #define pthread_create __use_ast_pthread_create_instead__
798 #endif
799
800 /*
801  * Same as above, definitions of ast_rwlock_t for the various cases:
802  * simple wrappers for the pthread equivalent in the non-debug case,
803  * more sophisticated tracking in the debug case.
804  */
805
806 typedef pthread_rwlock_t ast_rwlock_t;
807
808 #ifdef HAVE_PTHREAD_RWLOCK_INITIALIZER
809 #define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
810 #else
811 #define AST_RWLOCK_INIT_VALUE { 0 }
812 #endif
813
814 #ifdef DEBUG_THREADS
815
816 #define ast_rwlock_init(rwlock)         __ast_rwlock_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)
817 #define ast_rwlock_destroy(rwlock)      __ast_rwlock_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)
818 #define ast_rwlock_unlock(a)            _ast_rwlock_unlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
819 #define ast_rwlock_rdlock(a)            _ast_rwlock_rdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
820 #define ast_rwlock_wrlock(a)            _ast_rwlock_wrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
821 #define ast_rwlock_tryrdlock(a)         _ast_rwlock_tryrdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
822 #define ast_rwlock_trywrlock(a) _ast_rwlock_trywrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
823
824
825 static inline int __ast_rwlock_init(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *prwlock)
826 {
827         int res;
828         pthread_rwlockattr_t attr;
829 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
830         int canlog = strcmp(filename, "logger.c");
831
832         if (*prwlock != ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
833                 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
834                                 filename, lineno, func, rwlock_name);
835                 return 0;
836         }
837 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
838         pthread_rwlockattr_init(&attr);
839
840 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
841         pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
842 #endif
843
844         res = pthread_rwlock_init(prwlock, &attr);
845         pthread_rwlockattr_destroy(&attr);
846         return res;
847 }
848
849
850 static inline int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *prwlock)
851 {
852         int res;
853         int canlog = strcmp(filename, "logger.c");
854
855 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
856         if (*prwlock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
857                 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
858                                    filename, lineno, func, rwlock_name);
859                 return 0;
860         }
861 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
862         
863         if ((res = pthread_rwlock_destroy(prwlock)))
864                 __ast_mutex_logger("%s line %d (%s): Error destroying rwlock %s: %s\n",
865                                 filename, lineno, func, rwlock_name, strerror(res));
866
867         return res;
868 }
869
870
871 static inline int _ast_rwlock_unlock(ast_rwlock_t *lock, const char *name,
872         const char *file, int line, const char *func)
873 {
874         int res;
875 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
876         int canlog = strcmp(file, "logger.c");
877
878         if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
879                 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
880                                    file, line, func, name);
881                 res = __ast_rwlock_init(file, line, func, name, lock);
882                 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
883                         __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
884                                         file, line, func, name);
885                 }
886                 return res;
887         }
888 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
889         
890         res = pthread_rwlock_unlock(lock);
891         ast_remove_lock_info(lock);
892         return res;
893 }
894
895
896 static inline int _ast_rwlock_rdlock(ast_rwlock_t *lock, const char *name,
897         const char *file, int line, const char *func)
898 {
899         int res;
900 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
901         int canlog = strcmp(file, "logger.c");
902         
903         if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
904                  /* Don't warn abount uninitialized lock.
905                   * Simple try to initialize it.
906                   * May be not needed in linux system.
907                   */
908                 res = __ast_rwlock_init(file, line, func, name, lock);
909                 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
910                         __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
911                                         file, line, func, name);
912                         return res;
913                 }
914         }
915 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
916         
917         ast_store_lock_info(AST_RDLOCK, file, line, func, name, lock);
918         res = pthread_rwlock_rdlock(lock);
919         if (!res)
920                 ast_mark_lock_acquired(lock);
921         else
922                 ast_remove_lock_info(lock);
923         return res;
924 }
925
926
927 static inline int _ast_rwlock_wrlock(ast_rwlock_t *lock, const char *name,
928         const char *file, int line, const char *func)
929 {
930         int res;
931 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
932         int canlog = strcmp(file, "logger.c");
933         
934         if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
935                  /* Don't warn abount uninitialized lock.
936                   * Simple try to initialize it.
937                   * May be not needed in linux system.
938                   */
939                 res = __ast_rwlock_init(file, line, func, name, lock);
940                 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
941                         __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
942                                         file, line, func, name);
943                         return res;
944                 }
945         }
946 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
947
948         ast_store_lock_info(AST_WRLOCK, file, line, func, name, lock);
949         res = pthread_rwlock_wrlock(lock);
950         if (!res)
951                 ast_mark_lock_acquired(lock);
952         else
953                 ast_remove_lock_info(lock);
954         return res;
955 }
956
957
958 static inline int _ast_rwlock_tryrdlock(ast_rwlock_t *lock, const char *name,
959         const char *file, int line, const char *func)
960 {
961         int res;
962 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
963         int canlog = strcmp(file, "logger.c");
964         
965         if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
966                  /* Don't warn abount uninitialized lock.
967                   * Simple try to initialize it.
968                   * May be not needed in linux system.
969                   */
970                 res = __ast_rwlock_init(file, line, func, name, lock);
971                 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
972                         __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
973                                         file, line, func, name);
974                         return res;
975                 }
976         }
977 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
978
979         ast_store_lock_info(AST_RDLOCK, file, line, func, name, lock);
980         res = pthread_rwlock_tryrdlock(lock);
981         if (!res)
982                 ast_mark_lock_acquired(lock);
983         else
984                 ast_remove_lock_info(lock);
985         return res;
986 }
987
988
989 static inline int _ast_rwlock_trywrlock(ast_rwlock_t *lock, const char *name,
990         const char *file, int line, const char *func)
991 {
992         int res;
993 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
994         int canlog = strcmp(file, "logger.c");
995         
996         if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
997                  /* Don't warn abount uninitialized lock.
998                   * Simple try to initialize it.
999                   * May be not needed in linux system.
1000                   */
1001                 res = __ast_rwlock_init(file, line, func, name, lock);
1002                 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
1003                         __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1004                                         file, line, func, name);
1005                         return res;
1006                 }
1007         }
1008 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1009
1010         ast_store_lock_info(AST_WRLOCK, file, line, func, name, lock);
1011         res = pthread_rwlock_trywrlock(lock);
1012         if (!res)
1013                 ast_mark_lock_acquired(lock);
1014         else
1015                 ast_remove_lock_info(lock);
1016         return res;
1017 }
1018
1019 #else /* !DEBUG_THREADS */
1020
1021 static inline int ast_rwlock_init(ast_rwlock_t *prwlock)
1022 {
1023         int res;
1024         pthread_rwlockattr_t attr;
1025
1026         pthread_rwlockattr_init(&attr);
1027
1028 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
1029         pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
1030 #endif
1031
1032         res = pthread_rwlock_init(prwlock, &attr);
1033         pthread_rwlockattr_destroy(&attr);
1034         return res;
1035 }
1036
1037 static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
1038 {
1039         return pthread_rwlock_destroy(prwlock);
1040 }
1041
1042 static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
1043 {
1044         return pthread_rwlock_unlock(prwlock);
1045 }
1046
1047 static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
1048 {
1049         return pthread_rwlock_rdlock(prwlock);
1050 }
1051
1052 static inline int ast_rwlock_tryrdlock(ast_rwlock_t *prwlock)
1053 {
1054         return pthread_rwlock_tryrdlock(prwlock);
1055 }
1056
1057 static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
1058 {
1059         return pthread_rwlock_wrlock(prwlock);
1060 }
1061
1062 static inline int ast_rwlock_trywrlock(ast_rwlock_t *prwlock)
1063 {
1064         return pthread_rwlock_trywrlock(prwlock);
1065 }
1066 #endif /* !DEBUG_THREADS */
1067
1068 /* Statically declared read/write locks */
1069
1070 #ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
1071 #define __AST_RWLOCK_DEFINE(scope, rwlock)                      \
1072         scope ast_rwlock_t rwlock;                              \
1073 static void  __attribute__ ((constructor)) init_##rwlock(void)  \
1074 {                                                               \
1075         ast_rwlock_init(&rwlock);                               \
1076 }                                                               \
1077                                                                 \
1078 static void  __attribute__ ((destructor)) fini_##rwlock(void)   \
1079 {                                                               \
1080         ast_rwlock_destroy(&rwlock);                            \
1081 }
1082 #else
1083 #define __AST_RWLOCK_DEFINE(scope, rwlock)      scope ast_rwlock_t rwlock = AST_RWLOCK_INIT_VALUE
1084 #endif
1085
1086 #define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock)
1087
1088 /*
1089  * Support for atomic instructions.
1090  * For platforms that have it, use the native cpu instruction to
1091  * implement them. For other platforms, resort to a 'slow' version
1092  * (defined in utils.c) that protects the atomic instruction with
1093  * a single lock.
1094  * The slow versions is always available, for testing purposes,
1095  * as ast_atomic_fetchadd_int_slow()
1096  */
1097
1098 int ast_atomic_fetchadd_int_slow(volatile int *p, int v);
1099
1100 #include "asterisk/inline_api.h"
1101
1102 #if defined(HAVE_OSX_ATOMICS)
1103 #include "libkern/OSAtomic.h"
1104 #endif
1105
1106 /*! \brief Atomically add v to *p and return * the previous value of *p.
1107  * This can be used to handle reference counts, and the return value
1108  * can be used to generate unique identifiers.
1109  */
1110
1111 #if defined(HAVE_GCC_ATOMICS)
1112 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1113 {
1114         return __sync_fetch_and_add(p, v);
1115 })
1116 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
1117 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1118 {
1119         return OSAtomicAdd32(v, (int32_t *) p) - v;
1120 })
1121 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
1122 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1123 {
1124         return OSAtomicAdd64(v, (int64_t *) p) - v;
1125 #elif defined (__i386__) || defined(__x86_64__)
1126 #ifdef sun
1127 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1128 {
1129         __asm __volatile (
1130         "       lock;  xaddl   %0, %1 ;        "
1131         : "+r" (v),                     /* 0 (result) */   
1132           "=m" (*p)                     /* 1 */
1133         : "m" (*p));                    /* 2 */
1134         return (v);
1135 })
1136 #else /* ifndef sun */
1137 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1138 {
1139         __asm __volatile (
1140         "       lock   xaddl   %0, %1 ;        "
1141         : "+r" (v),                     /* 0 (result) */   
1142           "=m" (*p)                     /* 1 */
1143         : "m" (*p));                    /* 2 */
1144         return (v);
1145 })
1146 #endif
1147 #else   /* low performance version in utils.c */
1148 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1149 {
1150         return ast_atomic_fetchadd_int_slow(p, v);
1151 })
1152 #endif
1153
1154 /*! \brief decrement *p by 1 and return true if the variable has reached 0.
1155  * Useful e.g. to check if a refcount has reached 0.
1156  */
1157 #if defined(HAVE_GCC_ATOMICS)
1158 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
1159 {
1160         return __sync_sub_and_fetch(p, 1) == 0;
1161 })
1162 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
1163 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
1164 {
1165         return OSAtomicAdd32( -1, (int32_t *) p) == 0;
1166 })
1167 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
1168 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
1169 {
1170         return OSAtomicAdd64( -1, (int64_t *) p) == 0;
1171 #else
1172 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
1173 {
1174         int a = ast_atomic_fetchadd_int(p, -1);
1175         return a == 1; /* true if the value is 0 now (so it was 1 previously) */
1176 })
1177 #endif
1178
1179 #ifndef DEBUG_CHANNEL_LOCKS
1180 /*! \brief Lock a channel. If DEBUG_CHANNEL_LOCKS is defined 
1181         in the Makefile, print relevant output for debugging */
1182 #define ast_channel_lock(x)             ast_mutex_lock(&x->lock_dont_use)
1183 /*! \brief Unlock a channel. If DEBUG_CHANNEL_LOCKS is defined 
1184         in the Makefile, print relevant output for debugging */
1185 #define ast_channel_unlock(x)           ast_mutex_unlock(&x->lock_dont_use)
1186 /*! \brief Try locking a channel. If DEBUG_CHANNEL_LOCKS is defined 
1187         in the Makefile, print relevant output for debugging */
1188 #define ast_channel_trylock(x)          ast_mutex_trylock(&x->lock_dont_use)
1189 #else
1190
1191 /*! \brief Lock AST channel (and print debugging output)
1192 \note You need to enable DEBUG_CHANNEL_LOCKS for this function */
1193 int ast_channel_lock(struct ast_channel *chan);
1194
1195 /*! \brief Unlock AST channel (and print debugging output)
1196 \note You need to enable DEBUG_CHANNEL_LOCKS for this function
1197 */
1198 int ast_channel_unlock(struct ast_channel *chan);
1199
1200 /*! \brief Lock AST channel (and print debugging output)
1201 \note   You need to enable DEBUG_CHANNEL_LOCKS for this function */
1202 int ast_channel_trylock(struct ast_channel *chan);
1203 #endif
1204
1205 #endif /* _ASTERISK_LOCK_H */