(closes issue #13557)
[asterisk/asterisk.git] / utils / extconf.c
index a64258c..78b9113 100644 (file)
@@ -23,6 +23,9 @@
  * for operations outside of asterisk. A huge, awful hack.
  *
  */
+#include "asterisk.h"
+
+#undef DEBUG_THREADS
 
 #include "asterisk/compat.h"
 #include "asterisk/paths.h"    /* we use AST_CONFIG_DIR */
@@ -65,10 +68,9 @@ struct ast_channel
 #include "asterisk/inline_api.h"
 #include "asterisk/endian.h"
 #include "asterisk/ast_expr.h"
-#include "asterisk/ael_structs.h"
-#include "asterisk/pval.h"
 
 /* logger.h */
+
 #define EVENTLOG "event_log"
 #define        QUEUELOG        "queue_log"
 
@@ -81,12 +83,6 @@ struct ast_channel
 #define VERBOSE_PREFIX_3 "    -- "
 #define VERBOSE_PREFIX_4 "       > "
 
-/* IN CONFLICT: void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
-   __attribute__ ((format (printf, 5, 6))); */
-
-static void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...) __attribute__ ((format (printf,5,6)));
-
-
 void ast_backtrace(void);
 
 void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...)
@@ -100,9 +96,6 @@ int ast_unregister_verbose(void (*verboser)(const char *string));
 
 void ast_console_puts(const char *string);
 
-void ast_console_puts_mutable(const char *string);
-void ast_console_toggle_mute(int fd);
-
 #define _A_ __FILE__, __LINE__, __PRETTY_FUNCTION__
 
 #ifdef LOG_DEBUG
@@ -147,1707 +140,1666 @@ void ast_console_toggle_mute(int fd);
 #define __LOG_DTMF  6
 #define LOG_DTMF    __LOG_DTMF, _A_
 
-/* from utils.h */
-
-static unsigned int __unsigned_int_flags_dummy;
+/* lock.h */
 
-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)); \
-                                       })
+#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_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 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 */
 
-#ifdef __AST_DEBUG_MALLOC
-static void ast_free(void *ptr) attribute_unused;
-static void ast_free(void *ptr)
-{
-       free(ptr);
-}
+/* 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 ast_free free
-#endif
-
-#ifndef __AST_DEBUG_MALLOC
-
-#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 PTHREAD_MUTEX_INIT_VALUE       PTHREAD_MUTEX_INITIALIZER
+#define AST_MUTEX_KIND                 PTHREAD_MUTEX_RECURSIVE
+#endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
 
-AST_INLINE_API(
-void * attribute_malloc _ast_malloc(size_t len, const char *file, int lineno, const char *func),
-{
-       void *p;
+#ifdef DEBUG_THREADS
 
-       if (!(p = malloc(len)))
-               MALLOC_FAILURE_MSG;
+#define __ast_mutex_logger(...)  do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0)
 
-       return p;
-}
-)
+#ifdef THREAD_CRASH
+#define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
+#else
+#define DO_THREAD_CRASH do { } while (0)
+#endif
 
-/*!
- * \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__)
+#define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, { NULL }, { 0 }, 0, { NULL }, { 0 } }
 
-AST_INLINE_API(
-void * attribute_malloc _ast_calloc(size_t num, size_t len, const char *file, int lineno, const char *func),
-{
-       void *p;
+#define AST_MAX_REENTRANCY 10
 
-       if (!(p = calloc(num, len)))
-               MALLOC_FAILURE_MSG;
+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];
+};
 
-       return p;
-}
-)
+typedef struct ast_mutex_info ast_mutex_t;
 
-/*!
- * \brief A wrapper for calloc() for use in cache pools
- *
- * ast_calloc_cache() is a wrapper for calloc() that will generate an Asterisk log
- * message in the case that the allocation fails. When memory debugging is in use,
- * the memory allocated by this function will be marked as 'cache' so it can be
- * distinguished from normal memory allocations.
- *
- * The arguments and return value are the same as calloc()
- */
-#define ast_calloc_cache(num, len) \
-       _ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+typedef pthread_cond_t ast_cond_t;
 
-/*!
- * \brief A wrapper for realloc()
- *
- * ast_realloc() is a wrapper for realloc() that will generate an Asterisk log
- * message in the case that the allocation fails.
- *
- * The arguments and return value are the same as realloc()
- */
-#define ast_realloc(p, len) \
-       _ast_realloc((p), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+static pthread_mutex_t empty_mutex;
 
-AST_INLINE_API(
-void * attribute_malloc _ast_realloc(void *p, size_t len, const char *file, int lineno, const char *func),
+static void __attribute__((constructor)) init_empty_mutex(void)
 {
-       void *newp;
-
-       if (!(newp = realloc(p, len)))
-               MALLOC_FAILURE_MSG;
-
-       return newp;
+       memset(&empty_mutex, 0, sizeof(empty_mutex));
 }
-)
-
-/*!
- * \brief A wrapper for strdup()
- *
- * ast_strdup() is a wrapper for strdup() that will generate an Asterisk log
- * message in the case that the allocation fails.
- *
- * ast_strdup(), unlike strdup(), can safely accept a NULL argument. If a NULL
- * argument is provided, ast_strdup will return NULL without generating any
- * kind of error log message.
- *
- * The argument and return value are the same as strdup()
- */
-#define ast_strdup(str) \
-       _ast_strdup((str), __FILE__, __LINE__, __PRETTY_FUNCTION__)
 
-AST_INLINE_API(
-char * attribute_malloc _ast_strdup(const char *str, const char *file, int lineno, const char *func),
+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) 
 {
-       char *newstr = NULL;
+#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
+       int canlog = strcmp(filename, "logger.c");
 
-       if (str) {
-               if (!(newstr = strdup(str)))
-                       MALLOC_FAILURE_MSG;
+       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;
+               }
        }
+#endif
 
-       return newstr;
-}
-)
+       t->file[0] = filename;
+       t->lineno[0] = lineno;
+       t->func[0] = func;
+       t->thread[0]  = 0;
+       t->reentrancy = 0;
 
-/*!
- * \brief A wrapper for strndup()
- *
- * ast_strndup() is a wrapper for strndup() that will generate an Asterisk log
- * message in the case that the allocation fails.
- *
- * ast_strndup(), unlike strndup(), can safely accept a NULL argument for the
- * string to duplicate. If a NULL argument is provided, ast_strdup will return  
- * NULL without generating any kind of error log message.
- *
- * The arguments and return value are the same as strndup()
- */
-#define ast_strndup(str, len) \
-       _ast_strndup((str), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+       return pthread_mutex_init(&t->mutex, attr);
+}
 
-AST_INLINE_API(
-char * attribute_malloc _ast_strndup(const char *str, size_t len, const char *file, int lineno, const char *func),
+static inline int __ast_pthread_mutex_init(const char *filename, int lineno, const char *func,
+                                          const char *mutex_name, ast_mutex_t *t)
 {
-       char *newstr = NULL;
+       static pthread_mutexattr_t  attr;
 
-       if (str) {
-               if (!(newstr = strndup(str, len)))
-                       MALLOC_FAILURE_MSG;
-       }
+       pthread_mutexattr_init(&attr);
+       pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
 
-       return newstr;
+       return __ast_pthread_mutex_init_attr(filename, lineno, func, mutex_name, t, &attr);
 }
-)
-
-/*!
- * \brief A wrapper for asprintf()
- *
- * ast_asprintf() is a wrapper for asprintf() that will generate an Asterisk log
- * message in the case that the allocation fails.
- *
- * The arguments and return value are the same as asprintf()
- */
-#define ast_asprintf(ret, fmt, ...) \
-       _ast_asprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, __VA_ARGS__)
+#define ast_mutex_init(pmutex) __ast_pthread_mutex_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
 
-AST_INLINE_API(
-int _ast_asprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, ...),
+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;
-       va_list ap;
+       int canlog = strcmp(filename, "logger.c");
 
-       va_start(ap, fmt);
-       if ((res = vasprintf(ret, fmt, ap)) == -1)
-               MALLOC_FAILURE_MSG;
-       va_end(ap);
+#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;
 }
-)
-
-/*!
- * \brief A wrapper for vasprintf()
- *
- * ast_vasprintf() is a wrapper for vasprintf() that will generate an Asterisk log
- * message in the case that the allocation fails.
- *
- * The arguments and return value are the same as vasprintf()
- */
-#define ast_vasprintf(ret, fmt, ap) \
-       _ast_vasprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, (fmt), (ap))
 
-AST_INLINE_API(
-int _ast_vasprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, va_list ap),
+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;
+       int canlog = strcmp(filename, "logger.c");
 
-       if ((res = vasprintf(ret, fmt, ap)) == -1)
-               MALLOC_FAILURE_MSG;
+#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;
+       }
 
        return res;
 }
-)
 
-#else
+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 astmm is in use, let it handle these.  Otherwise, it will report that
-   all allocations are coming from this header file */
+#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 */
 
-#define ast_malloc(a)          malloc(a)
-#define ast_calloc(a,b)                calloc(a,b)
-#define ast_realloc(a,b)       realloc(a,b)
-#define ast_strdup(a)          strdup(a)
-#define ast_strndup(a,b)       strndup(a,b)
-#define ast_asprintf(a,b,c)    asprintf(a,b,c)
-#define ast_vasprintf(a,b,c)   vasprintf(a,b,c)
+       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);
+       }
 
-#endif /* AST_DEBUG_MALLOC */
+       return res;
+}
 
-#if !defined(ast_strdupa) && defined(__GNUC__)
-/*!
-  \brief duplicate a string in memory from the stack
-  \param s The string to duplicate
+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");
 
-  This macro will duplicate the given string.  It returns a pointer to the stack
-  allocatted memory for the new string.
-*/
-#define ast_strdupa(s)                                                    \
-       (__extension__                                                    \
-       ({                                                                \
-               const char *__old = (s);                                  \
-               size_t __len = strlen(__old) + 1;                         \
-               char *__new = __builtin_alloca(__len);                    \
-               memcpy (__new, __old, __len);                             \
-               __new;                                                    \
-       }))
+#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;
+       }
 
