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