Newer
Older
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2006, Digium, Inc.
*
* Steve Murphy <murf@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*
*
* A condensation of the pbx_config stuff, to read into exensions.conf, and provide an interface to the data there,
* for operations outside of asterisk. A huge, awful hack.
*
*/
/*** MODULEINFO
<support_level>extended</support_level>
***/
#include "asterisk.h"
#include "asterisk/compat.h"
#include "asterisk/paths.h" /* we use AST_CONFIG_DIR */
#include <errno.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <stdarg.h>
#include <string.h>
#include <locale.h>
#include <ctype.h>
#if !defined(SOLARIS) && !defined(__CYGWIN__)
#include <err.h>
#endif
#include <regex.h>
#include <limits.h>
#include <pthread.h>
#include <netdb.h>
#include <sys/param.h>
Kevin P. Fleming
committed
static void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...) __attribute__((format(printf, 5, 6)));
void ast_verbose(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
#define ASINCLUDE_GLOB 1
#ifdef AST_INCLUDE_GLOB
Kevin P. Fleming
committed
#if !defined(GLOB_ABORTED)
#define GLOB_ABORTED GLOB_ABEND
#endif
Kevin P. Fleming
committed
# include <glob.h>
#endif
#define AST_API_MODULE 1 /* gimme the inline defs! */
struct ast_channel
{
char x; /* basically empty! */
};
#include "asterisk/inline_api.h"
#include "asterisk/endian.h"
#include "asterisk/ast_expr.h"
/* logger.h */
#define EVENTLOG "event_log"
#define QUEUELOG "queue_log"
#define DEBUG_M(a) { \
a; \
}
#define VERBOSE_PREFIX_1 " "
#define VERBOSE_PREFIX_2 " == "
#define VERBOSE_PREFIX_3 " -- "
#define VERBOSE_PREFIX_4 " > "
void ast_backtrace(void);
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...)
__attribute__((format(printf, 5, 6)));
/* IN CONFLICT: void ast_verbose(const char *fmt, ...)
__attribute__((format(printf, 1, 2))); */
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
int ast_register_verbose(void (*verboser)(const char *string));
int ast_unregister_verbose(void (*verboser)(const char *string));
void ast_console_puts(const char *string);
#define _A_ __FILE__, __LINE__, __PRETTY_FUNCTION__
#ifdef LOG_DEBUG
#undef LOG_DEBUG
#endif
#define __LOG_DEBUG 0
#define LOG_DEBUG __LOG_DEBUG, _A_
#ifdef LOG_EVENT
#undef LOG_EVENT
#endif
#define __LOG_EVENT 1
#define LOG_EVENT __LOG_EVENT, _A_
#ifdef LOG_NOTICE
#undef LOG_NOTICE
#endif
#define __LOG_NOTICE 2
#define LOG_NOTICE __LOG_NOTICE, _A_
#ifdef LOG_WARNING
#undef LOG_WARNING
#endif
#define __LOG_WARNING 3
#define LOG_WARNING __LOG_WARNING, _A_
#ifdef LOG_ERROR
#undef LOG_ERROR
#endif
#define __LOG_ERROR 4
#define LOG_ERROR __LOG_ERROR, _A_
#ifdef LOG_VERBOSE
#undef LOG_VERBOSE
#endif
#define __LOG_VERBOSE 5
#define LOG_VERBOSE __LOG_VERBOSE, _A_
#ifdef LOG_DTMF
#undef LOG_DTMF
#endif
#define __LOG_DTMF 6
#define LOG_DTMF __LOG_DTMF, _A_
#ifndef HAVE_MTX_PROFILE
#define __MTX_PROF(a) return pthread_mutex_lock((a))
#else
#define __MTX_PROF(a) do { \
int i; \
/* profile only non-blocking events */ \
ast_mark(mtx_prof, 1); \
i = pthread_mutex_trylock((a)); \
ast_mark(mtx_prof, 0); \
if (!i) \
return i; \
else \
return pthread_mutex_lock((a)); \
} while (0)
#endif /* HAVE_MTX_PROFILE */
#define AST_PTHREADT_NULL (pthread_t) -1
#define AST_PTHREADT_STOP (pthread_t) -2
#if defined(SOLARIS) || defined(BSD)
#define AST_MUTEX_INIT_W_CONSTRUCTORS
#endif /* SOLARIS || BSD */
/* Asterisk REQUIRES recursive (not error checking) mutexes
and will not run without them. */
#if defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) && defined(PTHREAD_MUTEX_RECURSIVE_NP)
#define PTHREAD_MUTEX_INIT_VALUE PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
#define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE_NP
#else
#define PTHREAD_MUTEX_INIT_VALUE PTHREAD_MUTEX_INITIALIZER
#define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE
#endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
#define __ast_mutex_logger(...) do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0)
#ifdef THREAD_CRASH
#define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
#else
#define DO_THREAD_CRASH do { } while (0)
#endif
#define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, { NULL }, { 0 }, 0, { NULL }, { 0 } }
struct ast_mutex_info {
pthread_mutex_t mutex;
/*! Track which thread holds this lock */
unsigned int track:1;
const char *file[AST_MAX_REENTRANCY];
int lineno[AST_MAX_REENTRANCY];
int reentrancy;
const char *func[AST_MAX_REENTRANCY];
pthread_t thread[AST_MAX_REENTRANCY];
};
static void __attribute__((constructor)) init_empty_mutex(void)
{
}
static inline int __ast_pthread_mutex_init_attr(const char *filename, int lineno, const char *func,
const char *mutex_name, ast_mutex_t *t,
pthread_mutexattr_t *attr)
{
#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
int canlog = strcmp(filename, "logger.c");
if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
if ((t->mutex) != (empty_mutex)) {
__ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is already initialized.\n",
filename, lineno, func, mutex_name);
__ast_mutex_logger("%s line %d (%s): Error: previously initialization of mutex '%s'.\n",
t->file[0], t->lineno[0], t->func[0], mutex_name);
DO_THREAD_CRASH;
return 0;
}
}
t->file[0] = filename;
t->lineno[0] = lineno;
t->func[0] = func;
t->thread[0] = 0;
t->reentrancy = 0;
static inline int __ast_pthread_mutex_init(const char *filename, int lineno, const char *func,
const char *mutex_name, ast_mutex_t *t)
{
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
return __ast_pthread_mutex_init_attr(filename, lineno, func, mutex_name, t, &attr);
}
#define ast_mutex_init(pmutex) __ast_pthread_mutex_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
const char *mutex_name, ast_mutex_t *t)
{
int res;
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
__ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
filename, lineno, func, mutex_name);
}
#endif
res = pthread_mutex_trylock(&t->mutex);
switch (res) {
case 0:
pthread_mutex_unlock(&t->mutex);
break;
case EINVAL:
__ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
filename, lineno, func, mutex_name);
break;
case EBUSY:
__ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
filename, lineno, func, mutex_name);
__ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
break;
}
if ((res = pthread_mutex_destroy(&t->mutex)))
__ast_mutex_logger("%s line %d (%s): Error destroying mutex: %s\n",
filename, lineno, func, strerror(res));
#ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
else
t->mutex = PTHREAD_MUTEX_INIT_VALUE;
#endif
t->file[0] = filename;
t->lineno[0] = lineno;
t->func[0] = func;
return res;
}
static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
const char* mutex_name, ast_mutex_t *t)
{
int res;
#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
__ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
filename, lineno, func, mutex_name);
ast_mutex_init(t);
}
#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
#ifdef DETECT_DEADLOCKS
{
time_t seconds = time(NULL);
time_t current;
do {
#ifdef HAVE_MTX_PROFILE
ast_mark(mtx_prof, 1);
#endif
res = pthread_mutex_trylock(&t->mutex);
#ifdef HAVE_MTX_PROFILE
ast_mark(mtx_prof, 0);
#endif
if (res == EBUSY) {
current = time(NULL);
if ((current - seconds) && (!((current - seconds) % 5))) {
__ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
filename, lineno, func, (int)(current - seconds), mutex_name);
__ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
t->file[t->reentrancy-1], t->lineno[t->reentrancy-1],
t->func[t->reentrancy-1], mutex_name);
}
usleep(200);
}
} while (res == EBUSY);
}
#else
#ifdef HAVE_MTX_PROFILE
ast_mark(mtx_prof, 1);
res = pthread_mutex_trylock(&t->mutex);
ast_mark(mtx_prof, 0);
if (res)
#endif
res = pthread_mutex_lock(&t->mutex);
#endif /* DETECT_DEADLOCKS */
if (!res) {
if (t->reentrancy < AST_MAX_REENTRANCY) {
t->file[t->reentrancy] = filename;
t->lineno[t->reentrancy] = lineno;
t->func[t->reentrancy] = func;
t->thread[t->reentrancy] = pthread_self();
t->reentrancy++;
} else {
__ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
filename, lineno, func, mutex_name);
}
} else {
__ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
filename, lineno, func, strerror(errno));
DO_THREAD_CRASH;
}
static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
const char* mutex_name, ast_mutex_t *t)
{
int res;
int canlog = strcmp(filename, "logger.c");
#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
__ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
filename, lineno, func, mutex_name);
ast_mutex_init(t);
}
#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
if (!(res = pthread_mutex_trylock(&t->mutex))) {
if (t->reentrancy < AST_MAX_REENTRANCY) {
t->file[t->reentrancy] = filename;
t->lineno[t->reentrancy] = lineno;
t->func[t->reentrancy] = func;
t->thread[t->reentrancy] = pthread_self();
t->reentrancy++;
} else {
__ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
filename, lineno, func, mutex_name);
}
} else {
__ast_mutex_logger("%s line %d (%s): Warning: '%s' was locked here.\n",
t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
}
static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
const char *mutex_name, ast_mutex_t *t)
{
int res;
int canlog = strcmp(filename, "logger.c");
#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
__ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
filename, lineno, func, mutex_name);
}
#endif
if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
__ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
filename, lineno, func, mutex_name);
__ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
DO_THREAD_CRASH;
}
if (--t->reentrancy < 0) {
__ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
filename, lineno, func, mutex_name);
t->reentrancy = 0;
}
if (t->reentrancy < AST_MAX_REENTRANCY) {
t->file[t->reentrancy] = NULL;
t->lineno[t->reentrancy] = 0;
t->func[t->reentrancy] = NULL;
t->thread[t->reentrancy] = 0;
}
if ((res = pthread_mutex_unlock(&t->mutex))) {
__ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n",
filename, lineno, func, strerror(res));
DO_THREAD_CRASH;
}
static inline int __ast_cond_init(const char *filename, int lineno, const char *func,
const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
{
}
static inline int __ast_cond_signal(const char *filename, int lineno, const char *func,
const char *cond_name, ast_cond_t *cond)
{
}
static inline int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
const char *cond_name, ast_cond_t *cond)
{
}
static inline int __ast_cond_destroy(const char *filename, int lineno, const char *func,
const char *cond_name, ast_cond_t *cond)
{
}
static inline int __ast_cond_wait(const char *filename, int lineno, const char *func,
const char *cond_name, const char *mutex_name,
ast_cond_t *cond, ast_mutex_t *t)
{
int res;
int canlog = strcmp(filename, "logger.c");
#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
__ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
filename, lineno, func, mutex_name);
}
#endif
if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
__ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
filename, lineno, func, mutex_name);
__ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
DO_THREAD_CRASH;
}
if (--t->reentrancy < 0) {
__ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
filename, lineno, func, mutex_name);
t->reentrancy = 0;
}
if (t->reentrancy < AST_MAX_REENTRANCY) {
t->file[t->reentrancy] = NULL;
t->lineno[t->reentrancy] = 0;
t->func[t->reentrancy] = NULL;
t->thread[t->reentrancy] = 0;
}
if ((res = pthread_cond_wait(cond, &t->mutex))) {
__ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
filename, lineno, func, strerror(res));
DO_THREAD_CRASH;
} else {
if (t->reentrancy < AST_MAX_REENTRANCY) {
t->file[t->reentrancy] = filename;
t->lineno[t->reentrancy] = lineno;
t->func[t->reentrancy] = func;
t->thread[t->reentrancy] = pthread_self();
t->reentrancy++;
} else {
__ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
filename, lineno, func, mutex_name);
}
}
}
static inline int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
const char *cond_name, const char *mutex_name, ast_cond_t *cond,
ast_mutex_t *t, const struct timespec *abstime)
{
int res;
int canlog = strcmp(filename, "logger.c");
#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
__ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
filename, lineno, func, mutex_name);
}
#endif
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
__ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
filename, lineno, func, mutex_name);
__ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
DO_THREAD_CRASH;
}
if (--t->reentrancy < 0) {
__ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
filename, lineno, func, mutex_name);
t->reentrancy = 0;
}
if (t->reentrancy < AST_MAX_REENTRANCY) {
t->file[t->reentrancy] = NULL;
t->lineno[t->reentrancy] = 0;
t->func[t->reentrancy] = NULL;
t->thread[t->reentrancy] = 0;
}
if ((res = pthread_cond_timedwait(cond, &t->mutex, abstime)) && (res != ETIMEDOUT)) {
__ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
filename, lineno, func, strerror(res));
DO_THREAD_CRASH;
} else {
if (t->reentrancy < AST_MAX_REENTRANCY) {
t->file[t->reentrancy] = filename;
t->lineno[t->reentrancy] = lineno;
t->func[t->reentrancy] = func;
t->thread[t->reentrancy] = pthread_self();
t->reentrancy++;
} else {
__ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
filename, lineno, func, mutex_name);
}
}
}
#define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
#define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
#define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
#define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
#define ast_cond_init(cond, attr) __ast_cond_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond, attr)
#define ast_cond_destroy(cond) __ast_cond_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
#define ast_cond_signal(cond) __ast_cond_signal(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
#define ast_cond_broadcast(cond) __ast_cond_broadcast(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
#define ast_cond_wait(cond, mutex) __ast_cond_wait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex)
#define ast_cond_timedwait(cond, mutex, time) __ast_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex, time)
#else /* !DEBUG_THREADS */
typedef pthread_mutex_t ast_mutex_t;
#define AST_MUTEX_INIT_VALUE ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
static inline int ast_mutex_init(ast_mutex_t *pmutex)
{
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
#define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
static inline int ast_mutex_unlock(ast_mutex_t *pmutex)
{
return pthread_mutex_unlock(pmutex);
}
static inline int ast_mutex_destroy(ast_mutex_t *pmutex)
{
return pthread_mutex_destroy(pmutex);
}
static inline int ast_mutex_lock(ast_mutex_t *pmutex)
{
__MTX_PROF(pmutex);
}
static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
{
return pthread_mutex_trylock(pmutex);
}
static inline int ast_cond_init(ast_cond_t *cond, pthread_condattr_t *cond_attr)
{
return pthread_cond_init(cond, cond_attr);
}
static inline int ast_cond_signal(ast_cond_t *cond)
{
return pthread_cond_signal(cond);
}
static inline int ast_cond_broadcast(ast_cond_t *cond)
Steve Murphy
committed
{
Steve Murphy
committed
}
static inline int ast_cond_destroy(ast_cond_t *cond)
Steve Murphy
committed
{
Steve Murphy
committed
}
static inline int ast_cond_wait(ast_cond_t *cond, ast_mutex_t *t)
Steve Murphy
committed
{
Steve Murphy
committed
}
static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime)
Steve Murphy
committed
{
return pthread_cond_timedwait(cond, t, abstime);
}
Steve Murphy
committed
#endif /* !DEBUG_THREADS */
#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
/* If AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
constructors/destructors to create/destroy mutexes. */
#define __AST_MUTEX_DEFINE(scope, mutex) \
scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \
static void __attribute__((constructor)) init_##mutex(void) \
static void __attribute__((destructor)) fini_##mutex(void) \
Steve Murphy
committed
}
#else /* !AST_MUTEX_INIT_W_CONSTRUCTORS */
/* By default, use static initialization of mutexes. */
#define __AST_MUTEX_DEFINE(scope, mutex) \
scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
Steve Murphy
committed
#define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
#define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
#define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
#define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
#define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init
#define pthread_mutex_destroy use_ast_mutex_destroy_instead_of_pthread_mutex_destroy
#define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t
#define pthread_cond_init use_ast_cond_init_instead_of_pthread_cond_init
#define pthread_cond_destroy use_ast_cond_destroy_instead_of_pthread_cond_destroy
#define pthread_cond_signal use_ast_cond_signal_instead_of_pthread_cond_signal
#define pthread_cond_broadcast use_ast_cond_broadcast_instead_of_pthread_cond_broadcast
#define pthread_cond_wait use_ast_cond_wait_instead_of_pthread_cond_wait
#define pthread_cond_timedwait use_ast_cond_timedwait_instead_of_pthread_cond_timedwait
Steve Murphy
committed
#define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex)
Steve Murphy
committed
#define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
Steve Murphy
committed
#define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
#ifndef __linux__
#define pthread_create __use_ast_pthread_create_instead__
#endif
static inline int ast_rwlock_init(ast_rwlock_t *prwlock)
{
pthread_rwlockattr_t attr;
#ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
#endif
return pthread_rwlock_init(prwlock, &attr);
}
static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
{
static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
{
return pthread_rwlock_unlock(prwlock);
}
static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
{
return pthread_rwlock_rdlock(prwlock);
}
static inline int ast_rwlock_tryrdlock(ast_rwlock_t *prwlock)
Steve Murphy
committed
{
Steve Murphy
committed
}
static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
Steve Murphy
committed
{
Steve Murphy
committed
}
static inline int ast_rwlock_trywrlock(ast_rwlock_t *prwlock)
Steve Murphy
committed
{
Steve Murphy
committed
}
Steve Murphy
committed
#ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
#define __AST_RWLOCK_DEFINE(scope, rwlock) \
scope ast_rwlock_t rwlock; \
static void __attribute__((constructor)) init_##rwlock(void) \
static void __attribute__((destructor)) fini_##rwlock(void) \
}
#else
#define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
#define __AST_RWLOCK_DEFINE(scope, rwlock) \
scope ast_rwlock_t rwlock = AST_RWLOCK_INIT_VALUE
#endif
#define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock)
/*
* Initial support for atomic instructions.
* For platforms that have it, use the native cpu instruction to
* implement them. For other platforms, resort to a 'slow' version
* (defined in utils.c) that protects the atomic instruction with
* a single lock.
* The slow versions is always available, for testing purposes,
* as ast_atomic_fetchadd_int_slow()
*/
#if defined(HAVE_OSX_ATOMICS)
#include "libkern/OSAtomic.h"
#endif
/*! \brief Atomically add v to *p and return * the previous value of *p.
* This can be used to handle reference counts, and the return value
* can be used to generate unique identifiers.
*/
#if defined(HAVE_GCC_ATOMICS)
AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
{
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
return __sync_fetch_and_add(p, v);
})
#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
{
return OSAtomicAdd32(v, (int32_t *) p);
})
#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
{
return OSAtomicAdd64(v, (int64_t *) p);
#elif defined (__i386__) || defined(__x86_64__)
AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
{
__asm __volatile (
" lock xaddl %0, %1 ; "
: "+r" (v), /* 0 (result) */
"=m" (*p) /* 1 */
: "m" (*p)); /* 2 */
return (v);
})
#else
static int ast_atomic_fetchadd_int_slow(volatile int *p, int v)
{
int ret;
ret = *p;
*p += v;
return ret;
}
AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
{
return ast_atomic_fetchadd_int_slow(p, v);
})
#endif
/*! \brief decrement *p by 1 and return true if the variable has reached 0.
* Useful e.g. to check if a refcount has reached 0.
*/
#if defined(HAVE_GCC_ATOMICS)
AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
{
return __sync_sub_and_fetch(p, 1) == 0;
})
#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
{
return OSAtomicAdd32( -1, (int32_t *) p) == 0;
})
#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
{
return OSAtomicAdd64( -1, (int64_t *) p) == 0;
#else
AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
{
int a = ast_atomic_fetchadd_int(p, -1);
return a == 1; /* true if the value is 0 now (so it was 1 previously) */
})
#endif
#ifndef DEBUG_CHANNEL_LOCKS
/*! \brief Lock a channel. If DEBUG_CHANNEL_LOCKS is defined
in the Makefile, print relevant output for debugging */
#define ast_channel_lock(x) ast_mutex_lock(&x->lock)
/*! \brief Unlock a channel. If DEBUG_CHANNEL_LOCKS is defined
in the Makefile, print relevant output for debugging */
#define ast_channel_unlock(x) ast_mutex_unlock(&x->lock)
/*! \brief Try locking a channel. If DEBUG_CHANNEL_LOCKS is defined
in the Makefile, print relevant output for debugging */
#define ast_channel_trylock(x) ast_mutex_trylock(&x->lock)
#else
/*! \brief Lock AST channel (and print debugging output)
\note You need to enable DEBUG_CHANNEL_LOCKS for this function */
int ast_channel_lock(struct ast_channel *chan);
/*! \brief Unlock AST channel (and print debugging output)
\note You need to enable DEBUG_CHANNEL_LOCKS for this function
*/
int ast_channel_unlock(struct ast_channel *chan);
/*! \brief Lock AST channel (and print debugging output)
\note You need to enable DEBUG_CHANNEL_LOCKS for this function */
int ast_channel_trylock(struct ast_channel *chan);
#endif
#include "asterisk/hashtab.h"
#include "asterisk/ael_structs.h"
#include "asterisk/pval.h"
#define ast_free_ptr free
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
#define MALLOC_FAILURE_MSG \
ast_log(LOG_ERROR, "Memory Allocation Failure in function %s at line %d of %s\n", func, lineno, file);
/*!
* \brief A wrapper for malloc()
*
* ast_malloc() is a wrapper for malloc() that will generate an Asterisk log
* message in the case that the allocation fails.
*
* The argument and return value are the same as malloc()
*/
#define ast_malloc(len) \
_ast_malloc((len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define ast_calloc(num, len) \
_ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define ast_calloc_cache(num, len) \
_ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define ast_realloc(p, len) \
_ast_realloc((p), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define ast_strdup(str) \
_ast_strdup((str), __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define ast_strndup(str, len) \
_ast_strndup((str), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define ast_asprintf(ret, fmt, ...) \
_ast_asprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, __VA_ARGS__)
#define ast_vasprintf(ret, fmt, ap) \
_ast_vasprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, (fmt), (ap))
struct ast_flags { /* stolen from utils.h */
unsigned int flags;
};
#define ast_test_flag(p,flag) ({ \
typeof ((p)->flags) __p = (p)->flags; \
typeof (__unsigned_int_flags_dummy) __x = 0; \
(void) (&__p == &__x); \
((p)->flags & (flag)); \
})
#define ast_set2_flag(p,value,flag) do { \
typeof ((p)->flags) __p = (p)->flags; \
typeof (__unsigned_int_flags_dummy) __x = 0; \
(void) (&__p == &__x); \
if (value) \
(p)->flags |= (flag); \
else \
(p)->flags &= ~(flag); \
} while (0)
#define MALLOC_FAILURE_MSG \
ast_log(LOG_ERROR, "Memory Allocation Failure in function %s at line %d of %s\n", func, lineno, file);
/*!
* \brief A wrapper for malloc()
*
* ast_malloc() is a wrapper for malloc() that will generate an Asterisk log
* message in the case that the allocation fails.
*
* The argument and return value are the same as malloc()
*/
#define ast_malloc(len) \
_ast_malloc((len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
AST_INLINE_API(
void * attribute_malloc _ast_malloc(size_t len, const char *file, int lineno, const char *func),
Steve Murphy
committed
{
void *p;
if (!(p = malloc(len)))
MALLOC_FAILURE_MSG;
return p;
Steve Murphy
committed
}
Steve Murphy
committed
/*!
* \brief A wrapper for calloc()
*
* ast_calloc() is a wrapper for calloc() that will generate an Asterisk log
* message in the case that the allocation fails.
*
* The arguments and return value are the same as calloc()
*/
#define ast_calloc(num, len) \
_ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
AST_INLINE_API(
void * attribute_malloc _ast_calloc(size_t num, size_t len, const char *file, int lineno, const char *func),