-/* from config.c */
-
-#define MAX_NESTED_COMMENTS 128
-#define COMMENT_START ";--"
-#define COMMENT_END "--;"
-#define COMMENT_META ';'
-#define COMMENT_TAG '-'
-
-static char *extconfig_conf = "extconfig.conf";
+       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;
+       }
 
-/*! Growable string buffer */
-static char *comment_buffer;   /*!< this will be a comment collector.*/
-static int   comment_buffer_size;  /*!< the amount of storage so far alloc'd for the comment_buffer */
+       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;
+       }
 
-static char *lline_buffer;    /*!< A buffer for stuff behind the ; */
-static int  lline_buffer_size;
+       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;
+       }
 
-#define CB_INCR 250
+       return res;
+}
 
-struct ast_comment {
-       struct ast_comment *next;
-       char cmt[0];
-};
+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)
+{
+       return pthread_cond_init(cond, cond_attr);
+}
 
-static void CB_INIT(void)
+static inline int __ast_cond_signal(const char *filename, int lineno, const char *func,
+                                   const char *cond_name, ast_cond_t *cond)
 {
-       if (!comment_buffer) {
-               comment_buffer = ast_malloc(CB_INCR);
-               if (!comment_buffer)
-                       return;
-               comment_buffer[0] = 0;
-               comment_buffer_size = CB_INCR;
-               lline_buffer = ast_malloc(CB_INCR);
-               if (!lline_buffer)
-                       return;
-               lline_buffer[0] = 0;
-               lline_buffer_size = CB_INCR;
-       } else {
-               comment_buffer[0] = 0;
-               lline_buffer[0] = 0;
-       }
+       return pthread_cond_signal(cond);
 }
 
-static void  CB_ADD(char *str)
+static inline int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
+                                      const char *cond_name, ast_cond_t *cond)
 {
-       int rem = comment_buffer_size - strlen(comment_buffer) - 1;
-       int siz = strlen(str);
-       if (rem < siz+1) {
-               comment_buffer = ast_realloc(comment_buffer, comment_buffer_size + CB_INCR + siz + 1);
-               if (!comment_buffer)
-                       return;
-               comment_buffer_size += CB_INCR+siz+1;
-       }
-       strcat(comment_buffer,str);
+       return pthread_cond_broadcast(cond);
 }
 
-static void  CB_ADD_LEN(char *str, int len)
+static inline int __ast_cond_destroy(const char *filename, int lineno, const char *func,
+                                    const char *cond_name, ast_cond_t *cond)
 {
-       int cbl = strlen(comment_buffer) + 1;
-       int rem = comment_buffer_size - cbl;
-       if (rem < len+1) {
-               comment_buffer = ast_realloc(comment_buffer, comment_buffer_size + CB_INCR + len + 1);
-               if (!comment_buffer)
-                       return;
-               comment_buffer_size += CB_INCR+len+1;
-       }
-       strncat(comment_buffer,str,len);
-       comment_buffer[cbl+len-1] = 0;
+       return pthread_cond_destroy(cond);
 }
 
-static void  LLB_ADD(char *str)
+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 rem = lline_buffer_size - strlen(lline_buffer) - 1;
-       int siz = strlen(str);
-       if (rem < siz+1) {
-               lline_buffer = ast_realloc(lline_buffer, lline_buffer_size + CB_INCR + siz + 1);
-               if (!lline_buffer) 
-                       return;
-               lline_buffer_size += CB_INCR + siz + 1;
+       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);
        }
-       strcat(lline_buffer,str);
-}
+#endif
 
-static void CB_RESET(void )  
-{ 
-       comment_buffer[0] = 0; 
-       lline_buffer[0] = 0;
+       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);
+               }
+       }
+
+       return res;
 }
-               
-/*! \brief Keep track of how many threads are currently trying to wait*() on
- *  a child process */
-static unsigned int safe_system_level = 0;
-static void *safe_system_prev_handler;
 
-/*! \brief NULL handler so we can collect the child exit status */
-static void null_sig_handler(int signal)
+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
 
-void ast_replace_sigchld(void);
+       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;
+       }
 
-void ast_replace_sigchld(void)
-{
-       unsigned int level;
+       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;
+       }
 
-       level = safe_system_level++;
+       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;
+       }
 
-       /* only replace the handler if it has not already been done */
-       if (level == 0)
-               safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
+       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);
+               }
+       }
 
+       return res;
 }
 
-void ast_unreplace_sigchld(void);
-
-void ast_unreplace_sigchld(void)
-{
-       unsigned int level;
+#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)
 
-       level = --safe_system_level;
+#else /* !DEBUG_THREADS */
 
-       /* only restore the handler if we are the last one */
-       if (level == 0)
-               signal(SIGCHLD, safe_system_prev_handler);
 
-}
+typedef pthread_mutex_t ast_mutex_t;
 
-int ast_safe_system(const char *s);
+#define AST_MUTEX_INIT_VALUE   ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
 
-int ast_safe_system(const char *s)
+static inline int ast_mutex_init(ast_mutex_t *pmutex)
 {
-       pid_t pid;
-#ifdef HAVE_WORKING_FORK
-       int x;
-#endif
-       int res;
-       struct rusage rusage;
-       int status;
-
-#if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
-       ast_replace_sigchld();
+       pthread_mutexattr_t attr;
 
-#ifdef HAVE_WORKING_FORK
-       pid = fork();
-#else
-       pid = vfork();
-#endif 
+       pthread_mutexattr_init(&attr);
+       pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
 
-       if (pid == 0) {
-#ifdef HAVE_WORKING_FORK
-               /* Close file descriptors and launch system command */
-               for (x = STDERR_FILENO + 1; x < 4096; x++)
-                       close(x);
-#endif
-               execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
-               _exit(1);
-       } else if (pid > 0) {
-               for(;;) {
-                       res = wait4(pid, &status, 0, &rusage);
-                       if (res > -1) {
-                               res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
-                               break;
-                       } else if (errno != EINTR) 
-                               break;
-               }
-       } else {
-               ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
-               res = -1;
-       }
+       return pthread_mutex_init(pmutex, &attr);
+}
 
-       ast_unreplace_sigchld();
-#else
-       res = -1;
-#endif
+#define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
 
-       return res;
+static inline int ast_mutex_unlock(ast_mutex_t *pmutex)
+{
+       return pthread_mutex_unlock(pmutex);
 }
 
-static struct ast_comment *ALLOC_COMMENT(const char *buffer)
-{ 
-       struct ast_comment *x = ast_calloc(1,sizeof(struct ast_comment)+strlen(buffer)+1);
-       strcpy(x->cmt, buffer);
-       return x;
+static inline int ast_mutex_destroy(ast_mutex_t *pmutex)
+{
+       return pthread_mutex_destroy(pmutex);
 }
 
-static struct ast_config_map {
-       struct ast_config_map *next;
-       char *name;
-       char *driver;
-       char *database;
-       char *table;
-       char stuff[0];
-} *config_maps = NULL;
+static inline int ast_mutex_lock(ast_mutex_t *pmutex)
+{
+       __MTX_PROF(pmutex);
+}
 
-static struct ast_config_engine *config_engine_list;
+static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
+{
+       return pthread_mutex_trylock(pmutex);
+}
 
-#define MAX_INCLUDE_LEVEL 10
+typedef pthread_cond_t ast_cond_t;
 
+static inline int ast_cond_init(ast_cond_t *cond, pthread_condattr_t *cond_attr)
+{
+       return pthread_cond_init(cond, cond_attr);
+}
 
-struct ast_category {
-       char name[80];
-       int ignored;                    /*!< do not let user of the config see this category */
-       int include_level;      
-    char *file;                /*!< the file name from whence this declaration was read */
-    int lineno;
-       struct ast_comment *precomments;
-       struct ast_comment *sameline;
-       struct ast_variable *root;
-       struct ast_variable *last;
-       struct ast_category *next;
-};
-
-struct ast_config {
-       struct ast_category *root;
-       struct ast_category *last;
-       struct ast_category *current;
-       struct ast_category *last_browse;               /*!< used to cache the last category supplied via category_browse */
-       int include_level;
-       int max_include_level;
-    struct ast_config_include *includes;  /*!< a list of inclusions, which should describe the entire tree */
-};
-
-struct ast_config_include {
-       char *include_location_file;     /*!< file name in which the include occurs */
-       int  include_location_lineno;    /*!< lineno where include occurred */
-       int  exec;                       /*!< set to non-zero if itsa #exec statement */
-       char *exec_file;                 /*!< if it's an exec, you'll have both the /var/tmp to read, and the original script */
-       char *included_file;             /*!< file name included */
-       int inclusion_count;             /*!< if the file is included more than once, a running count thereof -- but, worry not,
-                                                                          we explode the instances and will include those-- so all entries will be unique */
-       int output;                      /*!< a flag to indicate if the inclusion has been output */
-       struct ast_config_include *next; /*!< ptr to next inclusion in the list */
-};
-
-typedef struct ast_config *config_load_func(const char *database, const char *table, const char *configfile, struct ast_config *config, int withcomments, const char *suggested_include_file);
-typedef struct ast_variable *realtime_var_get(const char *database, const char *table, va_list ap);
-typedef struct ast_config *realtime_multi_get(const char *database, const char *table, va_list ap);
-typedef int realtime_update(const char *database, const char *table, const char *keyfield, const char *entity, va_list ap);
-
-/*! \brief Configuration engine structure, used to define realtime drivers */
-struct ast_config_engine {
-       char *name;
-       config_load_func *load_func;
-       realtime_var_get *realtime_func;
-       realtime_multi_get *realtime_multi_func;
-       realtime_update *update_func;
-       struct ast_config_engine *next;
-};
-
-static struct ast_config_engine *config_engine_list;
-
-/* taken from strings.h */
-
-static force_inline int ast_strlen_zero(const char *s)
+static inline int ast_cond_signal(ast_cond_t *cond)
 {
-       return (!s || (*s == '\0'));
+       return pthread_cond_signal(cond);
 }
 
-#define S_OR(a, b)     (!ast_strlen_zero(a) ? (a) : (b))
+static inline int ast_cond_broadcast(ast_cond_t *cond)
+{
+       return pthread_cond_broadcast(cond);
+}
 
-AST_INLINE_API(
-void ast_copy_string(char *dst, const char *src, size_t size),
+static inline int ast_cond_destroy(ast_cond_t *cond)
 {
-       while (*src && size) {
-               *dst++ = *src++;
-               size--;
-       }
-       if (__builtin_expect(!size, 0))
-               dst--;
-       *dst = '\0';
+       return pthread_cond_destroy(cond);
 }
-)
 
-AST_INLINE_API(
-char *ast_skip_blanks(const char *str),
+static inline int ast_cond_wait(ast_cond_t *cond, ast_mutex_t *t)
 {
-       while (*str && *str < 33)
-               str++;
-       return (char *)str;
+       return pthread_cond_wait(cond, t);
 }
-)
 
-/*!
-  \brief Trims trailing whitespace characters from a string.
-  \param ast_trim_blanks function being used
-  \param str the input string
-  \return a pointer to the modified string
- */
-AST_INLINE_API(
-char *ast_trim_blanks(char *str),
+static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime)
 {
-       char *work = str;
+       return pthread_cond_timedwait(cond, t, abstime);
+}
 
-       if (work) {
-               work += strlen(work) - 1;
-               /* It's tempting to only want to erase after we exit this loop, 
-                  but since ast_trim_blanks *could* receive a constant string
-                  (which we presumably wouldn't have to touch), we shouldn't
-                  actually set anything unless we must, and it's easier just
-                  to set each position to \0 than to keep track of a variable
-                  for it */
-               while ((work >= str) && *work < 33)
-                       *(work--) = '\0';
-       }
-       return str;
+#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) \
+{ \
+       ast_mutex_init(&mutex); \
+} \
+static void  __attribute__ ((destructor)) fini_##mutex(void) \
+{ \
+       ast_mutex_destroy(&mutex); \
 }
-)
+#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 */
 
