Adds DAHDI support alongside Zaptel. DAHDI usage favored, but all Zap stuff should...
[asterisk-bristuff.git] / include / asterisk / lock.h
blobeae56f4cd79c7d788d6803c6bddc333f485d6387
1 /*
2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
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.
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.
19 /*! \file
20 * \brief General Asterisk channel locking definitions.
22 * - See \ref LockDef
25 /*! \page LockDef Asterisk thread locking models
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.
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.
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.
45 #ifndef _ASTERISK_LOCK_H
46 #define _ASTERISK_LOCK_H
48 #include <pthread.h>
49 #include <netdb.h>
50 #include <time.h>
51 #include <sys/param.h>
53 #include "asterisk/logger.h"
55 /* internal macro to profile mutexes. Only computes the delay on
56 * non-blocking calls.
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 */
74 #define AST_PTHREADT_NULL (pthread_t) -1
75 #define AST_PTHREADT_STOP (pthread_t) -2
77 #if defined(SOLARIS) || defined(BSD)
78 #define AST_MUTEX_INIT_W_CONSTRUCTORS
79 #endif /* SOLARIS || BSD */
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 */
91 #ifdef DEBUG_THREADS
93 #define __ast_mutex_logger(...) do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0)
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
101 #include <errno.h>
102 #include <string.h>
103 #include <stdio.h>
104 #include <unistd.h>
106 #define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, 1, { NULL }, { 0 }, 0, { NULL }, { 0 }, PTHREAD_MUTEX_INIT_VALUE }
107 #define AST_MUTEX_INIT_VALUE_NOTRACKING \
108 { PTHREAD_MUTEX_INIT_VALUE, 0, { NULL }, { 0 }, 0, { NULL }, { 0 }, PTHREAD_MUTEX_INIT_VALUE }
110 #define AST_MAX_REENTRANCY 10
112 struct ast_mutex_info {
113 pthread_mutex_t mutex;
114 /*! Track which thread holds this lock */
115 unsigned int track:1;
116 const char *file[AST_MAX_REENTRANCY];
117 int lineno[AST_MAX_REENTRANCY];
118 int reentrancy;
119 const char *func[AST_MAX_REENTRANCY];
120 pthread_t thread[AST_MAX_REENTRANCY];
121 pthread_mutex_t reentr_mutex;
124 typedef struct ast_mutex_info ast_mutex_t;
126 typedef pthread_cond_t ast_cond_t;
128 static pthread_mutex_t empty_mutex;
130 enum ast_lock_type {
131 AST_MUTEX,
132 AST_RDLOCK,
133 AST_WRLOCK,
137 * \brief Store lock info for the current thread
139 * This function gets called in ast_mutex_lock() and ast_mutex_trylock() so
140 * that information about this lock can be stored in this thread's
141 * lock info struct. The lock is marked as pending as the thread is waiting
142 * on the lock. ast_mark_lock_acquired() will mark it as held by this thread.
144 #if !defined(LOW_MEMORY)
145 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
146 int line_num, const char *func, const char *lock_name, void *lock_addr);
147 #else
148 #define ast_store_lock_info(I,DONT,CARE,ABOUT,THE,PARAMETERS)
149 #endif
153 * \brief Mark the last lock as acquired
155 #if !defined(LOW_MEMORY)
156 void ast_mark_lock_acquired(void *lock_addr);
157 #else
158 #define ast_mark_lock_acquired(ignore)
159 #endif
162 * \brief Mark the last lock as failed (trylock)
164 #if !defined(LOW_MEMORY)
165 void ast_mark_lock_failed(void *lock_addr);
166 #else
167 #define ast_mark_lock_failed(ignore)
168 #endif
171 * \brief remove lock info for the current thread
173 * this gets called by ast_mutex_unlock so that information on the lock can
174 * be removed from the current thread's lock info struct.
176 #if !defined(LOW_MEMORY)
177 void ast_remove_lock_info(void *lock_addr);
178 #else
179 #define ast_remove_lock_info(ignore)
180 #endif
183 * \brief retrieve lock info for the specified mutex
185 * this gets called during deadlock avoidance, so that the information may
186 * be preserved as to what location originally acquired the lock.
188 #if !defined(LOW_MEMORY)
189 int ast_find_lock_info(void *lock_addr, const char **filename, int *lineno, const char **func, const char **mutex_name);
190 #else
191 #define ast_find_lock_info(a,b,c,d,e) -1
192 #endif
195 * \brief Unlock a lock briefly
197 * used during deadlock avoidance, to preserve the original location where
198 * a lock was originally acquired.
200 #define DEADLOCK_AVOIDANCE(lock) \
201 do { \
202 const char *__filename, *__func, *__mutex_name; \
203 int __lineno; \
204 int __res = ast_find_lock_info(lock, &__filename, &__lineno, &__func, &__mutex_name); \
205 ast_mutex_unlock(lock); \
206 usleep(1); \
207 if (__res < 0) { /* Shouldn't ever happen, but just in case... */ \
208 ast_mutex_lock(lock); \
209 } else { \
210 __ast_pthread_mutex_lock(__filename, __lineno, __func, __mutex_name, lock); \
212 } while (0)
214 static void __attribute__((constructor)) init_empty_mutex(void)
216 memset(&empty_mutex, 0, sizeof(empty_mutex));
219 static inline void ast_reentrancy_lock(ast_mutex_t *p_ast_mutex)
221 pthread_mutex_lock(&p_ast_mutex->reentr_mutex);
224 static inline void ast_reentrancy_unlock(ast_mutex_t *p_ast_mutex)
226 pthread_mutex_unlock(&p_ast_mutex->reentr_mutex);
229 static inline void ast_reentrancy_init(ast_mutex_t *p_ast_mutex)
231 int i;
232 pthread_mutexattr_t reentr_attr;
234 for (i = 0; i < AST_MAX_REENTRANCY; i++) {
235 p_ast_mutex->file[i] = NULL;
236 p_ast_mutex->lineno[i] = 0;
237 p_ast_mutex->func[i] = NULL;
238 p_ast_mutex->thread[i] = 0;
241 p_ast_mutex->reentrancy = 0;
243 pthread_mutexattr_init(&reentr_attr);
244 pthread_mutexattr_settype(&reentr_attr, AST_MUTEX_KIND);
245 pthread_mutex_init(&p_ast_mutex->reentr_mutex, &reentr_attr);
246 pthread_mutexattr_destroy(&reentr_attr);
249 static inline void delete_reentrancy_cs(ast_mutex_t * p_ast_mutex)
251 pthread_mutex_destroy(&p_ast_mutex->reentr_mutex);
254 static inline int __ast_pthread_mutex_init(int track, const char *filename, int lineno, const char *func,
255 const char *mutex_name, ast_mutex_t *t)
257 int res;
258 pthread_mutexattr_t attr;
260 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
262 if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
264 int canlog = strcmp(filename, "logger.c") & track;
265 __ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is already initialized.\n",
266 filename, lineno, func, mutex_name);
267 DO_THREAD_CRASH;
269 return 0;
272 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
274 ast_reentrancy_init(t);
275 t->track = track;
277 pthread_mutexattr_init(&attr);
278 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
280 res = pthread_mutex_init(&t->mutex, &attr);
281 pthread_mutexattr_destroy(&attr);
282 return res;
285 #define ast_mutex_init(pmutex) __ast_pthread_mutex_init(1, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
286 #define ast_mutex_init_notracking(pmutex) \
287 __ast_pthread_mutex_init(0, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
289 static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
290 const char *mutex_name, ast_mutex_t *t)
292 int res;
293 int canlog = strcmp(filename, "logger.c") & t->track;
295 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
296 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
297 /* Don't try to uninitialize non initialized mutex
298 * This may no effect on linux
299 * And always ganerate core on *BSD with
300 * linked libpthread
301 * This not error condition if the mutex created on the fly.
303 __ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is uninitialized.\n",
304 filename, lineno, func, mutex_name);
305 return 0;
307 #endif
309 res = pthread_mutex_trylock(&t->mutex);
310 switch (res) {
311 case 0:
312 pthread_mutex_unlock(&t->mutex);
313 break;
314 case EINVAL:
315 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
316 filename, lineno, func, mutex_name);
317 break;
318 case EBUSY:
319 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
320 filename, lineno, func, mutex_name);
321 ast_reentrancy_lock(t);
322 __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
323 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
324 ast_reentrancy_unlock(t);
325 break;
328 if ((res = pthread_mutex_destroy(&t->mutex)))
329 __ast_mutex_logger("%s line %d (%s): Error destroying mutex %s: %s\n",
330 filename, lineno, func, mutex_name, strerror(res));
331 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
332 else
333 t->mutex = PTHREAD_MUTEX_INIT_VALUE;
334 #endif
335 ast_reentrancy_lock(t);
336 t->file[0] = filename;
337 t->lineno[0] = lineno;
338 t->func[0] = func;
339 t->reentrancy = 0;
340 t->thread[0] = 0;
341 ast_reentrancy_unlock(t);
342 delete_reentrancy_cs(t);
344 return res;
347 static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
348 const char* mutex_name, ast_mutex_t *t)
350 int res;
351 int canlog = strcmp(filename, "logger.c") & t->track;
353 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
354 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
355 /* Don't warn abount uninitialized mutex.
356 * Simple try to initialize it.
357 * May be not needed in linux system.
359 res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
360 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
361 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
362 filename, lineno, func, mutex_name);
363 return res;
366 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
368 if (t->track)
369 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
371 #ifdef DETECT_DEADLOCKS
373 time_t seconds = time(NULL);
374 time_t wait_time, reported_wait = 0;
375 do {
376 #ifdef HAVE_MTX_PROFILE
377 ast_mark(mtx_prof, 1);
378 #endif
379 res = pthread_mutex_trylock(&t->mutex);
380 #ifdef HAVE_MTX_PROFILE
381 ast_mark(mtx_prof, 0);
382 #endif
383 if (res == EBUSY) {
384 wait_time = time(NULL) - seconds;
385 if (wait_time > reported_wait && (wait_time % 5) == 0) {
386 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
387 filename, lineno, func, (int) wait_time, mutex_name);
388 ast_reentrancy_lock(t);
389 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
390 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1],
391 t->func[t->reentrancy-1], mutex_name);
392 ast_reentrancy_unlock(t);
393 reported_wait = wait_time;
395 usleep(200);
397 } while (res == EBUSY);
399 #else
400 #ifdef HAVE_MTX_PROFILE
401 ast_mark(mtx_prof, 1);
402 res = pthread_mutex_trylock(&t->mutex);
403 ast_mark(mtx_prof, 0);
404 if (res)
405 #endif
406 res = pthread_mutex_lock(&t->mutex);
407 #endif /* DETECT_DEADLOCKS */
409 if (!res) {
410 ast_reentrancy_lock(t);
411 if (t->reentrancy < AST_MAX_REENTRANCY) {
412 t->file[t->reentrancy] = filename;
413 t->lineno[t->reentrancy] = lineno;
414 t->func[t->reentrancy] = func;
415 t->thread[t->reentrancy] = pthread_self();
416 t->reentrancy++;
417 } else {
418 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
419 filename, lineno, func, mutex_name);
421 ast_reentrancy_unlock(t);
422 if (t->track)
423 ast_mark_lock_acquired(&t->mutex);
424 } else {
425 if (t->track)
426 ast_remove_lock_info(&t->mutex);
427 __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
428 filename, lineno, func, strerror(res));
429 DO_THREAD_CRASH;
432 return res;
435 static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
436 const char* mutex_name, ast_mutex_t *t)
438 int res;
439 int canlog = strcmp(filename, "logger.c") & t->track;
441 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
442 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
443 /* Don't warn abount uninitialized mutex.
444 * Simple try to initialize it.
445 * May be not needed in linux system.
447 res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
448 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
449 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
450 filename, lineno, func, mutex_name);
451 return res;
454 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
456 if (t->track)
457 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
459 if (!(res = pthread_mutex_trylock(&t->mutex))) {
460 ast_reentrancy_lock(t);
461 if (t->reentrancy < AST_MAX_REENTRANCY) {
462 t->file[t->reentrancy] = filename;
463 t->lineno[t->reentrancy] = lineno;
464 t->func[t->reentrancy] = func;
465 t->thread[t->reentrancy] = pthread_self();
466 t->reentrancy++;
467 } else {
468 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
469 filename, lineno, func, mutex_name);
471 ast_reentrancy_unlock(t);
472 if (t->track)
473 ast_mark_lock_acquired(&t->mutex);
474 } else if (t->track) {
475 ast_mark_lock_failed(&t->mutex);
478 return res;
481 static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
482 const char *mutex_name, ast_mutex_t *t)
484 int res;
485 int canlog = strcmp(filename, "logger.c") & t->track;
487 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
488 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
489 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
490 filename, lineno, func, mutex_name);
491 res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
492 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
493 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
494 filename, lineno, func, mutex_name);
496 return res;
498 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
500 ast_reentrancy_lock(t);
501 if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
502 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
503 filename, lineno, func, mutex_name);
504 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
505 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
506 DO_THREAD_CRASH;
509 if (--t->reentrancy < 0) {
510 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
511 filename, lineno, func, mutex_name);
512 t->reentrancy = 0;
515 if (t->reentrancy < AST_MAX_REENTRANCY) {
516 t->file[t->reentrancy] = NULL;
517 t->lineno[t->reentrancy] = 0;
518 t->func[t->reentrancy] = NULL;
519 t->thread[t->reentrancy] = 0;
521 ast_reentrancy_unlock(t);
523 if (t->track)
524 ast_remove_lock_info(&t->mutex);
526 if ((res = pthread_mutex_unlock(&t->mutex))) {
527 __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n",
528 filename, lineno, func, strerror(res));
529 DO_THREAD_CRASH;
532 return res;
535 static inline int __ast_cond_init(const char *filename, int lineno, const char *func,
536 const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
538 return pthread_cond_init(cond, cond_attr);
541 static inline int __ast_cond_signal(const char *filename, int lineno, const char *func,
542 const char *cond_name, ast_cond_t *cond)
544 return pthread_cond_signal(cond);
547 static inline int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
548 const char *cond_name, ast_cond_t *cond)
550 return pthread_cond_broadcast(cond);
553 static inline int __ast_cond_destroy(const char *filename, int lineno, const char *func,
554 const char *cond_name, ast_cond_t *cond)
556 return pthread_cond_destroy(cond);
559 static inline int __ast_cond_wait(const char *filename, int lineno, const char *func,
560 const char *cond_name, const char *mutex_name,
561 ast_cond_t *cond, ast_mutex_t *t)
563 int res;
564 int canlog = strcmp(filename, "logger.c") & t->track;
566 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
567 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
568 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
569 filename, lineno, func, mutex_name);
570 res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
571 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
572 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
573 filename, lineno, func, mutex_name);
575 return res;
577 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
579 ast_reentrancy_lock(t);
580 if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
581 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
582 filename, lineno, func, mutex_name);
583 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
584 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
585 DO_THREAD_CRASH;
588 if (--t->reentrancy < 0) {
589 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
590 filename, lineno, func, mutex_name);
591 t->reentrancy = 0;
594 if (t->reentrancy < AST_MAX_REENTRANCY) {
595 t->file[t->reentrancy] = NULL;
596 t->lineno[t->reentrancy] = 0;
597 t->func[t->reentrancy] = NULL;
598 t->thread[t->reentrancy] = 0;
600 ast_reentrancy_unlock(t);
602 if (t->track)
603 ast_remove_lock_info(&t->mutex);
605 if ((res = pthread_cond_wait(cond, &t->mutex))) {
606 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
607 filename, lineno, func, strerror(res));
608 DO_THREAD_CRASH;
609 } else {
610 ast_reentrancy_lock(t);
611 if (t->reentrancy < AST_MAX_REENTRANCY) {
612 t->file[t->reentrancy] = filename;
613 t->lineno[t->reentrancy] = lineno;
614 t->func[t->reentrancy] = func;
615 t->thread[t->reentrancy] = pthread_self();
616 t->reentrancy++;
617 } else {
618 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
619 filename, lineno, func, mutex_name);
621 ast_reentrancy_unlock(t);
623 if (t->track)
624 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
627 return res;
630 static inline int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
631 const char *cond_name, const char *mutex_name, ast_cond_t *cond,
632 ast_mutex_t *t, const struct timespec *abstime)
634 int res;
635 int canlog = strcmp(filename, "logger.c") & t->track;
637 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
638 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
639 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
640 filename, lineno, func, mutex_name);
641 res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
642 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
643 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
644 filename, lineno, func, mutex_name);
646 return res;
648 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
650 ast_reentrancy_lock(t);
651 if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
652 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
653 filename, lineno, func, mutex_name);
654 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
655 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
656 DO_THREAD_CRASH;
659 if (--t->reentrancy < 0) {
660 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
661 filename, lineno, func, mutex_name);
662 t->reentrancy = 0;
665 if (t->reentrancy < AST_MAX_REENTRANCY) {
666 t->file[t->reentrancy] = NULL;
667 t->lineno[t->reentrancy] = 0;
668 t->func[t->reentrancy] = NULL;
669 t->thread[t->reentrancy] = 0;
671 ast_reentrancy_unlock(t);
673 if (t->track)
674 ast_remove_lock_info(&t->mutex);
676 if ((res = pthread_cond_timedwait(cond, &t->mutex, abstime)) && (res != ETIMEDOUT)) {
677 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
678 filename, lineno, func, strerror(res));
679 DO_THREAD_CRASH;
680 } else {
681 ast_reentrancy_lock(t);
682 if (t->reentrancy < AST_MAX_REENTRANCY) {
683 t->file[t->reentrancy] = filename;
684 t->lineno[t->reentrancy] = lineno;
685 t->func[t->reentrancy] = func;
686 t->thread[t->reentrancy] = pthread_self();
687 t->reentrancy++;
688 } else {
689 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
690 filename, lineno, func, mutex_name);
692 ast_reentrancy_unlock(t);
694 if (t->track)
695 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
698 return res;
701 #define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
702 #define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
703 #define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
704 #define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
705 #define ast_cond_init(cond, attr) __ast_cond_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond, attr)
706 #define ast_cond_destroy(cond) __ast_cond_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
707 #define ast_cond_signal(cond) __ast_cond_signal(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
708 #define ast_cond_broadcast(cond) __ast_cond_broadcast(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
709 #define ast_cond_wait(cond, mutex) __ast_cond_wait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex)
710 #define ast_cond_timedwait(cond, mutex, time) __ast_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex, time)
712 #else /* !DEBUG_THREADS */
714 #define DEADLOCK_AVOIDANCE(lock) \
715 ast_mutex_lock(lock); \
716 usleep(1); \
717 ast_mutex_unlock(lock);
720 typedef pthread_mutex_t ast_mutex_t;
722 #define AST_MUTEX_INIT_VALUE ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
723 #define AST_MUTEX_INIT_VALUE_NOTRACKING \
724 ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
726 #define ast_mutex_init_notracking(m) ast_mutex_init(m)
728 static inline int ast_mutex_init(ast_mutex_t *pmutex)
730 int res;
731 pthread_mutexattr_t attr;
733 pthread_mutexattr_init(&attr);
734 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
736 res = pthread_mutex_init(pmutex, &attr);
737 pthread_mutexattr_destroy(&attr);
738 return res;
741 #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
743 static inline int ast_mutex_unlock(ast_mutex_t *pmutex)
745 return pthread_mutex_unlock(pmutex);
748 static inline int ast_mutex_destroy(ast_mutex_t *pmutex)
750 return pthread_mutex_destroy(pmutex);
753 static inline int ast_mutex_lock(ast_mutex_t *pmutex)
755 __MTX_PROF(pmutex);
758 static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
760 return pthread_mutex_trylock(pmutex);
763 typedef pthread_cond_t ast_cond_t;
765 static inline int ast_cond_init(ast_cond_t *cond, pthread_condattr_t *cond_attr)
767 return pthread_cond_init(cond, cond_attr);
770 static inline int ast_cond_signal(ast_cond_t *cond)
772 return pthread_cond_signal(cond);
775 static inline int ast_cond_broadcast(ast_cond_t *cond)
777 return pthread_cond_broadcast(cond);
780 static inline int ast_cond_destroy(ast_cond_t *cond)
782 return pthread_cond_destroy(cond);
785 static inline int ast_cond_wait(ast_cond_t *cond, ast_mutex_t *t)
787 return pthread_cond_wait(cond, t);
790 static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime)
792 return pthread_cond_timedwait(cond, t, abstime);
795 #endif /* !DEBUG_THREADS */
797 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
798 /* If AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
799 destructors to destroy mutexes and create it on the fly. */
800 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track) \
801 scope ast_mutex_t mutex = init_val; \
802 static void __attribute__ ((constructor)) init_##mutex(void) \
804 if (track) \
805 ast_mutex_init(&mutex); \
806 else \
807 ast_mutex_init_notracking(&mutex); \
809 static void __attribute__ ((destructor)) fini_##mutex(void) \
811 ast_mutex_destroy(&mutex); \
813 #else /* !AST_MUTEX_INIT_W_CONSTRUCTORS */
814 /* By default, use static initialization of mutexes. */
815 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track) \
816 scope ast_mutex_t mutex = init_val
817 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
819 #define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
820 #define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
821 #define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
822 #define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
823 #define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init
824 #define pthread_mutex_destroy use_ast_mutex_destroy_instead_of_pthread_mutex_destroy
825 #define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t
826 #define pthread_cond_init use_ast_cond_init_instead_of_pthread_cond_init
827 #define pthread_cond_destroy use_ast_cond_destroy_instead_of_pthread_cond_destroy
828 #define pthread_cond_signal use_ast_cond_signal_instead_of_pthread_cond_signal
829 #define pthread_cond_broadcast use_ast_cond_broadcast_instead_of_pthread_cond_broadcast
830 #define pthread_cond_wait use_ast_cond_wait_instead_of_pthread_cond_wait
831 #define pthread_cond_timedwait use_ast_cond_timedwait_instead_of_pthread_cond_timedwait
833 #define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE, 1)
834 #define AST_MUTEX_DEFINE_STATIC_NOTRACKING(mutex) __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE_NOTRACKING, 0)
836 #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
838 #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
840 #ifndef __linux__
841 #define pthread_create __use_ast_pthread_create_instead__
842 #endif
844 typedef pthread_rwlock_t ast_rwlock_t;
846 #ifdef HAVE_PTHREAD_RWLOCK_INITIALIZER
847 #define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
848 #else
849 #define AST_RWLOCK_INIT_VALUE NULL
850 #endif
852 #ifdef DEBUG_THREADS
854 #define ast_rwlock_init(rwlock) __ast_rwlock_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)
857 static inline int __ast_rwlock_init(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *prwlock)
859 int res;
860 pthread_rwlockattr_t attr;
861 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
862 int canlog = strcmp(filename, "logger.c");
864 if (*prwlock != ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
865 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
866 filename, lineno, func, rwlock_name);
867 return 0;
869 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
870 pthread_rwlockattr_init(&attr);
872 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
873 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
874 #endif
876 res = pthread_rwlock_init(prwlock, &attr);
877 pthread_rwlockattr_destroy(&attr);
878 return res;
881 #define ast_rwlock_destroy(rwlock) __ast_rwlock_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)
883 static inline int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *prwlock)
885 int res;
886 int canlog = strcmp(filename, "logger.c");
888 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
889 if (*prwlock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
890 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
891 filename, lineno, func, rwlock_name);
892 return 0;
894 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
896 if ((res = pthread_rwlock_destroy(prwlock)))
897 __ast_mutex_logger("%s line %d (%s): Error destroying rwlock %s: %s\n",
898 filename, lineno, func, rwlock_name, strerror(res));
900 return res;
903 #define ast_rwlock_unlock(a) \
904 _ast_rwlock_unlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
906 static inline int _ast_rwlock_unlock(ast_rwlock_t *lock, const char *name,
907 const char *file, int line, const char *func)
909 int res;
910 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
911 int canlog = strcmp(file, "logger.c");
913 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
914 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
915 file, line, func, name);
916 res = __ast_rwlock_init(file, line, func, name, lock);
917 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
918 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
919 file, line, func, name);
921 return res;
923 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
925 res = pthread_rwlock_unlock(lock);
926 ast_remove_lock_info(lock);
927 return res;
930 #define ast_rwlock_rdlock(a) \
931 _ast_rwlock_rdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
933 static inline int _ast_rwlock_rdlock(ast_rwlock_t *lock, const char *name,
934 const char *file, int line, const char *func)
936 int res;
937 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
938 int canlog = strcmp(file, "logger.c");
940 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
941 /* Don't warn abount uninitialized lock.
942 * Simple try to initialize it.
943 * May be not needed in linux system.
945 res = __ast_rwlock_init(file, line, func, name, lock);
946 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
947 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
948 file, line, func, name);
949 return res;
952 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
954 ast_store_lock_info(AST_RDLOCK, file, line, func, name, lock);
955 res = pthread_rwlock_rdlock(lock);
956 if (!res)
957 ast_mark_lock_acquired(lock);
958 else
959 ast_remove_lock_info(lock);
960 return res;
963 #define ast_rwlock_wrlock(a) \
964 _ast_rwlock_wrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
966 static inline int _ast_rwlock_wrlock(ast_rwlock_t *lock, const char *name,
967 const char *file, int line, const char *func)
969 int res;
970 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
971 int canlog = strcmp(file, "logger.c");
973 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
974 /* Don't warn abount uninitialized lock.
975 * Simple try to initialize it.
976 * May be not needed in linux system.
978 res = __ast_rwlock_init(file, line, func, name, lock);
979 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
980 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
981 file, line, func, name);
982 return res;
985 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
987 ast_store_lock_info(AST_WRLOCK, file, line, func, name, lock);
988 res = pthread_rwlock_wrlock(lock);
989 if (!res)
990 ast_mark_lock_acquired(lock);
991 else
992 ast_remove_lock_info(lock);
993 return res;
996 #define ast_rwlock_tryrdlock(a) \
997 _ast_rwlock_tryrdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
999 static inline int _ast_rwlock_tryrdlock(ast_rwlock_t *lock, const char *name,
1000 const char *file, int line, const char *func)
1002 int res;
1003 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
1004 int canlog = strcmp(file, "logger.c");
1006 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
1007 /* Don't warn abount uninitialized lock.
1008 * Simple try to initialize it.
1009 * May be not needed in linux system.
1011 res = __ast_rwlock_init(file, line, func, name, lock);
1012 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
1013 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1014 file, line, func, name);
1015 return res;
1018 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1020 ast_store_lock_info(AST_RDLOCK, file, line, func, name, lock);
1021 res = pthread_rwlock_tryrdlock(lock);
1022 if (!res)
1023 ast_mark_lock_acquired(lock);
1024 else
1025 ast_remove_lock_info(lock);
1026 return res;
1029 #define ast_rwlock_trywrlock(a) \
1030 _ast_rwlock_trywrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
1032 static inline int _ast_rwlock_trywrlock(ast_rwlock_t *lock, const char *name,
1033 const char *file, int line, const char *func)
1035 int res;
1036 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
1037 int canlog = strcmp(file, "logger.c");
1039 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
1040 /* Don't warn abount uninitialized lock.
1041 * Simple try to initialize it.
1042 * May be not needed in linux system.
1044 res = __ast_rwlock_init(file, line, func, name, lock);
1045 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
1046 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1047 file, line, func, name);
1048 return res;
1051 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1053 ast_store_lock_info(AST_WRLOCK, file, line, func, name, lock);
1054 res = pthread_rwlock_trywrlock(lock);
1055 if (!res)
1056 ast_mark_lock_acquired(lock);
1057 else
1058 ast_remove_lock_info(lock);
1059 return res;
1062 #else /* !DEBUG_THREADS */
1064 static inline int ast_rwlock_init(ast_rwlock_t *prwlock)
1066 int res;
1067 pthread_rwlockattr_t attr;
1069 pthread_rwlockattr_init(&attr);
1071 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
1072 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
1073 #endif
1075 res = pthread_rwlock_init(prwlock, &attr);
1076 pthread_rwlockattr_destroy(&attr);
1077 return res;
1080 static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
1082 return pthread_rwlock_destroy(prwlock);
1085 static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
1087 return pthread_rwlock_unlock(prwlock);
1090 static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
1092 return pthread_rwlock_rdlock(prwlock);
1095 static inline int ast_rwlock_tryrdlock(ast_rwlock_t *prwlock)
1097 return pthread_rwlock_tryrdlock(prwlock);
1100 static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
1102 return pthread_rwlock_wrlock(prwlock);
1105 static inline int ast_rwlock_trywrlock(ast_rwlock_t *prwlock)
1107 return pthread_rwlock_trywrlock(prwlock);
1109 #endif /* !DEBUG_THREADS */
1111 /* Statically declared read/write locks */
1113 #ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
1114 #define __AST_RWLOCK_DEFINE(scope, rwlock) \
1115 scope ast_rwlock_t rwlock; \
1116 static void __attribute__ ((constructor)) init_##rwlock(void) \
1118 ast_rwlock_init(&rwlock); \
1120 static void __attribute__ ((destructor)) fini_##rwlock(void) \
1122 ast_rwlock_destroy(&rwlock); \
1124 #else
1125 #define __AST_RWLOCK_DEFINE(scope, rwlock) \
1126 scope ast_rwlock_t rwlock = AST_RWLOCK_INIT_VALUE
1127 #endif
1129 #define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock)
1132 * Initial support for atomic instructions.
1133 * For platforms that have it, use the native cpu instruction to
1134 * implement them. For other platforms, resort to a 'slow' version
1135 * (defined in utils.c) that protects the atomic instruction with
1136 * a single lock.
1137 * The slow versions is always available, for testing purposes,
1138 * as ast_atomic_fetchadd_int_slow()
1141 int ast_atomic_fetchadd_int_slow(volatile int *p, int v);
1143 #include "asterisk/inline_api.h"
1145 #if defined(HAVE_OSX_ATOMICS)
1146 #include "libkern/OSAtomic.h"
1147 #endif
1149 /*! \brief Atomically add v to *p and return * the previous value of *p.
1150 * This can be used to handle reference counts, and the return value
1151 * can be used to generate unique identifiers.
1154 #if defined(HAVE_GCC_ATOMICS)
1155 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1157 return __sync_fetch_and_add(p, v);
1159 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
1160 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1162 return OSAtomicAdd32(v, (int32_t *) p) - v;
1164 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
1165 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1167 return OSAtomicAdd64(v, (int64_t *) p) - v;
1168 #elif defined (__i386__)
1169 #ifdef sun
1170 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1172 __asm __volatile (
1173 " lock; xaddl %0, %1 ; "
1174 : "+r" (v), /* 0 (result) */
1175 "=m" (*p) /* 1 */
1176 : "m" (*p)); /* 2 */
1177 return (v);
1179 #else /* ifndef sun */
1180 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1182 __asm __volatile (
1183 " lock xaddl %0, %1 ; "
1184 : "+r" (v), /* 0 (result) */
1185 "=m" (*p) /* 1 */
1186 : "m" (*p)); /* 2 */
1187 return (v);
1189 #endif
1190 #else /* low performance version in utils.c */
1191 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1193 return ast_atomic_fetchadd_int_slow(p, v);
1195 #endif
1197 /*! \brief decrement *p by 1 and return true if the variable has reached 0.
1198 * Useful e.g. to check if a refcount has reached 0.
1200 #if defined(HAVE_GCC_ATOMICS)
1201 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
1203 return __sync_sub_and_fetch(p, 1) == 0;
1205 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
1206 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
1208 return OSAtomicAdd32( -1, (int32_t *) p) == 0;
1210 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
1211 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
1213 return OSAtomicAdd64( -1, (int64_t *) p) == 0;
1214 #else
1215 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
1217 int a = ast_atomic_fetchadd_int(p, -1);
1218 return a == 1; /* true if the value is 0 now (so it was 1 previously) */
1220 #endif
1222 #ifndef DEBUG_CHANNEL_LOCKS
1223 /*! \brief Lock a channel. If DEBUG_CHANNEL_LOCKS is defined
1224 in the Makefile, print relevant output for debugging */
1225 #define ast_channel_lock(x) ast_mutex_lock(&x->lock)
1226 /*! \brief Unlock a channel. If DEBUG_CHANNEL_LOCKS is defined
1227 in the Makefile, print relevant output for debugging */
1228 #define ast_channel_unlock(x) ast_mutex_unlock(&x->lock)
1229 /*! \brief Try locking a channel. If DEBUG_CHANNEL_LOCKS is defined
1230 in the Makefile, print relevant output for debugging */
1231 #define ast_channel_trylock(x) ast_mutex_trylock(&x->lock)
1232 #else
1234 struct ast_channel;
1236 #define ast_channel_lock(a) __ast_channel_lock(a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
1237 /*! \brief Lock AST channel (and print debugging output)
1238 \note You need to enable DEBUG_CHANNEL_LOCKS for this function */
1239 int __ast_channel_lock(struct ast_channel *chan, const char *file, int lineno, const char *func);
1241 #define ast_channel_unlock(a) __ast_channel_unlock(a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
1242 /*! \brief Unlock AST channel (and print debugging output)
1243 \note You need to enable DEBUG_CHANNEL_LOCKS for this function
1245 int __ast_channel_unlock(struct ast_channel *chan, const char *file, int lineno, const char *func);
1247 #define ast_channel_trylock(a) __ast_channel_trylock(a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
1248 /*! \brief Lock AST channel (and print debugging output)
1249 \note You need to enable DEBUG_CHANNEL_LOCKS for this function */
1250 int __ast_channel_trylock(struct ast_channel *chan, const char *file, int lineno, const char *func);
1251 #endif
1253 #endif /* _ASTERISK_LOCK_H */