Merged revisions 114051 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 Asterisk locking-related definitions:
21  * - ast_mutext_t, ast_rwlock_t and related functions;
22  * - atomic arithmetic instructions;
23  * - wrappers for channel locking.
24  *
25  * - See \ref LockDef
26  */
27
28 /*! \page LockDef Asterisk thread locking models
29  *
30  * This file provides different implementation of the functions,
31  * depending on the platform, the use of DEBUG_THREADS, and the way
32  * module-level mutexes are initialized.
33  *
34  *  - \b static: the mutex is assigned the value AST_MUTEX_INIT_VALUE
35  *        this is done at compile time, and is the way used on Linux.
36  *        This method is not applicable to all platforms e.g. when the
37  *        initialization needs that some code is run.
38  *
39  *  - \b through constructors: for each mutex, a constructor function is
40  *        defined, which then runs when the program (or the module)
41  *        starts. The problem with this approach is that there is a
42  *        lot of code duplication (a new block of code is created for
43  *        each mutex). Also, it does not prevent a user from declaring
44  *        a global mutex without going through the wrapper macros,
45  *        so sane programming practices are still required.
46  */
47
48 #ifndef _ASTERISK_LOCK_H
49 #define _ASTERISK_LOCK_H
50
51 #include <pthread.h>
52 #include <sys/param.h>
53
54 #include "asterisk/logger.h"
55
56 /* internal macro to profile mutexes. Only computes the delay on
57  * non-blocking calls.
58  */
59 #ifndef HAVE_MTX_PROFILE
60 #define __MTX_PROF(a)   return pthread_mutex_lock((a))
61 #else
62 #define __MTX_PROF(a)   do {                    \
63         int i;                                  \
64         /* profile only non-blocking events */  \
65         ast_mark(mtx_prof, 1);                  \
66         i = pthread_mutex_trylock((a));         \
67         ast_mark(mtx_prof, 0);                  \
68         if (!i)                                 \
69                 return i;                       \
70         else                                    \
71                 return pthread_mutex_lock((a)); \
72         } while (0)
73 #endif  /* HAVE_MTX_PROFILE */
74
75 #define AST_PTHREADT_NULL (pthread_t) -1
76 #define AST_PTHREADT_STOP (pthread_t) -2
77
78 #if defined(SOLARIS) || defined(BSD)
79 #define AST_MUTEX_INIT_W_CONSTRUCTORS
80 #endif /* SOLARIS || BSD */
81
82 /* Asterisk REQUIRES recursive (not error checking) mutexes
83    and will not run without them. */
84 #if defined(HAVE_PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) && defined(HAVE_PTHREAD_MUTEX_RECURSIVE_NP)
85 #define PTHREAD_MUTEX_INIT_VALUE        PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
86 #define AST_MUTEX_KIND                  PTHREAD_MUTEX_RECURSIVE_NP
87 #else
88 #define PTHREAD_MUTEX_INIT_VALUE        PTHREAD_MUTEX_INITIALIZER
89 #define AST_MUTEX_KIND                  PTHREAD_MUTEX_RECURSIVE
90 #endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
91
92 /*
93  * Definition of ast_mutex_t, ast_cont_d and related functions with/without debugging
94  * (search for DEBUG_THREADS to find the start/end of the sections).
95  *
96  * The non-debug code contains just wrappers for the corresponding pthread functions.
97  * The debug code tracks usage and tries to identify deadlock situations.
98  */
99 #ifdef DEBUG_THREADS
100
101 #define __ast_mutex_logger(...)  do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0)
102
103 #ifdef THREAD_CRASH
104 #define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
105 #else
106 #define DO_THREAD_CRASH do { } while (0)
107 #endif
108
109 #include <errno.h>
110
111 #define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, 1, { NULL }, { 0 }, 0, { NULL }, { 0 }, PTHREAD_MUTEX_INIT_VALUE }
112 #define AST_MUTEX_INIT_VALUE_NOTRACKING \
113                              { PTHREAD_MUTEX_INIT_VALUE, 0, { NULL }, { 0 }, 0, { NULL }, { 0 }, PTHREAD_MUTEX_INIT_VALUE }
114
115 #define AST_MAX_REENTRANCY 10
116
117 struct ast_channel;
118
119 struct ast_mutex_info {
120         pthread_mutex_t mutex;
121         /*! Track which thread holds this lock */
122         unsigned int track:1;
123         const char *file[AST_MAX_REENTRANCY];
124         int lineno[AST_MAX_REENTRANCY];
125         int reentrancy;
126         const char *func[AST_MAX_REENTRANCY];
127         pthread_t thread[AST_MAX_REENTRANCY];
128         pthread_mutex_t reentr_mutex;
129 };
130
131 typedef struct ast_mutex_info ast_mutex_t;
132
133 typedef pthread_cond_t ast_cond_t;
134
135 static pthread_mutex_t empty_mutex;
136
137 enum ast_lock_type {
138         AST_MUTEX,
139         AST_RDLOCK,
140         AST_WRLOCK,
141 };
142
143 /*!
144  * \brief Store lock info for the current thread
145  *
146  * This function gets called in ast_mutex_lock() and ast_mutex_trylock() so
147  * that information about this lock can be stored in this thread's
148  * lock info struct.  The lock is marked as pending as the thread is waiting
149  * on the lock.  ast_mark_lock_acquired() will mark it as held by this thread.
150  */
151 #if !defined(LOW_MEMORY)
152 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
153         int line_num, const char *func, const char *lock_name, void *lock_addr);
154 #else
155 #define ast_store_lock_info(I,DONT,CARE,ABOUT,THE,PARAMETERS)
156 #endif
157
158
159 /*!
160  * \brief Mark the last lock as acquired
161  */
162 #if !defined(LOW_MEMORY)
163 void ast_mark_lock_acquired(void *lock_addr);
164 #else
165 #define ast_mark_lock_acquired(ignore)
166 #endif
167
168 /*!
169  * \brief Mark the last lock as failed (trylock)
170  */
171 #if !defined(LOW_MEMORY)
172 void ast_mark_lock_failed(void *lock_addr);
173 #else
174 #define ast_mark_lock_failed(ignore)
175 #endif
176
177 /*!
178  * \brief remove lock info for the current thread
179  *
180  * this gets called by ast_mutex_unlock so that information on the lock can
181  * be removed from the current thread's lock info struct.
182  */
183 #if !defined(LOW_MEMORY)
184 void ast_remove_lock_info(void *lock_addr);
185 #else
186 #define ast_remove_lock_info(ignore)
187 #endif
188
189 static void __attribute__((constructor)) init_empty_mutex(void)
190 {
191         memset(&empty_mutex, 0, sizeof(empty_mutex));
192 }
193
194 static inline void ast_reentrancy_lock(ast_mutex_t *p_ast_mutex)
195 {
196         pthread_mutex_lock(&p_ast_mutex->reentr_mutex);
197 }
198
199 static inline void ast_reentrancy_unlock(ast_mutex_t *p_ast_mutex)
200 {
201         pthread_mutex_unlock(&p_ast_mutex->reentr_mutex);
202 }
203
204 static inline void ast_reentrancy_init(ast_mutex_t *p_ast_mutex)
205 {
206         int i;
207         pthread_mutexattr_t reentr_attr;
208
209         for (i = 0; i < AST_MAX_REENTRANCY; i++) {
210                 p_ast_mutex->file[i] = NULL;
211                 p_ast_mutex->lineno[i] = 0;
212                 p_ast_mutex->func[i] = NULL;
213                 p_ast_mutex->thread[i] = 0;
214         }
215
216         p_ast_mutex->reentrancy = 0;
217
218         pthread_mutexattr_init(&reentr_attr);
219         pthread_mutexattr_settype(&reentr_attr, AST_MUTEX_KIND);
220         pthread_mutex_init(&p_ast_mutex->reentr_mutex, &reentr_attr);
221         pthread_mutexattr_destroy(&reentr_attr);
222 }
223
224 static inline void delete_reentrancy_cs(ast_mutex_t * p_ast_mutex)
225 {
226         pthread_mutex_destroy(&p_ast_mutex->reentr_mutex);
227 }
228
229 static inline int __ast_pthread_mutex_init(int track, const char *filename, int lineno, const char *func,
230                                                 const char *mutex_name, ast_mutex_t *t) 
231 {
232         int res;
233         pthread_mutexattr_t  attr;
234
235 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
236
237         if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
238 /*
239                 int canlog = strcmp(filename, "logger.c") & track;
240                 __ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is already initialized.\n",
241                                    filename, lineno, func, mutex_name);
242                 DO_THREAD_CRASH;
243 */
244                 return 0;
245         }
246
247 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
248
249         ast_reentrancy_init(t);
250         t->track = track;
251
252         pthread_mutexattr_init(&attr);
253         pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
254
255         res = pthread_mutex_init(&t->mutex, &attr);
256         pthread_mutexattr_destroy(&attr);
257         return res;
258 }
259
260 #define ast_mutex_init(pmutex) __ast_pthread_mutex_init(1, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
261 #define ast_mutex_init_notracking(pmutex) \
262         __ast_pthread_mutex_init(0, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
263
264 static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
265                                                 const char *mutex_name, ast_mutex_t *t)
266 {
267         int res;
268         int canlog = strcmp(filename, "logger.c") & t->track;
269
270 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
271         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
272                 /* Don't try to uninitialize non initialized mutex
273                  * This may no effect on linux
274                  * And always ganerate core on *BSD with 
275                  * linked libpthread
276                  * This not error condition if the mutex created on the fly.
277                  */
278                 __ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is uninitialized.\n",
279                                    filename, lineno, func, mutex_name);
280                 return 0;
281         }
282 #endif
283
284         res = pthread_mutex_trylock(&t->mutex);
285         switch (res) {
286         case 0:
287                 pthread_mutex_unlock(&t->mutex);
288                 break;
289         case EINVAL:
290                 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
291                                   filename, lineno, func, mutex_name);
292                 break;
293         case EBUSY:
294                 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
295                                    filename, lineno, func, mutex_name);
296                 ast_reentrancy_lock(t);
297                 __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
298                             t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
299                 ast_reentrancy_unlock(t);
300                 break;
301         }
302
303         if ((res = pthread_mutex_destroy(&t->mutex)))
304                 __ast_mutex_logger("%s line %d (%s): Error destroying mutex %s: %s\n",
305                                    filename, lineno, func, mutex_name, strerror(res));
306 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
307         else
308                 t->mutex = PTHREAD_MUTEX_INIT_VALUE;
309 #endif
310         ast_reentrancy_lock(t);
311         t->file[0] = filename;
312         t->lineno[0] = lineno;
313         t->func[0] = func;
314         t->reentrancy = 0;
315         t->thread[0] = 0;
316         ast_reentrancy_unlock(t);
317         delete_reentrancy_cs(t);
318
319         return res;
320 }
321
322 static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
323                                            const char* mutex_name, ast_mutex_t *t)
324 {
325         int res;
326         int canlog = strcmp(filename, "logger.c") & t->track;
327
328 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
329         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
330                 /* Don't warn abount uninitialized mutex.
331                  * Simple try to initialize it.
332                  * May be not needed in linux system.
333                  */
334                 res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
335                 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
336                         __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
337                                          filename, lineno, func, mutex_name);
338                         return res;
339                 }               
340         }
341 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
342
343         if (t->track)
344                 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
345
346 #ifdef DETECT_DEADLOCKS
347         {
348                 time_t seconds = time(NULL);
349                 time_t wait_time, reported_wait = 0;
350                 do {
351 #ifdef  HAVE_MTX_PROFILE
352                         ast_mark(mtx_prof, 1);
353 #endif
354                         res = pthread_mutex_trylock(&t->mutex);
355 #ifdef  HAVE_MTX_PROFILE
356                         ast_mark(mtx_prof, 0);
357 #endif
358                         if (res == EBUSY) {
359                                 wait_time = time(NULL) - seconds;
360                                 if (wait_time > reported_wait && (wait_time % 5) == 0) {
361                                         __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
362                                                            filename, lineno, func, (int) wait_time, mutex_name);
363                                         ast_reentrancy_lock(t);
364                                         __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
365                                                            t->file[t->reentrancy-1], t->lineno[t->reentrancy-1],
366                                                            t->func[t->reentrancy-1], mutex_name);
367                                         ast_reentrancy_unlock(t);
368                                         reported_wait = wait_time;
369                                 }
370                                 usleep(200);
371                         }
372                 } while (res == EBUSY);
373         }
374 #else
375 #ifdef  HAVE_MTX_PROFILE
376         ast_mark(mtx_prof, 1);
377         res = pthread_mutex_trylock(&t->mutex);
378         ast_mark(mtx_prof, 0);
379         if (res)
380 #endif
381         res = pthread_mutex_lock(&t->mutex);
382 #endif /* DETECT_DEADLOCKS */
383
384         if (!res) {
385                 ast_reentrancy_lock(t);
386                 if (t->reentrancy < AST_MAX_REENTRANCY) {
387                         t->file[t->reentrancy] = filename;
388                         t->lineno[t->reentrancy] = lineno;
389                         t->func[t->reentrancy] = func;
390                         t->thread[t->reentrancy] = pthread_self();
391                         t->reentrancy++;
392                 } else {
393                         __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
394                                                            filename, lineno, func, mutex_name);
395                 }
396                 ast_reentrancy_unlock(t);
397                 if (t->track)
398                         ast_mark_lock_acquired(&t->mutex);
399         } else {
400                 if (t->track)
401                         ast_remove_lock_info(&t->mutex);
402                 __ast_mutex_logger("%s line %d (%s): Error obtaining 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_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
411                                               const char* mutex_name, ast_mutex_t *t)
412 {
413         int res;
414         int canlog = strcmp(filename, "logger.c") & t->track;
415
416 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
417         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
418                 /* Don't warn abount uninitialized mutex.
419                  * Simple try to initialize it.
420                  * May be not needed in linux system.
421                  */
422                 res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
423                 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
424                         __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
425                                          filename, lineno, func, mutex_name);
426                         return res;
427                 }               
428         }
429 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
430
431         if (t->track)
432                 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
433
434         if (!(res = pthread_mutex_trylock(&t->mutex))) {
435                 ast_reentrancy_lock(t);
436                 if (t->reentrancy < AST_MAX_REENTRANCY) {
437                         t->file[t->reentrancy] = filename;
438                         t->lineno[t->reentrancy] = lineno;
439                         t->func[t->reentrancy] = func;
440                         t->thread[t->reentrancy] = pthread_self();
441                         t->reentrancy++;
442                 } else {
443                         __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
444                                            filename, lineno, func, mutex_name);
445                 }
446                 ast_reentrancy_unlock(t);
447                 if (t->track)
448                         ast_mark_lock_acquired(&t->mutex);
449         } else if (t->track) {
450                 ast_mark_lock_failed(&t->mutex);
451         }
452
453         return res;
454 }
455
456 static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
457                                              const char *mutex_name, ast_mutex_t *t)
458 {
459         int res;
460         int canlog = strcmp(filename, "logger.c") & t->track;
461
462 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
463         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
464                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
465                                    filename, lineno, func, mutex_name);
466                 res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
467                 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
468                         __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
469                                          filename, lineno, func, mutex_name);
470                 }
471                 return res;
472         }
473 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
474
475         ast_reentrancy_lock(t);
476         if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
477                 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
478                                    filename, lineno, func, mutex_name);
479                 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
480                                    t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
481                 DO_THREAD_CRASH;
482         }
483
484         if (--t->reentrancy < 0) {
485                 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
486                                    filename, lineno, func, mutex_name);
487                 t->reentrancy = 0;
488         }
489
490         if (t->reentrancy < AST_MAX_REENTRANCY) {
491                 t->file[t->reentrancy] = NULL;
492                 t->lineno[t->reentrancy] = 0;
493                 t->func[t->reentrancy] = NULL;
494                 t->thread[t->reentrancy] = 0;
495         }
496         ast_reentrancy_unlock(t);
497
498         if (t->track)
499                 ast_remove_lock_info(&t->mutex);
500
501         if ((res = pthread_mutex_unlock(&t->mutex))) {
502                 __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n", 
503                                    filename, lineno, func, strerror(res));
504                 DO_THREAD_CRASH;
505         }
506
507         return res;
508 }
509
510 static inline int __ast_cond_init(const char *filename, int lineno, const char *func,
511                                   const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
512 {
513         return pthread_cond_init(cond, cond_attr);
514 }
515
516 static inline int __ast_cond_signal(const char *filename, int lineno, const char *func,
517                                     const char *cond_name, ast_cond_t *cond)
518 {
519         return pthread_cond_signal(cond);
520 }
521
522 static inline int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
523                                        const char *cond_name, ast_cond_t *cond)
524 {
525         return pthread_cond_broadcast(cond);
526 }
527
528 static inline int __ast_cond_destroy(const char *filename, int lineno, const char *func,
529                                      const char *cond_name, ast_cond_t *cond)
530 {
531         return pthread_cond_destroy(cond);
532 }
533
534 static inline int __ast_cond_wait(const char *filename, int lineno, const char *func,
535                                   const char *cond_name, const char *mutex_name,
536                                   ast_cond_t *cond, ast_mutex_t *t)
537 {
538         int res;
539         int canlog = strcmp(filename, "logger.c") & t->track;
540
541 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
542         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
543                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
544                                    filename, lineno, func, mutex_name);
545                 res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
546                 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
547                         __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
548                                          filename, lineno, func, mutex_name);
549                 }
550                 return res;
551         }
552 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
553
554         ast_reentrancy_lock(t);
555         if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
556                 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
557                                    filename, lineno, func, mutex_name);
558                 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
559                                    t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
560                 DO_THREAD_CRASH;
561         }
562
563         if (--t->reentrancy < 0) {
564                 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
565                                    filename, lineno, func, mutex_name);
566                 t->reentrancy = 0;
567         }
568
569         if (t->reentrancy < AST_MAX_REENTRANCY) {
570                 t->file[t->reentrancy] = NULL;
571                 t->lineno[t->reentrancy] = 0;
572                 t->func[t->reentrancy] = NULL;
573                 t->thread[t->reentrancy] = 0;
574         }
575         ast_reentrancy_unlock(t);
576
577         if (t->track)
578                 ast_remove_lock_info(&t->mutex);
579
580         if ((res = pthread_cond_wait(cond, &t->mutex))) {
581                 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n", 
582                                    filename, lineno, func, strerror(res));
583                 DO_THREAD_CRASH;
584         } else {
585                 ast_reentrancy_lock(t);
586                 if (t->reentrancy < AST_MAX_REENTRANCY) {
587                         t->file[t->reentrancy] = filename;
588                         t->lineno[t->reentrancy] = lineno;
589                         t->func[t->reentrancy] = func;
590                         t->thread[t->reentrancy] = pthread_self();
591                         t->reentrancy++;
592                 } else {
593                         __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
594                                                            filename, lineno, func, mutex_name);
595                 }
596                 ast_reentrancy_unlock(t);
597
598                 if (t->track)
599                         ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
600         }
601
602         return res;
603 }
604
605 static inline int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
606                                        const char *cond_name, const char *mutex_name, ast_cond_t *cond,
607                                        ast_mutex_t *t, const struct timespec *abstime)
608 {
609         int res;
610         int canlog = strcmp(filename, "logger.c") & t->track;
611
612 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
613         if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
614                 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
615                                    filename, lineno, func, mutex_name);
616                 res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
617                 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
618                         __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
619                                          filename, lineno, func, mutex_name);
620                 }
621                 return res;
622         }
623 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
624
625         ast_reentrancy_lock(t);
626         if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
627                 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
628                                    filename, lineno, func, mutex_name);
629                 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
630                                    t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
631                 DO_THREAD_CRASH;
632         }
633
634         if (--t->reentrancy < 0) {
635                 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
636                                    filename, lineno, func, mutex_name);
637                 t->reentrancy = 0;
638         }
639
640         if (t->reentrancy < AST_MAX_REENTRANCY) {
641                 t->file[t->reentrancy] = NULL;
642                 t->lineno[t->reentrancy] = 0;
643                 t->func[t->reentrancy] = NULL;
644                 t->thread[t->reentrancy] = 0;
645         }
646         ast_reentrancy_unlock(t);
647
648         if (t->track)
649                 ast_remove_lock_info(&t->mutex);
650
651         if ((res = pthread_cond_timedwait(cond, &t->mutex, abstime)) && (res != ETIMEDOUT)) {
652                 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n", 
653                                    filename, lineno, func, strerror(res));
654                 DO_THREAD_CRASH;
655         } else {
656                 ast_reentrancy_lock(t);
657                 if (t->reentrancy < AST_MAX_REENTRANCY) {
658                         t->file[t->reentrancy] = filename;
659                         t->lineno[t->reentrancy] = lineno;
660                         t->func[t->reentrancy] = func;
661                         t->thread[t->reentrancy] = pthread_self();
662                         t->reentrancy++;
663                 } else {
664                         __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
665                                                            filename, lineno, func, mutex_name);
666                 }
667                 ast_reentrancy_unlock(t);
668
669                 if (t->track)
670                         ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
671         }
672
673         return res;
674 }
675
676 #define ast_mutex_destroy(a)                    __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
677 #define ast_mutex_lock(a)                       __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
678 #define ast_mutex_unlock(a)                     __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
679 #define ast_mutex_trylock(a)                    __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
680 #define ast_cond_init(cond, attr)               __ast_cond_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond, attr)
681 #define ast_cond_destroy(cond)                  __ast_cond_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
682 #define ast_cond_signal(cond)                   __ast_cond_signal(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
683 #define ast_cond_broadcast(cond)                __ast_cond_broadcast(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
684 #define ast_cond_wait(cond, mutex)              __ast_cond_wait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex)
685 #define ast_cond_timedwait(cond, mutex, time)   __ast_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex, time)
686
687 #else /* !DEBUG_THREADS */
688
689
690 typedef pthread_mutex_t ast_mutex_t;
691
692 #define AST_MUTEX_INIT_VALUE                    ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
693 #define AST_MUTEX_INIT_VALUE_NOTRACKING         ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
694
695 #define ast_mutex_init_notracking(m)            ast_mutex_init(m)
696
697 static inline int ast_mutex_init(ast_mutex_t *pmutex)
698 {
699         int res;
700         pthread_mutexattr_t attr;
701
702         pthread_mutexattr_init(&attr);
703         pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
704
705         res = pthread_mutex_init(pmutex, &attr);
706         pthread_mutexattr_destroy(&attr);
707         return res;
708 }
709
710 #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
711
712 static inline int ast_mutex_unlock(ast_mutex_t *pmutex)
713 {
714         return pthread_mutex_unlock(pmutex);
715 }
716
717 static inline int ast_mutex_destroy(ast_mutex_t *pmutex)
718 {
719         return pthread_mutex_destroy(pmutex);
720 }
721
722 static inline int ast_mutex_lock(ast_mutex_t *pmutex)
723 {
724         __MTX_PROF(pmutex);
725 }
726
727 static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
728 {
729         return pthread_mutex_trylock(pmutex);
730 }
731
732 typedef pthread_cond_t ast_cond_t;
733
734 static inline int ast_cond_init(ast_cond_t *cond, pthread_condattr_t *cond_attr)
735 {
736         return pthread_cond_init(cond, cond_attr);
737 }
738
739 static inline int ast_cond_signal(ast_cond_t *cond)
740 {
741         return pthread_cond_signal(cond);
742 }
743
744 static inline int ast_cond_broadcast(ast_cond_t *cond)
745 {
746         return pthread_cond_broadcast(cond);
747 }
748
749 static inline int ast_cond_destroy(ast_cond_t *cond)
750 {
751         return pthread_cond_destroy(cond);
752 }
753
754 static inline int ast_cond_wait(ast_cond_t *cond, ast_mutex_t *t)
755 {
756         return pthread_cond_wait(cond, t);
757 }
758
759 static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime)
760 {
761         return pthread_cond_timedwait(cond, t, abstime);
762 }
763
764 #endif /* !DEBUG_THREADS */
765
766 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
767 /*
768  * If AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope constructors
769  * and destructors to create/destroy global mutexes.
770  */
771 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track)       \
772         scope ast_mutex_t mutex = init_val;                     \
773 static void  __attribute__ ((constructor)) init_##mutex(void)   \
774 {                                                               \
775         if (track)                                              \
776                 ast_mutex_init(&mutex);                         \
777         else                                                    \
778                 ast_mutex_init_notracking(&mutex);              \
779 }                                                               \
780                                                                 \
781 static void  __attribute__ ((destructor)) fini_##mutex(void)    \
782 {                                                               \
783         ast_mutex_destroy(&mutex);                              \
784 }
785 #else /* !AST_MUTEX_INIT_W_CONSTRUCTORS */
786 /* By default, use static initialization of mutexes. */ 
787 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track)       scope ast_mutex_t mutex = init_val
788 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
789
790 #ifndef __CYGWIN__      /* temporary disabled for cygwin */
791 #define pthread_mutex_t         use_ast_mutex_t_instead_of_pthread_mutex_t
792 #define pthread_cond_t          use_ast_cond_t_instead_of_pthread_cond_t
793 #endif
794 #define pthread_mutex_lock      use_ast_mutex_lock_instead_of_pthread_mutex_lock
795 #define pthread_mutex_unlock    use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
796 #define pthread_mutex_trylock   use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
797 #define pthread_mutex_init      use_ast_mutex_init_instead_of_pthread_mutex_init
798 #define pthread_mutex_destroy   use_ast_mutex_destroy_instead_of_pthread_mutex_destroy
799 #define pthread_cond_init       use_ast_cond_init_instead_of_pthread_cond_init
800 #define pthread_cond_destroy    use_ast_cond_destroy_instead_of_pthread_cond_destroy
801 #define pthread_cond_signal     use_ast_cond_signal_instead_of_pthread_cond_signal
802 #define pthread_cond_broadcast  use_ast_cond_broadcast_instead_of_pthread_cond_broadcast
803 #define pthread_cond_wait       use_ast_cond_wait_instead_of_pthread_cond_wait
804 #define pthread_cond_timedwait  use_ast_cond_timedwait_instead_of_pthread_cond_timedwait
805
806 #define AST_MUTEX_DEFINE_STATIC(mutex)                  __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE, 1)
807 #define AST_MUTEX_DEFINE_STATIC_NOTRACKING(mutex)       __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE_NOTRACKING, 0)
808
809 #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
810
811 #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
812
813 #ifndef __linux__
814 #define pthread_create __use_ast_pthread_create_instead__
815 #endif
816
817 /*
818  * Same as above, definitions of ast_rwlock_t for the various cases:
819  * simple wrappers for the pthread equivalent in the non-debug case,
820  * more sophisticated tracking in the debug case.
821  */
822
823 typedef pthread_rwlock_t ast_rwlock_t;
824
825 #ifdef HAVE_PTHREAD_RWLOCK_INITIALIZER
826 #define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
827 #else
828 #define AST_RWLOCK_INIT_VALUE { 0 }
829 #endif
830
831 #ifdef DEBUG_THREADS
832
833 #define ast_rwlock_init(rwlock)         __ast_rwlock_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)
834 #define ast_rwlock_destroy(rwlock)      __ast_rwlock_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)
835 #define ast_rwlock_unlock(a)            _ast_rwlock_unlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
836 #define ast_rwlock_rdlock(a)            _ast_rwlock_rdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
837 #define ast_rwlock_wrlock(a)            _ast_rwlock_wrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
838 #define ast_rwlock_tryrdlock(a)         _ast_rwlock_tryrdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
839 #define ast_rwlock_trywrlock(a) _ast_rwlock_trywrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
840
841
842 static inline int __ast_rwlock_init(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *prwlock)
843 {
844         int res;
845         pthread_rwlockattr_t attr;
846 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
847         int canlog = strcmp(filename, "logger.c");
848
849         if (*prwlock != ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
850                 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
851                                 filename, lineno, func, rwlock_name);
852                 return 0;
853         }
854 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
855         pthread_rwlockattr_init(&attr);
856
857 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
858         pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
859 #endif
860
861         res = pthread_rwlock_init(prwlock, &attr);
862         pthread_rwlockattr_destroy(&attr);
863         return res;
864 }
865
866
867 static inline int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *prwlock)
868 {
869         int res;
870         int canlog = strcmp(filename, "logger.c");
871
872 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
873         if (*prwlock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
874                 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
875                                    filename, lineno, func, rwlock_name);
876                 return 0;
877         }
878 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
879         
880         if ((res = pthread_rwlock_destroy(prwlock)))
881                 __ast_mutex_logger("%s line %d (%s): Error destroying rwlock %s: %s\n",
882                                 filename, lineno, func, rwlock_name, strerror(res));
883
884         return res;
885 }
886
887
888 static inline int _ast_rwlock_unlock(ast_rwlock_t *lock, const char *name,
889         const char *file, int line, const char *func)
890 {
891         int res;
892 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
893         int canlog = strcmp(file, "logger.c");
894
895         if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
896                 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
897                                    file, line, func, name);
898                 res = __ast_rwlock_init(file, line, func, name, lock);
899                 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
900                         __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
901                                         file, line, func, name);
902                 }
903                 return res;
904         }
905 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
906         
907         res = pthread_rwlock_unlock(lock);
908         ast_remove_lock_info(lock);
909         return res;
910 }
911
912
913 static inline int _ast_rwlock_rdlock(ast_rwlock_t *lock, const char *name,
914         const char *file, int line, const char *func)
915 {
916         int res;
917 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
918         int canlog = strcmp(file, "logger.c");
919         
920         if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
921                  /* Don't warn abount uninitialized lock.
922                   * Simple try to initialize it.
923                   * May be not needed in linux system.
924                   */
925                 res = __ast_rwlock_init(file, line, func, name, lock);
926                 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
927                         __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
928                                         file, line, func, name);
929                         return res;
930                 }
931         }
932 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
933         
934         ast_store_lock_info(AST_RDLOCK, file, line, func, name, lock);
935         res = pthread_rwlock_rdlock(lock);
936         if (!res)
937                 ast_mark_lock_acquired(lock);
938         else
939                 ast_remove_lock_info(lock);
940         return res;
941 }
942
943
944 static inline int _ast_rwlock_wrlock(ast_rwlock_t *lock, const char *name,
945         const char *file, int line, const char *func)
946 {
947         int res;
948 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
949         int canlog = strcmp(file, "logger.c");
950         
951         if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
952                  /* Don't warn abount uninitialized lock.
953                   * Simple try to initialize it.
954                   * May be not needed in linux system.
955                   */
956                 res = __ast_rwlock_init(file, line, func, name, lock);
957                 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
958                         __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
959                                         file, line, func, name);
960                         return res;
961                 }
962         }
963 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
964
965         ast_store_lock_info(AST_WRLOCK, file, line, func, name, lock);
966         res = pthread_rwlock_wrlock(lock);
967         if (!res)
968                 ast_mark_lock_acquired(lock);
969         else
970                 ast_remove_lock_info(lock);
971         return res;
972 }
973
974
975 static inline int _ast_rwlock_tryrdlock(ast_rwlock_t *lock, const char *name,
976         const char *file, int line, const char *func)
977 {
978         int res;
979 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
980         int canlog = strcmp(file, "logger.c");
981         
982         if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
983                  /* Don't warn abount uninitialized lock.
984                   * Simple try to initialize it.
985                   * May be not needed in linux system.
986                   */
987                 res = __ast_rwlock_init(file, line, func, name, lock);
988                 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
989                         __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
990                                         file, line, func, name);
991                         return res;
992                 }
993         }
994 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
995
996         ast_store_lock_info(AST_RDLOCK, file, line, func, name, lock);
997         res = pthread_rwlock_tryrdlock(lock);
998         if (!res)
999                 ast_mark_lock_acquired(lock);
1000         else
1001                 ast_remove_lock_info(lock);
1002         return res;
1003 }
1004
1005
1006 static inline int _ast_rwlock_trywrlock(ast_rwlock_t *lock, const char *name,
1007         const char *file, int line, const char *func)
1008 {
1009         int res;
1010 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
1011         int canlog = strcmp(file, "logger.c");
1012         
1013         if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
1014                  /* Don't warn abount uninitialized lock.
1015                   * Simple try to initialize it.
1016                   * May be not needed in linux system.
1017                   */
1018                 res = __ast_rwlock_init(file, line, func, name, lock);
1019                 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
1020                         __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1021                                         file, line, func, name);
1022                         return res;
1023                 }
1024         }
1025 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1026
1027         ast_store_lock_info(AST_WRLOCK, file, line, func, name, lock);
1028         res = pthread_rwlock_trywrlock(lock);
1029         if (!res)
1030                 ast_mark_lock_acquired(lock);
1031         else
1032                 ast_remove_lock_info(lock);
1033         return res;
1034 }
1035
1036 #else /* !DEBUG_THREADS */
1037
1038 static inline int ast_rwlock_init(ast_rwlock_t *prwlock)
1039 {
1040         int res;
1041         pthread_rwlockattr_t attr;
1042
1043         pthread_rwlockattr_init(&attr);
1044
1045 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
1046         pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
1047 #endif
1048
1049         res = pthread_rwlock_init(prwlock, &attr);
1050         pthread_rwlockattr_destroy(&attr);
1051         return res;
1052 }
1053
1054 static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
1055 {
1056         return pthread_rwlock_destroy(prwlock);
1057 }
1058
1059 static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
1060 {
1061         return pthread_rwlock_unlock(prwlock);
1062 }
1063
1064 static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
1065 {
1066         return pthread_rwlock_rdlock(prwlock);
1067 }
1068
1069 static inline int ast_rwlock_tryrdlock(ast_rwlock_t *prwlock)
1070 {
1071         return pthread_rwlock_tryrdlock(prwlock);
1072 }
1073
1074 static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
1075 {
1076         return pthread_rwlock_wrlock(prwlock);
1077 }
1078
1079 static inline int ast_rwlock_trywrlock(ast_rwlock_t *prwlock)
1080 {
1081         return pthread_rwlock_trywrlock(prwlock);
1082 }
1083 #endif /* !DEBUG_THREADS */
1084
1085 /* Statically declared read/write locks */
1086
1087 #ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
1088 #define __AST_RWLOCK_DEFINE(scope, rwlock)                      \
1089         scope ast_rwlock_t rwlock;                              \
1090 static void  __attribute__ ((constructor)) init_##rwlock(void)  \
1091 {                                                               \
1092         ast_rwlock_init(&rwlock);                               \
1093 }                                                               \
1094                                                                 \
1095 static void  __attribute__ ((destructor)) fini_##rwlock(void)   \
1096 {                                                               \
1097         ast_rwlock_destroy(&rwlock);                            \
1098 }
1099 #else
1100 #define __AST_RWLOCK_DEFINE(scope, rwlock)      scope ast_rwlock_t rwlock = AST_RWLOCK_INIT_VALUE
1101 #endif
1102
1103 #define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock)
1104
1105 /*
1106  * Support for atomic instructions.
1107  * For platforms that have it, use the native cpu instruction to
1108  * implement them. For other platforms, resort to a 'slow' version
1109  * (defined in utils.c) that protects the atomic instruction with
1110  * a single lock.
1111  * The slow versions is always available, for testing purposes,
1112  * as ast_atomic_fetchadd_int_slow()
1113  */
1114
1115 int ast_atomic_fetchadd_int_slow(volatile int *p, int v);
1116
1117 #include "asterisk/inline_api.h"
1118
1119 #if defined(HAVE_OSX_ATOMICS)
1120 #include "libkern/OSAtomic.h"
1121 #endif
1122
1123 /*! \brief Atomically add v to *p and return * the previous value of *p.
1124  * This can be used to handle reference counts, and the return value
1125  * can be used to generate unique identifiers.
1126  */
1127
1128 #if defined(HAVE_GCC_ATOMICS)
1129 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1130 {
1131         return __sync_fetch_and_add(p, v);
1132 })
1133 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
1134 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1135 {
1136         return OSAtomicAdd32(v, (int32_t *) p) - v;
1137 })
1138 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
1139 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1140 {
1141         return OSAtomicAdd64(v, (int64_t *) p) - v;
1142 #elif defined (__i386__) || defined(__x86_64__)
1143 #ifdef sun
1144 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1145 {
1146         __asm __volatile (
1147         "       lock;  xaddl   %0, %1 ;        "
1148         : "+r" (v),                     /* 0 (result) */   
1149           "=m" (*p)                     /* 1 */
1150         : "m" (*p));                    /* 2 */
1151         return (v);
1152 })
1153 #else /* ifndef sun */
1154 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1155 {
1156         __asm __volatile (
1157         "       lock   xaddl   %0, %1 ;        "
1158         : "+r" (v),                     /* 0 (result) */   
1159           "=m" (*p)                     /* 1 */
1160         : "m" (*p));                    /* 2 */
1161         return (v);
1162 })
1163 #endif
1164 #else   /* low performance version in utils.c */
1165 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1166 {
1167         return ast_atomic_fetchadd_int_slow(p, v);
1168 })
1169 #endif
1170
1171 /*! \brief decrement *p by 1 and return true if the variable has reached 0.
1172  * Useful e.g. to check if a refcount has reached 0.
1173  */
1174 #if defined(HAVE_GCC_ATOMICS)
1175 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
1176 {
1177         return __sync_sub_and_fetch(p, 1) == 0;
1178 })
1179 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
1180 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
1181 {
1182         return OSAtomicAdd32( -1, (int32_t *) p) == 0;
1183 })
1184 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
1185 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
1186 {
1187         return OSAtomicAdd64( -1, (int64_t *) p) == 0;
1188 #else
1189 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
1190 {
1191         int a = ast_atomic_fetchadd_int(p, -1);
1192         return a == 1; /* true if the value is 0 now (so it was 1 previously) */
1193 })
1194 #endif
1195
1196 #ifndef DEBUG_CHANNEL_LOCKS
1197 /*! \brief Lock a channel. If DEBUG_CHANNEL_LOCKS is defined 
1198         in the Makefile, print relevant output for debugging */
1199 #define ast_channel_lock(x)             ast_mutex_lock(&x->lock_dont_use)
1200 /*! \brief Unlock a channel. If DEBUG_CHANNEL_LOCKS is defined 
1201         in the Makefile, print relevant output for debugging */
1202 #define ast_channel_unlock(x)           ast_mutex_unlock(&x->lock_dont_use)
1203 /*! \brief Try locking a channel. If DEBUG_CHANNEL_LOCKS is defined 
1204         in the Makefile, print relevant output for debugging */
1205 #define ast_channel_trylock(x)          ast_mutex_trylock(&x->lock_dont_use)
1206 #else
1207
1208 /*! \brief Lock AST channel (and print debugging output)
1209 \note You need to enable DEBUG_CHANNEL_LOCKS for this function */
1210 int ast_channel_lock(struct ast_channel *chan);
1211
1212 /*! \brief Unlock AST channel (and print debugging output)
1213 \note You need to enable DEBUG_CHANNEL_LOCKS for this function
1214 */
1215 int ast_channel_unlock(struct ast_channel *chan);
1216
1217 /*! \brief Lock AST channel (and print debugging output)
1218 \note   You need to enable DEBUG_CHANNEL_LOCKS for this function */
1219 int ast_channel_trylock(struct ast_channel *chan);
1220 #endif
1221
1222 #endif /* _ASTERISK_LOCK_H */