-/*!
-  \brief Strip leading/trailing whitespace from a string.
-  \param s The string to be stripped (will be modified).
-  \return The stripped string.
+#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
 
-  This functions strips all leading and trailing whitespace
-  characters from the input string, and returns a pointer to
-  the resulting string. The string is modified in place.
-*/
-AST_INLINE_API(
-char *ast_strip(char *s),
-{
-       s = ast_skip_blanks(s);
-       if (s)
-               ast_trim_blanks(s);
-       return s;
-} 
-)
+#define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex)
 
+#define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
 
-/* from config.h */
+#define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
 
-struct ast_variable {
-       char *name;
-       char *value;
-       char *file;
-       int lineno;
-       int object;             /*!< 0 for variable, 1 for object */
-       int blanklines;         /*!< Number of blanklines following entry */
-       struct ast_comment *precomments;
-       struct ast_comment *sameline;
-       struct ast_variable *next;
-       char stuff[0];
-};
+#ifndef __linux__
+#define pthread_create __use_ast_pthread_create_instead__
+#endif
 
-static const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable);
-static struct ast_config *config_text_file_load(const char *database, const char *table, const char *filename, struct ast_config *cfg, int withcomments, const char *suggested_include_file);
+typedef pthread_rwlock_t ast_rwlock_t;
 
-struct ast_config *localized_config_load_with_comments(const char *filename);
-static char *ast_category_browse(struct ast_config *config, const char *prev);
-static struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category);
-static void ast_variables_destroy(struct ast_variable *v);
-static void ast_config_destroy(struct ast_config *cfg);
-static struct ast_config_include *ast_include_new(struct ast_config *conf, const char *from_file, const char *included_file, int is_exec, const char *exec_file, int from_lineno, char *real_included_file_name, int real_included_file_name_size);
-static struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file);
-void localized_ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file);
+static inline int ast_rwlock_init(ast_rwlock_t *prwlock)
+{
+       pthread_rwlockattr_t attr;
 
-static struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename);
+       pthread_rwlockattr_init(&attr);
 
-static struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename) 
+#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)
 {
-       struct ast_variable *variable;
-       int name_len = strlen(name) + 1;        
+       return pthread_rwlock_destroy(prwlock);
+}
 
-       if ((variable = ast_calloc(1, name_len + strlen(value) + 1 + strlen(filename) + 1 + sizeof(*variable)))) {
-               variable->name = variable->stuff;
-               variable->value = variable->stuff + name_len;           
-               variable->file = variable->value + strlen(value) + 1;           
-               strcpy(variable->name,name);
-               strcpy(variable->value,value);
-               strcpy(variable->file,filename);
-       }
+static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
+{
+       return pthread_rwlock_unlock(prwlock);
+}
 
-       return variable;
+static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
+{
+       return pthread_rwlock_rdlock(prwlock);
 }
 
-static struct ast_config_include *ast_include_new(struct ast_config *conf, const char *from_file, const char *included_file, int is_exec, const char *exec_file, int from_lineno, char *real_included_file_name, int real_included_file_name_size)
+static inline int ast_rwlock_tryrdlock(ast_rwlock_t *prwlock)
 {
-       /* a file should be included ONCE. Otherwise, if one of the instances is changed,
-       then all be changed. -- how do we know to include it? -- Handling modified 
-       instances is possible, I'd have
-       to create a new master for each instance. */
-       struct ast_config_include *inc;
-    
-       inc = ast_include_find(conf, included_file);
-       if (inc)
-       {
-               inc->inclusion_count++;
-               snprintf(real_included_file_name, real_included_file_name_size, "%s~~%d", included_file, inc->inclusion_count);
-               ast_log(LOG_WARNING,"'%s', line %d:  Same File included more than once! This data will be saved in %s if saved back to disk.\n", from_file, from_lineno, real_included_file_name);
-       } else
-               *real_included_file_name = 0;
-       
-       inc = ast_calloc(1,sizeof(struct ast_config_include));
-       inc->include_location_file = ast_strdup(from_file);
-       inc->include_location_lineno = from_lineno;
-       if (!ast_strlen_zero(real_included_file_name))
-               inc->included_file = ast_strdup(real_included_file_name);
-       else
-               inc->included_file = ast_strdup(included_file);
-       
-       inc->exec = is_exec;
-       if (is_exec)
-               inc->exec_file = ast_strdup(exec_file);
-       
-       /* attach this new struct to the conf struct */
-       inc->next = conf->includes;
-       conf->includes = inc;
-    
-       return inc;
+       return pthread_rwlock_tryrdlock(prwlock);
 }
 
-void localized_ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file)
+static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
 {
-       struct ast_config_include *incl;
-       struct ast_category *cat;
-       struct ast_variable *v;
-    
-       int from_len = strlen(from_file);
-       int to_len = strlen(to_file);
-    
-       if (strcmp(from_file, to_file) == 0) /* no use wasting time if the name is the same */
-               return;
-       
-       /* the manager code allows you to read in one config file, then
-       write it back out under a different name. But, the new arrangement
-          ties output lines to the file name. So, before you try to write
-       the config file to disk, better riffle thru the data and make sure
-       the file names are changed.
-       */
-       /* file names are on categories, includes (of course), and on variables. So,
-          traverse all this and swap names */
-       
-       for (incl = conf->includes; incl; incl=incl->next) {
-               if (strcmp(incl->include_location_file,from_file) == 0) {
-                       if (from_len >= to_len)
-                               strcpy(incl->include_location_file, to_file);
-                       else {
-                               free(incl->include_location_file);
-                               incl->include_location_file = strdup(to_file);
-                       }
-               }
-       }
-       for (cat = conf->root; cat; cat = cat->next) {
-               if (strcmp(cat->file,from_file) == 0) {
-                       if (from_len >= to_len)
-                               strcpy(cat->file, to_file);
-                       else {
-                               free(cat->file);
-                               cat->file = strdup(to_file);
-                       }
-               }
-               for (v = cat->root; v; v = v->next) {
-                       if (strcmp(v->file,from_file) == 0) {
-                               if (from_len >= to_len)
-                                       strcpy(v->file, to_file);
-                               else {
-                                       free(v->file);
-                                       v->file = strdup(to_file);
-                               }
-                       }
-               }
-       }
+       return pthread_rwlock_wrlock(prwlock);
 }
 
-static struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file)
+static inline int ast_rwlock_trywrlock(ast_rwlock_t *prwlock)
 {
-       struct ast_config_include *x;
-       for (x=conf->includes;x;x=x->next)
-       {
-               if (strcmp(x->included_file,included_file) == 0)
-                       return x;
-       }
-       return 0;
+       return pthread_rwlock_trywrlock(prwlock);
 }
 
+/* Statically declared read/write locks */
 
-static void ast_variable_append(struct ast_category *category, struct ast_variable *variable);
-
-static void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
-{
-       if (!variable)
-               return;
-       if (category->last)
-               category->last->next = variable;
-       else
-               category->root = variable;
-       category->last = variable;
-       while (category->last->next)
-               category->last = category->last->next;
+#ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
+#define __AST_RWLOCK_DEFINE(scope, rwlock) \
+        scope ast_rwlock_t rwlock; \
+static void  __attribute__ ((constructor)) init_##rwlock(void) \
+{ \
+        ast_rwlock_init(&rwlock); \
+} \
+static void  __attribute__ ((destructor)) fini_##rwlock(void) \
+{ \
+        ast_rwlock_destroy(&rwlock); \
 }
+#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
 
-static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored);
-
-static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored)
-{
-       struct ast_category *cat;
+#define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock)
 
-       /* try exact match first, then case-insensitive match */
-       for (cat = config->root; cat; cat = cat->next) {
-               if (cat->name == category_name && (ignored || !cat->ignored))
-                       return cat;
-       }
+/*
+ * 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()
+ */
 
-       for (cat = config->root; cat; cat = cat->next) {
-               if (!strcasecmp(cat->name, category_name) && (ignored || !cat->ignored))
-                       return cat;
-       }
+#if defined(HAVE_OSX_ATOMICS)
+#include "libkern/OSAtomic.h"
+#endif
 
-       return NULL;
-}
+/*! \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.
+ */
 
