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