diff --git a/asterisk.c b/asterisk.c
index d9d962797eddead67a1a6186276c1d8f733848ff..b523bfb0d6b523c2aa923dc4555349a6a64c0b8c 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 f2700b29ec6d7beeb145b54cbc8f66ec35b8cba3..e978f4888120368095f0c3ee42f13818646683d9 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 d78b3f2006762bd6512558ab1bf0ad9361a640a3..2809003e670b2394c2550e5b147864219025d726 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 cbe8cbb8c1165dcc0600a0be125a9d05c8178512..0aeb0f5c322c234efbf732f8beae029af6364d2a 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 6afd56d5e703b66b57b13288abebb16118973608..6e1d950392e6f564568f34c3f5be0dff568c0a41 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 a36138d8ac7bd0882a09388eeef0b804e394829c..575a1b2d3a5582b58136cdf472252ed306589a53 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 247ac83260b4eccf15e6c0e69964ce65ae6b946b..6e486620df8a5c3ffad0d6bc427b80558d0db92c 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 0000000000000000000000000000000000000000..6e141a5d2d19bad1937a78db940175e067e7519a
--- /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 ba1cd5948313f5eb860c7ab7787012b893b07e18..ea8b352fbff1692aaebb60b68ccc969b7c6f833d 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 a4f7c8c1d7dea348b40f0b9be39dde310c8a1a9d..532023b216708a0852596a34dc4a0a863e35517f 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 99f726fdf12adcb4e4e4ef43d75bb221d90e2746..03bfdbd2701fae6595dddd6d9160230e801aafeb 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 17bcada960ab94294401981e06f5fa7650b5af4f..f7a5f6c543fa38358ebdeb3277e1cb90fa6ea6be 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 6b6edbc4865a2cbf4c6b15c6beaeea2c264440ae..c74c4c105982698a16ef043ca0b7dea92a126479 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 64c0390ebbea9404a90ee70ee209e84d56bc7363..d12de6e2dcee874093c1d71a2a9f0b55e2546e7f 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 1b7212c25ab1606f2c1c9872c5515fbd943dbc4c..d584ee814c0239401d52f0b8416cbe1cce325dc6 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 ef251bfa96ddb668b2b15b1b129f2a1ab27dd203..0aaa791a509e034da9df8d36b4d281d14415094b 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;
+}