-static struct ast_category *ast_category_get(const struct ast_config *config, const char *category_name)
+#if defined(HAVE_GCC_ATOMICS)
+AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
 {
-       return category_get(config, category_name, 0);
+       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
 
-static struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category)
+/*! \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),
 {
-       struct ast_category *cat = NULL;
+       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
 
-       if (category && config->last_browse && (config->last_browse->name == category))
-               cat = config->last_browse;
-       else
-               cat = ast_category_get(config, category);
+#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
 
-       return (cat) ? cat->root : NULL;
-}
+/*! \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);
 
-static const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
-{
-       struct ast_variable *v;
+/*! \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);
 
-       if (category) {
-               for (v = ast_variable_browse(config, category); v; v = v->next) {
-                       if (!strcasecmp(variable, v->name))
-                               return v->value;
-               }
-       } else {
-               struct ast_category *cat;
+/*! \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
 
-               for (cat = config->root; cat; cat = cat->next)
-                       for (v = cat->root; v; v = v->next)
-                               if (!strcasecmp(variable, v->name))
-                                       return v->value;
-       }
 
-       return NULL;
+#include "asterisk/hashtab.h"
+#include "asterisk/ael_structs.h"
+#include "asterisk/pval.h"
+
+/* from utils.h */
+
+static unsigned int __unsigned_int_flags_dummy;
+
+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)
+
+
+#ifdef __AST_DEBUG_MALLOC
+static void ast_free(void *ptr) attribute_unused;
+static void ast_free(void *ptr)
+{
+       free(ptr);
 }
+#else
+#define ast_free free
+#endif
 
-static struct ast_variable *variable_clone(const struct ast_variable *old)
+#ifndef __AST_DEBUG_MALLOC
+
+#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),
 {
-       struct ast_variable *new = ast_variable_new(old->name, old->value, old->file);
+       void *p;
 
-       if (new) {
-               new->lineno = old->lineno;
-               new->object = old->object;
-               new->blanklines = old->blanklines;
-               /* TODO: clone comments? */
-       }
+       if (!(p = malloc(len)))
+               MALLOC_FAILURE_MSG;
 
-       return new;
+       return p;
 }
-static void ast_variables_destroy(struct ast_variable *v)
+)
+
+/*!
+ * \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),
 {
-       struct ast_variable *vn;
+       void *p;
 
-       while (v) {
-               vn = v;
-               v = v->next;
-               free(vn);
-       }
+       if (!(p = calloc(num, len)))
+               MALLOC_FAILURE_MSG;
+
+       return p;
 }
+)
 
-static void ast_includes_destroy(struct ast_config_include *incls)
+/*!
+ * \brief A wrapper for calloc() for use in cache pools
+ *
+ * ast_calloc_cache() is a wrapper for calloc() that will generate an Asterisk log
+ * message in the case that the allocation fails. When memory debugging is in use,
+ * the memory allocated by this function will be marked as 'cache' so it can be
+ * distinguished from normal memory allocations.
+ *
+ * The arguments and return value are the same as calloc()
+ */
+#define ast_calloc_cache(num, len) \
+       _ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+
+/*!
+ * \brief A wrapper for realloc()
+ *
+ * ast_realloc() is a wrapper for realloc() that will generate an Asterisk log
+ * message in the case that the allocation fails.
+ *
+ * The arguments and return value are the same as realloc()
+ */
+#define ast_realloc(p, len) \
+       _ast_realloc((p), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+
+AST_INLINE_API(
+void * attribute_malloc _ast_realloc(void *p, size_t len, const char *file, int lineno, const char *func),
 {
-       struct ast_config_include *incl,*inclnext;
-    
-       for (incl=incls; incl; incl = inclnext) {
-               inclnext = incl->next;
-               if (incl->include_location_file)
-                       free(incl->include_location_file);
-               if (incl->exec_file)
-                       free(incl->exec_file);
-               if (incl->included_file)
-                       free(incl->included_file);
-               free(incl);
-       }
+       void *newp;
+
+       if (!(newp = realloc(p, len)))
+               MALLOC_FAILURE_MSG;
+
+       return newp;
 }
+)
+
+/*!
+ * \brief A wrapper for strdup()
+ *
+ * ast_strdup() is a wrapper for strdup() that will generate an Asterisk log
+ * message in the case that the allocation fails.
+ *
+ * ast_strdup(), unlike strdup(), can safely accept a NULL argument. If a NULL
+ * argument is provided, ast_strdup will return NULL without generating any
+ * kind of error log message.
+ *
+ * The argument and return value are the same as strdup()
+ */
+#define ast_strdup(str) \
+       _ast_strdup((str), __FILE__, __LINE__, __PRETTY_FUNCTION__)
 
-static void ast_config_destroy(struct ast_config *cfg)
+AST_INLINE_API(
+char * attribute_malloc _ast_strdup(const char *str, const char *file, int lineno, const char *func),
 {
-       struct ast_category *cat, *catn;
-
-       if (!cfg)
-               return;
+       char *newstr = NULL;
 
-       ast_includes_destroy(cfg->includes);
-       
-       cat = cfg->root;
-       while (cat) {
-               ast_variables_destroy(cat->root);
-               catn = cat;
-               cat = cat->next;
-               free(catn);
+       if (str) {
+               if (!(newstr = strdup(str)))
+                       MALLOC_FAILURE_MSG;
        }
-       free(cfg);
-}
 
+       return newstr;
+}
+)
 
-/* options.h declars ast_options extern; I need it static? */
+/*!
+ * \brief A wrapper for strndup()
+ *
+ * ast_strndup() is a wrapper for strndup() that will generate an Asterisk log
+ * message in the case that the allocation fails.
+ *
+ * ast_strndup(), unlike strndup(), can safely accept a NULL argument for the
+ * string to duplicate. If a NULL argument is provided, ast_strdup will return  
+ * NULL without generating any kind of error log message.
+ *
+ * The arguments and return value are the same as strndup()
+ */
+#define ast_strndup(str, len) \
+       _ast_strndup((str), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
 
-#define AST_CACHE_DIR_LEN      512
-#define AST_FILENAME_MAX       80
+AST_INLINE_API(
+char * attribute_malloc _ast_strndup(const char *str, size_t len, const char *file, int lineno, const char *func),
+{
+       char *newstr = NULL;
 
-/*! \ingroup main_options */
-enum ast_option_flags {
-       /*! Allow \#exec in config files */
-       AST_OPT_FLAG_EXEC_INCLUDES = (1 << 0),
-       /*! Do not fork() */
-       AST_OPT_FLAG_NO_FORK = (1 << 1),
-       /*! Keep quiet */
-       AST_OPT_FLAG_QUIET = (1 << 2),
-       /*! Console mode */
-       AST_OPT_FLAG_CONSOLE = (1 << 3),
-       /*! Run in realtime Linux priority */
-       AST_OPT_FLAG_HIGH_PRIORITY = (1 << 4),
-       /*! Initialize keys for RSA authentication */
-       AST_OPT_FLAG_INIT_KEYS = (1 << 5),
-       /*! Remote console */
-       AST_OPT_FLAG_REMOTE = (1 << 6),
-       /*! Execute an asterisk CLI command upon startup */
-       AST_OPT_FLAG_EXEC = (1 << 7),
-       /*! Don't use termcap colors */
-       AST_OPT_FLAG_NO_COLOR = (1 << 8),
-       /*! Are we fully started yet? */
-       AST_OPT_FLAG_FULLY_BOOTED = (1 << 9),
-       /*! Trascode via signed linear */
-       AST_OPT_FLAG_TRANSCODE_VIA_SLIN = (1 << 10),
-       /*! Enable priority jumping in applications */
-       AST_OPT_FLAG_PRIORITY_JUMPING = (1 << 11),
-       /*! Dump core on a seg fault */
-       AST_OPT_FLAG_DUMP_CORE = (1 << 12),
-       /*! Cache sound files */
-       AST_OPT_FLAG_CACHE_RECORD_FILES = (1 << 13),
-       /*! Display timestamp in CLI verbose output */
-       AST_OPT_FLAG_TIMESTAMP = (1 << 14),
-       /*! Override config */
-       AST_OPT_FLAG_OVERRIDE_CONFIG = (1 << 15),
-       /*! Reconnect */
-       AST_OPT_FLAG_RECONNECT = (1 << 16),
-       /*! Transmit Silence during Record() */
-       AST_OPT_FLAG_TRANSMIT_SILENCE = (1 << 17),
-       /*! Suppress some warnings */
-       AST_OPT_FLAG_DONT_WARN = (1 << 18),
-       /*! End CDRs before the 'h' extension */
-       AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN = (1 << 19),
-       /*! Use Zaptel Timing for generators if available */
-       AST_OPT_FLAG_INTERNAL_TIMING = (1 << 20),
-       /*! Always fork, even if verbose or debug settings are non-zero */
-       AST_OPT_FLAG_ALWAYS_FORK = (1 << 21),
-       /*! Disable log/verbose output to remote consoles */
-       AST_OPT_FLAG_MUTE = (1 << 22)
-};
+       if (str) {
+               if (!(newstr = strndup(str, len)))
+                       MALLOC_FAILURE_MSG;
+       }
 
-/*! These are the options that set by default when Asterisk starts */
-#define AST_DEFAULT_OPTIONS AST_OPT_FLAG_TRANSCODE_VIA_SLIN
+       return newstr;
+}
+)
 
-#define ast_opt_exec_includes          ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES)
-#define ast_opt_no_fork                        ast_test_flag(&ast_options, AST_OPT_FLAG_NO_FORK)
-#define ast_opt_quiet                  ast_test_flag(&ast_options, AST_OPT_FLAG_QUIET)
-#define ast_opt_console                        ast_test_flag(&ast_options, AST_OPT_FLAG_CONSOLE)
-#define ast_opt_high_priority          ast_test_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY)
-#define ast_opt_init_keys              ast_test_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS)
-#define ast_opt_remote                 ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)
-#define ast_opt_exec                   ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC)
-#define ast_opt_no_color               ast_test_flag(&ast_options, AST_OPT_FLAG_NO_COLOR)
-#define ast_fully_booted               ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)
-#define ast_opt_transcode_via_slin     ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN)
-#define ast_opt_priority_jumping       ast_test_flag(&ast_options, AST_OPT_FLAG_PRIORITY_JUMPING)
-#define ast_opt_dump_core              ast_test_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE)
-#define ast_opt_cache_record_files     ast_test_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES)
-#define ast_opt_timestamp              ast_test_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP)
-#define ast_opt_override_config                ast_test_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG)
-#define ast_opt_reconnect              ast_test_flag(&ast_options, AST_OPT_FLAG_RECONNECT)
-#define ast_opt_transmit_silence       ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE)
-#define ast_opt_dont_warn              ast_test_flag(&ast_options, AST_OPT_FLAG_DONT_WARN)
-#define ast_opt_end_cdr_before_h_exten ast_test_flag(&ast_options, AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN)
-#define ast_opt_internal_timing                ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING)
-#define ast_opt_always_fork            ast_test_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK)
-#define ast_opt_mute                   ast_test_flag(&ast_options, AST_OPT_FLAG_MUTE)
+/*!
+ * \brief A wrapper for asprintf()
+ *
+ * ast_asprintf() is a wrapper for asprintf() that will generate an Asterisk log
+ * message in the case that the allocation fails.
+ *
+ * The arguments and return value are the same as asprintf()
+ */
+#define ast_asprintf(ret, fmt, ...) \
+       _ast_asprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, __VA_ARGS__)
 
-/*  IN CONFLICT: extern int option_verbose; */
-/*  IN CONFLICT: extern int option_debug;      */      /*!< Debugging */
-extern int option_maxcalls;            /*!< Maximum number of simultaneous channels */
-extern double option_maxload;
-extern char defaultlanguage[];
+AST_INLINE_API(
+__attribute__((format (printf, 5, 6)))
+int _ast_asprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, ...),
+{
+       int res;
+       va_list ap;
 
-extern time_t ast_startuptime;
-extern time_t ast_lastreloadtime;
-extern pid_t ast_mainpid;
+       va_start(ap, fmt);
+       if ((res = vasprintf(ret, fmt, ap)) == -1)
+               MALLOC_FAILURE_MSG;
+       va_end(ap);
 
-extern char record_cache_dir[AST_CACHE_DIR_LEN];
-extern char debug_filename[AST_FILENAME_MAX];
+       return res;
+}
+)
 
