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