use atomic operations provided by the compiler if they are available (yay for gcc...
[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 several different implementation of the functions,
28  * depending on the platform, the use of DEBUG_THREADS, and the way
29  * global mutexes are initialized.
30  *
31  * \par At the moment, we have 3 ways to initialize global mutexes, depending on
32  *
33  *  - \b static: the mutex is assigned the value AST_MUTEX_INIT_VALUE
34  *        this is done at compile time, and is the way used on Linux.
35  *        This method is not applicable to all platforms e.g. when the
36  *        initialization needs that some code is run.
37  *
38  *  - \b on first use: the mutex is assigned a magic value at compile time,
39  *        and ast_mutex_init() is called when this magic value is detected.
40  *        This technique is generally applicable, though it has a bit of
41  *        overhead on each access to check whether initialization is needed.
42  *        On the other hand, the overall cost of a mutex_lock operation
43  *        is such that this overhead is often negligible.
44
45  *  - \b through constructors: for each mutex, a constructor function is
46  *        defined, which then runs when the program (or the module)
47  *        starts. The problem with this approach is that there is a
48  *        lot of code duplication (a new block of code is created for
49  *        each mutex). Also, it does not prevent a user from declaring
50  *        a global mutex without going through the wrapper macros,
51  *        so sane programming practices are still required.
52  *
53  * Eventually we should converge on a single method for all platforms.
54  */
55
56 #ifndef _ASTERISK_LOCK_H
57 #define _ASTERISK_LOCK_H
58
59 /* internal macro to profile mutexes. Only computes the delay on
60  * non-blocking calls.
61  */
62 #ifndef HAVE_MTX_PROFILE
63 #define __MTX_PROF(a)   return pthread_mutex_lock((a))
64 #else
65 #define __MTX_PROF(a)   do {                    \
66         int i;                                  \
67         /* profile only non-blocking events */  \
68         ast_mark(mtx_prof, 1);                  \
69         i = pthread_mutex_trylock((a));         \
70         ast_mark(mtx_prof, 0);                  \
71         if (!i)                                 \
72                 return i;                       \
73         else                                    \
74                 return pthread_mutex_lock((a)); \
75         } while (0)
76 #endif  /* HAVE_MTX_PROFILE */
77
78 #include <pthread.h>
79 #include <netdb.h>
80 #include <time.h>
81 #include <sys/param.h>
82
83 #include "asterisk/logger.h"
84
85 #define AST_PTHREADT_NULL (pthread_t) -1
86 #define AST_PTHREADT_STOP (pthread_t) -2
87
88 #ifdef __APPLE__
89 /* Provide the Linux initializers for MacOS X */
90 #define PTHREAD_MUTEX_RECURSIVE_NP                      PTHREAD_MUTEX_RECURSIVE
91 #define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP          { 0x4d555458, \
92                                                         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
93                                                         0x20 } }
94 #endif
95
96 #ifdef BSD
97 #if 1 && defined( __GNUC__)
98 #define AST_MUTEX_INIT_W_CONSTRUCTORS
99 #else
100 #define AST_MUTEX_INIT_ON_FIRST_USE
101 #endif
102 #endif /* BSD */
103
104 /* From now on, Asterisk REQUIRES Recursive (not error checking) mutexes
105    and will not run without them. */
106 #if defined(__CYGWIN__)
107 #define PTHREAD_MUTEX_RECURSIVE_NP      PTHREAD_MUTEX_RECURSIVE
108 #define PTHREAD_MUTEX_INIT_VALUE        (ast_mutex_t)18
109 #define AST_MUTEX_KIND                  PTHREAD_MUTEX_RECURSIVE_NP
110 #elif defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
111 #define PTHREAD_MUTEX_INIT_VALUE        PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
112 #define AST_MUTEX_KIND                  PTHREAD_MUTEX_RECURSIVE_NP
113 #else
114 #define PTHREAD_MUTEX_INIT_VALUE        PTHREAD_MUTEX_INITIALIZER
115 #define AST_MUTEX_KIND                  PTHREAD_MUTEX_RECURSIVE
116 #endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
117
118 #ifdef SOLARIS
119 #define AST_MUTEX_INIT_W_CONSTRUCTORS
120 #endif
121
122 #ifdef DEBUG_THREADS
123
124 #define __ast_mutex_logger(...)  do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0)
125
126 #ifdef THREAD_CRASH
127 #define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
128 #endif
129
130 #include <errno.h>
131 #include <string.h>
132 #include <stdio.h>
133 #include <unistd.h>
134
135 #define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, { NULL }, { 0 }, 0, { NULL }, { 0 } }
136
137 #define AST_MAX_REENTRANCY 10
138
139 struct ast_mutex_info {
140         pthread_mutex_t mutex;
141         const char *file[AST_MAX_REENTRANCY];
142         int lineno[AST_MAX_REENTRANCY];
143         int reentrancy;
144         const char *func[AST_MAX_REENTRANCY];
145         pthread_t thread[AST_MAX_REENTRANCY];
146 };
147
148 typedef struct ast_mutex_info ast_mutex_t;
149
150 typedef pthread_cond_t ast_cond_t;
151
152 static pthread_mutex_t empty_mutex;
153
154 static void __attribute__((constructor)) init_empty_mutex(void)
155 {
156         memset(&empty_mutex, 0, sizeof(empty_mutex));
157 }
158
159 static inline int __ast_pthread_mutex_init_attr(const char *filename, int lineno, const char *func,
160                                                 const char *mutex_name, ast_mutex_t *t,
161                                                 pthread_mutexattr_t *attr) 
162 {
163 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
164         int canlog = strcmp(filename, "logger.c");
165
166         if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
167                 if ((t->mutex) != (empty_mutex)) {
168                         __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is already initialized.\n",
169                                            filename, lineno, func, mutex_name);
170                         __ast_mutex_logger("%s line %d (%s): Error: previously initialization of mutex '%s'.\n",
171                                            t->file[0], t->lineno[0], t->func[0], mutex_name);
172 #ifdef THREAD_CRASH
173                         DO_THREAD_CRASH;
174 #endif
175                         return 0;
176                 }
177         }
178 #endif
179
180         t->file[0] = filename;
181         t->lineno[0] = lineno;
182         t->func[0] = func;
183         t->thread[0]  = 0;
184         t->reentrancy = 0;
185
186         return pthread_mutex_init(&t->mutex, attr);
187 }
188
189 static inline int __ast_pthread_mutex_init(const char *filename, int lineno, const char *func,
190                                            const char *mutex_name, ast_mutex_t *t)
191 {
192         static pthread_mutexattr_t  attr;
193
194         pthread_mutexattr_init(&attr);
195         pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
196
197         return __ast_pthread_mutex_init_attr(filename, lineno, func, mutex_name, t, &attr);
198 }
199 #define ast_mutex_init(pmutex) __ast_pthread_mutex_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
200
201 static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
202                                                 const char *mutex_name, ast_mutex_t *t)
203 {
204         int res;
205         int canlog = strcmp(filename, "logger.c");
206
207 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
208         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
209                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
210                                    filename, lineno, func, mutex_name);
211         }
212 #endif
213
214         res = pthread_mutex_trylock(&t->mutex);
215         switch (res) {
216         case 0:
217                 pthread_mutex_unlock(&t->mutex);
218                 break;
219         case EINVAL:
220                 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
221                                   filename, lineno, func, mutex_name);
222                 break;
223         case EBUSY:
224                 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
225                                    filename, lineno, func, mutex_name);
226                 __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
227                                    t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
228                 break;
229         }
230
231         if ((res = pthread_mutex_destroy(&t->mutex)))
232                 __ast_mutex_logger("%s line %d (%s): Error destroying mutex: %s\n",
233                                    filename, lineno, func, strerror(res));
234 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
235         else
236                 t->mutex = PTHREAD_MUTEX_INIT_VALUE;
237 #endif
238         t->file[0] = filename;
239         t->lineno[0] = lineno;
240         t->func[0] = func;
241
242         return res;
243 }
244
245 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
246 /*! \brief  if AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
247  constrictors/destructors to create/destroy mutexes.  */
248 #define __AST_MUTEX_DEFINE(scope,mutex) \
249         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \
250 static void  __attribute__ ((constructor)) init_##mutex(void) \
251 { \
252         ast_mutex_init(&mutex); \
253 } \
254 static void  __attribute__ ((destructor)) fini_##mutex(void) \
255 { \
256         ast_mutex_destroy(&mutex); \
257 }
258 #elif defined(AST_MUTEX_INIT_ON_FIRST_USE)
259 /*! \note
260  if AST_MUTEX_INIT_ON_FIRST_USE is defined, mutexes are created on
261  first use.  The performance impact on FreeBSD should be small since
262  the pthreads library does this itself to initialize errror checking
263  (defaulty type) mutexes.  If nither is defined, the pthreads librariy
264  does the initialization itself on first use. 
265 */ 
266 #define __AST_MUTEX_DEFINE(scope,mutex) \
267         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
268 #else /* AST_MUTEX_INIT_W_CONSTRUCTORS */
269 /* By default, use static initialization of mutexes.*/ 
270 #define __AST_MUTEX_DEFINE(scope,mutex) \
271         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
272 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
273
274 static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
275                                            const char* mutex_name, ast_mutex_t *t)
276 {
277         int res;
278         int canlog = strcmp(filename, "logger.c");
279
280 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE)
281         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
282 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
283                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
284                                  filename, lineno, func, mutex_name);
285 #endif
286                 ast_mutex_init(t);
287         }
288 #endif /* defined(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE) */
289
290 #ifdef DETECT_DEADLOCKS
291         {
292                 time_t seconds = time(NULL);
293                 time_t current;
294                 do {
295 #ifdef  HAVE_MTX_PROFILE
296                         ast_mark(mtx_prof, 1);
297 #endif
298                         res = pthread_mutex_trylock(&t->mutex);
299 #ifdef  HAVE_MTX_PROFILE
300                         ast_mark(mtx_prof, 0);
301 #endif
302                         if (res == EBUSY) {
303                                 current = time(NULL);
304                                 if ((current - seconds) && (!((current - seconds) % 5))) {
305                                         __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
306                                                            filename, lineno, func, (int)(current - seconds), mutex_name);
307                                         __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
308                                                            t->file[t->reentrancy-1], t->lineno[t->reentrancy-1],
309                                                            t->func[t->reentrancy-1], mutex_name);
310                                 }
311                                 usleep(200);
312                         }
313                 } while (res == EBUSY);
314         }
315 #else
316 #ifdef  HAVE_MTX_PROFILE
317         ast_mark(mtx_prof, 1);
318         res = pthread_mutex_trylock(&t->mutex);
319         ast_mark(mtx_prof, 0);
320         if (res)
321 #endif
322         res = pthread_mutex_lock(&t->mutex);
323 #endif /* DETECT_DEADLOCKS */
324
325         if (!res) {
326                 if (t->reentrancy < AST_MAX_REENTRANCY) {
327                         t->file[t->reentrancy] = filename;
328                         t->lineno[t->reentrancy] = lineno;
329                         t->func[t->reentrancy] = func;
330                         t->thread[t->reentrancy] = pthread_self();
331                         t->reentrancy++;
332                 } else {
333                         __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
334                                                            filename, lineno, func, mutex_name);
335                 }
336         } else {
337                 __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
338                                    filename, lineno, func, strerror(errno));
339 #ifdef THREAD_CRASH
340                 DO_THREAD_CRASH;
341 #endif
342         }
343
344         return res;
345 }
346
347 static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
348                                               const char* mutex_name, ast_mutex_t *t)
349 {
350         int res;
351         int canlog = strcmp(filename, "logger.c");
352
353 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE)
354         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
355 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
356
357                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
358                                    filename, lineno, func, mutex_name);
359 #endif
360                 ast_mutex_init(t);
361         }
362 #endif /* defined(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE) */
363
364         if (!(res = pthread_mutex_trylock(&t->mutex))) {
365                 if (t->reentrancy < AST_MAX_REENTRANCY) {
366                         t->file[t->reentrancy] = filename;
367                         t->lineno[t->reentrancy] = lineno;
368                         t->func[t->reentrancy] = func;
369                         t->thread[t->reentrancy] = pthread_self();
370                         t->reentrancy++;
371                 } else {
372                         __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
373                                                            filename, lineno, func, mutex_name);
374                 }
375         }
376
377         return res;
378 }
379
380 static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
381                                              const char *mutex_name, ast_mutex_t *t)
382 {
383         int res;
384         int canlog = strcmp(filename, "logger.c");
385
386 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
387         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
388                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
389                                    filename, lineno, func, mutex_name);
390         }
391 #endif
392
393         if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
394                 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
395                                    filename, lineno, func, mutex_name);
396                 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
397                                    t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
398 #ifdef THREAD_CRASH
399                 DO_THREAD_CRASH;
400 #endif
401         }
402
403         if (--t->reentrancy < 0) {
404                 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
405                                    filename, lineno, func, mutex_name);
406                 t->reentrancy = 0;
407         }
408
409         if (t->reentrancy < AST_MAX_REENTRANCY) {
410                 t->file[t->reentrancy] = NULL;
411                 t->lineno[t->reentrancy] = 0;
412                 t->func[t->reentrancy] = NULL;
413                 t->thread[t->reentrancy] = 0;
414         }
415
416         if ((res = pthread_mutex_unlock(&t->mutex))) {
417                 __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n", 
418                                    filename, lineno, func, strerror(res));
419 #ifdef THREAD_CRASH
420                 DO_THREAD_CRASH;
421 #endif
422         }
423
424         return res;
425 }
426
427 static inline int __ast_cond_init(const char *filename, int lineno, const char *func,
428                                   const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
429 {
430         return pthread_cond_init(cond, cond_attr);
431 }
432
433 static inline int __ast_cond_signal(const char *filename, int lineno, const char *func,
434                                     const char *cond_name, ast_cond_t *cond)
435 {
436         return pthread_cond_signal(cond);
437 }
438
439 static inline int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
440                                        const char *cond_name, ast_cond_t *cond)
441 {
442         return pthread_cond_broadcast(cond);
443 }
444
445 static inline int __ast_cond_destroy(const char *filename, int lineno, const char *func,
446                                      const char *cond_name, ast_cond_t *cond)
447 {
448         return pthread_cond_destroy(cond);
449 }
450
451 static inline int __ast_cond_wait(const char *filename, int lineno, const char *func,
452                                   const char *cond_name, const char *mutex_name,
453                                   ast_cond_t *cond, ast_mutex_t *t)
454 {
455         int res;
456         int canlog = strcmp(filename, "logger.c");
457
458 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
459         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
460                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
461                                    filename, lineno, func, mutex_name);
462         }
463 #endif
464
465         if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
466                 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
467                                    filename, lineno, func, mutex_name);
468                 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
469                                    t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
470 #ifdef THREAD_CRASH
471                 DO_THREAD_CRASH;
472 #endif
473         }
474
475         if (--t->reentrancy < 0) {
476                 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
477                                    filename, lineno, func, mutex_name);
478                 t->reentrancy = 0;
479         }
480
481         if (t->reentrancy < AST_MAX_REENTRANCY) {
482                 t->file[t->reentrancy] = NULL;
483                 t->lineno[t->reentrancy] = 0;
484                 t->func[t->reentrancy] = NULL;
485                 t->thread[t->reentrancy] = 0;
486         }
487
488         if ((res = pthread_cond_wait(cond, &t->mutex))) {
489                 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n", 
490                                    filename, lineno, func, strerror(res));
491 #ifdef THREAD_CRASH
492                 DO_THREAD_CRASH;
493 #endif
494         } else {
495                 if (t->reentrancy < AST_MAX_REENTRANCY) {
496                         t->file[t->reentrancy] = filename;
497                         t->lineno[t->reentrancy] = lineno;
498                         t->func[t->reentrancy] = func;
499                         t->thread[t->reentrancy] = pthread_self();
500                         t->reentrancy++;
501                 } else {
502                         __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
503                                                            filename, lineno, func, mutex_name);
504                 }
505         }
506
507         return res;
508 }
509
510 static inline int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
511                                        const char *cond_name, const char *mutex_name, ast_cond_t *cond,
512                                        ast_mutex_t *t, const struct timespec *abstime)
513 {
514         int res;
515         int canlog = strcmp(filename, "logger.c");
516
517 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
518         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
519                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
520                                    filename, lineno, func, mutex_name);
521         }
522 #endif
523
524         if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
525                 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
526                                    filename, lineno, func, mutex_name);
527                 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
528                                    t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
529 #ifdef THREAD_CRASH
530                 DO_THREAD_CRASH;
531 #endif
532         }
533
534         if (--t->reentrancy < 0) {
535                 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
536                                    filename, lineno, func, mutex_name);
537                 t->reentrancy = 0;
538         }
539
540         if (t->reentrancy < AST_MAX_REENTRANCY) {
541                 t->file[t->reentrancy] = NULL;
542                 t->lineno[t->reentrancy] = 0;
543                 t->func[t->reentrancy] = NULL;
544                 t->thread[t->reentrancy] = 0;
545         }
546
547         if ((res = pthread_cond_timedwait(cond, &t->mutex, abstime)) && (res != ETIMEDOUT)) {
548                 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n", 
549                                    filename, lineno, func, strerror(res));
550 #ifdef THREAD_CRASH
551                 DO_THREAD_CRASH;
552 #endif
553         } else {
554                 if (t->reentrancy < AST_MAX_REENTRANCY) {
555                         t->file[t->reentrancy] = filename;
556                         t->lineno[t->reentrancy] = lineno;
557                         t->func[t->reentrancy] = func;
558                         t->thread[t->reentrancy] = pthread_self();
559                         t->reentrancy++;
560                 } else {
561                         __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
562                                                            filename, lineno, func, mutex_name);
563                 }
564         }
565
566         return res;
567 }
568
569 #define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
570 #define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
571 #define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
572 #define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
573 #define ast_cond_init(cond, attr) __ast_cond_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond, attr)
574 #define ast_cond_destroy(cond) __ast_cond_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
575 #define ast_cond_signal(cond) __ast_cond_signal(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
576 #define ast_cond_broadcast(cond) __ast_cond_broadcast(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
577 #define ast_cond_wait(cond, mutex) __ast_cond_wait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex)
578 #define ast_cond_timedwait(cond, mutex, time) __ast_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex, time)
579
580 #else /* !DEBUG_THREADS */
581
582
583
584 typedef pthread_mutex_t ast_mutex_t;
585
586 #define AST_MUTEX_INIT_VALUE    ((ast_mutex_t)PTHREAD_MUTEX_INIT_VALUE)
587
588 static inline int ast_mutex_init(ast_mutex_t *pmutex)
589 {
590         pthread_mutexattr_t attr;
591         pthread_mutexattr_init(&attr);
592         pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
593         return pthread_mutex_init(pmutex, &attr);
594 }
595
596 #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
597
598 static inline int ast_mutex_unlock(ast_mutex_t *pmutex)
599 {
600         return pthread_mutex_unlock(pmutex);
601 }
602
603 static inline int ast_mutex_destroy(ast_mutex_t *pmutex)
604 {
605         return pthread_mutex_destroy(pmutex);
606 }
607
608 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
609 /* if AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
610  constrictors/destructors to create/destroy mutexes.  */ 
611 #define __AST_MUTEX_DEFINE(scope,mutex) \
612         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \
613 static void  __attribute__ ((constructor)) init_##mutex(void) \
614 { \
615         ast_mutex_init(&mutex); \
616 } \
617 static void  __attribute__ ((destructor)) fini_##mutex(void) \
618 { \
619         ast_mutex_destroy(&mutex); \
620 }
621
622 static inline int ast_mutex_lock(ast_mutex_t *pmutex)
623 {
624         __MTX_PROF(pmutex);
625 }
626
627 static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
628 {
629         return pthread_mutex_trylock(pmutex);
630 }
631
632 #elif defined(AST_MUTEX_INIT_ON_FIRST_USE)
633 /* if AST_MUTEX_INIT_ON_FIRST_USE is defined, mutexes are created on
634  first use.  The performance impact on FreeBSD should be small since
635  the pthreads library does this itself to initialize errror checking
636  (defaulty type) mutexes.*/ 
637 #define __AST_MUTEX_DEFINE(scope,mutex) \
638         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
639
640 static inline int ast_mutex_lock(ast_mutex_t *pmutex)
641 {
642         if (*pmutex == (ast_mutex_t)AST_MUTEX_KIND)
643                 ast_mutex_init(pmutex);
644         __MTX_PROF(pmutex);
645 }
646
647 static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
648 {
649         if (*pmutex == (ast_mutex_t)AST_MUTEX_KIND)
650                 ast_mutex_init(pmutex);
651         return pthread_mutex_trylock(pmutex);
652 }
653 #else
654 /* By default, use static initialization of mutexes.*/ 
655 #define __AST_MUTEX_DEFINE(scope,mutex) \
656         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
657
658 static inline int ast_mutex_lock(ast_mutex_t *pmutex)
659 {
660         __MTX_PROF(pmutex);
661 }
662
663 static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
664 {
665         return pthread_mutex_trylock(pmutex);
666 }
667
668 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
669
670 typedef pthread_cond_t ast_cond_t;
671
672 static inline int ast_cond_init(ast_cond_t *cond, pthread_condattr_t *cond_attr)
673 {
674         return pthread_cond_init(cond, cond_attr);
675 }
676
677 static inline int ast_cond_signal(ast_cond_t *cond)
678 {
679         return pthread_cond_signal(cond);
680 }
681
682 static inline int ast_cond_broadcast(ast_cond_t *cond)
683 {
684         return pthread_cond_broadcast(cond);
685 }
686
687 static inline int ast_cond_destroy(ast_cond_t *cond)
688 {
689         return pthread_cond_destroy(cond);
690 }
691
692 static inline int ast_cond_wait(ast_cond_t *cond, ast_mutex_t *t)
693 {
694         return pthread_cond_wait(cond, t);
695 }
696
697 static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime)
698 {
699         return pthread_cond_timedwait(cond, t, abstime);
700 }
701
702 #endif /* !DEBUG_THREADS */
703
704 #define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
705 #define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
706 #define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
707 #define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
708 #define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init
709 #define pthread_mutex_destroy use_ast_mutex_destroy_instead_of_pthread_mutex_destroy
710 #define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t
711 #define pthread_cond_init use_ast_cond_init_instead_of_pthread_cond_init
712 #define pthread_cond_destroy use_ast_cond_destroy_instead_of_pthread_cond_destroy
713 #define pthread_cond_signal use_ast_cond_signal_instead_of_pthread_cond_signal
714 #define pthread_cond_broadcast use_ast_cond_broadcast_instead_of_pthread_cond_broadcast
715 #define pthread_cond_wait use_ast_cond_wait_instead_of_pthread_cond_wait
716 #define pthread_cond_timedwait use_ast_cond_timedwait_instead_of_pthread_cond_timedwait
717
718 #define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static,mutex)
719
720 #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
721
722 #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
723 #ifndef __linux__
724 #define pthread_create __use_ast_pthread_create_instead__
725 #endif
726
727 /*
728  * Initial support for atomic instructions.
729  * For platforms that have it, use the native cpu instruction to
730  * implement them. For other platforms, resort to a 'slow' version
731  * (defined in utils.c) that protects the atomic instruction with
732  * a single lock.
733  * The slow versions is always available, for testing purposes,
734  * as ast_atomic_fetchadd_int_slow()
735  */
736
737 int ast_atomic_fetchadd_int_slow(volatile int *p, int v);
738
739 #include "asterisk/inline_api.h"
740
741 /*! \brief Atomically add v to *p and return * the previous value of *p.
742  * This can be used to handle reference counts, and the return value
743  * can be used to generate unique identifiers.
744  */
745
746 #if defined(HAVE_GCC_ATOMICS)
747 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
748 {
749         return __sync_fetch_and_add(p, v);
750 })
751 #elif defined ( __i386__)
752 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
753 {
754         __asm __volatile (
755         "       lock   xaddl   %0, %1 ;        "
756         : "+r" (v),                     /* 0 (result) */   
757           "=m" (*p)                     /* 1 */
758         : "m" (*p));                    /* 2 */
759         return (v);
760 })
761 #else   /* low performance version in utils.c */
762 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
763 {
764         return ast_atomic_fetchadd_int_slow(p, v);
765 })
766 #endif
767
768 /*! \brief decrement *p by 1 and return true if the variable has reached 0.
769  * Useful e.g. to check if a refcount has reached 0.
770  */
771 #if defined(HAVE_GCC_ATOMICS)
772 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
773 {
774         return __sync_sub_and_fetch(p, 1) == 0;
775 })
776 #else
777 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
778 {
779         int a = ast_atomic_fetchadd_int(p, -1);
780         return a == 1; /* true if the value is 0 now (so it was 1 previously) */
781 })
782 #endif
783
784 #ifndef DEBUG_CHANNEL_LOCKS
785 /*! \brief Lock a channel. If DEBUG_CHANNEL_LOCKS is defined 
786         in the Makefile, print relevant output for debugging */
787 #define ast_channel_lock(x)             ast_mutex_lock(&x->lock)
788 /*! \brief Unlock a channel. If DEBUG_CHANNEL_LOCKS is defined 
789         in the Makefile, print relevant output for debugging */
790 #define ast_channel_unlock(x)           ast_mutex_unlock(&x->lock)
791 /*! \brief Try locking a channel. If DEBUG_CHANNEL_LOCKS is defined 
792         in the Makefile, print relevant output for debugging */
793 #define ast_channel_trylock(x)          ast_mutex_trylock(&x->lock)
794 #else
795
796 struct ast_channel;
797
798 /*! \brief Lock AST channel (and print debugging output)
799 \note You need to enable DEBUG_CHANNEL_LOCKS for this function */
800 int ast_channel_lock(struct ast_channel *chan);
801
802 /*! \brief Unlock AST channel (and print debugging output)
803 \note You need to enable DEBUG_CHANNEL_LOCKS for this function
804 */
805 int ast_channel_unlock(struct ast_channel *chan);
806
807 /*! \brief Lock AST channel (and print debugging output)
808 \note   You need to enable DEBUG_CHANNEL_LOCKS for this function */
809 int ast_channel_trylock(struct ast_channel *chan);
810 #endif
811
812 #endif /* _ASTERISK_LOCK_H */