-extern int ast_language_is_prefix;
+/*!
+ * \brief A wrapper for vasprintf()
+ *
+ * ast_vasprintf() is a wrapper for vasprintf() that will generate an Asterisk log
+ * message in the case that the allocation fails.
+ *
+ * The arguments and return value are the same as vasprintf()
+ */
+#define ast_vasprintf(ret, fmt, ap) \
+       _ast_vasprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, (fmt), (ap))
 
+AST_INLINE_API(
+__attribute__((format (printf, 5, 0)))
+int _ast_vasprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, va_list ap),
+{
+       int res;
 
+       if ((res = vasprintf(ret, fmt, ap)) == -1)
+               MALLOC_FAILURE_MSG;
 
-/* lock.h */
+       return res;
+}
+)
 
-#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 */
+/* If astmm is in use, let it handle these.  Otherwise, it will report that
+   all allocations are coming from this header file */
 
-/* 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_malloc(a)          malloc(a)
+#define ast_calloc(a,b)                calloc(a,b)
+#define ast_realloc(a,b)       realloc(a,b)
+#define ast_strdup(a)          strdup(a)
+#define ast_strndup(a,b)       strndup(a,b)
+#define ast_asprintf(a,b,c)    asprintf(a,b,c)
+#define ast_vasprintf(a,b,c)   vasprintf(a,b,c)
 
-#ifdef DEBUG_THREADS
+#endif /* AST_DEBUG_MALLOC */
 
-#define __ast_mutex_logger(...)  do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0)
+#if !defined(ast_strdupa) && defined(__GNUC__)
+/*!
+  \brief duplicate a string in memory from the stack
+  \param s The string to duplicate
 
-#ifdef THREAD_CRASH
-#define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
-#else
-#define DO_THREAD_CRASH do { } while (0)
+  This macro will duplicate the given string.  It returns a pointer to the stack
+  allocatted memory for the new string.
+*/
+#define ast_strdupa(s)                                                    \
+       (__extension__                                                    \
+       ({                                                                \
+               const char *__old = (s);                                  \
+               size_t __len = strlen(__old) + 1;                         \
+               char *__new = __builtin_alloca(__len);                    \
+               memcpy (__new, __old, __len);                             \
+               __new;                                                    \
+       }))
 #endif
 
-#define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, { NULL }, { 0 }, 0, { NULL }, { 0 } }
 
-#define AST_MAX_REENTRANCY 10
+/* from config.c */
 
-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];
-};
+#define MAX_NESTED_COMMENTS 128
+#define COMMENT_START ";--"
+#define COMMENT_END "--;"
+#define COMMENT_META ';'
+#define COMMENT_TAG '-'
 
-typedef struct ast_mutex_info ast_mutex_t;
+static char *extconfig_conf = "extconfig.conf";
 
-typedef pthread_cond_t ast_cond_t;
+/*! Growable string buffer */
+static char *comment_buffer;   /*!< this will be a comment collector.*/
+static int   comment_buffer_size;  /*!< the amount of storage so far alloc'd for the comment_buffer */
 
-static pthread_mutex_t empty_mutex;
+static char *lline_buffer;    /*!< A buffer for stuff behind the ; */
+static int  lline_buffer_size;
 
-static void __attribute__((constructor)) init_empty_mutex(void)
-{
-       memset(&empty_mutex, 0, sizeof(empty_mutex));
-}
+#define CB_INCR 250
 
-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");
+struct ast_comment {
+       struct ast_comment *next;
+       char cmt[0];
+};
 
-       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;
-               }
+static void CB_INIT(void)
+{
+       if (!comment_buffer) {
+               comment_buffer = ast_malloc(CB_INCR);
+               if (!comment_buffer)
+                       return;
+               comment_buffer[0] = 0;
+               comment_buffer_size = CB_INCR;
+               lline_buffer = ast_malloc(CB_INCR);
+               if (!lline_buffer)
+                       return;
+               lline_buffer[0] = 0;
+               lline_buffer_size = CB_INCR;
+       } else {
+               comment_buffer[0] = 0;
+               lline_buffer[0] = 0;
        }
-#endif
-
-       t->file[0] = filename;
-       t->lineno[0] = lineno;
-       t->func[0] = func;
-       t->thread[0]  = 0;
-       t->reentrancy = 0;
-
-       return pthread_mutex_init(&t->mutex, attr);
 }
 
-static inline int __ast_pthread_mutex_init(const char *filename, int lineno, const char *func,
-                                          const char *mutex_name, ast_mutex_t *t)
+static void  CB_ADD(char *str)
 {
-       static pthread_mutexattr_t  attr;
-
-       pthread_mutexattr_init(&attr);
-       pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
-
-       return __ast_pthread_mutex_init_attr(filename, lineno, func, mutex_name, t, &attr);
+       int rem = comment_buffer_size - strlen(comment_buffer) - 1;
+       int siz = strlen(str);
+       if (rem < siz+1) {
+               comment_buffer = ast_realloc(comment_buffer, comment_buffer_size + CB_INCR + siz + 1);
+               if (!comment_buffer)
+                       return;
+               comment_buffer_size += CB_INCR+siz+1;
+       }
+       strcat(comment_buffer,str);
 }
-#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)
+static void  CB_ADD_LEN(char *str, int len)
 {
-       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);
+       int cbl = strlen(comment_buffer) + 1;
+       int rem = comment_buffer_size - cbl;
+       if (rem < len+1) {
+               comment_buffer = ast_realloc(comment_buffer, comment_buffer_size + CB_INCR + len + 1);
+               if (!comment_buffer)
+                       return;
+               comment_buffer_size += CB_INCR+len+1;
        }
-#endif
+       strncat(comment_buffer,str,len); /* safe */
+       comment_buffer[cbl+len-1] = 0;
+}
 
-       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;
+static void  LLB_ADD(char *str)
+{
+       int rem = lline_buffer_size - strlen(lline_buffer) - 1;
+       int siz = strlen(str);
+       if (rem < siz+1) {
+               lline_buffer = ast_realloc(lline_buffer, lline_buffer_size + CB_INCR + siz + 1);
+               if (!lline_buffer) 
+                       return;
+               lline_buffer_size += CB_INCR + siz + 1;
        }
+       strcat(lline_buffer,str);
+}
 
-       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 void CB_RESET(void )  
+{ 
+       comment_buffer[0] = 0; 
+       lline_buffer[0] = 0;
 }
+               
+/*! \brief Keep track of how many threads are currently trying to wait*() on
+ *  a child process */
+static unsigned int safe_system_level = 0;
+static void *safe_system_prev_handler;
 
-static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
-                                           const char* mutex_name, ast_mutex_t *t)
+/*! \brief NULL handler so we can collect the child exit status */
+static void null_sig_handler(int sig)
 {
-       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 */
+}
 
-#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 */
+void ast_replace_sigchld(void);
 
-       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;
-       }
+void ast_replace_sigchld(void)
+{
+       unsigned int level;
+
+       level = safe_system_level++;
+
+       /* only replace the handler if it has not already been done */
+       if (level == 0)
+               safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
 
-       return res;
 }
 
-static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
-                                              const char* mutex_name, ast_mutex_t *t)
+void ast_unreplace_sigchld(void);
+
+void ast_unreplace_sigchld(void)
 {
-       int res;
-       int canlog = strcmp(filename, "logger.c");
+       unsigned int level;
 
-#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 */
+       level = --safe_system_level;
 
-       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);
-       }
+       /* only restore the handler if we are the last one */
+       if (level == 0)
+               signal(SIGCHLD, safe_system_prev_handler);
 
-       return res;
 }
 
