aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--asterisk.c77
-rw-r--r--channel.c26
-rw-r--r--channels/chan_iax2.c11
-rw-r--r--channels/chan_sip.c11
-rw-r--r--cli.c47
-rw-r--r--include/asterisk/compiler.h1
-rw-r--r--include/asterisk/logger.h6
-rw-r--r--include/asterisk/threadstorage.h427
-rw-r--r--include/asterisk/utils.h17
-rw-r--r--logger.c371
-rw-r--r--manager.c28
-rw-r--r--pbx/pbx_ael.c14
-rw-r--r--pbx/pbx_config.c11
-rw-r--r--res/res_agi.c2
-rw-r--r--res/res_features.c15
-rw-r--r--utils.c62
16 files changed, 700 insertions, 426 deletions
diff --git a/asterisk.c b/asterisk.c
index d9d962797..b523bfb0d 100644
--- a/asterisk.c
+++ b/asterisk.c
@@ -746,23 +746,9 @@ void ast_console_puts(const char *string)
ast_network_puts(string);
}
-static void network_verboser(const char *s, int pos, int replace, int complete)
- /* ARGUSED */
-{
- if (replace) {
- char *t;
- if ((t = alloca(strlen(s) + 2))) {
- sprintf(t, "\r%s", s);
- if (complete)
- ast_network_puts_mutable(t);
- } else {
- ast_log(LOG_ERROR, "Out of memory\n");
- ast_network_puts_mutable(s);
- }
- } else {
- if (complete)
- ast_network_puts_mutable(s);
- }
+static void network_verboser(const char *s)
+{
+ ast_network_puts_mutable(s);
}
static pthread_t lthread;
@@ -1203,29 +1189,25 @@ static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp
return NULL;
}
-static void console_verboser(const char *s, int pos, int replace, int complete)
+static void console_verboser(const char *s)
{
char tmp[80];
const char *c = NULL;
- /* Return to the beginning of the line */
- if (!pos) {
- fprintf(stdout, "\r");
- if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
- (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
- (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
- (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1)))
- fputs(tmp, stdout);
- }
- if (c)
- fputs(c + pos,stdout);
- else
- fputs(s + pos,stdout);
+
+ if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
+ (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
+ (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
+ (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
+ fputs(tmp, stdout);
+ fputs(c, stdout);
+ } else
+ fputs(s, stdout);
+
fflush(stdout);
- if (complete) {
- /* Wake up a poll()ing console */
- if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
- pthread_kill(consolethread, SIGURG);
- }
+
+ /* Wake up a poll()ing console */
+ if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
+ pthread_kill(consolethread, SIGURG);
}
static int ast_all_zeros(char *s)
@@ -2427,6 +2409,14 @@ int main(int argc, char *argv[])
}
}
+ if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
+ ast_register_verbose(console_verboser);
+ WELCOME_MESSAGE;
+ }
+
+ if (ast_opt_console && !option_verbose)
+ ast_verbose("[ Booting...\n");
+
if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
@@ -2443,7 +2433,7 @@ int main(int argc, char *argv[])
}
if (ast_opt_console && !option_verbose)
- ast_verbose("[ Reading Master Configuration ]");
+ ast_verbose("[ Reading Master Configuration ]\n");
ast_readconfig();
if (ast_opt_dump_core) {
@@ -2526,7 +2516,7 @@ int main(int argc, char *argv[])
fflush(stdout);
if (ast_opt_console && !option_verbose)
- ast_verbose("[ Initializing Custom Configuration Options ]");
+ ast_verbose("[ Initializing Custom Configuration Options ]\n");
/* custom config setup */
register_config_cli();
read_config_maps();
@@ -2548,8 +2538,6 @@ int main(int argc, char *argv[])
exit(0);
}
printf(term_quit());
- ast_register_verbose(console_verboser);
- WELCOME_MESSAGE;
ast_remotecontrol(NULL);
quit_handler(0, 0, 0, 0);
exit(0);
@@ -2597,15 +2585,6 @@ int main(int argc, char *argv[])
sigaddset(&sigs, SIGPIPE);
sigaddset(&sigs, SIGWINCH);
pthread_sigmask(SIG_BLOCK, &sigs, NULL);
- if (ast_opt_console || option_verbose || ast_opt_remote)
- ast_register_verbose(console_verboser);
- /* Print a welcome message if desired */
- if (option_verbose || ast_opt_console) {
- WELCOME_MESSAGE;
- }
- if (ast_opt_console && !option_verbose)
- ast_verbose("[ Booting...");
-
signal(SIGURG, urg_handler);
signal(SIGINT, __quit_handler);
signal(SIGTERM, __quit_handler);
diff --git a/channel.c b/channel.c
index f2700b29e..e978f4888 100644
--- a/channel.c
+++ b/channel.c
@@ -66,6 +66,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/transcap.h"
#include "asterisk/devicestate.h"
#include "asterisk/sha1.h"
+#include "asterisk/threadstorage.h"
#include "asterisk/slinfactory.h"
struct channel_spy_trans {
@@ -99,8 +100,7 @@ static int uniqueint = 0;
unsigned long global_fin = 0, global_fout = 0;
-static pthread_key_t state2str_buf_key;
-static pthread_once_t state2str_buf_once = PTHREAD_ONCE_INIT;
+AST_THREADSTORAGE(state2str_threadbuf, state2str_threadbuf_init);
#define STATE2STR_BUFSIZE 32
struct chanlist {
@@ -167,15 +167,6 @@ const struct ast_cause {
{ AST_CAUSE_INTERWORKING, "INTERWORKING", "Interworking, unspecified" },
};
-#ifdef __AST_DEBUG_MALLOC
-static void FREE(void *ptr)
-{
- free(ptr);
-}
-#else
-#define FREE free
-#endif
-
struct ast_variable *ast_channeltype_list(void)
{
struct chanlist *cl;
@@ -500,11 +491,6 @@ int ast_str2cause(const char *name)
return -1;
}
-static void state2str_buf_key_create(void)
-{
- pthread_key_create(&state2str_buf_key, FREE);
-}
-
/*! \brief Gives the string form of a given channel state */
char *ast_state2str(int state)
{
@@ -532,12 +518,8 @@ char *ast_state2str(int state)
case AST_STATE_PRERING:
return "Pre-ring";
default:
- pthread_once(&state2str_buf_once, state2str_buf_key_create);
- if (!(buf = pthread_getspecific(state2str_buf_key))) {
- if (!(buf = ast_malloc(STATE2STR_BUFSIZE)))
- return NULL;
- pthread_setspecific(state2str_buf_key, buf);
- }
+ if (!(buf = ast_threadstorage_get(&state2str_threadbuf, STATE2STR_BUFSIZE)))
+ return "Unknown";
snprintf(buf, STATE2STR_BUFSIZE, "Unknown (%d)", state);
return buf;
}
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index d78b3f200..2809003e6 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -712,15 +712,6 @@ static AST_LIST_HEAD_STATIC(dynamic_list, iax2_thread);
static void *iax2_process_thread(void *data);
-#ifdef __AST_DEBUG_MALLOC
-static void FREE(void *ptr)
-{
- free(ptr);
-}
-#else
-#define FREE free
-#endif
-
static void signal_condition(ast_mutex_t *lock, ast_cond_t *cond)
{
ast_mutex_lock(lock);
@@ -5472,7 +5463,7 @@ static void register_peer_exten(struct iax2_peer *peer, int onoff)
if (onoff) {
if (!ast_exists_extension(NULL, regcontext, ext, 1, NULL))
ast_add_extension(regcontext, 1, ext, 1, NULL, NULL,
- "Noop", ast_strdup(peer->name), FREE, "IAX2");
+ "Noop", ast_strdup(peer->name), ast_free, "IAX2");
} else
ast_context_remove_extension(regcontext, ext, 1, NULL);
}
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index cbe8cbb8c..0aeb0f5c3 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -1538,15 +1538,6 @@ static struct ast_udptl_protocol sip_udptl = {
set_udptl_peer: sip_set_udptl_peer,
};
-#ifdef __AST_DEBUG_MALLOC
-static void FREE(void *ptr)
-{
- free(ptr);
-}
-#else
-#define FREE free
-#endif
-
/*! \brief Convert transfer status to string */
static char *referstatus2str(enum referstatus rstatus)
{
@@ -2253,7 +2244,7 @@ static void register_peer_exten(struct sip_peer *peer, int onoff)
}
if (onoff)
ast_add_extension(context, 1, ext, 1, NULL, NULL, "Noop",
- ast_strdup(peer->name), FREE, "SIP");
+ ast_strdup(peer->name), ast_free, "SIP");
else
ast_context_remove_extension(context, ext, 1, NULL);
}
diff --git a/cli.c b/cli.c
index 6afd56d5e..6e1d95039 100644
--- a/cli.c
+++ b/cli.c
@@ -48,62 +48,29 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/app.h"
#include "asterisk/lock.h"
#include "editline/readline/readline.h"
+#include "asterisk/threadstorage.h"
extern unsigned long global_fin, global_fout;
-static pthread_key_t ast_cli_buf_key;
-static pthread_once_t ast_cli_buf_once = PTHREAD_ONCE_INIT;
+AST_THREADSTORAGE(ast_cli_buf, ast_cli_buf_init);
/*! \brief Initial buffer size for resulting strings in ast_cli() */
#define AST_CLI_MAXSTRLEN 256
-#ifdef __AST_DEBUG_MALLOC
-static void FREE(void *ptr)
-{
- free(ptr);
-}
-#else
-#define FREE free
-#endif
-
-static void ast_cli_buf_key_create(void)
-{
- pthread_key_create(&ast_cli_buf_key, FREE);
-}
-
void ast_cli(int fd, char *fmt, ...)
{
- struct {
- size_t len;
- char str[0];
- } *buf;
int res;
+ struct ast_dynamic_str *buf;
va_list ap;
- pthread_once(&ast_cli_buf_once, ast_cli_buf_key_create);
- if (!(buf = pthread_getspecific(ast_cli_buf_key))) {
- if (!(buf = ast_malloc(AST_CLI_MAXSTRLEN + sizeof(*buf))))
- return;
- buf->len = AST_CLI_MAXSTRLEN;
- pthread_setspecific(ast_cli_buf_key, buf);
- }
+ if (!(buf = ast_dynamic_str_thread_get(&ast_cli_buf, AST_CLI_MAXSTRLEN)))
+ return;
va_start(ap, fmt);
- res = vsnprintf(buf->str, buf->len, fmt, ap);
- while (res >= buf->len) {
- if (!(buf = ast_realloc(buf, (buf->len * 2) + sizeof(*buf)))) {
- va_end(ap);
- return;
- }
- buf->len *= 2;
- pthread_setspecific(ast_cli_buf_key, buf);
- va_end(ap);
- va_start(ap, fmt);
- res = vsnprintf(buf->str, buf->len, fmt, ap);
- }
+ res = ast_dynamic_str_thread_set_va(&buf, 0, &ast_cli_buf, fmt, ap);
va_end(ap);
- if (res > 0)
+ if (res != AST_DYNSTR_BUILD_FAILED)
ast_carefulwrite(fd, buf->str, strlen(buf->str), 100);
}
diff --git a/include/asterisk/compiler.h b/include/asterisk/compiler.h
index a36138d8a..575a1b2d3 100644
--- a/include/asterisk/compiler.h
+++ b/include/asterisk/compiler.h
@@ -33,5 +33,6 @@
#endif
#define attribute_const __attribute__((const))
+#define attribute_unused __attribute__((unused))
#endif /* _ASTERISK_COMPILER_H */
diff --git a/include/asterisk/logger.h b/include/asterisk/logger.h
index 247ac8326..6e486620d 100644
--- a/include/asterisk/logger.h
+++ b/include/asterisk/logger.h
@@ -77,9 +77,9 @@ void ast_queue_log(const char *queuename, const char *callid, const char *agent,
void ast_verbose(const char *fmt, ...)
__attribute__ ((format (printf, 1, 2)));
-int ast_register_verbose(void (*verboser)(const char *string, int opos, int replacelast, int complete));
-int ast_unregister_verbose(void (*verboser)(const char *string, int opos, int replacelast, int complete));
-int ast_verbose_dmesg(void (*verboser)(const char *string, int opos, int replacelast, int complete));
+int ast_register_verbose(void (*verboser)(const char *string));
+int ast_unregister_verbose(void (*verboser)(const char *string));
+
void ast_console_puts(const char *string);
void ast_console_puts_mutable(const char *string);
diff --git a/include/asterisk/threadstorage.h b/include/asterisk/threadstorage.h
new file mode 100644
index 000000000..6e141a5d2
--- /dev/null
+++ b/include/asterisk/threadstorage.h
@@ -0,0 +1,427 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2006, Digium, Inc.
+ *
+ * Russell Bryant <russell@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file threadstorage.h
+ * \author Russell Bryant <russell@digium.com>
+ *
+ * \brief Definitions to aid in the use of thread local storage
+*/
+
+#ifndef ASTERISK_THREADSTORAGE_H
+#define ASTERISK_THREADSTORAGE_H
+
+#include <pthread.h>
+
+#include "asterisk/utils.h"
+#include "asterisk/inline_api.h"
+
+/*!
+ * \brief data for a thread locally stored variable
+ */
+struct ast_threadstorage {
+ /*! Ensure that the key is only initialized by one thread */
+ pthread_once_t once;
+ /*! The key used to retrieve this thread's data */
+ pthread_key_t key;
+ /*! The function that initializes the key */
+ void (*key_init)(void);
+};
+
+/*!
+ * \brief Define a thread storage variable
+ *
+ * \arg name The name of the thread storage
+ * \arg name_init This is a name used to create the function that gets called
+ * to initialize this thread storage. It can be anything since it will not
+ * be referred to anywhere else
+ *
+ * This macro would be used to declare an instance of thread storage in a file.
+ *
+ * Example usage:
+ * \code
+ * AST_THREADSTORAGE(my_buf, my_buf_init);
+ * \endcode
+ */
+#define AST_THREADSTORAGE(name, name_init) \
+ AST_THREADSTORAGE_CUSTOM(name, name_init, ast_free)
+
+#define AST_THREADSTORAGE_CUSTOM(name, name_init, cleanup) \
+static void name_init(void); \
+static struct ast_threadstorage name = { \
+ .once = PTHREAD_ONCE_INIT, \
+ .key_init = name_init, \
+}; \
+static void name_init(void) \
+{ \
+ pthread_key_create(&(name).key, cleanup); \
+}
+
+/*!
+ * \brief Retrieve thread storage
+ *
+ * \arg ts This is a pointer to the thread storage structure declared by using
+ * the AST_THREADSTORAGE macro. If declared with
+ * AST_THREADSTORAGE(my_buf, my_buf_init), then this argument would be
+ * (&my_buf).
+ * \arg init_size This is the amount of space to be allocated the first time
+ * this thread requests its data. Thus, this should be the size that the
+ * code accessing this thread storage is assuming the size to be.
+ *
+ * \return This function will return the thread local storage associated with
+ * the thread storage management variable passed as the first argument.
+ * The result will be NULL in the case of a memory allocation error.
+ *
+ * Example usage:
+ * \code
+ * AST_THREADSTORAGE(my_buf, my_buf_init);
+ * #define MY_BUF_SIZE 128
+ * ...
+ * void my_func(const char *fmt, ...)
+ * {
+ * void *buf;
+ *
+ * if (!(buf = ast_threadstorage_get(&my_buf, MY_BUF_SIZE)))
+ * return;
+ * ...
+ * }
+ * \endcode
+ */
+AST_INLINE_API(
+void *ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size),
+{
+ void *buf;
+
+ pthread_once(&ts->once, ts->key_init);
+ if (!(buf = pthread_getspecific(ts->key))) {
+ if (!(buf = ast_calloc(1, init_size)))
+ return NULL;
+ pthread_setspecific(ts->key, buf);
+ }
+
+ return buf;
+}
+)
+
+/*!
+ * \brief A dynamic length string
+ */
+struct ast_dynamic_str {
+ /* The current maximum length of the string */
+ size_t len;
+ /* The string buffer */
+ char str[0];
+};
+
+/*!
+ * \brief Create a dynamic length string
+ *
+ * \arg init_len This is the initial length of the string buffer
+ *
+ * \return This function returns a pointer to the dynamic string length. The
+ * result will be NULL in the case of a memory allocation error.
+ *
+ * /note The result of this function is dynamically allocated memory, and must
+ * be free()'d after it is no longer needed.
+ */
+AST_INLINE_API(
+struct ast_dynamic_str *__attribute__ ((malloc)) ast_dynamic_str_create(size_t init_len),
+{
+ struct ast_dynamic_str *buf;
+
+ if (!(buf = ast_calloc(1, sizeof(*buf) + init_len)))
+ return NULL;
+
+ buf->len = init_len;
+
+ return buf;
+}
+)
+
+/*!
+ * \brief Retrieve a thread locally stored dynamic string
+ *
+ * \arg ts This is a pointer to the thread storage structure declared by using
+ * the AST_THREADSTORAGE macro. If declared with
+ * AST_THREADSTORAGE(my_buf, my_buf_init), then this argument would be
+ * (&my_buf).
+ * \arg init_len This is the initial length of the thread's dynamic string. The
+ * current length may be bigger if previous operations in this thread have
+ * caused it to increase.
+ *
+ * \return This function will return the thread locally storaged dynamic string
+ * associated with the thread storage management variable passed as the
+ * first argument.
+ * The result will be NULL in the case of a memory allocation error.
+ *
+ * Example usage:
+ * \code
+ * AST_THREADSTORAGE(my_str, my_str_init);
+ * #define MY_STR_INIT_SIZE 128
+ * ...
+ * void my_func(const char *fmt, ...)
+ * {
+ * struct ast_dynamic_str *buf;
+ *
+ * if (!(buf = ast_dynamic_str_thread_get(&my_str, MY_STR_INIT_SIZE)))
+ * return;
+ * ...
+ * }
+ * \endcode
+ */
+AST_INLINE_API(
+struct ast_dynamic_str *ast_dynamic_str_thread_get(struct ast_threadstorage *ts,
+ size_t init_len),
+{
+ struct ast_dynamic_str *buf;
+
+ if (!(buf = ast_threadstorage_get(ts, sizeof(*buf) + init_len)))
+ return NULL;
+
+ if (!buf->len)
+ buf->len = init_len;
+
+ return buf;
+}
+)
+
+/*!
+ * \brief Error codes from ast_dynamic_str_thread_build_va()
+ */
+enum {
+ /*! An error has occured and the contents of the dynamic string
+ * are undefined */
+ AST_DYNSTR_BUILD_FAILED = -1,
+ /*! The buffer size for the dynamic string had to be increased, and
+ * ast_dynamic_str_thread_build_va() needs to be called again after
+ * a va_end() and va_start().
+ */
+ AST_DYNSTR_BUILD_RETRY = -2
+};
+
+/*!
+ * \brief Set a thread locally stored dynamic string from a va_list
+ *
+ * \arg buf This is the address of a pointer to an ast_dynamic_str which should
+ * have been retrieved using ast_dynamic_str_thread_get. It will need to
+ * be updated in the case that the buffer has to be reallocated to
+ * accomodate a longer string than what it currently has space for.
+ * \arg max_len This is the maximum length to allow the string buffer to grow
+ * to. If this is set to 0, then there is no maximum length.
+ * \arg ts This is a pointer to the thread storage structure declared by using
+ * the AST_THREADSTORAGE macro. If declared with
+ * AST_THREADSTORAGE(my_buf, my_buf_init), then this argument would be
+ * (&my_buf).
+ * \arg fmt This is the format string (printf style)
+ * \arg ap This is the va_list
+ *
+ * \return The return value of this function is the same as that of the printf
+ * family of functions.
+ *
+ * Example usage:
+ * \code
+ * AST_THREADSTORAGE(my_str, my_str_init);
+ * #define MY_STR_INIT_SIZE 128
+ * ...
+ * void my_func(const char *fmt, ...)
+ * {
+ * struct ast_dynamic_str *buf;
+ * va_list ap;
+ *
+ * if (!(buf = ast_dynamic_str_thread_get(&my_str, MY_STR_INIT_SIZE)))
+ * return;
+ * ...
+ * va_start(fmt, ap);
+ * ast_dynamic_str_thread_set_va(&buf, 0, &my_str, fmt, ap);
+ * va_end(ap);
+ *
+ * printf("This is the string we just built: %s\n", buf->str);
+ * ...
+ * }
+ * \endcode
+ */
+#define ast_dynamic_str_thread_set_va(buf, max_len, ts, fmt, ap) \
+ ({ \
+ int __res; \
+ while ((__res = ast_dynamic_str_thread_build_va(buf, max_len, \
+ ts, 0, fmt, ap)) == AST_DYNSTR_BUILD_RETRY) { \
+ va_end(ap); \
+ va_start(ap, fmt); \
+ } \
+ (__res); \
+ })
+
+/*!
+ * \brief Append to a thread local dynamic string using a va_list
+ *
+ * The arguments, return values, and usage of this are the same as those for
+ * ast_dynamic_str_thread_set_va(). However, instead of setting a new value
+ * for the string, this will append to the current value.
+ */
+#define ast_dynamic_str_thread_append_va(buf, max_len, ts, fmt, ap) \
+ ({ \
+ int __res; \
+ while ((__res = ast_dynamic_str_thread_build_va(buf, max_len, \
+ ts, 1, fmt, ap)) == AST_DYNSTR_BUILD_RETRY) { \
+ va_end(ap); \
+ va_start(ap, fmt); \
+ } \
+ (__res); \
+ })
+
+/*!
+ * \brief Core functionality of ast_dynamic_str_thread_(set|append)_va
+ *
+ * The arguments to this function are the same as those described for
+ * ast_dynamic_str_thread_set_va except for an addition argument, append.
+ * If append is non-zero, this will append to the current string instead of
+ * writing over it.
+ */
+int ast_dynamic_str_thread_build_va(struct ast_dynamic_str **buf, size_t max_len,
+ struct ast_threadstorage *ts, int append, const char *fmt, va_list ap);
+
+/*!
+ * \brief Set a thread locally stored dynamic string using variable arguments
+ *
+ * \arg buf This is the address of a pointer to an ast_dynamic_str which should
+ * have been retrieved using ast_dynamic_str_thread_get. It will need to
+ * be updated in the case that the buffer has to be reallocated to
+ * accomodate a longer string than what it currently has space for.
+ * \arg max_len This is the maximum length to allow the string buffer to grow
+ * to. If this is set to 0, then there is no maximum length.
+ * \arg ts This is a pointer to the thread storage structure declared by using
+ * the AST_THREADSTORAGE macro. If declared with
+ * AST_THREADSTORAGE(my_buf, my_buf_init), then this argument would be
+ * (&my_buf).
+ * \arg fmt This is the format string (printf style)
+ *
+ * \return The return value of this function is the same as that of the printf
+ * family of functions.
+ *
+ * Example usage:
+ * \code
+ * AST_THREADSTORAGE(my_str, my_str_init);
+ * #define MY_STR_INIT_SIZE 128
+ * ...
+ * void my_func(int arg1, int arg2)
+ * {
+ * struct ast_dynamic_str *buf;
+ * va_list ap;
+ *
+ * if (!(buf = ast_dynamic_str_thread_get(&my_str, MY_STR_INIT_SIZE)))
+ * return;
+ * ...
+ * ast_dynamic_str_thread_set(&buf, 0, &my_str, "arg1: %d arg2: %d\n",
+ * arg1, arg2);
+ *
+ * printf("This is the string we just built: %s\n", buf->str);
+ * ...
+ * }
+ * \endcode
+ */
+AST_INLINE_API(
+int __attribute__ ((format (printf, 4, 5))) ast_dynamic_str_thread_set(
+ struct ast_dynamic_str **buf, size_t max_len,
+ struct ast_threadstorage *ts, const char *fmt, ...),
+{
+ int res;
+ va_list ap;
+
+ va_start(ap, fmt);
+ res = ast_dynamic_str_thread_set_va(buf, max_len, ts, fmt, ap);
+ va_end(ap);
+
+ return res;
+}
+)
+
+/*!
+ * \brief Append to a thread local dynamic string
+ *
+ * The arguments, return values, and usage of this function are the same as
+ * ast_dynamic_str_thread_set(). However, instead of setting a new value for
+ * the string, this function appends to the current value.
+ */
+AST_INLINE_API(
+int __attribute__ ((format (printf, 4, 5))) ast_dynamic_str_thread_append(
+ struct ast_dynamic_str **buf, size_t max_len,
+ struct ast_threadstorage *ts, const char *fmt, ...),
+{
+ int res;
+ va_list ap;
+
+ va_start(ap, fmt);
+ res = ast_dynamic_str_thread_append_va(buf, max_len, ts, fmt, ap);
+ va_end(ap);
+
+ return res;
+}
+)
+
+/*!
+ * \brief Set a dynamic string
+ *
+ * \arg buf This is the address of a pointer to an ast_dynamic_str. It will
+ * need to be updated in the case that the buffer has to be reallocated to
+ * accomodate a longer string than what it currently has space for.
+ * \arg max_len This is the maximum length to allow the string buffer to grow
+ * to. If this is set to 0, then there is no maximum length.
+ *
+ * \return The return value of this function is the same as that of the printf
+ * family of functions.
+ */
+AST_INLINE_API(
+int __attribute__ ((format (printf, 3, 4))) ast_dynamic_str_set(
+ struct ast_dynamic_str **buf, size_t max_len,
+ const char *fmt, ...),
+{
+ int res;
+ va_list ap;
+
+ va_start(ap, fmt);
+ res = ast_dynamic_str_thread_set_va(buf, max_len, NULL, fmt, ap);
+ va_end(ap);
+
+ return res;
+}
+)
+
+/*!
+ * \brief Append to a dynatic string
+ *
+ * The arguments, return values, and usage of this function are the same as
+ * ast_dynamic_str_set(). However, this function appends to the string instead
+ * of setting a new value.
+ */
+AST_INLINE_API(
+int __attribute__ ((format (printf, 3, 4))) ast_dynamic_str_append(
+ struct ast_dynamic_str **buf, size_t max_len,
+ const char *fmt, ...),
+{
+ int res;
+ va_list ap;
+
+ va_start(ap, fmt);
+ res = ast_dynamic_str_thread_append_va(buf, max_len, NULL, fmt, ap);
+ va_end(ap);
+
+ return res;
+}
+)
+
+#endif /* ASTERISK_THREADSTORAGE_H */
diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h
index ba1cd5948..ea8b352fb 100644
--- a/include/asterisk/utils.h
+++ b/include/asterisk/utils.h
@@ -35,6 +35,7 @@
#include "asterisk/time.h"
#include "asterisk/strings.h"
#include "asterisk/logger.h"
+#include "asterisk/compiler.h"
/*! \note
\verbatim
@@ -272,6 +273,22 @@ int getloadavg(double *list, int nelem);
long int ast_random(void);
#endif
+/*!
+ * \brief free() wrapper
+ *
+ * ast_free should be used when a function pointer for free() needs to be passed
+ * as the argument to a function. Otherwise, astmm will cause seg faults.
+ */
+#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
+
#ifndef __AST_DEBUG_MALLOC
/*!
diff --git a/logger.c b/logger.c
index a4f7c8c1d..532023b21 100644
--- a/logger.c
+++ b/logger.c
@@ -68,8 +68,7 @@ static int syslog_level_map[] = {
#include "asterisk/cli.h"
#include "asterisk/utils.h"
#include "asterisk/manager.h"
-
-#define MAX_MSG_QUEUE 200
+#include "asterisk/threadstorage.h"
#if defined(__linux__) && !defined(__NR_gettid)
#include <asm/unistd.h>
@@ -84,8 +83,6 @@ static int syslog_level_map[] = {
static char dateformat[256] = "%b %e %T"; /* Original Asterisk Format */
-AST_MUTEX_DEFINE_STATIC(msglist_lock);
-AST_MUTEX_DEFINE_STATIC(loglock);
static int filesize_reload_needed = 0;
static int global_logmask = -1;
@@ -94,11 +91,6 @@ static struct {
unsigned int event_log:1;
} logfiles = { 1, 1 };
-static struct msglist {
- char *msg;
- struct msglist *next;
-} *list = NULL, *last = NULL;
-
static char hostname[MAXHOSTNAMELEN];
enum logtypes {
@@ -114,12 +106,10 @@ struct logchannel {
enum logtypes type; /* Type of log channel */
FILE *fileptr; /* logfile logging file pointer */
char filename[256]; /* Filename */
- struct logchannel *next; /* Next channel in chain */
+ AST_LIST_ENTRY(logchannel) list;
};
-static struct logchannel *logchannels = NULL;
-
-static int msgcnt = 0;
+static AST_LIST_HEAD_STATIC(logchannels, logchannel);
static FILE *eventlog = NULL;
static FILE *qlog = NULL;
@@ -144,6 +134,12 @@ static int colors[] = {
COLOR_BRGREEN
};
+AST_THREADSTORAGE(verbose_buf, verbose_buf_init);
+#define VERBOSE_BUF_INIT_SIZE 128
+
+AST_THREADSTORAGE(log_buf, log_buf_init);
+#define LOG_BUF_INIT_SIZE 128
+
static int make_components(char *s, int lineno)
{
char *w;
@@ -287,21 +283,16 @@ static struct logchannel *make_logchannel(char *channel, char *components, int l
static void init_logger_chain(void)
{
- struct logchannel *chan, *cur;
+ struct logchannel *chan;
struct ast_config *cfg;
struct ast_variable *var;
char *s;
/* delete our list of log channels */
- ast_mutex_lock(&loglock);
- chan = logchannels;
- while (chan) {
- cur = chan->next;
+ AST_LIST_LOCK(&logchannels);
+ while ((chan = AST_LIST_REMOVE_HEAD(&logchannels, list)))
free(chan);
- chan = cur;
- }
- logchannels = NULL;
- ast_mutex_unlock(&loglock);
+ AST_LIST_UNLOCK(&logchannels);
global_logmask = 0;
/* close syslog */
@@ -316,16 +307,16 @@ static void init_logger_chain(void)
return;
chan->type = LOGTYPE_CONSOLE;
chan->logmask = 28; /*warning,notice,error */
- chan->next = logchannels;
- logchannels = chan;
+ AST_LIST_LOCK(&logchannels);
+ AST_LIST_INSERT_HEAD(&logchannels, chan, list);
+ AST_LIST_UNLOCK(&logchannels);
global_logmask |= chan->logmask;
return;
}
- ast_mutex_lock(&loglock);
if ((s = ast_variable_retrieve(cfg, "general", "appendhostname"))) {
- if(ast_true(s)) {
- if(gethostname(hostname, sizeof(hostname)-1)) {
+ if (ast_true(s)) {
+ if (gethostname(hostname, sizeof(hostname) - 1)) {
ast_copy_string(hostname, "unknown", sizeof(hostname));
ast_log(LOG_WARNING, "What box has no hostname???\n");
}
@@ -333,36 +324,32 @@ static void init_logger_chain(void)
hostname[0] = '\0';
} else
hostname[0] = '\0';
- if ((s = ast_variable_retrieve(cfg, "general", "dateformat"))) {
+ if ((s = ast_variable_retrieve(cfg, "general", "dateformat")))
ast_copy_string(dateformat, s, sizeof(dateformat));
- } else
+ else
ast_copy_string(dateformat, "%b %e %T", sizeof(dateformat));
- if ((s = ast_variable_retrieve(cfg, "general", "queue_log"))) {
+ if ((s = ast_variable_retrieve(cfg, "general", "queue_log")))
logfiles.queue_log = ast_true(s);
- }
- if ((s = ast_variable_retrieve(cfg, "general", "event_log"))) {
+ if ((s = ast_variable_retrieve(cfg, "general", "event_log")))
logfiles.event_log = ast_true(s);
- }
+ AST_LIST_LOCK(&logchannels);
var = ast_variable_browse(cfg, "logfiles");
- while(var) {
- chan = make_logchannel(var->name, var->value, var->lineno);
- if (chan) {
- chan->next = logchannels;
- logchannels = chan;
- global_logmask |= chan->logmask;
- }
- var = var->next;
+ for (; var; var = var->next) {
+ if (!(chan = make_logchannel(var->name, var->value, var->lineno)))
+ continue;
+ AST_LIST_INSERT_HEAD(&logchannels, chan, list);
+ global_logmask |= chan->logmask;
}
+ AST_LIST_UNLOCK(&logchannels);
ast_config_destroy(cfg);
- ast_mutex_unlock(&loglock);
}
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...)
{
va_list ap;
- ast_mutex_lock(&loglock);
+ AST_LIST_LOCK(&logchannels);
if (qlog) {
va_start(ap, fmt);
fprintf(qlog, "%ld|%s|%s|%s|%s|", (long)time(NULL), callid, queuename, agent, event);
@@ -371,7 +358,7 @@ void ast_queue_log(const char *queuename, const char *callid, const char *agent,
va_end(ap);
fflush(qlog);
}
- ast_mutex_unlock(&loglock);
+ AST_LIST_UNLOCK(&logchannels);
}
int reload_logger(int rotate)
@@ -383,8 +370,8 @@ int reload_logger(int rotate)
FILE *myf;
int x, res = 0;
- ast_mutex_lock(&msglist_lock); /* to avoid deadlock */
- ast_mutex_lock(&loglock);
+ AST_LIST_LOCK(&logchannels);
+
if (eventlog)
fclose(eventlog);
else
@@ -399,8 +386,7 @@ int reload_logger(int rotate)
mkdir((char *)ast_config_AST_LOG_DIR, 0755);
- f = logchannels;
- while(f) {
+ AST_LIST_TRAVERSE(&logchannels, f, list) {
if (f->disabled) {
f->disabled = 0; /* Re-enable logging at reload */
manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: Yes\r\n", f->filename);
@@ -408,17 +394,16 @@ int reload_logger(int rotate)
if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
fclose(f->fileptr); /* Close file */
f->fileptr = NULL;
- if(rotate) {
+ if (rotate) {
ast_copy_string(old, f->filename, sizeof(old));
- for(x=0;;x++) {
+ for (x = 0; ; x++) {
snprintf(new, sizeof(new), "%s.%d", f->filename, x);
myf = fopen((char *)new, "r");
- if (myf) {
+ if (myf)
fclose(myf);
- } else {
+ else
break;
- }
}
/* do it */
@@ -426,7 +411,6 @@ int reload_logger(int rotate)
fprintf(stderr, "Unable to rename file '%s' to '%s'\n", old, new);
}
}
- f = f->next;
}
filesize_reload_needed = 0;
@@ -489,8 +473,8 @@ int reload_logger(int rotate)
res = -1;
}
}
- ast_mutex_unlock(&loglock);
- ast_mutex_unlock(&msglist_lock);
+
+ AST_LIST_UNLOCK(&logchannels);
return res;
}
@@ -519,14 +503,12 @@ static int handle_logger_show_channels(int fd, int argc, char *argv[])
#define FORMATL "%-35.35s %-8.8s %-9.9s "
struct logchannel *chan;
- ast_mutex_lock(&loglock);
-
- chan = logchannels;
ast_cli(fd,FORMATL, "Channel", "Type", "Status");
ast_cli(fd, "Configuration\n");
ast_cli(fd,FORMATL, "-------", "----", "------");
ast_cli(fd, "-------------\n");
- while (chan) {
+ AST_LIST_LOCK(&logchannels);
+ AST_LIST_TRAVERSE(&logchannels, chan, list) {
ast_cli(fd, FORMATL, chan->filename, chan->type==LOGTYPE_CONSOLE ? "Console" : (chan->type==LOGTYPE_SYSLOG ? "Syslog" : "File"),
chan->disabled ? "Disabled" : "Enabled");
ast_cli(fd, " - ");
@@ -545,20 +527,19 @@ static int handle_logger_show_channels(int fd, int argc, char *argv[])
if (chan->logmask & (1 << __LOG_EVENT))
ast_cli(fd, "Event ");
ast_cli(fd, "\n");
- chan = chan->next;
}
+ AST_LIST_UNLOCK(&logchannels);
ast_cli(fd, "\n");
-
- ast_mutex_unlock(&loglock);
return RESULT_SUCCESS;
}
-static struct verb {
- void (*verboser)(const char *string, int opos, int replacelast, int complete);
- struct verb *next;
-} *verboser = NULL;
+struct verb {
+ void (*verboser)(const char *string);
+ AST_LIST_ENTRY(verb) list;
+};
+static AST_LIST_HEAD_STATIC(verbosers, verb);
static char logger_reload_help[] =
"Usage: logger reload\n"
@@ -637,21 +618,31 @@ int init_logger(void)
void close_logger(void)
{
- struct msglist *m, *tmp;
+ struct logchannel *f;
- ast_mutex_lock(&msglist_lock);
- m = list;
- while(m) {
- if (m->msg) {
- free(m->msg);
+ AST_LIST_LOCK(&logchannels);
+
+ if (eventlog) {
+ fclose(eventlog);
+ eventlog = NULL;
+ }
+
+ if (qlog) {
+ fclose(qlog);
+ qlog = NULL;
+ }
+
+ AST_LIST_TRAVERSE(&logchannels, f, list) {
+ if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
+ fclose(f->fileptr);
+ f->fileptr = NULL;
}
- tmp = m->next;
- free(m);
- m = tmp;
}
- list = last = NULL;
- msgcnt = 0;
- ast_mutex_unlock(&msglist_lock);
+
+ closelog(); /* syslog */
+
+ AST_LIST_UNLOCK(&logchannels);
+
return;
}
@@ -681,28 +672,30 @@ static void ast_log_vsyslog(int level, const char *file, int line, const char *f
syslog(syslog_level_map[level], "%s", buf);
}
-/*
- * send log messages to syslog and/or the console
+/*!
+ * \brief send log messages to syslog and/or the console
*/
void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
{
struct logchannel *chan;
- char buf[BUFSIZ];
+ struct ast_dynamic_str *buf;
time_t t;
struct tm tm;
char date[256];
va_list ap;
-
+
+ if (!(buf = ast_dynamic_str_thread_get(&log_buf, LOG_BUF_INIT_SIZE)))
+ return;
+
/* don't display LOG_DEBUG messages unless option_verbose _or_ option_debug
are non-zero; LOG_DEBUG messages can still be displayed if option_debug
is zero, if option_verbose is non-zero (this allows for 'level zero'
LOG_DEBUG messages to be displayed, if the logmask on any channel
allows it)
*/
- if (!option_verbose && !option_debug && (level == __LOG_DEBUG)) {
+ if (!option_verbose && !option_debug && (level == __LOG_DEBUG))
return;
- }
/* Ignore anything that never gets logged anywhere */
if (!(global_logmask & (1 << level)))
@@ -712,13 +705,12 @@ void ast_log(int level, const char *file, int line, const char *function, const
if ((level == __LOG_DEBUG) && !ast_strlen_zero(debug_filename) && strcasecmp(debug_filename, file))
return;
- /* begin critical section */
- ast_mutex_lock(&loglock);
-
time(&t);
localtime_r(&t, &tm);
strftime(date, sizeof(date), dateformat, &tm);
+ AST_LIST_LOCK(&logchannels);
+
if (logfiles.event_log && level == __LOG_EVENT) {
va_start(ap, fmt);
@@ -727,13 +719,14 @@ void ast_log(int level, const char *file, int line, const char *function, const
fflush(eventlog);
va_end(ap);
- ast_mutex_unlock(&loglock);
+ AST_LIST_UNLOCK(&logchannels);
return;
}
- if (logchannels) {
- chan = logchannels;
- while(chan && !chan->disabled) {
+ if (!AST_LIST_EMPTY(&logchannels)) {
+ AST_LIST_TRAVERSE(&logchannels, chan, list) {
+ if (chan->disabled)
+ break;
/* Check syslog channels */
if (chan->type == LOGTYPE_SYSLOG && (chan->logmask & (1 << level))) {
va_start(ap, fmt);
@@ -745,28 +738,33 @@ void ast_log(int level, const char *file, int line, const char *function, const
char tmp1[80], tmp2[80], tmp3[80], tmp4[80];
if (level != __LOG_VERBOSE) {
+ int res;
sprintf(linestr, "%d", line);
- snprintf(buf, sizeof(buf), "[%s] %s[%ld]: %s:%s %s: ",
+ ast_dynamic_str_thread_set(&buf, BUFSIZ, &log_buf,
+ "[%s] %s[%ld]: %s:%s %s: ",
date,
term_color(tmp1, levels[level], colors[level], 0, sizeof(tmp1)),
(long)GETTID(),
term_color(tmp2, file, COLOR_BRWHITE, 0, sizeof(tmp2)),
term_color(tmp3, linestr, COLOR_BRWHITE, 0, sizeof(tmp3)),
term_color(tmp4, function, COLOR_BRWHITE, 0, sizeof(tmp4)));
+
+ ast_console_puts_mutable(buf->str);
- ast_console_puts_mutable(buf);
va_start(ap, fmt);
- vsnprintf(buf, sizeof(buf), fmt, ap);
+ res = ast_dynamic_str_thread_set_va(&buf, BUFSIZ, &log_buf, fmt, ap);
va_end(ap);
- ast_console_puts_mutable(buf);
+ if (res != AST_DYNSTR_BUILD_FAILED)
+ ast_console_puts_mutable(buf->str);
}
/* File channels */
} else if ((chan->logmask & (1 << level)) && (chan->fileptr)) {
int res;
- snprintf(buf, sizeof(buf), "[%s] %s[%ld] %s: ", date,
- levels[level], (long)GETTID(), file);
- res = fprintf(chan->fileptr, buf);
- if (res <= 0 && buf[0] != '\0') { /* Error, no characters printed */
+ ast_dynamic_str_thread_set(&buf, BUFSIZ, &log_buf,
+ "[%s] %s[%ld] %s: ",
+ date, levels[level], (long)GETTID(), file);
+ res = fprintf(chan->fileptr, "%s", buf->str);
+ if (res <= 0 && !ast_strlen_zero(buf->str)) { /* Error, no characters printed */
fprintf(stderr,"**** Asterisk Logging Error: ***********\n");
if (errno == ENOMEM || errno == ENOSPC) {
fprintf(stderr, "Asterisk logging error: Out of disk space, can't log to log file %s\n", chan->filename);
@@ -775,16 +773,18 @@ void ast_log(int level, const char *file, int line, const char *function, const
manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: No\r\nReason: %d - %s\r\n", chan->filename, errno, strerror(errno));
chan->disabled = 1;
} else {
+ int res;
/* No error message, continue printing */
va_start(ap, fmt);
- vsnprintf(buf, sizeof(buf), fmt, ap);
+ res = ast_dynamic_str_thread_set_va(&buf, BUFSIZ, &log_buf, fmt, ap);
va_end(ap);
- term_strip(buf, buf, sizeof(buf));
- fputs(buf, chan->fileptr);
- fflush(chan->fileptr);
+ if (res != AST_DYNSTR_BUILD_FAILED) {
+ term_strip(buf->str, buf->str, buf->len);
+ fputs(buf->str, chan->fileptr);
+ fflush(chan->fileptr);
+ }
}
}
- chan = chan->next;
}
} else {
/*
@@ -792,15 +792,17 @@ void ast_log(int level, const char *file, int line, const char *function, const
* so just log to stdout
*/
if (level != __LOG_VERBOSE) {
+ int res;
va_start(ap, fmt);
- vsnprintf(buf, sizeof(buf), fmt, ap);
+ res = ast_dynamic_str_thread_set_va(&buf, BUFSIZ, &log_buf, fmt, ap);
va_end(ap);
- fputs(buf, stdout);
+ if (res != AST_DYNSTR_BUILD_FAILED)
+ fputs(buf->str, stdout);
}
}
- ast_mutex_unlock(&loglock);
- /* end critical section */
+ AST_LIST_UNLOCK(&logchannels);
+
if (filesize_reload_needed) {
reload_logger(1);
ast_log(LOG_EVENT,"Rotated Logs Per SIGXFSZ (Exceeded file size limit)\n");
@@ -840,17 +842,10 @@ void ast_backtrace(void)
void ast_verbose(const char *fmt, ...)
{
- static char stuff[4096];
- static int len = 0;
- static int replacelast = 0;
-
- int complete;
- int olen;
- struct msglist *m;
struct verb *v;
-
+ struct ast_dynamic_str *buf;
+ int res;
va_list ap;
- va_start(ap, fmt);
if (ast_opt_timestamp) {
time_t t;
@@ -866,128 +861,54 @@ void ast_verbose(const char *fmt, ...)
fmt = datefmt;
}
- /* this lock is also protecting against multiple threads
- being in this function at the same time, so it must be
- held before any of the static variables are accessed
- */
- ast_mutex_lock(&msglist_lock);
+ if (!(buf = ast_dynamic_str_thread_get(&verbose_buf, VERBOSE_BUF_INIT_SIZE)))
+ return;
- /* there is a potential security problem here: if formatting
- the current date using 'dateformat' results in a string
- containing '%', then the vsnprintf() call below will
- probably try to access random memory
- */
- vsnprintf(stuff + len, sizeof(stuff) - len, fmt, ap);
+ va_start(ap, fmt);
+ res = ast_dynamic_str_thread_set_va(&buf, 0, &verbose_buf, fmt, ap);
va_end(ap);
- olen = len;
- len = strlen(stuff);
-
- complete = (stuff[len - 1] == '\n') ? 1 : 0;
-
- /* If we filled up the stuff completely, then log it even without the '\n' */
- if (len >= sizeof(stuff) - 1) {
- complete = 1;
- len = 0;
- }
+ if (res == AST_DYNSTR_BUILD_FAILED)
+ return;
- if (complete) {
- if (msgcnt < MAX_MSG_QUEUE) {
- /* Allocate new structure */
- if ((m = ast_malloc(sizeof(*m))))
- msgcnt++;
- } else {
- /* Recycle the oldest entry */
- m = list;
- list = list->next;
- free(m->msg);
- }
- if (m) {
- if ((m->msg = ast_strdup(stuff))) {
- if (last)
- last->next = m;
- else
- list = m;
- m->next = NULL;
- last = m;
- } else {
- msgcnt--;
- free(m);
- }
- }
- }
+ AST_LIST_LOCK(&verbosers);
+ AST_LIST_TRAVERSE(&verbosers, v, list)
+ v->verboser(buf->str);
+ AST_LIST_UNLOCK(&verbosers);
- for (v = verboser; v; v = v->next)
- v->verboser(stuff, olen, replacelast, complete);
+ ast_log(LOG_VERBOSE, "%s", buf->str);
+}
- ast_log(LOG_VERBOSE, "%s", stuff);
+int ast_register_verbose(void (*v)(const char *string))
+{
+ struct verb *verb;
- if (len) {
- if (!complete)
- replacelast = 1;
- else
- replacelast = len = 0;
- }
+ if (!(verb = ast_malloc(sizeof(*verb))))
+ return -1;
- ast_mutex_unlock(&msglist_lock);
-}
+ verb->verboser = v;
-int ast_verbose_dmesg(void (*v)(const char *string, int opos, int replacelast, int complete))
-{
- struct msglist *m;
- ast_mutex_lock(&msglist_lock);
- m = list;
- while(m) {
- /* Send all the existing entries that we have queued (i.e. they're likely to have missed) */
- v(m->msg, 0, 0, 1);
- m = m->next;
- }
- ast_mutex_unlock(&msglist_lock);
+ AST_LIST_LOCK(&verbosers);
+ AST_LIST_INSERT_HEAD(&verbosers, verb, list);
+ AST_LIST_UNLOCK(&verbosers);
+
return 0;
}
-int ast_register_verbose(void (*v)(const char *string, int opos, int replacelast, int complete))
+int ast_unregister_verbose(void (*v)(const char *string))
{
- struct msglist *m;
- struct verb *tmp;
- /* XXX Should be more flexible here, taking > 1 verboser XXX */
- if ((tmp = ast_malloc(sizeof(*tmp)))) {
- tmp->verboser = v;
- ast_mutex_lock(&msglist_lock);
- tmp->next = verboser;
- verboser = tmp;
- m = list;
- while(m) {
- /* Send all the existing entries that we have queued (i.e. they're likely to have missed) */
- v(m->msg, 0, 0, 1);
- m = m->next;
- }
- ast_mutex_unlock(&msglist_lock);
- return 0;
- }
- return -1;
-}
+ struct verb *cur;
-int ast_unregister_verbose(void (*v)(const char *string, int opos, int replacelast, int complete))
-{
- int res = -1;
- struct verb *tmp, *tmpl=NULL;
- ast_mutex_lock(&msglist_lock);
- tmp = verboser;
- while(tmp) {
- if (tmp->verboser == v) {
- if (tmpl)
- tmpl->next = tmp->next;
- else
- verboser = tmp->next;
- free(tmp);
+ AST_LIST_LOCK(&verbosers);
+ AST_LIST_TRAVERSE_SAFE_BEGIN(&verbosers, cur, list) {
+ if (cur->verboser == v) {
+ AST_LIST_REMOVE_CURRENT(&verbosers, list);
+ free(cur);
break;
}
- tmpl = tmp;
- tmp = tmp->next;
}
- if (tmp)
- res = 0;
- ast_mutex_unlock(&msglist_lock);
- return res;
+ AST_LIST_TRAVERSE_SAFE_END
+ AST_LIST_UNLOCK(&verbosers);
+
+ return cur ? 0 : -1;
}
diff --git a/manager.c b/manager.c
index 99f726fdf..03bfdbd27 100644
--- a/manager.c
+++ b/manager.c
@@ -66,6 +66,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/acl.h"
#include "asterisk/utils.h"
#include "asterisk/http.h"
+#include "asterisk/threadstorage.h"
struct fast_originate_helper {
char tech[AST_MAX_MANHEADER_LEN];
@@ -104,6 +105,9 @@ static int block_sockets = 0;
static int num_sessions = 0;
struct eventqent *master_eventq = NULL;
+AST_THREADSTORAGE(manager_event_buf, manager_event_buf_init);
+#define MANAGER_EVENT_BUF_INITSIZE 256
+
static struct permalias {
int num;
char *label;
@@ -2113,33 +2117,37 @@ int manager_event(int category, const char *event, const char *fmt, ...)
{
struct mansession *s;
char auth[80];
- char tmp[4096] = "";
- char *tmp_next = tmp;
- size_t tmp_left = sizeof(tmp) - 2;
va_list ap;
struct timeval now;
+ struct ast_dynamic_str *buf;
/* Abort if there aren't any manager sessions */
if (!num_sessions)
return 0;
- ast_build_string(&tmp_next, &tmp_left, "Event: %s\r\nPrivilege: %s\r\n",
+ if (!(buf = ast_dynamic_str_thread_get(&manager_event_buf, MANAGER_EVENT_BUF_INITSIZE)))
+ return -1;
+
+ ast_dynamic_str_thread_set(&buf, 0, &manager_event_buf,
+ "Event: %s\r\nPrivilege: %s\r\n",
event, authority_to_str(category, auth, sizeof(auth)));
+
if (timestampevents) {
now = ast_tvnow();
- ast_build_string(&tmp_next, &tmp_left, "Timestamp: %ld.%06lu\r\n",
+ ast_dynamic_str_thread_append(&buf, 0, &manager_event_buf,
+ "Timestamp: %ld.%06lu\r\n",
now.tv_sec, (unsigned long) now.tv_usec);
}
+
va_start(ap, fmt);
- ast_build_string_va(&tmp_next, &tmp_left, fmt, ap);
+ ast_dynamic_str_thread_append_va(&buf, 0, &manager_event_buf, fmt, ap);
va_end(ap);
- *tmp_next++ = '\r';
- *tmp_next++ = '\n';
- *tmp_next = '\0';
+
+ ast_dynamic_str_thread_append(&buf, 0, &manager_event_buf, "\r\n");
ast_mutex_lock(&sessionlock);
/* Append even to master list and wake up any sleeping sessions */
- append_event(tmp, category);
+ append_event(buf->str, category);
for (s = sessions; s; s = s->next) {
ast_mutex_lock(&s->__lock);
if (s->waiting_thread != AST_PTHREADT_NULL)
diff --git a/pbx/pbx_ael.c b/pbx/pbx_ael.c
index 17bcada96..f7a5f6c54 100644
--- a/pbx/pbx_ael.c
+++ b/pbx/pbx_ael.c
@@ -51,16 +51,6 @@ static char expr_output[2096];
/* these functions are in ../ast_expr2.fl */
-
-#ifdef __AST_DEBUG_MALLOC
-static void FREE(void *ptr)
-{
- free(ptr);
-}
-#else
-#define FREE free
-#endif
-
#define DEBUG_READ (1 << 0)
#define DEBUG_TOKENS (1 << 1)
#define DEBUG_MACROS (1 << 2)
@@ -3403,7 +3393,7 @@ void add_extensions(struct ael_extension *exten)
if (exten->hints) {
if (ast_add_extension2(exten->context, 0 /*no replace*/, exten->name, PRIORITY_HINT, NULL, exten->cidmatch,
- exten->hints, NULL, FREE, registrar)) {
+ exten->hints, NULL, ast_free, registrar)) {
ast_log(LOG_WARNING, "Unable to add step at priority 'hint' of extension '%s'\n",
exten->name);
}
@@ -3483,7 +3473,7 @@ void add_extensions(struct ael_extension *exten)
label = 0;
if (ast_add_extension2(exten->context, 0 /*no replace*/, exten->name, pr->priority_num, (label?label:NULL), exten->cidmatch,
- app, strdup(appargs), FREE, registrar)) {
+ app, strdup(appargs), ast_free, registrar)) {
ast_log(LOG_WARNING, "Unable to add step at priority '%d' of extension '%s'\n", pr->priority_num,
exten->name);
}
diff --git a/pbx/pbx_config.c b/pbx/pbx_config.c
index 6b6edbc48..c74c4c105 100644
--- a/pbx/pbx_config.c
+++ b/pbx/pbx_config.c
@@ -42,15 +42,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/cli.h"
#include "asterisk/callerid.h"
-#ifdef __AST_DEBUG_MALLOC
-static void FREE(void *ptr)
-{
- free(ptr);
-}
-#else
-#define FREE free
-#endif
-
static char *config = "extensions.conf";
static char *registrar = "pbx_config";
@@ -1458,7 +1449,7 @@ static void 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), FREE, registrar)) {
+ if (ast_add_extension2(con, 0, realext, ipri, label, cidmatch, appl, strdup(data), ast_free, registrar)) {
ast_log(LOG_WARNING, "Unable to register extension at line %d\n", v->lineno);
}
}
diff --git a/res/res_agi.c b/res/res_agi.c
index 64c0390eb..d12de6e2d 100644
--- a/res/res_agi.c
+++ b/res/res_agi.c
@@ -130,7 +130,7 @@ static void agi_debug_cli(int fd, char *fmt, ...)
ast_log(LOG_ERROR, "Out of memory\n");
} else {
if (agidebug)
- ast_verbose("AGI Tx >> %s", stuff);
+ ast_verbose("AGI Tx >> %s\n", stuff);
ast_carefulwrite(fd, stuff, strlen(stuff), 100);
free(stuff);
}
diff --git a/res/res_features.c b/res/res_features.c
index 1b7212c25..d584ee814 100644
--- a/res/res_features.c
+++ b/res/res_features.c
@@ -59,15 +59,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/devicestate.h"
#include "asterisk/monitor.h"
-#ifdef __AST_DEBUG_MALLOC
-static void FREE(void *ptr)
-{
- free(ptr);
-}
-#else
-#define FREE free
-#endif
-
#define DEFAULT_PARK_TIME 45000
#define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
#define DEFAULT_FEATURE_DIGIT_TIMEOUT 500
@@ -427,7 +418,7 @@ int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeou
if (!con) /* Still no context? Bad */
ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
else { /* Add extension to context */
- if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), FREE, registrar))
+ if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), ast_free, registrar))
notify_metermaids(pu->parkingexten, parking_con);
}
/* Tell the peer channel the number of the parking space */
@@ -1555,7 +1546,7 @@ static void *do_parking_thread(void *ignore)
if (con) {
char returnexten[AST_MAX_EXTENSION];
snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
- ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), FREE, registrar);
+ ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar);
}
set_c_e_p(chan, parking_con_dial, peername, 1);
} else {
@@ -2250,7 +2241,7 @@ static int load_config(void)
ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
return -1;
}
- res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), FREE, registrar);
+ res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), ast_free, registrar);
if (parkaddhints)
park_add_hints(parking_con, parking_start, parking_stop);
if (!res)
diff --git a/utils.c b/utils.c
index ef251bfa9..0aaa791a5 100644
--- a/utils.c
+++ b/utils.c
@@ -59,20 +59,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */
#include "asterisk/utils.h"
+#define AST_API_MODULE
+#include "asterisk/threadstorage.h"
+
static char base64[64];
static char b2a[256];
-static pthread_key_t inet_ntoa_buf_key;
-static pthread_once_t inet_ntoa_buf_once = PTHREAD_ONCE_INIT;
-
-#ifdef __AST_DEBUG_MALLOC
-static void FREE(void *ptr)
-{
- free(ptr);
-}
-#else
-#define FREE free
-#endif
+AST_THREADSTORAGE(inet_ntoa_buf, inet_ntoa_buf_init);
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__) || defined(__CYGWIN__)
@@ -495,22 +488,13 @@ void ast_uri_decode(char *s)
*o = '\0';
}
-static void inet_ntoa_buf_key_create(void)
-{
- pthread_key_create(&inet_ntoa_buf_key, FREE);
-}
-
/*! \brief ast_inet_ntoa: Recursive thread safe replacement of inet_ntoa */
const char *ast_inet_ntoa(struct in_addr ia)
{
char *buf;
- pthread_once(&inet_ntoa_buf_once, inet_ntoa_buf_key_create);
- if (!(buf = pthread_getspecific(inet_ntoa_buf_key))) {
- if (!(buf = ast_calloc(1, INET_ADDRSTRLEN)))
- return NULL;
- pthread_setspecific(inet_ntoa_buf_key, buf);
- }
+ if (!(buf = ast_threadstorage_get(&inet_ntoa_buf, INET_ADDRSTRLEN)))
+ return "";
return inet_ntop(AF_INET, &ia, buf, INET_ADDRSTRLEN);
}
@@ -1211,3 +1195,37 @@ int ast_get_time_t(const char *src, time_t *dst, time_t _default, int *consumed)
return -1;
}
+int ast_dynamic_str_thread_build_va(struct ast_dynamic_str **buf, size_t max_len,
+ struct ast_threadstorage *ts, int append, const char *fmt, va_list ap)
+{
+ int res;
+ int offset = append ? strlen((*buf)->str) : 0;
+
+ res = vsnprintf((*buf)->str + offset, (*buf)->len - offset, fmt, ap);
+
+ /* Check to see if there was not enough space in the string buffer to prepare
+ * the string. Also, if a maximum length is present, make sure the current
+ * length is less than the maximum before increasing the size. */
+ if ((res + offset + 1) > (*buf)->len && (max_len ? ((*buf)->len < max_len) : 1)) {
+ /* Set the new size of the string buffer to be the size needed
+ * to hold the resulting string (res) plus one byte for the
+ * terminating '\0'. If this size is greater than the max, set
+ * the new length to be the maximum allowed. */
+ if (max_len)
+ (*buf)->len = ((res + offset + 1) < max_len) ? (res + offset + 1) : max_len;
+ else
+ (*buf)->len = res + offset + 1;
+
+ if (!(*buf = ast_realloc(*buf, (*buf)->len + sizeof(*(*buf)))))
+ return AST_DYNSTR_BUILD_FAILED;
+
+ if (ts)
+ pthread_setspecific(ts->key, *buf);
+
+ /* va_end() and va_start() must be done before calling
+ * vsnprintf() again. */
+ return AST_DYNSTR_BUILD_RETRY;
+ }
+
+ return res;
+}