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