-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");
+int ast_safe_system(const char *s);
 
-#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);
-       }
+int ast_safe_system(const char *s)
+{
+       pid_t pid;
+#ifdef HAVE_WORKING_FORK
+       int x;
 #endif
+       int res;
+       struct rusage rusage;
+       int status;
 
-       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 defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
+       ast_replace_sigchld();
 
-       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;
-       }
+#ifdef HAVE_WORKING_FORK
+       pid = fork();
+#else
+       pid = vfork();
+#endif 
 
-       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 (pid == 0) {
+#ifdef HAVE_WORKING_FORK
+               /* Close file descriptors and launch system command */
+               for (x = STDERR_FILENO + 1; x < 4096; x++)
+                       close(x);
+#endif
+               execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
+               _exit(1);
+       } else if (pid > 0) {
+               for(;;) {
+                       res = wait4(pid, &status, 0, &rusage);
+                       if (res > -1) {
+                               res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
+                               break;
+                       } else if (errno != EINTR) 
+                               break;
+               }
+       } else {
+               ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
+               res = -1;
        }
 
-       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;
-       }
+       ast_unreplace_sigchld();
+#else
+       res = -1;
+#endif
 
        return res;
 }
 
-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)
-{
-       return pthread_cond_init(cond, cond_attr);
-}
-
-static inline int __ast_cond_signal(const char *filename, int lineno, const char *func,
-                                   const char *cond_name, ast_cond_t *cond)
-{
-       return pthread_cond_signal(cond);
-}
-
-static inline int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
-                                      const char *cond_name, ast_cond_t *cond)
-{
-       return pthread_cond_broadcast(cond);
+static struct ast_comment *ALLOC_COMMENT(const char *buffer)
+{ 
+       struct ast_comment *x = ast_calloc(1,sizeof(struct ast_comment)+strlen(buffer)+1);
+       strcpy(x->cmt, buffer);
+       return x;
 }
 
-static inline int __ast_cond_destroy(const char *filename, int lineno, const char *func,
-                                    const char *cond_name, ast_cond_t *cond)
-{
-       return pthread_cond_destroy(cond);
-}
+static struct ast_config_map {
+       struct ast_config_map *next;
+       char *name;
+       char *driver;
+       char *database;
+       char *table;
+       char stuff[0];
+} *config_maps = NULL;
 
-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");
+static struct ast_config_engine *config_engine_list;
 
-#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
+#define MAX_INCLUDE_LEVEL 10
 
-       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;
-       }
+struct ast_category {
+       char name[80];
+       int ignored;                    /*!< do not let user of the config see this category */
+       int include_level;      
+    char *file;                /*!< the file name from whence this declaration was read */
+    int lineno;
+       struct ast_comment *precomments;
+       struct ast_comment *sameline;
+       struct ast_variable *root;
+       struct ast_variable *last;
+       struct ast_category *next;
+};
 
-       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;
-       }
+struct ast_config {
+       struct ast_category *root;
+       struct ast_category *last;
+       struct ast_category *current;
+       struct ast_category *last_browse;               /*!< used to cache the last category supplied via category_browse */
+       int include_level;
+       int max_include_level;
+    struct ast_config_include *includes;  /*!< a list of inclusions, which should describe the entire tree */
+};
 
-       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);
-               }
-       }
+struct ast_config_include {
+       char *include_location_file;     /*!< file name in which the include occurs */
+       int  include_location_lineno;    /*!< lineno where include occurred */
+       int  exec;                       /*!< set to non-zero if itsa #exec statement */
+       char *exec_file;                 /*!< if it's an exec, you'll have both the /var/tmp to read, and the original script */
+       char *included_file;             /*!< file name included */
+       int inclusion_count;             /*!< if the file is included more than once, a running count thereof -- but, worry not,
+                                                                          we explode the instances and will include those-- so all entries will be unique */
+       int output;                      /*!< a flag to indicate if the inclusion has been output */
+       struct ast_config_include *next; /*!< ptr to next inclusion in the list */
+};
 
-       return res;
-}
+typedef struct ast_config *config_load_func(const char *database, const char *table, const char *configfile, struct ast_config *config, int withcomments, const char *suggested_include_file);
+typedef struct ast_variable *realtime_var_get(const char *database, const char *table, va_list ap);
+typedef struct ast_config *realtime_multi_get(const char *database, const char *table, va_list ap);
+typedef int realtime_update(const char *database, const char *table, const char *keyfield, const char *entity, va_list ap);
 
-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");
+/*! \brief Configuration engine structure, used to define realtime drivers */
+struct ast_config_engine {
+       char *name;
+       config_load_func *load_func;
+       realtime_var_get *realtime_func;
+       realtime_multi_get *realtime_multi_func;
+       realtime_update *update_func;
+       struct ast_config_engine *next;
+};
 
-#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
+static struct ast_config_engine *config_engine_list;
 
-       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;
-       }
+/* taken from strings.h */
 
-       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;
-       }
+static force_inline int ast_strlen_zero(const char *s)
+{
+       return (!s || (*s == '\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;
-       }
+#define S_OR(a, b)     (!ast_strlen_zero(a) ? (a) : (b))
 
-       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);
-               }
+AST_INLINE_API(
+void ast_copy_string(char *dst, const char *src, size_t size),
+{
+       while (*src && size) {
+               *dst++ = *src++;
+               size--;
        }
-
-       return res;
+       if (__builtin_expect(!size, 0))
+               dst--;
+       *dst = '\0';
 }
+)
 
-#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 */
+AST_INLINE_API(
+char *ast_skip_blanks(const char *str),
+{
+       while (*str && *str < 33)
+               str++;
+       return (char *)str;
+}
+)
 
+/*!
+  \brief Trims trailing whitespace characters from a string.
+  \param ast_trim_blanks function being used
+  \param str the input string
+  \return a pointer to the modified string
+ */
+AST_INLINE_API(
+char *ast_trim_blanks(char *str),
+{
+       char *work = str;
 
-typedef pthread_mutex_t ast_mutex_t;
+       if (work) {
+               work += strlen(work) - 1;
+               /* It's tempting to only want to erase after we exit this loop, 
+                  but since ast_trim_blanks *could* receive a constant string
+                  (which we presumably wouldn't have to touch), we shouldn't
+                  actually set anything unless we must, and it's easier just
+                  to set each position to \0 than to keep track of a variable
+                  for it */
+               while ((work >= str) && *work < 33)
+                       *(work--) = '\0';
+       }
+       return str;
+}
+)
 
-#define AST_MUTEX_INIT_VALUE   ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
+/*!
+  \brief Strip leading/trailing whitespace from a string.
+  \param s The string to be stripped (will be modified).
+  \return The stripped string.
 
-static inline int ast_mutex_init(ast_mutex_t *pmutex)
+  This functions strips all leading and trailing whitespace
+  characters from the input string, and returns a pointer to
+  the resulting string. The string is modified in place.
+*/
+AST_INLINE_API(
+char *ast_strip(char *s),
 {
-       pthread_mutexattr_t attr;
+       s = ast_skip_blanks(s);
+       if (s)
+               ast_trim_blanks(s);
+       return s;
+} 
+)
 
-       pthread_mutexattr_init(&attr);
-       pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
 
-       return pthread_mutex_init(pmutex, &attr);
-}
+/* from config.h */
 
-#define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
+struct ast_variable {
+       char *name;
+       char *value;
+       char *file;
+       int lineno;
+       int object;             /*!< 0 for variable, 1 for object */
+       int blanklines;         /*!< Number of blanklines following entry */
+       struct ast_comment *precomments;
+       struct ast_comment *sameline;
+       struct ast_variable *next;
+       char stuff[0];
+};
 
-static inline int ast_mutex_unlock(ast_mutex_t *pmutex)
-{
-       return pthread_mutex_unlock(pmutex);
-}
+static const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable);
+static struct ast_config *config_text_file_load(const char *database, const char *table, const char *filename, struct ast_config *cfg, int withcomments, const char *suggested_include_file);
 
-static inline int ast_mutex_destroy(ast_mutex_t *pmutex)
-{
-       return pthread_mutex_destroy(pmutex);
-}
+struct ast_config *localized_config_load_with_comments(const char *filename);
+static char *ast_category_browse(struct ast_config *config, const char *prev);
+static struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category);
+static void ast_variables_destroy(struct ast_variable *v);
+static void ast_config_destroy(struct ast_config *cfg);
+static struct ast_config_include *ast_include_new(struct ast_config *conf, const char *from_file, const char *included_file, int is_exec, const char *exec_file, int from_lineno, char *real_included_file_name, int real_included_file_name_size);
+static struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file);
+void localized_ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file);
 
-static inline int ast_mutex_lock(ast_mutex_t *pmutex)
-{
-       __MTX_PROF(pmutex);
-}
+static struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename);
 
-static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
+static struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename) 
 {
-       return pthread_mutex_trylock(pmutex);
-}
-
-typedef pthread_cond_t ast_cond_t;
+       struct ast_variable *variable;
+       int name_len = strlen(name) + 1;        
 
-static inline int ast_cond_init(ast_cond_t *cond, pthread_condattr_t *cond_attr)
-{
-       return pthread_cond_init(cond, cond_attr);
-}
+       if ((variable = ast_calloc(1, name_len + strlen(value) + 1 + strlen(filename) + 1 + sizeof(*variable)))) {
+               variable->name = variable->stuff;
+               variable->value = variable->stuff + name_len;           
+               variable->file = variable->value + strlen(value) + 1;           
+               strcpy(variable->name,name);
+               strcpy(variable->value,value);
+               strcpy(variable->file,filename);
+       }
 
-static inline int ast_cond_signal(ast_cond_t *cond)
-{
-       return pthread_cond_signal(cond);
+       return variable;
 }
 
