aa5c5bd56584bfb3462fc563223485be5ed2285d
[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         pthread_mutex_t reentr_mutex;
122 };
123
124 typedef struct ast_mutex_info ast_mutex_t;
125
126 typedef pthread_cond_t ast_cond_t;
127
128 static pthread_mutex_t empty_mutex;
129
130 enum ast_lock_type {
131         AST_MUTEX,
132         AST_RDLOCK,
133         AST_WRLOCK,
134 };
135
136 /*!
137  * \brief Store lock info for the current thread
138  *
139  * This function gets called in ast_mutex_lock() and ast_mutex_trylock() so
140  * that information about this lock can be stored in this thread's
141  * lock info struct.  The lock is marked as pending as the thread is waiting
142  * on the lock.  ast_mark_lock_acquired() will mark it as held by this thread.
143  */
144 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
145         int line_num, const char *func, const char *lock_name, void *lock_addr);
146
147 /*!
148  * \brief Mark the last lock as acquired
149  */
150 void ast_mark_lock_acquired(void);
151
152 /*!
153  * \brief Mark the last lock as failed (trylock)
154  */
155 void ast_mark_lock_failed(void);
156
157 /*!
158  * \brief remove lock info for the current thread
159  *
160  * this gets called by ast_mutex_unlock so that information on the lock can
161  * be removed from the current thread's lock info struct.
162  */
163 void ast_remove_lock_info(void *lock_addr);
164
165 static void __attribute__((constructor)) init_empty_mutex(void)
166 {
167         memset(&empty_mutex, 0, sizeof(empty_mutex));
168 }
169
170 static inline void reentrancy_lock_cs(ast_mutex_t *p_ast_mutex)
171 {
172         pthread_mutex_lock(&p_ast_mutex->reentr_mutex);
173 }
174
175 static inline void reentrancy_unlock_cs(ast_mutex_t *p_ast_mutex)
176 {
177         pthread_mutex_unlock(&p_ast_mutex->reentr_mutex);
178 }
179
180 static inline void init_reentrancy_cs(ast_mutex_t *p_ast_mutex)
181 {
182         int i;
183         static pthread_mutexattr_t reentr_attr;
184
185         for (i = 0; i < AST_MAX_REENTRANCY; i++) {
186                 p_ast_mutex->file[i] = NULL;
187                 p_ast_mutex->lineno[i] = 0;
188                 p_ast_mutex->func[i] = NULL;
189                 p_ast_mutex->thread[i] = 0;
190         }
191
192         p_ast_mutex->reentrancy = 0;
193
194         pthread_mutexattr_init(&reentr_attr);
195         pthread_mutexattr_settype(&reentr_attr, AST_MUTEX_KIND);
196         pthread_mutex_init(&p_ast_mutex->reentr_mutex, &reentr_attr);
197         pthread_mutexattr_destroy(&reentr_attr);
198 }
199
200 static inline void delete_reentrancy_cs(ast_mutex_t * p_ast_mutex)
201 {
202         pthread_mutex_destroy(&p_ast_mutex->reentr_mutex);
203 }
204
205 static inline int __ast_pthread_mutex_init_attr(int track, const char *filename, int lineno, const char *func,
206                                                 const char *mutex_name, ast_mutex_t *t,
207                                                 pthread_mutexattr_t *attr) 
208 {
209 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
210         int canlog = strcmp(filename, "logger.c");
211
212         if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
213                 if ((t->mutex) != (empty_mutex)) {
214                         __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is already initialized.\n",
215                                            filename, lineno, func, mutex_name);
216                         __ast_mutex_logger("%s line %d (%s): Error: previously initialization of mutex '%s'.\n",
217                                            t->file[0], t->lineno[0], t->func[0], mutex_name);
218                         DO_THREAD_CRASH;
219                         return 0;
220                 }
221         }
222 #endif
223
224         init_reentrancy_cs(t);
225         t->track = track;
226
227         return pthread_mutex_init(&t->mutex, attr);
228 }
229
230 static inline int __ast_pthread_mutex_init(int track, const char *filename, int lineno, const char *func,
231                                            const char *mutex_name, ast_mutex_t *t)
232 {
233         static pthread_mutexattr_t  attr;
234
235         pthread_mutexattr_init(&attr);
236         pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
237
238         return __ast_pthread_mutex_init_attr(track, filename, lineno, func, mutex_name, t, &attr);
239 }
240 #define ast_mutex_init(pmutex) __ast_pthread_mutex_init(1, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
241 #define ast_mutex_init_notracking(pmutex) \
242         __ast_pthread_mutex_init(0, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
243
244 static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
245                                                 const char *mutex_name, ast_mutex_t *t)
246 {
247         int res;
248         int canlog = strcmp(filename, "logger.c");
249
250 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
251         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
252                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
253                                    filename, lineno, func, mutex_name);
254         }
255 #endif
256
257         res = pthread_mutex_trylock(&t->mutex);
258         switch (res) {
259         case 0:
260                 pthread_mutex_unlock(&t->mutex);
261                 break;
262         case EINVAL:
263                 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
264                                   filename, lineno, func, mutex_name);
265                 break;
266         case EBUSY:
267                 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
268                                    filename, lineno, func, mutex_name);
269                 reentrancy_lock_cs(t);
270                 __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
271                             t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
272                 reentrancy_unlock_cs(t);
273                 break;
274         }
275
276         if ((res = pthread_mutex_destroy(&t->mutex)))
277                 __ast_mutex_logger("%s line %d (%s): Error destroying mutex: %s\n",
278                                    filename, lineno, func, strerror(res));
279 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
280         else
281                 t->mutex = PTHREAD_MUTEX_INIT_VALUE;
282 #endif
283         reentrancy_lock_cs(t);
284         t->file[0] = filename;
285         t->lineno[0] = lineno;
286         t->func[0] = func;
287         t->reentrancy=0;
288         t->thread[0]  = 0;
289         reentrancy_unlock_cs(t);
290         delete_reentrancy_cs(t);
291
292         return res;
293 }
294
295 static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
296                                            const char* mutex_name, ast_mutex_t *t)
297 {
298         int res;
299         int canlog = strcmp(filename, "logger.c");
300
301         if (t->track)
302                 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
303
304 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
305         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
306                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
307                                  filename, lineno, func, mutex_name);
308                 ast_mutex_init(t);
309         }
310 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
311
312 #ifdef DETECT_DEADLOCKS
313         {
314                 time_t seconds = time(NULL);
315                 time_t current;
316                 do {
317 #ifdef  HAVE_MTX_PROFILE
318                         ast_mark(mtx_prof, 1);
319 #endif
320                         res = pthread_mutex_trylock(&t->mutex);
321 #ifdef  HAVE_MTX_PROFILE
322                         ast_mark(mtx_prof, 0);
323 #endif
324                         if (res == EBUSY) {
325                                 current = time(NULL);
326                                 if ((current - seconds) && (!((current - seconds) % 5))) {
327                                         __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
328                                                            filename, lineno, func, (int)(current - seconds), mutex_name);
329                                         reentrancy_lock_cs(t);
330                                         __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
331                                                            t->file[t->reentrancy-1], t->lineno[t->reentrancy-1],
332                                                            t->func[t->reentrancy-1], mutex_name);
333                                         reentrancy_unlock_cs(t);
334                                 }
335                                 usleep(200);
336                         }
337                 } while (res == EBUSY);
338         }
339 #else
340 #ifdef  HAVE_MTX_PROFILE
341         ast_mark(mtx_prof, 1);
342         res = pthread_mutex_trylock(&t->mutex);
343         ast_mark(mtx_prof, 0);
344         if (res)
345 #endif
346         res = pthread_mutex_lock(&t->mutex);
347 #endif /* DETECT_DEADLOCKS */
348
349         if (!res) {
350                 reentrancy_lock_cs(t);
351                 if (t->reentrancy < AST_MAX_REENTRANCY) {
352                         t->file[t->reentrancy] = filename;
353                         t->lineno[t->reentrancy] = lineno;
354                         t->func[t->reentrancy] = func;
355                         t->thread[t->reentrancy] = pthread_self();
356                         t->reentrancy++;
357                 } else {
358                         __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
359                                                            filename, lineno, func, mutex_name);
360                 }
361                 reentrancy_unlock_cs(t);
362                 if (t->track)
363                         ast_mark_lock_acquired();
364         } else {
365                 if (t->track)
366                         ast_remove_lock_info(&t->mutex);
367                 __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
368                                    filename, lineno, func, strerror(res));
369                 DO_THREAD_CRASH;
370         }
371
372         return res;
373 }
374
375 static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
376                                               const char* mutex_name, ast_mutex_t *t)
377 {
378         int res;
379         int canlog = strcmp(filename, "logger.c");
380
381 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
382         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
383                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
384                                    filename, lineno, func, mutex_name);
385                 ast_mutex_init(t);
386         }
387 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
388
389         if (t->track)
390                 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
391
392         if (!(res = pthread_mutex_trylock(&t->mutex))) {
393                 reentrancy_lock_cs(t);
394                 if (t->reentrancy < AST_MAX_REENTRANCY) {
395                         t->file[t->reentrancy] = filename;
396                         t->lineno[t->reentrancy] = lineno;
397                         t->func[t->reentrancy] = func;
398                         t->thread[t->reentrancy] = pthread_self();
399                         t->reentrancy++;
400                 } else {
401                         __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
402                                            filename, lineno, func, mutex_name);
403                 }
404                 reentrancy_unlock_cs(t);
405                 if (t->track)
406                         ast_mark_lock_acquired();
407         } else if (t->track) {
408                         ast_remove_lock_info(&t->mutex);
409         }
410
411         return res;
412 }
413
414 static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
415                                              const char *mutex_name, ast_mutex_t *t)
416 {
417         int res;
418         int canlog = strcmp(filename, "logger.c");
419
420 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
421         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
422                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
423                                    filename, lineno, func, mutex_name);
424         }
425 #endif
426
427         reentrancy_lock_cs(t);
428         if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
429                 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
430                                    filename, lineno, func, mutex_name);
431                 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
432                                    t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
433                 DO_THREAD_CRASH;
434         }
435
436         if (--t->reentrancy < 0) {
437                 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
438                                    filename, lineno, func, mutex_name);
439                 t->reentrancy = 0;
440         }
441
442         if (t->reentrancy < AST_MAX_REENTRANCY) {
443                 t->file[t->reentrancy] = NULL;
444                 t->lineno[t->reentrancy] = 0;
445                 t->func[t->reentrancy] = NULL;
446                 t->thread[t->reentrancy] = 0;
447         }
448         reentrancy_unlock_cs(t);
449
450         if (t->track)
451                 ast_remove_lock_info(&t->mutex);
452
453         if ((res = pthread_mutex_unlock(&t->mutex))) {
454                 __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n", 
455                                    filename, lineno, func, strerror(res));
456                 DO_THREAD_CRASH;
457         }
458
459         return res;
460 }
461
462 static inline int __ast_cond_init(const char *filename, int lineno, const char *func,
463                                   const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
464 {
465         return pthread_cond_init(cond, cond_attr);
466 }
467
468 static inline int __ast_cond_signal(const char *filename, int lineno, const char *func,
469                                     const char *cond_name, ast_cond_t *cond)
470 {
471         return pthread_cond_signal(cond);
472 }
473
474 static inline int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
475                                        const char *cond_name, ast_cond_t *cond)
476 {
477         return pthread_cond_broadcast(cond);
478 }
479
480 static inline int __ast_cond_destroy(const char *filename, int lineno, const char *func,
481                                      const char *cond_name, ast_cond_t *cond)
482 {
483         return pthread_cond_destroy(cond);
484 }
485
486 static inline int __ast_cond_wait(const char *filename, int lineno, const char *func,
487                                   const char *cond_name, const char *mutex_name,
488                                   ast_cond_t *cond, ast_mutex_t *t)
489 {
490         int res;
491         int canlog = strcmp(filename, "logger.c");
492
493 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
494         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
495                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
496                                    filename, lineno, func, mutex_name);
497         }
498 #endif
499
500         reentrancy_lock_cs(t);
501         if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
502                 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
503                                    filename, lineno, func, mutex_name);
504                 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
505                                    t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
506                 DO_THREAD_CRASH;
507         }
508
509         if (--t->reentrancy < 0) {
510                 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
511                                    filename, lineno, func, mutex_name);
512                 t->reentrancy = 0;
513         }
514
515         if (t->reentrancy < AST_MAX_REENTRANCY) {
516                 t->file[t->reentrancy] = NULL;
517                 t->lineno[t->reentrancy] = 0;
518                 t->func[t->reentrancy] = NULL;
519                 t->thread[t->reentrancy] = 0;
520         }
521         reentrancy_unlock_cs(t);
522
523         if (t->track)
524                 ast_remove_lock_info(&t->mutex);
525
526         if ((res = pthread_cond_wait(cond, &t->mutex))) {
527                 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n", 
528                                    filename, lineno, func, strerror(res));
529                 DO_THREAD_CRASH;
530         } else {
531                 reentrancy_lock_cs(t);
532                 if (t->reentrancy < AST_MAX_REENTRANCY) {
533                         t->file[t->reentrancy] = filename;
534                         t->lineno[t->reentrancy] = lineno;
535                         t->func[t->reentrancy] = func;
536                         t->thread[t->reentrancy] = pthread_self();
537                         t->reentrancy++;
538                 } else {
539                         __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
540                                                            filename, lineno, func, mutex_name);
541                 }
542                 reentrancy_unlock_cs(t);
543
544                 if (t->track)
545                         ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
546         }
547
548         return res;
549 }
550
551 static inline int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
552                                        const char *cond_name, const char *mutex_name, ast_cond_t *cond,
553                                        ast_mutex_t *t, const struct timespec *abstime)
554 {
555         int res;
556         int canlog = strcmp(filename, "logger.c");
557
558 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
559         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
560                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
561                                    filename, lineno, func, mutex_name);
562         }
563 #endif
564
565         reentrancy_lock_cs(t);
566         if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
567                 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
568                                    filename, lineno, func, mutex_name);
569                 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
570                                    t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
571                 DO_THREAD_CRASH;
572         }
573
574         if (--t->reentrancy < 0) {
575                 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
576                                    filename, lineno, func, mutex_name);
577                 t->reentrancy = 0;
578         }
579
580         if (t->reentrancy < AST_MAX_REENTRANCY) {
581                 t->file[t->reentrancy] = NULL;
582                 t->lineno[t->reentrancy] = 0;
583                 t->func[t->reentrancy] = NULL;
584                 t->thread[t->reentrancy] = 0;
585         }
586         reentrancy_unlock_cs(t);
587
588         if (t->track)
589                 ast_remove_lock_info(&t->mutex);
590
591         if ((res = pthread_cond_timedwait(cond, &t->mutex, abstime)) && (res != ETIMEDOUT)) {
592                 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n", 
593                                    filename, lineno, func, strerror(res));
594                 DO_THREAD_CRASH;
595         } else {
596                 reentrancy_lock_cs(t);
597                 if (t->reentrancy < AST_MAX_REENTRANCY) {
598                         t->file[t->reentrancy] = filename;
599                         t->lineno[t->reentrancy] = lineno;
600                         t->func[t->reentrancy] = func;
601                         t->thread[t->reentrancy] = pthread_self();
602                         t->reentrancy++;
603                 } else {
604                         __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
605                                                            filename, lineno, func, mutex_name);
606                 }
607                 reentrancy_unlock_cs(t);
608
609                 if (t->track)
610                         ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
611         }
612
613         return res;
614 }
615
616 #define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
617 #define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
618 #define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
619 #define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
620 #define ast_cond_init(cond, attr) __ast_cond_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond, attr)
621 #define ast_cond_destroy(cond) __ast_cond_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
622 #define ast_cond_signal(cond) __ast_cond_signal(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
623 #define ast_cond_broadcast(cond) __ast_cond_broadcast(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
624 #define ast_cond_wait(cond, mutex) __ast_cond_wait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex)
625 #define ast_cond_timedwait(cond, mutex, time) __ast_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex, time)
626
627 #else /* !DEBUG_THREADS */
628
629
630 typedef pthread_mutex_t ast_mutex_t;
631
632 #define AST_MUTEX_INIT_VALUE    ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
633 #define AST_MUTEX_INIT_VALUE_NOTRACKING \
634         ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
635
636 #define ast_mutex_init_notracking(m) ast_mutex_init(m)
637
638 static inline int ast_mutex_init(ast_mutex_t *pmutex)
639 {
640         pthread_mutexattr_t attr;
641
642         pthread_mutexattr_init(&attr);
643         pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
644
645         return pthread_mutex_init(pmutex, &attr);
646 }
647
648 #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
649
650 static inline int ast_mutex_unlock(ast_mutex_t *pmutex)
651 {
652         return pthread_mutex_unlock(pmutex);
653 }
654
655 static inline int ast_mutex_destroy(ast_mutex_t *pmutex)
656 {
657         return pthread_mutex_destroy(pmutex);
658 }
659
660 static inline int ast_mutex_lock(ast_mutex_t *pmutex)
661 {
662         __MTX_PROF(pmutex);
663 }
664
665 static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
666 {
667         return pthread_mutex_trylock(pmutex);
668 }
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 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
705 /* If AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
706  constructors/destructors to create/destroy mutexes.  */
707 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track) \
708         scope ast_mutex_t mutex = init_val; \
709 static void  __attribute__ ((constructor)) init_##mutex(void) \
710 { \
711         if (track) \
712                 ast_mutex_init(&mutex); \
713         else \
714                 ast_mutex_init_notracking(&mutex); \
715 } \
716 static void  __attribute__ ((destructor)) fini_##mutex(void) \
717 { \
718         ast_mutex_destroy(&mutex); \
719 }
720 #else /* !AST_MUTEX_INIT_W_CONSTRUCTORS */
721 /* By default, use static initialization of mutexes. */ 
722 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track) \
723         scope ast_mutex_t mutex = init_val
724 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
725
726 #define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
727 #define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
728 #define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
729 #define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
730 #define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init
731 #define pthread_mutex_destroy use_ast_mutex_destroy_instead_of_pthread_mutex_destroy
732 #define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t
733 #define pthread_cond_init use_ast_cond_init_instead_of_pthread_cond_init
734 #define pthread_cond_destroy use_ast_cond_destroy_instead_of_pthread_cond_destroy
735 #define pthread_cond_signal use_ast_cond_signal_instead_of_pthread_cond_signal
736 #define pthread_cond_broadcast use_ast_cond_broadcast_instead_of_pthread_cond_broadcast
737 #define pthread_cond_wait use_ast_cond_wait_instead_of_pthread_cond_wait
738 #define pthread_cond_timedwait use_ast_cond_timedwait_instead_of_pthread_cond_timedwait
739
740 #define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE, 1)
741 #define AST_MUTEX_DEFINE_STATIC_NOTRACKING(mutex) __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE_NOTRACKING, 0)
742
743 #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
744
745 #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
746
747 #ifndef __linux__
748 #define pthread_create __use_ast_pthread_create_instead__
749 #endif
750
751 typedef pthread_rwlock_t ast_rwlock_t;
752
753 static inline int ast_rwlock_init(ast_rwlock_t *prwlock)
754 {
755         pthread_rwlockattr_t attr;
756
757         pthread_rwlockattr_init(&attr);
758
759 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
760         pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
761 #endif
762
763         return pthread_rwlock_init(prwlock, &attr);
764 }
765
766 static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
767 {
768         return pthread_rwlock_destroy(prwlock);
769 }
770
771 #ifdef DEBUG_THREADS
772 #define ast_rwlock_unlock(a) \
773         _ast_rwlock_unlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
774
775 static inline int _ast_rwlock_unlock(ast_rwlock_t *lock, const char *name,
776         const char *file, int line, const char *func)
777 {
778         int res;
779         res = pthread_rwlock_unlock(lock);
780         ast_remove_lock_info(lock);
781         return res;
782 }
783
784 #define ast_rwlock_rdlock(a) \
785         _ast_rwlock_rdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
786
787 static inline int _ast_rwlock_rdlock(ast_rwlock_t *lock, const char *name,
788         const char *file, int line, const char *func)
789 {
790         int res;
791         ast_store_lock_info(AST_RDLOCK, file, line, func, name, lock);
792         res = pthread_rwlock_rdlock(lock);
793         if (!res)
794                 ast_mark_lock_acquired();
795         else
796                 ast_remove_lock_info(lock);
797         return res;
798 }
799
800 #define ast_rwlock_wrlock(a) \
801         _ast_rwlock_wrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
802
803 static inline int _ast_rwlock_wrlock(ast_rwlock_t *lock, const char *name,
804         const char *file, int line, const char *func)
805 {
806         int res;
807         ast_store_lock_info(AST_WRLOCK, file, line, func, name, lock);
808         res = pthread_rwlock_wrlock(lock);
809         if (!res)
810                 ast_mark_lock_acquired();
811         else
812                 ast_remove_lock_info(lock);
813         return res;
814 }
815
816 #define ast_rwlock_tryrdlock(a) \
817         _ast_rwlock_tryrdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
818
819 static inline int _ast_rwlock_tryrdlock(ast_rwlock_t *lock, const char *name,
820         const char *file, int line, const char *func)
821 {
822         int res;
823         ast_store_lock_info(AST_RDLOCK, file, line, func, name, lock);
824         res = pthread_rwlock_tryrdlock(lock);
825         if (!res)
826                 ast_mark_lock_acquired();
827         else
828                 ast_remove_lock_info(lock);
829         return res;
830 }
831
832 #define ast_rwlock_trywrlock(a) \
833         _ast_rwlock_trywrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
834
835 static inline int _ast_rwlock_trywrlock(ast_rwlock_t *lock, const char *name,
836         const char *file, int line, const char *func)
837 {
838         int res;
839         ast_store_lock_info(AST_WRLOCK, file, line, func, name, lock);
840         res = pthread_rwlock_trywrlock(lock);
841         if (!res)
842                 ast_mark_lock_acquired();
843         else
844                 ast_remove_lock_info(lock);
845         return res;
846 }
847
848 #else
849
850 static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
851 {
852         return pthread_rwlock_unlock(prwlock);
853 }
854
855 static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
856 {
857         return pthread_rwlock_rdlock(prwlock);
858 }
859
860 static inline int ast_rwlock_tryrdlock(ast_rwlock_t *prwlock)
861 {
862         return pthread_rwlock_tryrdlock(prwlock);
863 }
864
865 static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
866 {
867         return pthread_rwlock_wrlock(prwlock);
868 }
869
870 static inline int ast_rwlock_trywrlock(ast_rwlock_t *prwlock)
871 {
872         return pthread_rwlock_trywrlock(prwlock);
873 }
874 #endif /* DEBUG_THREADS */
875
876 /* Statically declared read/write locks */
877
878 #ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
879 #define __AST_RWLOCK_DEFINE(scope, rwlock) \
880         scope ast_rwlock_t rwlock; \
881 static void  __attribute__ ((constructor)) init_##rwlock(void) \
882 { \
883         ast_rwlock_init(&rwlock); \
884 } \
885 static void  __attribute__ ((destructor)) fini_##rwlock(void) \
886 { \
887         ast_rwlock_destroy(&rwlock); \
888 }
889 #else
890 #define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
891 #define __AST_RWLOCK_DEFINE(scope, rwlock) \
892         scope ast_rwlock_t rwlock = AST_RWLOCK_INIT_VALUE
893 #endif
894
895 #define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock)
896
897 /*
898  * Initial support for atomic instructions.
899  * For platforms that have it, use the native cpu instruction to
900  * implement them. For other platforms, resort to a 'slow' version
901  * (defined in utils.c) that protects the atomic instruction with
902  * a single lock.
903  * The slow versions is always available, for testing purposes,
904  * as ast_atomic_fetchadd_int_slow()
905  */
906
907 int ast_atomic_fetchadd_int_slow(volatile int *p, int v);
908
909 #include "asterisk/inline_api.h"
910
911 #if defined(HAVE_OSX_ATOMICS)
912 #include "libkern/OSAtomic.h"
913 #endif
914
915 /*! \brief Atomically add v to *p and return * the previous value of *p.
916  * This can be used to handle reference counts, and the return value
917  * can be used to generate unique identifiers.
918  */
919
920 #if defined(HAVE_GCC_ATOMICS)
921 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
922 {
923         return __sync_fetch_and_add(p, v);
924 })
925 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
926 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
927 {
928         return OSAtomicAdd32(v, (int32_t *) p);
929 })
930 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
931 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
932 {
933         return OSAtomicAdd64(v, (int64_t *) p);
934 #elif defined (__i386__) || defined(__x86_64__)
935 #ifdef sun
936 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
937 {
938         __asm __volatile (
939         "       lock;  xaddl   %0, %1 ;        "
940         : "+r" (v),                     /* 0 (result) */   
941           "=m" (*p)                     /* 1 */
942         : "m" (*p));                    /* 2 */
943         return (v);
944 })
945 #else /* ifndef sun */
946 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
947 {
948         __asm __volatile (
949         "       lock   xaddl   %0, %1 ;        "
950         : "+r" (v),                     /* 0 (result) */   
951           "=m" (*p)                     /* 1 */
952         : "m" (*p));                    /* 2 */
953         return (v);
954 })
955 #endif
956 #else   /* low performance version in utils.c */
957 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
958 {
959         return ast_atomic_fetchadd_int_slow(p, v);
960 })
961 #endif
962
963 /*! \brief decrement *p by 1 and return true if the variable has reached 0.
964  * Useful e.g. to check if a refcount has reached 0.
965  */
966 #if defined(HAVE_GCC_ATOMICS)
967 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
968 {
969         return __sync_sub_and_fetch(p, 1) == 0;
970 })
971 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
972 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
973 {
974         return OSAtomicAdd32( -1, (int32_t *) p) == 0;
975 })
976 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
977 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
978 {
979         return OSAtomicAdd64( -1, (int64_t *) p) == 0;
980 #else
981 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
982 {
983         int a = ast_atomic_fetchadd_int(p, -1);
984         return a == 1; /* true if the value is 0 now (so it was 1 previously) */
985 })
986 #endif
987
988 #ifndef DEBUG_CHANNEL_LOCKS
989 /*! \brief Lock a channel. If DEBUG_CHANNEL_LOCKS is defined 
990         in the Makefile, print relevant output for debugging */
991 #define ast_channel_lock(x)             ast_mutex_lock(&x->lock)
992 /*! \brief Unlock a channel. If DEBUG_CHANNEL_LOCKS is defined 
993         in the Makefile, print relevant output for debugging */
994 #define ast_channel_unlock(x)           ast_mutex_unlock(&x->lock)
995 /*! \brief Try locking a channel. If DEBUG_CHANNEL_LOCKS is defined 
996         in the Makefile, print relevant output for debugging */
997 #define ast_channel_trylock(x)          ast_mutex_trylock(&x->lock)
998 #else
999
1000 struct ast_channel;
1001
1002 /*! \brief Lock AST channel (and print debugging output)
1003 \note You need to enable DEBUG_CHANNEL_LOCKS for this function */
1004 int ast_channel_lock(struct ast_channel *chan);
1005
1006 /*! \brief Unlock AST channel (and print debugging output)
1007 \note You need to enable DEBUG_CHANNEL_LOCKS for this function
1008 */
1009 int ast_channel_unlock(struct ast_channel *chan);
1010
1011 /*! \brief Lock AST channel (and print debugging output)
1012 \note   You need to enable DEBUG_CHANNEL_LOCKS for this function */
1013 int ast_channel_trylock(struct ast_channel *chan);
1014 #endif
1015
1016 #endif /* _ASTERISK_LOCK_H */