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