-static inline int ast_cond_broadcast(ast_cond_t *cond)
+static struct ast_config_include *ast_include_new(struct ast_config *conf, const char *from_file, const char *included_file, int is_exec, const char *exec_file, int from_lineno, char *real_included_file_name, int real_included_file_name_size)
 {
-       return pthread_cond_broadcast(cond);
+       /* a file should be included ONCE. Otherwise, if one of the instances is changed,
+       then all be changed. -- how do we know to include it? -- Handling modified 
+       instances is possible, I'd have
+       to create a new master for each instance. */
+       struct ast_config_include *inc;
+    
+       inc = ast_include_find(conf, included_file);
+       if (inc)
+       {
+               inc->inclusion_count++;
+               snprintf(real_included_file_name, real_included_file_name_size, "%s~~%d", included_file, inc->inclusion_count);
+               ast_log(LOG_WARNING,"'%s', line %d:  Same File included more than once! This data will be saved in %s if saved back to disk.\n", from_file, from_lineno, real_included_file_name);
+       } else
+               *real_included_file_name = 0;
+       
+       inc = ast_calloc(1,sizeof(struct ast_config_include));
+       inc->include_location_file = ast_strdup(from_file);
+       inc->include_location_lineno = from_lineno;
+       if (!ast_strlen_zero(real_included_file_name))
+               inc->included_file = ast_strdup(real_included_file_name);
+       else
+               inc->included_file = ast_strdup(included_file);
+       
+       inc->exec = is_exec;
+       if (is_exec)
+               inc->exec_file = ast_strdup(exec_file);
+       
+       /* attach this new struct to the conf struct */
+       inc->next = conf->includes;
+       conf->includes = inc;
+    
+       return inc;
 }
 
-static inline int ast_cond_destroy(ast_cond_t *cond)
+void localized_ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file)
 {
-       return pthread_cond_destroy(cond);
+       struct ast_config_include *incl;
+       struct ast_category *cat;
+       struct ast_variable *v;
+    
+       int from_len = strlen(from_file);
+       int to_len = strlen(to_file);
+    
+       if (strcmp(from_file, to_file) == 0) /* no use wasting time if the name is the same */
+               return;
+       
+       /* the manager code allows you to read in one config file, then
+       write it back out under a different name. But, the new arrangement
+          ties output lines to the file name. So, before you try to write
+       the config file to disk, better riffle thru the data and make sure
+       the file names are changed.
+       */
+       /* file names are on categories, includes (of course), and on variables. So,
+          traverse all this and swap names */
+       
+       for (incl = conf->includes; incl; incl=incl->next) {
+               if (strcmp(incl->include_location_file,from_file) == 0) {
+                       if (from_len >= to_len)
+                               strcpy(incl->include_location_file, to_file);
+                       else {
+                               free(incl->include_location_file);
+                               incl->include_location_file = strdup(to_file);
+                       }
+               }
+       }
+       for (cat = conf->root; cat; cat = cat->next) {
+               if (strcmp(cat->file,from_file) == 0) {
+                       if (from_len >= to_len)
+                               strcpy(cat->file, to_file);
+                       else {
+                               free(cat->file);
+                               cat->file = strdup(to_file);
+                       }
+               }
+               for (v = cat->root; v; v = v->next) {
+                       if (strcmp(v->file,from_file) == 0) {
+                               if (from_len >= to_len)
+                                       strcpy(v->file, to_file);
+                               else {
+                                       free(v->file);
+                                       v->file = strdup(to_file);
+                               }
+                       }
+               }
+       }
 }
 
-static inline int ast_cond_wait(ast_cond_t *cond, ast_mutex_t *t)
+static struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file)
 {
-       return pthread_cond_wait(cond, t);
+       struct ast_config_include *x;
+       for (x=conf->includes;x;x=x->next)
+       {
+               if (strcmp(x->included_file,included_file) == 0)
+                       return x;
+       }
+       return 0;
 }
 
-static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime)
-{
-       return pthread_cond_timedwait(cond, t, abstime);
-}
 
-#endif /* !DEBUG_THREADS */
+static void ast_variable_append(struct ast_category *category, struct ast_variable *variable);
 
-#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) \
-{ \
-       ast_mutex_init(&mutex); \
-} \
-static void  __attribute__ ((destructor)) fini_##mutex(void) \
-{ \
-       ast_mutex_destroy(&mutex); \
+static void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
+{
+       if (!variable)
+               return;
+       if (category->last)
+               category->last->next = variable;
+       else
+               category->root = variable;
+       category->last = variable;
+       while (category->last->next)
+               category->last = category->last->next;
 }
-#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 */
-
-#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
 
-#define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex)
+static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored);
 
-#define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
+static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored)
+{
+       struct ast_category *cat;
 
-#define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
+       /* try exact match first, then case-insensitive match */
+       for (cat = config->root; cat; cat = cat->next) {
+               if (cat->name == category_name && (ignored || !cat->ignored))
+                       return cat;
+       }
 
-#ifndef __linux__
-#define pthread_create __use_ast_pthread_create_instead__
-#endif
+       for (cat = config->root; cat; cat = cat->next) {
+               if (!strcasecmp(cat->name, category_name) && (ignored || !cat->ignored))
+                       return cat;
+       }
 
-typedef pthread_rwlock_t ast_rwlock_t;
+       return NULL;
+}
 
-static inline int ast_rwlock_init(ast_rwlock_t *prwlock)
+static struct ast_category *ast_category_get(const struct ast_config *config, const char *category_name)
 {
-       pthread_rwlockattr_t attr;
+       return category_get(config, category_name, 0);
+}
 
-       pthread_rwlockattr_init(&attr);
+static struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category)
+{
+       struct ast_category *cat = NULL;
 
-#ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
-       pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
-#endif
+       if (category && config->last_browse && (config->last_browse->name == category))
+               cat = config->last_browse;
+       else
+               cat = ast_category_get(config, category);
 
-       return pthread_rwlock_init(prwlock, &attr);
+       return (cat) ? cat->root : NULL;
 }
 
-static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
+static const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
 {
-       return pthread_rwlock_destroy(prwlock);
-}
+       struct ast_variable *v;
 
-static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
-{
-       return pthread_rwlock_unlock(prwlock);
+       if (category) {
+               for (v = ast_variable_browse(config, category); v; v = v->next) {
+                       if (!strcasecmp(variable, v->name))
+                               return v->value;
+               }
+       } else {
+               struct ast_category *cat;
+
+               for (cat = config->root; cat; cat = cat->next)
+                       for (v = cat->root; v; v = v->next)
+                               if (!strcasecmp(variable, v->name))
+                                       return v->value;
+       }
+
+       return NULL;
 }
 
-static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
+static struct ast_variable *variable_clone(const struct ast_variable *old)
 {
-       return pthread_rwlock_rdlock(prwlock);
-}
+       struct ast_variable *new = ast_variable_new(old->name, old->value, old->file);
 
-static inline int ast_rwlock_tryrdlock(ast_rwlock_t *prwlock)
+       if (new) {
+               new->lineno = old->lineno;
+               new->object = old->object;
+               new->blanklines = old->blanklines;
+               /* TODO: clone comments? */
+       }
+
+       return new;
+}
+static void ast_variables_destroy(struct ast_variable *v)
 {
-       return pthread_rwlock_tryrdlock(prwlock);
+       struct ast_variable *vn;
+
+       while (v) {
+               vn = v;
+               v = v->next;
+               free(vn);
+       }
 }
 
-static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
+static void ast_includes_destroy(struct ast_config_include *incls)
 {
-       return pthread_rwlock_wrlock(prwlock);
+       struct ast_config_include *incl,*inclnext;
+    
+       for (incl=incls; incl; incl = inclnext) {
+               inclnext = incl->next;
+               if (incl->include_location_file)
+                       free(incl->include_location_file);
+               if (incl->exec_file)
+                       free(incl->exec_file);
+               if (incl->included_file)
+                       free(incl->included_file);
+               free(incl);
+       }
 }
 
-static inline int ast_rwlock_trywrlock(ast_rwlock_t *prwlock)
+static void ast_config_destroy(struct ast_config *cfg)
 {
-       return pthread_rwlock_trywrlock(prwlock);
-}
+       struct ast_category *cat, *catn;
 
-/* Statically declared read/write locks */
+       if (!cfg)
+               return;
 
-#ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
-#define __AST_RWLOCK_DEFINE(scope, rwlock) \
-        scope ast_rwlock_t rwlock; \
-static void  __attribute__ ((constructor)) init_##rwlock(void) \
-{ \
-        ast_rwlock_init(&rwlock); \
-} \
-static void  __attribute__ ((destructor)) fini_##rwlock(void) \
-{ \
-        ast_rwlock_destroy(&rwlock); \
+       ast_includes_destroy(cfg->includes);
+       
+       cat = cfg->root;
+       while (cat) {
+               ast_variables_destroy(cat->root);
+               catn = cat;
+               cat = cat->next;
+               free(catn);
+       }
+       free(cfg);
 }
-#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()
- */
 
-int ast_atomic_fetchadd_int_slow(volatile int *p, int v);
+/* options.h declars ast_options extern; I need it static? */
 
-#if defined(HAVE_OSX_ATOMICS)
-#include "libkern/OSAtomic.h"
-#endif
+#define AST_CACHE_DIR_LEN      512
+#define AST_FILENAME_MAX       80
 
-/*! \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.
- */
+/*! These are the options that set by default when Asterisk starts */
+#define AST_DEFAULT_OPTIONS AST_OPT_FLAG_TRANSCODE_VIA_SLIN
 
