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