diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/asterisk/compiler.h | 1 | ||||
-rw-r--r-- | include/asterisk/logger.h | 6 | ||||
-rw-r--r-- | include/asterisk/threadstorage.h | 427 | ||||
-rw-r--r-- | include/asterisk/utils.h | 17 |
4 files changed, 448 insertions, 3 deletions
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 /*! |