-#if defined(HAVE_GCC_ATOMICS)
-AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
-{
-       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   /* low performance version in utils.c */
-AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
-{
-       return ast_atomic_fetchadd_int_slow(p, v);
-})
-#endif
+#define ast_opt_exec_includes          ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES)
+#define ast_opt_no_fork                        ast_test_flag(&ast_options, AST_OPT_FLAG_NO_FORK)
+#define ast_opt_quiet                  ast_test_flag(&ast_options, AST_OPT_FLAG_QUIET)
+#define ast_opt_console                        ast_test_flag(&ast_options, AST_OPT_FLAG_CONSOLE)
+#define ast_opt_high_priority          ast_test_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY)
+#define ast_opt_init_keys              ast_test_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS)
+#define ast_opt_remote                 ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)
+#define ast_opt_exec                   ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC)
+#define ast_opt_no_color               ast_test_flag(&ast_options, AST_OPT_FLAG_NO_COLOR)
+#define ast_fully_booted               ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)
+#define ast_opt_transcode_via_slin     ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN)
+#define ast_opt_priority_jumping       ast_test_flag(&ast_options, AST_OPT_FLAG_PRIORITY_JUMPING)
+#define ast_opt_dump_core              ast_test_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE)
+#define ast_opt_cache_record_files     ast_test_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES)
+#define ast_opt_timestamp              ast_test_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP)
+#define ast_opt_override_config                ast_test_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG)
+#define ast_opt_reconnect              ast_test_flag(&ast_options, AST_OPT_FLAG_RECONNECT)
+#define ast_opt_transmit_silence       ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE)
+#define ast_opt_dont_warn              ast_test_flag(&ast_options, AST_OPT_FLAG_DONT_WARN)
+#define ast_opt_end_cdr_before_h_exten ast_test_flag(&ast_options, AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN)
+#define ast_opt_internal_timing                ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING)
+#define ast_opt_always_fork            ast_test_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK)
+#define ast_opt_mute                   ast_test_flag(&ast_options, AST_OPT_FLAG_MUTE)
 
-/*! \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
+/*  IN CONFLICT: extern int option_verbose; */
+/*  IN CONFLICT: extern int option_debug;      */      /*!< Debugging */
+extern int option_maxcalls;            /*!< Maximum number of simultaneous channels */
+extern double option_maxload;
+extern char defaultlanguage[];
 
-#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
+extern pid_t ast_mainpid;
 
-/*! \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);
+extern char record_cache_dir[AST_CACHE_DIR_LEN];
+extern char debug_filename[AST_FILENAME_MAX];
 
-/*! \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);
+extern int ast_language_is_prefix;
 
-/*! \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
 
 
 /* linkedlists.h */
@@ -2628,8 +2580,8 @@ struct ast_switch {
 };
 
 
-static char *config = "extensions.conf";
-static char *registrar = "conf2ael";
+static char *config_filename = "extensions.conf";
+static char *global_registrar = "conf2ael";
 static char userscontext[AST_MAX_EXTENSION] = "default";
 static int static_config = 0;
 static int write_protect_config = 1;
@@ -2695,14 +2647,6 @@ static const char *ast_var_name(const struct ast_var_t *var)
        return name;
 }
 
-
-/* stolen from asterisk.c */
-
-static struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
-static int option_verbose = 0;                         /*!< Verbosity level */
-static int option_debug = 0;                           /*!< Debug level */
-
-
 /* experiment 1: see if it's easier just to use existing config code
  *               to read in the extensions.conf file. In this scenario, 
                  I have to rip/copy code from other modules, because they
@@ -2724,7 +2668,7 @@ static void ast_log(int level, const char *file, int line, const char *function,
        va_end(vars);
 }
 
-static void ast_verbose(const char *fmt, ...)
+void __attribute__((format (printf, 1, 2))) ast_verbose(const char *fmt, ...)
 {
        va_list vars;
        va_start(vars,fmt);
@@ -3780,9 +3724,9 @@ static struct ast_config *config_text_file_load(const char *database, const char
                                }
                                
                                if (process_buf) {
-                                       char *buf = ast_strip(process_buf);
-                                       if (!ast_strlen_zero(buf)) {
-                                               if (process_text_line(cfg, &cat, buf, lineno, filename, withcomments, suggested_include_file)) {
+                                       char *stripped_process_buf = ast_strip(process_buf);
+                                       if (!ast_strlen_zero(stripped_process_buf)) {
+                                               if (process_text_line(cfg, &cat, stripped_process_buf, lineno, filename, withcomments, suggested_include_file)) {
                                                        cfg = NULL;
                                                        break;
                                                }
@@ -4462,7 +4406,7 @@ static int ext_cmp1(const char **p)
                return 0x40000; /* XXX make this entry go last... */
        }
 
-       bzero(chars, sizeof(chars));    /* clear all chars in the set */
+       memset(chars, '\0', sizeof(chars));     /* clear all chars in the set */
        for (; *p < end  ; (*p)++) {
                unsigned char c1, c2;   /* first-last char in range */
                c1 = (unsigned char)((*p)[0]);
@@ -5238,16 +5182,16 @@ int localized_context_add_switch2(struct ast_context *con, const char *value,
 
 static struct ast_context *__ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar, int existsokay)
 {
-       struct ast_context *tmp, **local_contexts;
+       struct ast_context *tmp, **loc_contexts;
        int length = sizeof(struct ast_context) + strlen(name) + 1;
 
        if (!extcontexts) {
                ast_wrlock_contexts();
-               local_contexts = &contexts;
+               loc_contexts = &contexts;
        } else
-               local_contexts = extcontexts;
+               loc_contexts = extcontexts;
 
-       for (tmp = *local_contexts; tmp; tmp = tmp->next) {
+       for (tmp = *loc_contexts; tmp; tmp = tmp->next) {
                if (!strcasecmp(tmp->name, name)) {
                        if (!existsokay) {
                                ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
@@ -5264,10 +5208,10 @@ static struct ast_context *__ast_context_create(struct ast_context **extcontexts
                strcpy(tmp->name, name);
                tmp->root = NULL;
                tmp->registrar = registrar;
-               tmp->next = *local_contexts;
+               tmp->next = *loc_contexts;
                tmp->includes = NULL;
                tmp->ignorepats = NULL;
-               *local_contexts = tmp;
+               *loc_contexts = tmp;
                if (option_debug)
                        ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
                if (option_verbose > 2)
@@ -5511,20 +5455,18 @@ static int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *c
        return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL);
 }
 
-static struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, const char *name, const char *registrar)
+static struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, void *tab, const char *name, const char *registrar)
 {
        return __ast_context_create(extcontexts, name, registrar, 1);
 }
 
-struct ast_context *localized_context_create(struct ast_context **extcontexts, const char *name, const char *registrar);
-
-struct ast_context *localized_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
+struct ast_context *localized_context_find_or_create(struct ast_context **extcontexts, void *tab, const char *name, const char *registrar);
+struct ast_context *localized_context_find_or_create(struct ast_context **extcontexts, void *tab, const char *name, const char *registrar)
 {
-       return __ast_context_create(extcontexts, name, registrar, 0);
+       return __ast_context_create(extcontexts, name, registrar, 1);
 }
 
 
-
 /* chopped this one off at the knees */
 static int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
 {
@@ -5907,7 +5849,7 @@ static int pbx_load_config(const char *config_file)
                /* All categories but "general" or "globals" are considered contexts */
                if (!strcasecmp(cxt, "general") || !strcasecmp(cxt, "globals"))
                        continue;
-               con=ast_context_find_or_create(&local_contexts,cxt, registrar);
+               con=ast_context_find_or_create(&local_contexts,NULL,cxt, global_registrar);
                if (con == NULL)
                        continue;
 
@@ -5995,7 +5937,7 @@ static int pbx_load_config(const char *config_file)
                                                lastpri = ipri;
                                                if (!ast_opt_dont_warn && !strcmp(realext, "_."))
                                                        ast_log(LOG_WARNING, "The use of '_.' for an extension is strongly discouraged and can have unexpected behavior.  Please use '_X.' instead at line %d\n", v->lineno);
-                                               if (ast_add_extension2(con, 0, realext, ipri, label, cidmatch, appl, strdup(data), ast_free, registrar)) {
+                                               if (ast_add_extension2(con, 0, realext, ipri, label, cidmatch, appl, strdup(data), ast_free, global_registrar)) {
                                                        ast_log(LOG_WARNING, "Unable to register extension at line %d\n", v->lineno);
                                                }
                                        }
@@ -6004,12 +5946,12 @@ static int pbx_load_config(const char *config_file)
                        } else if (!strcasecmp(v->name, "include")) {
                                memset(realvalue, 0, sizeof(realvalue));
                                pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
-                               if (ast_context_add_include2(con, realvalue, registrar))
+                               if (ast_context_add_include2(con, realvalue, global_registrar))
                                        ast_log(LOG_WARNING, "Unable to include context '%s' in context '%s'\n", v->value, cxt);
                        } else if (!strcasecmp(v->name, "ignorepat")) {
                                memset(realvalue, 0, sizeof(realvalue));
                                pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
-                               if (ast_context_add_ignorepat2(con, realvalue, registrar))
+                               if (ast_context_add_ignorepat2(con, realvalue, global_registrar))
                                        ast_log(LOG_WARNING, "Unable to include ignorepat '%s' in context '%s'\n", v->value, cxt);
                        } else if (!strcasecmp(v->name, "switch") || !strcasecmp(v->name, "lswitch") || !strcasecmp(v->name, "eswitch")) {
                                char *stringp= realvalue;
@@ -6024,7 +5966,7 @@ static int pbx_load_config(const char *config_file)
                                data = strsep(&stringp, ""); /* XXX what for ? */
                                if (!data)
                                        data = "";
-                               if (ast_context_add_switch2(con, appl, data, !strcasecmp(v->name, "eswitch"), registrar))
+                               if (ast_context_add_switch2(con, appl, data, !strcasecmp(v->name, "eswitch"), global_registrar))
                                        ast_log(LOG_WARNING, "Unable to include switch '%s' in context '%s'\n", v->value, cxt);
                        } else {
                                ast_log(LOG_WARNING, "==!!== Unknown directive: %s at line %d -- IGNORING!!!\n", v->name, v->lineno);
@@ -6184,12 +6126,12 @@ int localized_pbx_load_module(void)
 {
        struct ast_context *con;
 
-       if(!pbx_load_config(config))
+       if(!pbx_load_config(config_filename))
                return -1 /* AST_MODULE_LOAD_DECLINE*/;
 
        /* pbx_load_users(); */ /* does this affect the dialplan? */
 
-       ast_merge_contexts_and_delete(&local_contexts, registrar);
+       ast_merge_contexts_and_delete(&local_contexts, global_registrar);
 
        for (con = NULL; (con = ast_walk_contexts(con));)
                ast_context_verify_includes(con);