Merged revisions 85158 via svnmerge from
[asterisk/asterisk.git] / include / asterisk / lock.h
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  * \brief General Asterisk channel locking definitions.
21  *
22  * - See \ref LockDef
23  */
24
25 /*! \page LockDef Asterisk thread locking models
26  *
27  * This file provides different implementation of the functions,
28  * depending on the platform, the use of DEBUG_THREADS, and the way
29  * module-level mutexes are initialized.
30  *
31  *  - \b static: the mutex is assigned the value AST_MUTEX_INIT_VALUE
32  *        this is done at compile time, and is the way used on Linux.
33  *        This method is not applicable to all platforms e.g. when the
34  *        initialization needs that some code is run.
35  *
36  *  - \b through constructors: for each mutex, a constructor function is
37  *        defined, which then runs when the program (or the module)
38  *        starts. The problem with this approach is that there is a
39  *        lot of code duplication (a new block of code is created for
40  *        each mutex). Also, it does not prevent a user from declaring
41  *        a global mutex without going through the wrapper macros,
42  *        so sane programming practices are still required.
43  */
44
45 #ifndef _ASTERISK_LOCK_H
46 #define _ASTERISK_LOCK_H
47
48 #include <pthread.h>
49 #include <netdb.h>
50 #include <time.h>
51 #include <sys/param.h>
52
53 #include "asterisk/logger.h"
54
55 /* internal macro to profile mutexes. Only computes the delay on
56  * non-blocking calls.
57  */
58 #ifndef HAVE_MTX_PROFILE
59 #define __MTX_PROF(a)   return pthread_mutex_lock((a))
60 #else
61 #define __MTX_PROF(a)   do {                    \
62         int i;                                  \
63         /* profile only non-blocking events */  \
64         ast_mark(mtx_prof, 1);                  \
65         i = pthread_mutex_trylock((a));         \
66         ast_mark(mtx_prof, 0);                  \
67         if (!i)                                 \
68                 return i;                       \
69         else                                    \
70                 return pthread_mutex_lock((a)); \
71         } while (0)
72 #endif  /* HAVE_MTX_PROFILE */
73
74 #define AST_PTHREADT_NULL (pthread_t) -1
75 #define AST_PTHREADT_STOP (pthread_t) -2
76
77 #if defined(SOLARIS) || defined(BSD)
78 #define AST_MUTEX_INIT_W_CONSTRUCTORS
79 #endif /* SOLARIS || BSD */
80
81 /* Asterisk REQUIRES recursive (not error checking) mutexes
82    and will not run without them. */
83 #if defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
84 #define PTHREAD_MUTEX_INIT_VALUE        PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
85 #define AST_MUTEX_KIND                  PTHREAD_MUTEX_RECURSIVE_NP
86 #else
87 #define PTHREAD_MUTEX_INIT_VALUE        PTHREAD_MUTEX_INITIALIZER
88 #define AST_MUTEX_KIND                  PTHREAD_MUTEX_RECURSIVE
89 #endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
90
91 #ifdef DEBUG_THREADS
92
93 #define __ast_mutex_logger(...)  do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0)
94
95 #ifdef THREAD_CRASH
96 #define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
97 #else
98 #define DO_THREAD_CRASH do { } while (0)
99 #endif
100
101 #include <errno.h>
102 #include <string.h>
103 #include <stdio.h>
104 #include <unistd.h>
105
106 #define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, 1, { NULL }, { 0 }, 0, { NULL }, { 0 } }
107 #define AST_MUTEX_INIT_VALUE_NOTRACKING \
108                              { PTHREAD_MUTEX_INIT_VALUE, 0, { NULL }, { 0 }, 0, { NULL }, { 0 } }
109
110 #define AST_MAX_REENTRANCY 10
111
112 struct ast_mutex_info {
113         pthread_mutex_t mutex;
114         /*! Track which thread holds this lock */
115         unsigned int track:1;
116         const char *file[AST_MAX_REENTRANCY];
117         int lineno[AST_MAX_REENTRANCY];
118         int reentrancy;
119         const char *func[AST_MAX_REENTRANCY];
120         pthread_t thread[AST_MAX_REENTRANCY];
121 };
122
123 typedef struct ast_mutex_info ast_mutex_t;
124
125 typedef pthread_cond_t ast_cond_t;
126
127 static pthread_mutex_t empty_mutex;
128
129 enum ast_lock_type {
130         AST_MUTEX,
131         AST_RDLOCK,
132         AST_WRLOCK,
133 };
134
135 /*!
136  * \brief Store lock info for the current thread
137  *
138  * This function gets called in ast_mutex_lock() and ast_mutex_trylock() so
139  * that information about this lock can be stored in this thread's
140  * lock info struct.  The lock is marked as pending as the thread is waiting
141  * on the lock.  ast_mark_lock_acquired() will mark it as held by this thread.
142  */
143 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
144         int line_num, const char *func, const char *lock_name, void *lock_addr);
145
146 /*!
147  * \brief Mark the last lock as acquired
148  */
149 void ast_mark_lock_acquired(void);
150
151 /*!
152  * \brief Mark the last lock as failed (trylock)
153  */
154 void ast_mark_lock_failed(void);
155
156 /*!
157  * \brief remove lock info for the current thread
158  *
159  * this gets called by ast_mutex_unlock so that information on the lock can
160  * be removed from the current thread's lock info struct.
161  */
162 void ast_remove_lock_info(void *lock_addr);
163
164 static void __attribute__((constructor)) init_empty_mutex(void)
165 {
166         memset(&empty_mutex, 0, sizeof(empty_mutex));
167 }
168
169 static inline int __ast_pthread_mutex_init_attr(int track, const char *filename, int lineno, const char *func,
170                                                 const char *mutex_name, ast_mutex_t *t,
171                                                 pthread_mutexattr_t *attr) 
172 {
173         int i;
174 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
175         int canlog = strcmp(filename, "logger.c");
176
177         if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
178                 if ((t->mutex) != (empty_mutex)) {
179                         __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is already initialized.\n",
180                                            filename, lineno, func, mutex_name);
181                         __ast_mutex_logger("%s line %d (%s): Error: previously initialization of mutex '%s'.\n",
182                                            t->file[0], t->lineno[0], t->func[0], mutex_name);
183                         DO_THREAD_CRASH;
184                         return 0;
185                 }
186         }
187 #endif
188
189         for (i = 0; i < AST_MAX_REENTRANCY; i++) {
190                 t->file[i] = NULL;
191                 t->lineno[i] = 0;
192                 t->func[i] = NULL;
193                 t->thread[i]  = 0;
194         }
195         t->reentrancy = 0;
196         t->track = track;
197
198         return pthread_mutex_init(&t->mutex, attr);
199 }
200
201 static inline int __ast_pthread_mutex_init(int track, const char *filename, int lineno, const char *func,
202                                            const char *mutex_name, ast_mutex_t *t)
203 {
204         static pthread_mutexattr_t  attr;
205
206         pthread_mutexattr_init(&attr);
207         pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
208
209         return __ast_pthread_mutex_init_attr(track, filename, lineno, func, mutex_name, t, &attr);
210 }
211 #define ast_mutex_init(pmutex) __ast_pthread_mutex_init(1, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
212 #define ast_mutex_init_notracking(pmutex) \
213         __ast_pthread_mutex_init(0, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
214
215 static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
216                                                 const char *mutex_name, ast_mutex_t *t)
217 {
218         int res;
219         int canlog = strcmp(filename, "logger.c");
220
221 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
222         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
223                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
224                                    filename, lineno, func, mutex_name);
225         }
226 #endif
227
228         res = pthread_mutex_trylock(&t->mutex);
229         switch (res) {
230         case 0:
231                 pthread_mutex_unlock(&t->mutex);
232                 break;
233         case EINVAL:
234                 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
235                                   filename, lineno, func, mutex_name);
236                 break;
237         case EBUSY:
238                 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
239                                    filename, lineno, func, mutex_name);
240                 __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
241                                    t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
242                 break;
243         }
244
245         if ((res = pthread_mutex_destroy(&t->mutex)))
246                 __ast_mutex_logger("%s line %d (%s): Error destroying mutex: %s\n",
247                                    filename, lineno, func, strerror(res));
248 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
249         else
250                 t->mutex = PTHREAD_MUTEX_INIT_VALUE;
251 #endif
252         t->file[0] = filename;
253         t->lineno[0] = lineno;
254         t->func[0] = func;
255
256         return res;
257 }
258
259 static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
260                                            const char* mutex_name, ast_mutex_t *t)
261 {
262         int res;
263         int canlog = strcmp(filename, "logger.c");
264
265         if (t->track)
266                 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
267
268 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
269         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
270                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
271                                  filename, lineno, func, mutex_name);
272                 ast_mutex_init(t);
273         }
274 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
275
276 #ifdef DETECT_DEADLOCKS
277         {
278                 time_t seconds = time(NULL);
279                 time_t current;
280                 do {
281 #ifdef  HAVE_MTX_PROFILE
282                         ast_mark(mtx_prof, 1);
283 #endif
284                         res = pthread_mutex_trylock(&t->mutex);
285 #ifdef  HAVE_MTX_PROFILE
286                         ast_mark(mtx_prof, 0);
287 #endif
288                         if (res == EBUSY) {
289                                 current = time(NULL);
290                                 if ((current - seconds) && (!((current - seconds) % 5))) {
291                                         __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
292                                                            filename, lineno, func, (int)(current - seconds), mutex_name);
293                                         __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
294                                                            t->file[t->reentrancy-1], t->lineno[t->reentrancy-1],
295                                                            t->func[t->reentrancy-1], mutex_name);
296                                 }
297                                 usleep(200);
298                         }
299                 } while (res == EBUSY);
300         }
301 #else
302 #ifdef  HAVE_MTX_PROFILE
303         ast_mark(mtx_prof, 1);
304         res = pthread_mutex_trylock(&t->mutex);
305         ast_mark(mtx_prof, 0);
306         if (res)
307 #endif
308         res = pthread_mutex_lock(&t->mutex);
309 #endif /* DETECT_DEADLOCKS */
310
311         if (!res) {
312                 if (t->track)
313                         ast_mark_lock_acquired();
314                 if (t->reentrancy < AST_MAX_REENTRANCY) {
315                         t->file[t->reentrancy] = filename;
316                         t->lineno[t->reentrancy] = lineno;
317                         t->func[t->reentrancy] = func;
318                         t->thread[t->reentrancy] = pthread_self();
319                         t->reentrancy++;
320                 } else {
321                         __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
322                                                            filename, lineno, func, mutex_name);
323                 }
324         } else {
325                 if (t->track)
326                         ast_remove_lock_info(&t->mutex);
327                 __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
328                                    filename, lineno, func, strerror(res));
329                 DO_THREAD_CRASH;
330         }
331
332         return res;
333 }
334
335 static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
336                                               const char* mutex_name, ast_mutex_t *t)
337 {
338         int res;
339         int canlog = strcmp(filename, "logger.c");
340
341 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
342         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
343                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
344                                    filename, lineno, func, mutex_name);
345                 ast_mutex_init(t);
346         }
347 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
348
349         if (t->track)
350                 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
351
352         if (!(res = pthread_mutex_trylock(&t->mutex))) {
353                 if (t->track)
354                         ast_mark_lock_acquired();
355                 if (t->reentrancy < AST_MAX_REENTRANCY) {
356                         t->file[t->reentrancy] = filename;
357                         t->lineno[t->reentrancy] = lineno;
358                         t->func[t->reentrancy] = func;
359                         t->thread[t->reentrancy] = pthread_self();
360                         t->reentrancy++;
361                 } else {
362                         __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
363                                            filename, lineno, func, mutex_name);
364                 }
365         } else if (t->track) {
366                         ast_remove_lock_info(&t->mutex);
367         }
368
369         return res;
370 }
371
372 static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
373                                              const char *mutex_name, ast_mutex_t *t)
374 {
375         int res;
376         int canlog = strcmp(filename, "logger.c");
377
378 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
379         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
380                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
381                                    filename, lineno, func, mutex_name);
382         }
383 #endif
384
385         if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
386                 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
387                                    filename, lineno, func, mutex_name);
388                 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
389                                    t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
390                 DO_THREAD_CRASH;
391         }
392
393         if (--t->reentrancy < 0) {
394                 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
395                                    filename, lineno, func, mutex_name);
396                 t->reentrancy = 0;
397         }
398
399         if (t->reentrancy < AST_MAX_REENTRANCY) {
400                 t->file[t->reentrancy] = NULL;
401                 t->lineno[t->reentrancy] = 0;
402                 t->func[t->reentrancy] = NULL;
403                 t->thread[t->reentrancy] = 0;
404         }
405
406         if (t->track)
407                 ast_remove_lock_info(&t->mutex);
408
409         if ((res = pthread_mutex_unlock(&t->mutex))) {
410                 __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n", 
411                                    filename, lineno, func, strerror(res));
412                 DO_THREAD_CRASH;
413         }
414
415         return res;
416 }
417
418 static inline int __ast_cond_init(const char *filename, int lineno, const char *func,
419                                   const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
420 {
421         return pthread_cond_init(cond, cond_attr);
422 }
423
424 static inline int __ast_cond_signal(const char *filename, int lineno, const char *func,
425                                     const char *cond_name, ast_cond_t *cond)
426 {
427         return pthread_cond_signal(cond);
428 }
429
430 static inline int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
431                                        const char *cond_name, ast_cond_t *cond)
432 {
433         return pthread_cond_broadcast(cond);
434 }
435
436 static inline int __ast_cond_destroy(const char *filename, int lineno, const char *func,
437                                      const char *cond_name, ast_cond_t *cond)
438 {
439         return pthread_cond_destroy(cond);
440 }
441
442 static inline int __ast_cond_wait(const char *filename, int lineno, const char *func,
443                                   const char *cond_name, const char *mutex_name,
444                                   ast_cond_t *cond, ast_mutex_t *t)
445 {
446         int res;
447         int canlog = strcmp(filename, "logger.c");
448
449 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
450         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
451                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
452                                    filename, lineno, func, mutex_name);
453         }
454 #endif
455
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
477         if (t->track)
478                 ast_remove_lock_info(&t->mutex);
479
480         if ((res = pthread_cond_wait(cond, &t->mutex))) {
481                 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n", 
482                                    filename, lineno, func, strerror(res));
483                 DO_THREAD_CRASH;
484         } else {
485                 if (t->track)
486                         ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
487
488                 if (t->reentrancy < AST_MAX_REENTRANCY) {
489                         t->file[t->reentrancy] = filename;
490                         t->lineno[t->reentrancy] = lineno;
491                         t->func[t->reentrancy] = func;
492                         t->thread[t->reentrancy] = pthread_self();
493                         t->reentrancy++;
494                 } else {
495                         __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
496                                                            filename, lineno, func, mutex_name);
497                 }
498         }
499
500         return res;
501 }
502
503 static inline int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
504                                        const char *cond_name, const char *mutex_name, ast_cond_t *cond,
505                                        ast_mutex_t *t, const struct timespec *abstime)
506 {
507         int res;
508         int canlog = strcmp(filename, "logger.c");
509
510 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
511         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
512                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
513                                    filename, lineno, func, mutex_name);
514         }
515 #endif
516
517         if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
518                 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
519                                    filename, lineno, func, mutex_name);
520                 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
521                                    t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
522                 DO_THREAD_CRASH;
523         }
524
525         if (--t->reentrancy < 0) {
526                 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
527                                    filename, lineno, func, mutex_name);
528                 t->reentrancy = 0;
529         }
530
531         if (t->reentrancy < AST_MAX_REENTRANCY) {
532                 t->file[t->reentrancy] = NULL;
533                 t->lineno[t->reentrancy] = 0;
534                 t->func[t->reentrancy] = NULL;
535                 t->thread[t->reentrancy] = 0;
536         }
537
538         if (t->track)
539                 ast_remove_lock_info(&t->mutex);
540
541         if ((res = pthread_cond_timedwait(cond, &t->mutex, abstime)) && (res != ETIMEDOUT)) {
542                 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n", 
543                                    filename, lineno, func, strerror(res));
544                 DO_THREAD_CRASH;
545         } else {
546                 if (t->track)
547                         ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
548
549                 if (t->reentrancy < AST_MAX_REENTRANCY) {
550                         t->file[t->reentrancy] = filename;
551                         t->lineno[t->reentrancy] = lineno;
552                         t->func[t->reentrancy] = func;
553                         t->thread[t->reentrancy] = pthread_self();
554                         t->reentrancy++;
555                 } else {
556                         __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
557                                                            filename, lineno, func, mutex_name);
558                 }
559         }
560
561         return res;
562 }
563
564 #define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
565 #define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
566 #define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
567 #define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
568 #define ast_cond_init(cond, attr) __ast_cond_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond, attr)
569 #define ast_cond_destroy(cond) __ast_cond_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
570 #define ast_cond_signal(cond) __ast_cond_signal(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
571 #define ast_cond_broadcast(cond) __ast_cond_broadcast(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
572 #define ast_cond_wait(cond, mutex) __ast_cond_wait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex)
573 #define ast_cond_timedwait(cond, mutex, time) __ast_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex, time)
574
575 #else /* !DEBUG_THREADS */
576
577
578 typedef pthread_mutex_t ast_mutex_t;
579
580 #define AST_MUTEX_INIT_VALUE    ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
581 #define AST_MUTEX_INIT_VALUE_NOTRACKING \
582         ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
583
584 #define ast_mutex_init_notracking(m) ast_mutex_init(m)
585
586 static inline int ast_mutex_init(ast_mutex_t *pmutex)
587 {
588         pthread_mutexattr_t attr;
589
590         pthread_mutexattr_init(&attr);
591         pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
592
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 static inline int ast_mutex_lock(ast_mutex_t *pmutex)
609 {
610         __MTX_PROF(pmutex);
611 }
612
613 static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
614 {
615         return pthread_mutex_trylock(pmutex);
616 }
617
618 typedef pthread_cond_t ast_cond_t;
619
620 static inline int ast_cond_init(ast_cond_t *cond, pthread_condattr_t *cond_attr)
621 {
622         return pthread_cond_init(cond, cond_attr);
623 }
624
625 static inline int ast_cond_signal(ast_cond_t *cond)
626 {
627         return pthread_cond_signal(cond);
628 }
629
630 static inline int ast_cond_broadcast(ast_cond_t *cond)
631 {
632         return pthread_cond_broadcast(cond);
633 }
634
635 static inline int ast_cond_destroy(ast_cond_t *cond)
636 {
637         return pthread_cond_destroy(cond);
638 }
639
640 static inline int ast_cond_wait(ast_cond_t *cond, ast_mutex_t *t)
641 {
642         return pthread_cond_wait(cond, t);
643 }
644
645 static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime)
646 {
647         return pthread_cond_timedwait(cond, t, abstime);
648 }
649
650 #endif /* !DEBUG_THREADS */
651
652 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
653 /* If AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
654  constructors/destructors to create/destroy mutexes.  */
655 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track) \
656         scope ast_mutex_t mutex = init_val; \
657 static void  __attribute__ ((constructor)) init_##mutex(void) \
658 { \
659         if (track) \
660                 ast_mutex_init(&mutex); \
661         else \
662                 ast_mutex_init_notracking(&mutex); \
663 } \
664 static void  __attribute__ ((destructor)) fini_##mutex(void) \
665 { \
666         ast_mutex_destroy(&mutex); \
667 }
668 #else /* !AST_MUTEX_INIT_W_CONSTRUCTORS */
669 /* By default, use static initialization of mutexes. */ 
670 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track) \
671         scope ast_mutex_t mutex = init_val
672 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
673
674 #define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
675 #define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
676 #define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
677 #define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
678 #define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init
679 #define pthread_mutex_destroy use_ast_mutex_destroy_instead_of_pthread_mutex_destroy
680 #define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t
681 #define pthread_cond_init use_ast_cond_init_instead_of_pthread_cond_init
682 #define pthread_cond_destroy use_ast_cond_destroy_instead_of_pthread_cond_destroy
683 #define pthread_cond_signal use_ast_cond_signal_instead_of_pthread_cond_signal
684 #define pthread_cond_broadcast use_ast_cond_broadcast_instead_of_pthread_cond_broadcast
685 #define pthread_cond_wait use_ast_cond_wait_instead_of_pthread_cond_wait
686 #define pthread_cond_timedwait use_ast_cond_timedwait_instead_of_pthread_cond_timedwait
687
688 #define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE, 1)
689 #define AST_MUTEX_DEFINE_STATIC_NOTRACKING(mutex) __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE_NOTRACKING, 0)
690
691 #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
692
693 #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
694
695 #ifndef __linux__
696 #define pthread_create __use_ast_pthread_create_instead__
697 #endif
698
699 typedef pthread_rwlock_t ast_rwlock_t;
700
701 static inline int ast_rwlock_init(ast_rwlock_t *prwlock)
702 {
703         pthread_rwlockattr_t attr;
704
705         pthread_rwlockattr_init(&attr);
706
707 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
708         pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
709 #endif
710
711         return pthread_rwlock_init(prwlock, &attr);
712 }
713
714 static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
715 {
716         return pthread_rwlock_destroy(prwlock);
717 }
718
719 #ifdef DEBUG_THREADS
720 #define ast_rwlock_unlock(a) \
721         _ast_rwlock_unlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
722
723 static inline int _ast_rwlock_unlock(ast_rwlock_t *lock, const char *name,
724         const char *file, int line, const char *func)
725 {
726         int res;
727         res = pthread_rwlock_unlock(lock);
728         ast_remove_lock_info(lock);
729         return res;
730 }
731
732 #define ast_rwlock_rdlock(a) \
733         _ast_rwlock_rdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
734
735 static inline int _ast_rwlock_rdlock(ast_rwlock_t *lock, const char *name,
736         const char *file, int line, const char *func)
737 {
738         int res;
739         ast_store_lock_info(AST_RDLOCK, file, line, func, name, lock);
740         res = pthread_rwlock_rdlock(lock);
741         if (!res)
742                 ast_mark_lock_acquired();
743         else
744                 ast_remove_lock_info(lock);
745         return res;
746 }
747
748 #define ast_rwlock_wrlock(a) \
749         _ast_rwlock_wrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
750
751 static inline int _ast_rwlock_wrlock(ast_rwlock_t *lock, const char *name,
752         const char *file, int line, const char *func)
753 {
754         int res;
755         ast_store_lock_info(AST_WRLOCK, file, line, func, name, lock);
756         res = pthread_rwlock_wrlock(lock);
757         if (!res)
758                 ast_mark_lock_acquired();
759         else
760                 ast_remove_lock_info(lock);
761         return res;
762 }
763
764 #define ast_rwlock_tryrdlock(a) \
765         _ast_rwlock_tryrdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
766
767 static inline int _ast_rwlock_tryrdlock(ast_rwlock_t *lock, const char *name,
768         const char *file, int line, const char *func)
769 {
770         int res;
771         ast_store_lock_info(AST_RDLOCK, file, line, func, name, lock);
772         res = pthread_rwlock_tryrdlock(lock);
773         if (!res)
774                 ast_mark_lock_acquired();
775         else
776                 ast_remove_lock_info(lock);
777         return res;
778 }
779
780 #define ast_rwlock_trywrlock(a) \
781         _ast_rwlock_trywrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
782
783 static inline int _ast_rwlock_trywrlock(ast_rwlock_t *lock, const char *name,
784         const char *file, int line, const char *func)
785 {
786         int res;
787         ast_store_lock_info(AST_WRLOCK, file, line, func, name, lock);
788         res = pthread_rwlock_trywrlock(lock);
789         if (!res)
790                 ast_mark_lock_acquired();
791         else
792                 ast_remove_lock_info(lock);
793         return res;
794 }
795
796 #else
797
798 static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
799 {
800         return pthread_rwlock_unlock(prwlock);
801 }
802
803 static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
804 {
805         return pthread_rwlock_rdlock(prwlock);
806 }
807
808 static inline int ast_rwlock_tryrdlock(ast_rwlock_t *prwlock)
809 {
810         return pthread_rwlock_tryrdlock(prwlock);
811 }
812
813 static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
814 {
815         return pthread_rwlock_wrlock(prwlock);
816 }
817
818 static inline int ast_rwlock_trywrlock(ast_rwlock_t *prwlock)
819 {
820         return pthread_rwlock_trywrlock(prwlock);
821 }
822 #endif /* DEBUG_THREADS */
823
824 /* Statically declared read/write locks */
825
826 #ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
827 #define __AST_RWLOCK_DEFINE(scope, rwlock) \
828         scope ast_rwlock_t rwlock; \
829 static void  __attribute__ ((constructor)) init_##rwlock(void) \
830 { \
831         ast_rwlock_init(&rwlock); \
832 } \
833 static void  __attribute__ ((destructor)) fini_##rwlock(void) \
834 { \
835         ast_rwlock_destroy(&rwlock); \
836 }
837 #else
838 #define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
839 #define __AST_RWLOCK_DEFINE(scope, rwlock) \
840         scope ast_rwlock_t rwlock = AST_RWLOCK_INIT_VALUE
841 #endif
842
843 #define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock)
844
845 /*
846  * Initial support for atomic instructions.
847  * For platforms that have it, use the native cpu instruction to
848  * implement them. For other platforms, resort to a 'slow' version
849  * (defined in utils.c) that protects the atomic instruction with
850  * a single lock.
851  * The slow versions is always available, for testing purposes,
852  * as ast_atomic_fetchadd_int_slow()
853  */
854
855 int ast_atomic_fetchadd_int_slow(volatile int *p, int v);
856
857 #include "asterisk/inline_api.h"
858
859 #if defined(HAVE_OSX_ATOMICS)
860 #include "libkern/OSAtomic.h"
861 #endif
862
863 /*! \brief Atomically add v to *p and return * the previous value of *p.
864  * This can be used to handle reference counts, and the return value
865  * can be used to generate unique identifiers.
866  */
867
868 #if defined(HAVE_GCC_ATOMICS)
869 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
870 {
871         return __sync_fetch_and_add(p, v);
872 })
873 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
874 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
875 {
876         return OSAtomicAdd32(v, (int32_t *) p);
877 })
878 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
879 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
880 {
881         return OSAtomicAdd64(v, (int64_t *) p);
882 #elif defined (__i386__) || defined(__x86_64__)
883 #ifdef sun
884 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
885 {
886         __asm __volatile (
887         "       lock;  xaddl   %0, %1 ;        "
888         : "+r" (v),                     /* 0 (result) */   
889           "=m" (*p)                     /* 1 */
890         : "m" (*p));                    /* 2 */
891         return (v);
892 })
893 #else /* ifndef sun */
894 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
895 {
896         __asm __volatile (
897         "       lock   xaddl   %0, %1 ;        "
898         : "+r" (v),                     /* 0 (result) */   
899           "=m" (*p)                     /* 1 */
900         : "m" (*p));                    /* 2 */
901         return (v);
902 })
903 #endif
904 #else   /* low performance version in utils.c */
905 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
906 {
907         return ast_atomic_fetchadd_int_slow(p, v);
908 })
909 #endif
910
911 /*! \brief decrement *p by 1 and return true if the variable has reached 0.
912  * Useful e.g. to check if a refcount has reached 0.
913  */
914 #if defined(HAVE_GCC_ATOMICS)
915 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
916 {
917         return __sync_sub_and_fetch(p, 1) == 0;
918 })
919 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
920 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
921 {
922         return OSAtomicAdd32( -1, (int32_t *) p) == 0;
923 })
924 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
925 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
926 {
927         return OSAtomicAdd64( -1, (int64_t *) p) == 0;
928 #else
929 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
930 {
931         int a = ast_atomic_fetchadd_int(p, -1);
932         return a == 1; /* true if the value is 0 now (so it was 1 previously) */
933 })
934 #endif
935
936 #ifndef DEBUG_CHANNEL_LOCKS
937 /*! \brief Lock a channel. If DEBUG_CHANNEL_LOCKS is defined 
938         in the Makefile, print relevant output for debugging */
939 #define ast_channel_lock(x)             ast_mutex_lock(&x->lock)
940 /*! \brief Unlock a channel. If DEBUG_CHANNEL_LOCKS is defined 
941         in the Makefile, print relevant output for debugging */
942 #define ast_channel_unlock(x)           ast_mutex_unlock(&x->lock)
943 /*! \brief Try locking a channel. If DEBUG_CHANNEL_LOCKS is defined 
944         in the Makefile, print relevant output for debugging */
945 #define ast_channel_trylock(x)          ast_mutex_trylock(&x->lock)
946 #else
947
948 struct ast_channel;
949
950 /*! \brief Lock AST channel (and print debugging output)
951 \note You need to enable DEBUG_CHANNEL_LOCKS for this function */
952 int ast_channel_lock(struct ast_channel *chan);
953
954 /*! \brief Unlock AST channel (and print debugging output)
955 \note You need to enable DEBUG_CHANNEL_LOCKS for this function
956 */
957 int ast_channel_unlock(struct ast_channel *chan);
958
959 /*! \brief Lock AST channel (and print debugging output)
960 \note   You need to enable DEBUG_CHANNEL_LOCKS for this function */
961 int ast_channel_trylock(struct ast_channel *chan);
962 #endif
963
964 #endif /* _ASTERISK_LOCK_H */