Show rwlocks in the "core show locks" output. Before, it only showed mutexes.
[asterisk-bristuff.git] / include / asterisk / lock.h
bloba0d1542e164b0e7322d5042df35688e6f0864bfb
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 } }
107 #define AST_MUTEX_INIT_VALUE_NOTRACKING \
108 { PTHREAD_MUTEX_INIT_VALUE, 0, { NULL }, { 0 }, 0, { NULL }, { 0 } }
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];
123 typedef struct ast_mutex_info ast_mutex_t;
125 typedef pthread_cond_t ast_cond_t;
127 static pthread_mutex_t empty_mutex;
130 * \brief Store lock info for the current thread
132 * This function gets called in ast_mutex_lock() and ast_mutex_trylock() so
133 * that information about this lock can be stored in this thread's
134 * lock info struct. The lock is marked as pending as the thread is waiting
135 * on the lock. ast_mark_lock_acquired() will mark it as held by this thread.
137 void ast_store_lock_info(const char *filename, int line_num,
138 const char *func, const char *lock_name, void *lock_addr);
141 * \brief Mark the last lock as acquired
143 void ast_mark_lock_acquired(void);
146 * \brief remove lock info for the current thread
148 * this gets called by ast_mutex_unlock so that information on the lock can
149 * be removed from the current thread's lock info struct.
151 void ast_remove_lock_info(void *lock_addr);
153 static void __attribute__((constructor)) init_empty_mutex(void)
155 memset(&empty_mutex, 0, sizeof(empty_mutex));
158 static inline int __ast_pthread_mutex_init_attr(int track, const char *filename, int lineno, const char *func,
159 const char *mutex_name, ast_mutex_t *t,
160 pthread_mutexattr_t *attr)
162 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
163 int canlog = strcmp(filename, "logger.c");
165 if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
166 if ((t->mutex) != (empty_mutex)) {
167 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is already initialized.\n",
168 filename, lineno, func, mutex_name);
169 __ast_mutex_logger("%s line %d (%s): Error: previously initialization of mutex '%s'.\n",
170 t->file[0], t->lineno[0], t->func[0], mutex_name);
171 DO_THREAD_CRASH;
172 return 0;
175 #endif
177 t->file[0] = filename;
178 t->lineno[0] = lineno;
179 t->func[0] = func;
180 t->thread[0] = 0;
181 t->reentrancy = 0;
182 t->track = track;
184 return pthread_mutex_init(&t->mutex, attr);
187 static inline int __ast_pthread_mutex_init(int track, const char *filename, int lineno, const char *func,
188 const char *mutex_name, ast_mutex_t *t)
190 static pthread_mutexattr_t attr;
192 pthread_mutexattr_init(&attr);
193 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
195 return __ast_pthread_mutex_init_attr(track, filename, lineno, func, mutex_name, t, &attr);
197 #define ast_mutex_init(pmutex) __ast_pthread_mutex_init(1, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
198 #define ast_mutex_init_notracking(pmutex) \
199 __ast_pthread_mutex_init(0, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
201 static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
202 const char *mutex_name, ast_mutex_t *t)
204 int res;
205 int canlog = strcmp(filename, "logger.c");
207 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
208 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
209 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
210 filename, lineno, func, mutex_name);
212 #endif
214 res = pthread_mutex_trylock(&t->mutex);
215 switch (res) {
216 case 0:
217 pthread_mutex_unlock(&t->mutex);
218 break;
219 case EINVAL:
220 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
221 filename, lineno, func, mutex_name);
222 break;
223 case EBUSY:
224 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
225 filename, lineno, func, mutex_name);
226 __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
227 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
228 break;
231 if ((res = pthread_mutex_destroy(&t->mutex)))
232 __ast_mutex_logger("%s line %d (%s): Error destroying mutex: %s\n",
233 filename, lineno, func, strerror(res));
234 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
235 else
236 t->mutex = PTHREAD_MUTEX_INIT_VALUE;
237 #endif
238 t->file[0] = filename;
239 t->lineno[0] = lineno;
240 t->func[0] = func;
242 return res;
245 static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
246 const char* mutex_name, ast_mutex_t *t)
248 int res;
249 int canlog = strcmp(filename, "logger.c");
251 if (t->track)
252 ast_store_lock_info(filename, lineno, func, mutex_name, &t->mutex);
254 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
255 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
256 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
257 filename, lineno, func, mutex_name);
258 ast_mutex_init(t);
260 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
262 #ifdef DETECT_DEADLOCKS
264 time_t seconds = time(NULL);
265 time_t current;
266 do {
267 #ifdef HAVE_MTX_PROFILE
268 ast_mark(mtx_prof, 1);
269 #endif
270 res = pthread_mutex_trylock(&t->mutex);
271 #ifdef HAVE_MTX_PROFILE
272 ast_mark(mtx_prof, 0);
273 #endif
274 if (res == EBUSY) {
275 current = time(NULL);
276 if ((current - seconds) && (!((current - seconds) % 5))) {
277 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
278 filename, lineno, func, (int)(current - seconds), mutex_name);
279 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
280 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1],
281 t->func[t->reentrancy-1], mutex_name);
283 usleep(200);
285 } while (res == EBUSY);
287 #else
288 #ifdef HAVE_MTX_PROFILE
289 ast_mark(mtx_prof, 1);
290 res = pthread_mutex_trylock(&t->mutex);
291 ast_mark(mtx_prof, 0);
292 if (res)
293 #endif
294 res = pthread_mutex_lock(&t->mutex);
295 #endif /* DETECT_DEADLOCKS */
297 if (!res) {
298 if (t->track)
299 ast_mark_lock_acquired();
300 if (t->reentrancy < AST_MAX_REENTRANCY) {
301 t->file[t->reentrancy] = filename;
302 t->lineno[t->reentrancy] = lineno;
303 t->func[t->reentrancy] = func;
304 t->thread[t->reentrancy] = pthread_self();
305 t->reentrancy++;
306 } else {
307 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
308 filename, lineno, func, mutex_name);
310 } else {
311 if (t->track)
312 ast_remove_lock_info(&t->mutex);
313 __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
314 filename, lineno, func, strerror(res));
315 DO_THREAD_CRASH;
318 return res;
321 static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
322 const char* mutex_name, ast_mutex_t *t)
324 int res;
325 int canlog = strcmp(filename, "logger.c");
327 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
328 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
329 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
330 filename, lineno, func, mutex_name);
331 ast_mutex_init(t);
333 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
335 if (t->track)
336 ast_store_lock_info(filename, lineno, func, mutex_name, &t->mutex);
338 if (!(res = pthread_mutex_trylock(&t->mutex))) {
339 if (t->track)
340 ast_mark_lock_acquired();
341 if (t->reentrancy < AST_MAX_REENTRANCY) {
342 t->file[t->reentrancy] = filename;
343 t->lineno[t->reentrancy] = lineno;
344 t->func[t->reentrancy] = func;
345 t->thread[t->reentrancy] = pthread_self();
346 t->reentrancy++;
347 } else {
348 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
349 filename, lineno, func, mutex_name);
351 } else if (t->track) {
352 ast_remove_lock_info(&t->mutex);
355 return res;
358 static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
359 const char *mutex_name, ast_mutex_t *t)
361 int res;
362 int canlog = strcmp(filename, "logger.c");
364 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
365 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
366 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
367 filename, lineno, func, mutex_name);
369 #endif
371 if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
372 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
373 filename, lineno, func, mutex_name);
374 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
375 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
376 DO_THREAD_CRASH;
379 if (--t->reentrancy < 0) {
380 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
381 filename, lineno, func, mutex_name);
382 t->reentrancy = 0;
385 if (t->reentrancy < AST_MAX_REENTRANCY) {
386 t->file[t->reentrancy] = NULL;
387 t->lineno[t->reentrancy] = 0;
388 t->func[t->reentrancy] = NULL;
389 t->thread[t->reentrancy] = 0;
392 if (t->track)
393 ast_remove_lock_info(&t->mutex);
395 if ((res = pthread_mutex_unlock(&t->mutex))) {
396 __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n",
397 filename, lineno, func, strerror(res));
398 DO_THREAD_CRASH;
401 return res;
404 static inline int __ast_cond_init(const char *filename, int lineno, const char *func,
405 const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
407 return pthread_cond_init(cond, cond_attr);
410 static inline int __ast_cond_signal(const char *filename, int lineno, const char *func,
411 const char *cond_name, ast_cond_t *cond)
413 return pthread_cond_signal(cond);
416 static inline int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
417 const char *cond_name, ast_cond_t *cond)
419 return pthread_cond_broadcast(cond);
422 static inline int __ast_cond_destroy(const char *filename, int lineno, const char *func,
423 const char *cond_name, ast_cond_t *cond)
425 return pthread_cond_destroy(cond);
428 static inline int __ast_cond_wait(const char *filename, int lineno, const char *func,
429 const char *cond_name, const char *mutex_name,
430 ast_cond_t *cond, ast_mutex_t *t)
432 int res;
433 int canlog = strcmp(filename, "logger.c");
435 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
436 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
437 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
438 filename, lineno, func, mutex_name);
440 #endif
442 if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
443 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
444 filename, lineno, func, mutex_name);
445 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
446 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
447 DO_THREAD_CRASH;
450 if (--t->reentrancy < 0) {
451 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
452 filename, lineno, func, mutex_name);
453 t->reentrancy = 0;
456 if (t->reentrancy < AST_MAX_REENTRANCY) {
457 t->file[t->reentrancy] = NULL;
458 t->lineno[t->reentrancy] = 0;
459 t->func[t->reentrancy] = NULL;
460 t->thread[t->reentrancy] = 0;
463 if (t->track)
464 ast_remove_lock_info(&t->mutex);
466 if ((res = pthread_cond_wait(cond, &t->mutex))) {
467 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
468 filename, lineno, func, strerror(res));
469 DO_THREAD_CRASH;
470 } else {
471 if (t->track)
472 ast_store_lock_info(filename, lineno, func, mutex_name, &t->mutex);
474 if (t->reentrancy < AST_MAX_REENTRANCY) {
475 t->file[t->reentrancy] = filename;
476 t->lineno[t->reentrancy] = lineno;
477 t->func[t->reentrancy] = func;
478 t->thread[t->reentrancy] = pthread_self();
479 t->reentrancy++;
480 } else {
481 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
482 filename, lineno, func, mutex_name);
486 return res;
489 static inline int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
490 const char *cond_name, const char *mutex_name, ast_cond_t *cond,
491 ast_mutex_t *t, const struct timespec *abstime)
493 int res;
494 int canlog = strcmp(filename, "logger.c");
496 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
497 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
498 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
499 filename, lineno, func, mutex_name);
501 #endif
503 if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
504 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
505 filename, lineno, func, mutex_name);
506 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
507 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
508 DO_THREAD_CRASH;
511 if (--t->reentrancy < 0) {
512 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
513 filename, lineno, func, mutex_name);
514 t->reentrancy = 0;
517 if (t->reentrancy < AST_MAX_REENTRANCY) {
518 t->file[t->reentrancy] = NULL;
519 t->lineno[t->reentrancy] = 0;
520 t->func[t->reentrancy] = NULL;
521 t->thread[t->reentrancy] = 0;
524 if (t->track)
525 ast_remove_lock_info(&t->mutex);
527 if ((res = pthread_cond_timedwait(cond, &t->mutex, abstime)) && (res != ETIMEDOUT)) {
528 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
529 filename, lineno, func, strerror(res));
530 DO_THREAD_CRASH;
531 } else {
532 if (t->track)
533 ast_store_lock_info(filename, lineno, func, mutex_name, &t->mutex);
535 if (t->reentrancy < AST_MAX_REENTRANCY) {
536 t->file[t->reentrancy] = filename;
537 t->lineno[t->reentrancy] = lineno;
538 t->func[t->reentrancy] = func;
539 t->thread[t->reentrancy] = pthread_self();
540 t->reentrancy++;
541 } else {
542 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
543 filename, lineno, func, mutex_name);
547 return res;
550 #define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
551 #define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
552 #define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
553 #define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
554 #define ast_cond_init(cond, attr) __ast_cond_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond, attr)
555 #define ast_cond_destroy(cond) __ast_cond_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
556 #define ast_cond_signal(cond) __ast_cond_signal(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
557 #define ast_cond_broadcast(cond) __ast_cond_broadcast(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
558 #define ast_cond_wait(cond, mutex) __ast_cond_wait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex)
559 #define ast_cond_timedwait(cond, mutex, time) __ast_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex, time)
561 #else /* !DEBUG_THREADS */
564 typedef pthread_mutex_t ast_mutex_t;
566 #define AST_MUTEX_INIT_VALUE ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
567 #define AST_MUTEX_INIT_VALUE_NOTRACKING \
568 ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
570 #define ast_mutex_init_notracking(m) ast_mutex_init(m)
572 static inline int ast_mutex_init(ast_mutex_t *pmutex)
574 pthread_mutexattr_t attr;
576 pthread_mutexattr_init(&attr);
577 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
579 return pthread_mutex_init(pmutex, &attr);
582 #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
584 static inline int ast_mutex_unlock(ast_mutex_t *pmutex)
586 return pthread_mutex_unlock(pmutex);
589 static inline int ast_mutex_destroy(ast_mutex_t *pmutex)
591 return pthread_mutex_destroy(pmutex);
594 static inline int ast_mutex_lock(ast_mutex_t *pmutex)
596 __MTX_PROF(pmutex);
599 static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
601 return pthread_mutex_trylock(pmutex);
604 typedef pthread_cond_t ast_cond_t;
606 static inline int ast_cond_init(ast_cond_t *cond, pthread_condattr_t *cond_attr)
608 return pthread_cond_init(cond, cond_attr);
611 static inline int ast_cond_signal(ast_cond_t *cond)
613 return pthread_cond_signal(cond);
616 static inline int ast_cond_broadcast(ast_cond_t *cond)
618 return pthread_cond_broadcast(cond);
621 static inline int ast_cond_destroy(ast_cond_t *cond)
623 return pthread_cond_destroy(cond);
626 static inline int ast_cond_wait(ast_cond_t *cond, ast_mutex_t *t)
628 return pthread_cond_wait(cond, t);
631 static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime)
633 return pthread_cond_timedwait(cond, t, abstime);
636 #endif /* !DEBUG_THREADS */
638 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
639 /* If AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
640 constructors/destructors to create/destroy mutexes. */
641 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track) \
642 scope ast_mutex_t mutex = init_val; \
643 static void __attribute__ ((constructor)) init_##mutex(void) \
645 if (track) \
646 ast_mutex_init(&mutex); \
647 else \
648 ast_mutex_init_notracking(&mutex); \
650 static void __attribute__ ((destructor)) fini_##mutex(void) \
652 ast_mutex_destroy(&mutex); \
654 #else /* !AST_MUTEX_INIT_W_CONSTRUCTORS */
655 /* By default, use static initialization of mutexes. */
656 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track) \
657 scope ast_mutex_t mutex = init_val
658 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
660 #define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
661 #define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
662 #define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
663 #define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
664 #define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init
665 #define pthread_mutex_destroy use_ast_mutex_destroy_instead_of_pthread_mutex_destroy
666 #define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t
667 #define pthread_cond_init use_ast_cond_init_instead_of_pthread_cond_init
668 #define pthread_cond_destroy use_ast_cond_destroy_instead_of_pthread_cond_destroy
669 #define pthread_cond_signal use_ast_cond_signal_instead_of_pthread_cond_signal
670 #define pthread_cond_broadcast use_ast_cond_broadcast_instead_of_pthread_cond_broadcast
671 #define pthread_cond_wait use_ast_cond_wait_instead_of_pthread_cond_wait
672 #define pthread_cond_timedwait use_ast_cond_timedwait_instead_of_pthread_cond_timedwait
674 #define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE, 1)
675 #define AST_MUTEX_DEFINE_STATIC_NOTRACKING(mutex) __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE_NOTRACKING, 0)
677 #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
679 #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
681 #ifndef __linux__
682 #define pthread_create __use_ast_pthread_create_instead__
683 #endif
685 typedef pthread_rwlock_t ast_rwlock_t;
687 static inline int ast_rwlock_init(ast_rwlock_t *prwlock)
689 pthread_rwlockattr_t attr;
691 pthread_rwlockattr_init(&attr);
693 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
694 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
695 #endif
697 return pthread_rwlock_init(prwlock, &attr);
700 static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
702 return pthread_rwlock_destroy(prwlock);
705 #ifdef DEBUG_THREADS
706 #define ast_rwlock_unlock(a) \
707 _ast_rwlock_unlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
709 static inline int _ast_rwlock_unlock(ast_rwlock_t *lock, const char *name,
710 const char *file, int line, const char *func)
712 int res;
713 res = pthread_rwlock_unlock(lock);
714 ast_remove_lock_info(lock);
715 return res;
718 #define ast_rwlock_rdlock(a) \
719 _ast_rwlock_rdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
721 static inline int _ast_rwlock_rdlock(ast_rwlock_t *lock, const char *name,
722 const char *file, int line, const char *func)
724 int res;
725 ast_store_lock_info(file, line, func, name, lock);
726 res = pthread_rwlock_rdlock(lock);
727 if (!res)
728 ast_mark_lock_acquired();
729 else
730 ast_remove_lock_info(lock);
731 return res;
734 #define ast_rwlock_wrlock(a) \
735 _ast_rwlock_wrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
737 static inline int _ast_rwlock_wrlock(ast_rwlock_t *lock, const char *name,
738 const char *file, int line, const char *func)
740 int res;
741 ast_store_lock_info(file, line, func, name, lock);
742 res = pthread_rwlock_wrlock(lock);
743 if (!res)
744 ast_mark_lock_acquired();
745 else
746 ast_remove_lock_info(lock);
747 return res;
750 #define ast_rwlock_tryrdlock(a) \
751 _ast_rwlock_tryrdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
753 static inline int _ast_rwlock_tryrdlock(ast_rwlock_t *lock, const char *name,
754 const char *file, int line, const char *func)
756 int res;
757 ast_store_lock_info(file, line, func, name, lock);
758 res = pthread_rwlock_tryrdlock(lock);
759 if (!res)
760 ast_mark_lock_acquired();
761 else
762 ast_remove_lock_info(lock);
763 return res;
766 #define ast_rwlock_trywrlock(a) \
767 _ast_rwlock_trywrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
769 static inline int _ast_rwlock_trywrlock(ast_rwlock_t *lock, const char *name,
770 const char *file, int line, const char *func)
772 int res;
773 ast_store_lock_info(file, line, func, name, lock);
774 res = pthread_rwlock_trywrlock(lock);
775 if (!res)
776 ast_mark_lock_acquired();
777 else
778 ast_remove_lock_info(lock);
779 return res;
782 #else
783 static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
785 return pthread_rwlock_unlock(prwlock);
788 static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
790 return pthread_rwlock_rdlock(prwlock);
793 static inline int ast_rwlock_tryrdlock(ast_rwlock_t *prwlock)
795 return pthread_rwlock_tryrdlock(prwlock);
798 static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
800 return pthread_rwlock_wrlock(prwlock);
803 static inline int ast_rwlock_trywrlock(ast_rwlock_t *prwlock)
805 return pthread_rwlock_trywrlock(prwlock);
807 #endif /* DEBUG_THREADS */
809 /* Statically declared read/write locks */
811 #ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
812 #define __AST_RWLOCK_DEFINE(scope, rwlock) \
813 scope ast_rwlock_t rwlock; \
814 static void __attribute__ ((constructor)) init_##rwlock(void) \
816 ast_rwlock_init(&rwlock); \
818 static void __attribute__ ((destructor)) fini_##rwlock(void) \
820 ast_rwlock_destroy(&rwlock); \
822 #else
823 #define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
824 #define __AST_RWLOCK_DEFINE(scope, rwlock) \
825 scope ast_rwlock_t rwlock = AST_RWLOCK_INIT_VALUE
826 #endif
828 #define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock)
831 * Initial support for atomic instructions.
832 * For platforms that have it, use the native cpu instruction to
833 * implement them. For other platforms, resort to a 'slow' version
834 * (defined in utils.c) that protects the atomic instruction with
835 * a single lock.
836 * The slow versions is always available, for testing purposes,
837 * as ast_atomic_fetchadd_int_slow()
840 int ast_atomic_fetchadd_int_slow(volatile int *p, int v);
842 #include "asterisk/inline_api.h"
844 #if defined(HAVE_OSX_ATOMICS)
845 #include "libkern/OSAtomic.h"
846 #endif
848 /*! \brief Atomically add v to *p and return * the previous value of *p.
849 * This can be used to handle reference counts, and the return value
850 * can be used to generate unique identifiers.
853 #if defined(HAVE_GCC_ATOMICS)
854 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
856 return __sync_fetch_and_add(p, v);
858 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
859 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
861 return OSAtomicAdd32(v, (int32_t *) p);
863 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
864 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
866 return OSAtomicAdd64(v, (int64_t *) p);
867 #elif defined (__i386__)
868 #ifdef sun
869 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
871 __asm __volatile (
872 " lock; xaddl %0, %1 ; "
873 : "+r" (v), /* 0 (result) */
874 "=m" (*p) /* 1 */
875 : "m" (*p)); /* 2 */
876 return (v);
878 #else /* ifndef sun */
879 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
881 __asm __volatile (
882 " lock xaddl %0, %1 ; "
883 : "+r" (v), /* 0 (result) */
884 "=m" (*p) /* 1 */
885 : "m" (*p)); /* 2 */
886 return (v);
888 #endif
889 #else /* low performance version in utils.c */
890 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
892 return ast_atomic_fetchadd_int_slow(p, v);
894 #endif
896 /*! \brief decrement *p by 1 and return true if the variable has reached 0.
897 * Useful e.g. to check if a refcount has reached 0.
899 #if defined(HAVE_GCC_ATOMICS)
900 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
902 return __sync_sub_and_fetch(p, 1) == 0;
904 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
905 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
907 return OSAtomicAdd32( -1, (int32_t *) p) == 0;
909 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
910 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
912 return OSAtomicAdd64( -1, (int64_t *) p) == 0;
913 #else
914 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
916 int a = ast_atomic_fetchadd_int(p, -1);
917 return a == 1; /* true if the value is 0 now (so it was 1 previously) */
919 #endif
921 #ifndef DEBUG_CHANNEL_LOCKS
922 /*! \brief Lock a channel. If DEBUG_CHANNEL_LOCKS is defined
923 in the Makefile, print relevant output for debugging */
924 #define ast_channel_lock(x) ast_mutex_lock(&x->lock)
925 /*! \brief Unlock a channel. If DEBUG_CHANNEL_LOCKS is defined
926 in the Makefile, print relevant output for debugging */
927 #define ast_channel_unlock(x) ast_mutex_unlock(&x->lock)
928 /*! \brief Try locking a channel. If DEBUG_CHANNEL_LOCKS is defined
929 in the Makefile, print relevant output for debugging */
930 #define ast_channel_trylock(x) ast_mutex_trylock(&x->lock)
931 #else
933 struct ast_channel;
935 /*! \brief Lock AST channel (and print debugging output)
936 \note You need to enable DEBUG_CHANNEL_LOCKS for this function */
937 int ast_channel_lock(struct ast_channel *chan);
939 /*! \brief Unlock AST channel (and print debugging output)
940 \note You need to enable DEBUG_CHANNEL_LOCKS for this function
942 int ast_channel_unlock(struct ast_channel *chan);
944 /*! \brief Lock AST channel (and print debugging output)
945 \note You need to enable DEBUG_CHANNEL_LOCKS for this function */
946 int ast_channel_trylock(struct ast_channel *chan);
947 #endif
949 #endif /* _ASTERISK_LOCK_H */