Merged revisions 88931 via svnmerge from
[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         pthread_mutexattr_init(&attr);
679         pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
680
681         res = pthread_mutex_init(pmutex, &attr);
682         pthread_mutexattr_destroy(&attr);
683         return res;
684 }
685
686 #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
687
688 static inline int ast_mutex_unlock(ast_mutex_t *pmutex)
689 {
690         return pthread_mutex_unlock(pmutex);
691 }
692
693 static inline int ast_mutex_destroy(ast_mutex_t *pmutex)
694 {
695         return pthread_mutex_destroy(pmutex);
696 }
697
698 static inline int ast_mutex_lock(ast_mutex_t *pmutex)
699 {
700         __MTX_PROF(pmutex);
701 }
702
703 static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
704 {
705         return pthread_mutex_trylock(pmutex);
706 }
707
708 typedef pthread_cond_t ast_cond_t;
709
710 static inline int ast_cond_init(ast_cond_t *cond, pthread_condattr_t *cond_attr)
711 {
712         return pthread_cond_init(cond, cond_attr);
713 }
714
715 static inline int ast_cond_signal(ast_cond_t *cond)
716 {
717         return pthread_cond_signal(cond);
718 }
719
720 static inline int ast_cond_broadcast(ast_cond_t *cond)
721 {
722         return pthread_cond_broadcast(cond);
723 }
724
725 static inline int ast_cond_destroy(ast_cond_t *cond)
726 {
727         return pthread_cond_destroy(cond);
728 }
729
730 static inline int ast_cond_wait(ast_cond_t *cond, ast_mutex_t *t)
731 {
732         return pthread_cond_wait(cond, t);
733 }
734
735 static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime)
736 {
737         return pthread_cond_timedwait(cond, t, abstime);
738 }
739
740 #endif /* !DEBUG_THREADS */
741
742 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
743 /* If AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
744  destructors to destroy mutexes and create it on the fly.  */
745 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track) \
746         scope ast_mutex_t mutex = init_val; \
747 static void  __attribute__ ((constructor)) init_##mutex(void) \
748 { \
749         if (track) \
750                 ast_mutex_init(&mutex); \
751         else \
752                 ast_mutex_init_notracking(&mutex); \
753 } \
754 static void  __attribute__ ((destructor)) fini_##mutex(void) \
755 { \
756         ast_mutex_destroy(&mutex); \
757 }
758 #else /* !AST_MUTEX_INIT_W_CONSTRUCTORS */
759 /* By default, use static initialization of mutexes. */ 
760 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track) \
761         scope ast_mutex_t mutex = init_val
762 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
763
764 #define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
765 #define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
766 #define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
767 #define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
768 #define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init
769 #define pthread_mutex_destroy use_ast_mutex_destroy_instead_of_pthread_mutex_destroy
770 #define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t
771 #define pthread_cond_init use_ast_cond_init_instead_of_pthread_cond_init
772 #define pthread_cond_destroy use_ast_cond_destroy_instead_of_pthread_cond_destroy
773 #define pthread_cond_signal use_ast_cond_signal_instead_of_pthread_cond_signal
774 #define pthread_cond_broadcast use_ast_cond_broadcast_instead_of_pthread_cond_broadcast
775 #define pthread_cond_wait use_ast_cond_wait_instead_of_pthread_cond_wait
776 #define pthread_cond_timedwait use_ast_cond_timedwait_instead_of_pthread_cond_timedwait
777
778 #define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE, 1)
779 #define AST_MUTEX_DEFINE_STATIC_NOTRACKING(mutex) __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE_NOTRACKING, 0)
780
781 #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
782
783 #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
784
785 #ifndef __linux__
786 #define pthread_create __use_ast_pthread_create_instead__
787 #endif
788
789 typedef pthread_rwlock_t ast_rwlock_t;
790
791 #ifdef HAVE_PTHREAD_RWLOCK_INITIALIZER
792 #define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
793 #else
794 #define AST_RWLOCK_INIT_VALUE NULL
795 #endif
796
797 #ifdef DEBUG_THREADS
798
799 #define ast_rwlock_init(rwlock) __ast_rwlock_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)
800
801
802 static inline int __ast_rwlock_init(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *prwlock)
803 {
804         int res;
805         pthread_rwlockattr_t attr;
806 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
807         int canlog = strcmp(filename, "logger.c");
808
809         if (*prwlock != ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
810                 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
811                                 filename, lineno, func, rwlock_name);
812                 return 0;
813         }
814 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
815         pthread_rwlockattr_init(&attr);
816
817 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
818         pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
819 #endif
820
821         res = pthread_rwlock_init(prwlock, &attr);
822         pthread_rwlockattr_destroy(&attr);
823         return res;
824 }
825
826 #define ast_rwlock_destroy(rwlock) __ast_rwlock_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)
827
828 static inline int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *prwlock)
829 {
830         int res;
831         int canlog = strcmp(filename, "logger.c");
832
833 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
834         if (*prwlock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
835                 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
836                                    filename, lineno, func, rwlock_name);
837                 return 0;
838         }
839 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
840         
841         if ((res = pthread_rwlock_destroy(prwlock)))
842                 __ast_mutex_logger("%s line %d (%s): Error destroying rwlock %s: %s\n",
843                                 filename, lineno, func, rwlock_name, strerror(res));
844
845         return res;
846 }
847
848 #define ast_rwlock_unlock(a) \
849         _ast_rwlock_unlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
850
851 static inline int _ast_rwlock_unlock(ast_rwlock_t *lock, const char *name,
852         const char *file, int line, const char *func)
853 {
854         int res;
855 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
856         int canlog = strcmp(file, "logger.c");
857
858         if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
859                 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
860                                    file, line, func, name);
861                 res = __ast_rwlock_init(file, line, func, name, lock);
862                 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
863                         __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
864                                         file, line, func, name);
865                 }
866                 return res;
867         }
868 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
869         
870         res = pthread_rwlock_unlock(lock);
871         ast_remove_lock_info(lock);
872         return res;
873 }
874
875 #define ast_rwlock_rdlock(a) \
876         _ast_rwlock_rdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
877
878 static inline int _ast_rwlock_rdlock(ast_rwlock_t *lock, const char *name,
879         const char *file, int line, const char *func)
880 {
881         int res;
882 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
883         int canlog = strcmp(file, "logger.c");
884         
885         if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
886                  /* Don't warn abount uninitialized lock.
887                   * Simple try to initialize it.
888                   * May be not needed in linux system.
889                   */
890                 res = __ast_rwlock_init(file, line, func, name, lock);
891                 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
892                         __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
893                                         file, line, func, name);
894                         return res;
895                 }
896         }
897 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
898         
899         ast_store_lock_info(AST_RDLOCK, file, line, func, name, lock);
900         res = pthread_rwlock_rdlock(lock);
901         if (!res)
902                 ast_mark_lock_acquired();
903         else
904                 ast_remove_lock_info(lock);
905         return res;
906 }
907
908 #define ast_rwlock_wrlock(a) \
909         _ast_rwlock_wrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
910
911 static inline int _ast_rwlock_wrlock(ast_rwlock_t *lock, const char *name,
912         const char *file, int line, const char *func)
913 {
914         int res;
915 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
916         int canlog = strcmp(file, "logger.c");
917         
918         if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
919                  /* Don't warn abount uninitialized lock.
920                   * Simple try to initialize it.
921                   * May be not needed in linux system.
922                   */
923                 res = __ast_rwlock_init(file, line, func, name, lock);
924                 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
925                         __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
926                                         file, line, func, name);
927                         return res;
928                 }
929         }
930 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
931
932         ast_store_lock_info(AST_WRLOCK, file, line, func, name, lock);
933         res = pthread_rwlock_wrlock(lock);
934         if (!res)
935                 ast_mark_lock_acquired();
936         else
937                 ast_remove_lock_info(lock);
938         return res;
939 }
940
941 #define ast_rwlock_tryrdlock(a) \
942         _ast_rwlock_tryrdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
943
944 static inline int _ast_rwlock_tryrdlock(ast_rwlock_t *lock, const char *name,
945         const char *file, int line, const char *func)
946 {
947         int res;
948 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
949         int canlog = strcmp(file, "logger.c");
950         
951         if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
952                  /* Don't warn abount uninitialized lock.
953                   * Simple try to initialize it.
954                   * May be not needed in linux system.
955                   */
956                 res = __ast_rwlock_init(file, line, func, name, lock);
957                 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
958                         __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
959                                         file, line, func, name);
960                         return res;
961                 }
962         }
963 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
964
965         ast_store_lock_info(AST_RDLOCK, file, line, func, name, lock);
966         res = pthread_rwlock_tryrdlock(lock);
967         if (!res)
968                 ast_mark_lock_acquired();
969         else
970                 ast_remove_lock_info(lock);
971         return res;
972 }
973
974 #define ast_rwlock_trywrlock(a) \
975         _ast_rwlock_trywrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
976
977 static inline int _ast_rwlock_trywrlock(ast_rwlock_t *lock, const char *name,
978         const char *file, int line, const char *func)
979 {
980         int res;
981 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
982         int canlog = strcmp(file, "logger.c");
983         
984         if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
985                  /* Don't warn abount uninitialized lock.
986                   * Simple try to initialize it.
987                   * May be not needed in linux system.
988                   */
989                 res = __ast_rwlock_init(file, line, func, name, lock);
990                 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
991                         __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
992                                         file, line, func, name);
993                         return res;
994                 }
995         }
996 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
997
998         ast_store_lock_info(AST_WRLOCK, file, line, func, name, lock);
999         res = pthread_rwlock_trywrlock(lock);
1000         if (!res)
1001                 ast_mark_lock_acquired();
1002         else
1003                 ast_remove_lock_info(lock);
1004         return res;
1005 }
1006
1007 #else /* !DEBUG_THREADS */
1008
1009 static inline int ast_rwlock_init(ast_rwlock_t *prwlock)
1010 {
1011         int res;
1012         pthread_rwlockattr_t attr;
1013
1014         pthread_rwlockattr_init(&attr);
1015
1016 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
1017         pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
1018 #endif
1019
1020         res = pthread_rwlock_init(prwlock, &attr);
1021         pthread_rwlockattr_destroy(&attr);
1022         return res;
1023 }
1024
1025 static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
1026 {
1027         return pthread_rwlock_destroy(prwlock);
1028 }
1029
1030 static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
1031 {
1032         return pthread_rwlock_unlock(prwlock);
1033 }
1034
1035 static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
1036 {
1037         return pthread_rwlock_rdlock(prwlock);
1038 }
1039
1040 static inline int ast_rwlock_tryrdlock(ast_rwlock_t *prwlock)
1041 {
1042         return pthread_rwlock_tryrdlock(prwlock);
1043 }
1044
1045 static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
1046 {
1047         return pthread_rwlock_wrlock(prwlock);
1048 }
1049
1050 static inline int ast_rwlock_trywrlock(ast_rwlock_t *prwlock)
1051 {
1052         return pthread_rwlock_trywrlock(prwlock);
1053 }
1054 #endif /* !DEBUG_THREADS */
1055
1056 /* Statically declared read/write locks */
1057
1058 #ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
1059 #define __AST_RWLOCK_DEFINE(scope, rwlock) \
1060         scope ast_rwlock_t rwlock; \
1061 static void  __attribute__ ((constructor)) init_##rwlock(void) \
1062 { \
1063         ast_rwlock_init(&rwlock); \
1064 } \
1065 static void  __attribute__ ((destructor)) fini_##rwlock(void) \
1066 { \
1067         ast_rwlock_destroy(&rwlock); \
1068 }
1069 #else
1070 #define __AST_RWLOCK_DEFINE(scope, rwlock) \
1071         scope ast_rwlock_t rwlock = AST_RWLOCK_INIT_VALUE
1072 #endif
1073
1074 #define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock)
1075
1076 /*
1077  * Initial support for atomic instructions.
1078  * For platforms that have it, use the native cpu instruction to
1079  * implement them. For other platforms, resort to a 'slow' version
1080  * (defined in utils.c) that protects the atomic instruction with
1081  * a single lock.
1082  * The slow versions is always available, for testing purposes,
1083  * as ast_atomic_fetchadd_int_slow()
1084  */
1085
1086 int ast_atomic_fetchadd_int_slow(volatile int *p, int v);
1087
1088 #include "asterisk/inline_api.h"
1089
1090 #if defined(HAVE_OSX_ATOMICS)
1091 #include "libkern/OSAtomic.h"
1092 #endif
1093
1094 /*! \brief Atomically add v to *p and return * the previous value of *p.
1095  * This can be used to handle reference counts, and the return value
1096  * can be used to generate unique identifiers.
1097  */
1098
1099 #if defined(HAVE_GCC_ATOMICS)
1100 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1101 {
1102         return __sync_fetch_and_add(p, v);
1103 })
1104 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
1105 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1106 {
1107         return OSAtomicAdd32(v, (int32_t *) p);
1108 })
1109 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
1110 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1111 {
1112         return OSAtomicAdd64(v, (int64_t *) p);
1113 #elif defined (__i386__) || defined(__x86_64__)
1114 #ifdef sun
1115 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1116 {
1117         __asm __volatile (
1118         "       lock;  xaddl   %0, %1 ;        "
1119         : "+r" (v),                     /* 0 (result) */   
1120           "=m" (*p)                     /* 1 */
1121         : "m" (*p));                    /* 2 */
1122         return (v);
1123 })
1124 #else /* ifndef sun */
1125 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1126 {
1127         __asm __volatile (
1128         "       lock   xaddl   %0, %1 ;        "
1129         : "+r" (v),                     /* 0 (result) */   
1130           "=m" (*p)                     /* 1 */
1131         : "m" (*p));                    /* 2 */
1132         return (v);
1133 })
1134 #endif
1135 #else   /* low performance version in utils.c */
1136 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1137 {
1138         return ast_atomic_fetchadd_int_slow(p, v);
1139 })
1140 #endif
1141
1142 /*! \brief decrement *p by 1 and return true if the variable has reached 0.
1143  * Useful e.g. to check if a refcount has reached 0.
1144  */
1145 #if defined(HAVE_GCC_ATOMICS)
1146 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
1147 {
1148         return __sync_sub_and_fetch(p, 1) == 0;
1149 })
1150 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
1151 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
1152 {
1153         return OSAtomicAdd32( -1, (int32_t *) p) == 0;
1154 })
1155 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
1156 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
1157 {
1158         return OSAtomicAdd64( -1, (int64_t *) p) == 0;
1159 #else
1160 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
1161 {
1162         int a = ast_atomic_fetchadd_int(p, -1);
1163         return a == 1; /* true if the value is 0 now (so it was 1 previously) */
1164 })
1165 #endif
1166
1167 #ifndef DEBUG_CHANNEL_LOCKS
1168 /*! \brief Lock a channel. If DEBUG_CHANNEL_LOCKS is defined 
1169         in the Makefile, print relevant output for debugging */
1170 #define ast_channel_lock(x)             ast_mutex_lock(&x->lock)
1171 /*! \brief Unlock a channel. If DEBUG_CHANNEL_LOCKS is defined 
1172         in the Makefile, print relevant output for debugging */
1173 #define ast_channel_unlock(x)           ast_mutex_unlock(&x->lock)
1174 /*! \brief Try locking a channel. If DEBUG_CHANNEL_LOCKS is defined 
1175         in the Makefile, print relevant output for debugging */
1176 #define ast_channel_trylock(x)          ast_mutex_trylock(&x->lock)
1177 #else
1178
1179 struct ast_channel;
1180
1181 /*! \brief Lock AST channel (and print debugging output)
1182 \note You need to enable DEBUG_CHANNEL_LOCKS for this function */
1183 int ast_channel_lock(struct ast_channel *chan);
1184
1185 /*! \brief Unlock AST channel (and print debugging output)
1186 \note You need to enable DEBUG_CHANNEL_LOCKS for this function
1187 */
1188 int ast_channel_unlock(struct ast_channel *chan);
1189
1190 /*! \brief Lock AST channel (and print debugging output)
1191 \note   You need to enable DEBUG_CHANNEL_LOCKS for this function */
1192 int ast_channel_trylock(struct ast_channel *chan);
1193 #endif
1194
1195 #endif /* _ASTERISK_LOCK_H */