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