Mon Mar 31 07:38:05 2008

Asterisk developer's documentation


threadstorage.h

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2006, Digium, Inc.
00005  *
00006  * Russell Bryant <russell@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*!
00020  * \file threadstorage.h
00021  * \author Russell Bryant <russell@digium.com>
00022  * \brief Definitions to aid in the use of thread local storage
00023  */
00024 
00025 /*!
00026  * \page AstThreadStorage The Asterisk Thread Storage API
00027  *
00028  *
00029  * The POSIX threads (pthreads) API provides the ability to define thread
00030  * specific data.  The functions and structures defined here are intended
00031  * to centralize the code that is commonly used when using thread local
00032  * storage.
00033  *
00034  * The motivation for using this code in Asterisk is for situations where
00035  * storing data on a thread-specific basis can provide some amount of
00036  * performance benefit.  For example, there are some call types in Asterisk
00037  * where ast_frame structures must be allocated very rapidly (easily 50, 100,
00038  * 200 times a second).  Instead of doing the equivalent of that many calls
00039  * to malloc() and free() per second, thread local storage is used to keep a
00040  * list of unused frame structures so that they can be continuously reused.
00041  *
00042  * - \ref threadstorage.h
00043  */
00044 
00045 #ifndef ASTERISK_THREADSTORAGE_H
00046 #define ASTERISK_THREADSTORAGE_H
00047 
00048 #include <pthread.h>
00049 
00050 #include "asterisk/utils.h"
00051 #include "asterisk/inline_api.h"
00052 
00053 /*!
00054  * \brief data for a thread locally stored variable
00055  */
00056 struct ast_threadstorage {
00057    /*! Ensure that the key is only initialized by one thread */
00058    pthread_once_t once;
00059    /*! The key used to retrieve this thread's data */
00060    pthread_key_t key;
00061    /*! The function that initializes the key */
00062    void (*key_init)(void);
00063 };
00064 
00065 #ifdef SOLARIS
00066 #define THREADSTORAGE_ONCE_INIT {PTHREAD_ONCE_INIT}
00067 #else
00068 #define THREADSTORAGE_ONCE_INIT PTHREAD_ONCE_INIT
00069 #endif
00070 
00071 #if defined(DEBUG_THREADLOCALS)
00072 void __ast_threadstorage_object_add(void *key, size_t len, const char *file, const char *function, unsigned int line);
00073 void __ast_threadstorage_object_remove(void *key);
00074 void __ast_threadstorage_object_replace(void *key_old, void *key_new, size_t len);
00075 #endif /* defined(DEBUG_THREADLOCALS) */
00076 
00077 /*!
00078  * \brief Define a thread storage variable
00079  *
00080  * \arg name The name of the thread storage
00081  * \arg name_init This is a name used to create the function that gets called
00082  *      to initialize this thread storage. It can be anything since it will not
00083  *      be referred to anywhere else
00084  *
00085  * This macro would be used to declare an instance of thread storage in a file.
00086  *
00087  * Example usage:
00088  * \code
00089  * AST_THREADSTORAGE(my_buf, my_buf_init);
00090  * \endcode
00091  */
00092 #define AST_THREADSTORAGE(name, name_init) \
00093    AST_THREADSTORAGE_CUSTOM(name, name_init, ast_free) 
00094 
00095 #if !defined(DEBUG_THREADLOCALS)
00096 #define AST_THREADSTORAGE_CUSTOM(name, name_init, cleanup)  \
00097 static void name_init(void);                                \
00098 static struct ast_threadstorage name = {                    \
00099    .once = THREADSTORAGE_ONCE_INIT,                    \
00100    .key_init = name_init,                              \
00101 };                                                          \
00102 static void name_init(void)                                 \
00103 {                                                           \
00104    pthread_key_create(&(name).key, cleanup);           \
00105 }
00106 #else /* defined(DEBUG_THREADLOCALS) */
00107 #define AST_THREADSTORAGE_CUSTOM(name, name_init, cleanup)  \
00108 static void name_init(void);                                \
00109 static struct ast_threadstorage name = {                    \
00110    .once = THREADSTORAGE_ONCE_INIT,                    \
00111    .key_init = name_init,                              \
00112 };                                                          \
00113 static void __cleanup_##name(void *data)         \
00114 {                        \
00115    __ast_threadstorage_object_remove(data);      \
00116    cleanup(data);                 \
00117 }                        \
00118 static void name_init(void)                                 \
00119 {                                                           \
00120    pthread_key_create(&(name).key, __cleanup_##name);  \
00121 }
00122 #endif /* defined(DEBUG_THREADLOCALS) */
00123 
00124 /*!
00125  * \brief Retrieve thread storage
00126  *
00127  * \arg ts This is a pointer to the thread storage structure declared by using
00128  *      the AST_THREADSTORAGE macro.  If declared with 
00129  *      AST_THREADSTORAGE(my_buf, my_buf_init), then this argument would be 
00130  *      (&my_buf).
00131  * \arg init_size This is the amount of space to be allocated the first time
00132  *      this thread requests its data. Thus, this should be the size that the
00133  *      code accessing this thread storage is assuming the size to be.
00134  *
00135  * \return This function will return the thread local storage associated with
00136  *         the thread storage management variable passed as the first argument.
00137  *         The result will be NULL in the case of a memory allocation error.
00138  *
00139  * Example usage:
00140  * \code
00141  * AST_THREADSTORAGE(my_buf, my_buf_init);
00142  * #define MY_BUF_SIZE   128
00143  * ...
00144  * void my_func(const char *fmt, ...)
00145  * {
00146  *      void *buf;
00147  *
00148  *      if (!(buf = ast_threadstorage_get(&my_buf, MY_BUF_SIZE)))
00149  *           return;
00150  *      ...
00151  * }
00152  * \endcode
00153  */
00154 #if !defined(DEBUG_THREADLOCALS)
00155 AST_INLINE_API(
00156 void *ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size),
00157 {
00158    void *buf;
00159 
00160    pthread_once(&ts->once, ts->key_init);
00161    if (!(buf = pthread_getspecific(ts->key))) {
00162       if (!(buf = ast_calloc(1, init_size)))
00163          return NULL;
00164       pthread_setspecific(ts->key, buf);
00165    }
00166 
00167    return buf;
00168 }
00169 )
00170 #else /* defined(DEBUG_THREADLOCALS) */
00171 AST_INLINE_API(
00172 void *__ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size, const char *file, const char *function, unsigned int line),
00173 {
00174    void *buf;
00175 
00176    pthread_once(&ts->once, ts->key_init);
00177    if (!(buf = pthread_getspecific(ts->key))) {
00178       if (!(buf = ast_calloc(1, init_size)))
00179          return NULL;
00180       pthread_setspecific(ts->key, buf);
00181       __ast_threadstorage_object_add(buf, init_size, file, function, line);
00182    }
00183 
00184    return buf;
00185 }
00186 )
00187 
00188 #define ast_threadstorage_get(ts, init_size) __ast_threadstorage_get(ts, init_size, __FILE__, __PRETTY_FUNCTION__, __LINE__)
00189 #endif /* defined(DEBUG_THREADLOCALS) */
00190 
00191 /*!
00192  * \brief A dynamic length string
00193  */
00194 struct ast_dynamic_str {
00195    /* The current maximum length of the string */
00196    size_t len;
00197    /* The string buffer */
00198    char str[0];
00199 };
00200 
00201 /*!
00202  * \brief Create a dynamic length string
00203  *
00204  * \arg init_len This is the initial length of the string buffer
00205  *
00206  * \return This function returns a pointer to the dynamic string length.  The
00207  *         result will be NULL in the case of a memory allocation error.
00208  *
00209  * /note The result of this function is dynamically allocated memory, and must
00210  *       be free()'d after it is no longer needed.
00211  */
00212 AST_INLINE_API(
00213 struct ast_dynamic_str * attribute_malloc ast_dynamic_str_create(size_t init_len),
00214 {
00215    struct ast_dynamic_str *buf;
00216 
00217    if (!(buf = ast_calloc(1, sizeof(*buf) + init_len)))
00218       return NULL;
00219    
00220    buf->len = init_len;
00221 
00222    return buf;
00223 }
00224 )
00225 
00226 /*!
00227  * \brief Retrieve a thread locally stored dynamic string
00228  *
00229  * \arg ts This is a pointer to the thread storage structure declared by using
00230  *      the AST_THREADSTORAGE macro.  If declared with 
00231  *      AST_THREADSTORAGE(my_buf, my_buf_init), then this argument would be 
00232  *      (&my_buf).
00233  * \arg init_len This is the initial length of the thread's dynamic string. The
00234  *      current length may be bigger if previous operations in this thread have
00235  *      caused it to increase.
00236  *
00237  * \return This function will return the thread locally stored dynamic string
00238  *         associated with the thread storage management variable passed as the
00239  *         first argument.
00240  *         The result will be NULL in the case of a memory allocation error.
00241  *
00242  * Example usage:
00243  * \code
00244  * AST_THREADSTORAGE(my_str, my_str_init);
00245  * #define MY_STR_INIT_SIZE   128
00246  * ...
00247  * void my_func(const char *fmt, ...)
00248  * {
00249  *      struct ast_dynamic_str *buf;
00250  *
00251  *      if (!(buf = ast_dynamic_str_thread_get(&my_str, MY_STR_INIT_SIZE)))
00252  *           return;
00253  *      ...
00254  * }
00255  * \endcode
00256  */
00257 #if !defined(DEBUG_THREADLOCALS)
00258 AST_INLINE_API(
00259 struct ast_dynamic_str *ast_dynamic_str_thread_get(struct ast_threadstorage *ts,
00260    size_t init_len),
00261 {
00262    struct ast_dynamic_str *buf;
00263 
00264    if (!(buf = ast_threadstorage_get(ts, sizeof(*buf) + init_len)))
00265       return NULL;
00266    
00267    if (!buf->len)
00268       buf->len = init_len;
00269 
00270    return buf;
00271 }
00272 )
00273 #else /* defined(DEBUG_THREADLOCALS) */
00274 AST_INLINE_API(
00275 struct ast_dynamic_str *__ast_dynamic_str_thread_get(struct ast_threadstorage *ts,
00276    size_t init_len, const char *file, const char *function, unsigned int line),
00277 {
00278    struct ast_dynamic_str *buf;
00279 
00280    if (!(buf = __ast_threadstorage_get(ts, sizeof(*buf) + init_len, file, function, line)))
00281       return NULL;
00282    
00283    if (!buf->len)
00284       buf->len = init_len;
00285 
00286    return buf;
00287 }
00288 )
00289 
00290 #define ast_dynamic_str_thread_get(ts, init_len) __ast_dynamic_str_thread_get(ts, init_len, __FILE__, __PRETTY_FUNCTION__, __LINE__)
00291 #endif /* defined(DEBUG_THREADLOCALS) */ 
00292 
00293 /*!
00294  * \brief Error codes from ast_dynamic_str_thread_build_va()
00295  */
00296 enum {
00297    /*! An error has occured and the contents of the dynamic string
00298     *  are undefined */
00299    AST_DYNSTR_BUILD_FAILED = -1,
00300    /*! The buffer size for the dynamic string had to be increased, and
00301     *  ast_dynamic_str_thread_build_va() needs to be called again after
00302     *  a va_end() and va_start().
00303     */
00304    AST_DYNSTR_BUILD_RETRY = -2
00305 };
00306 
00307 /*!
00308  * \brief Set a thread locally stored dynamic string from a va_list
00309  *
00310  * \arg buf This is the address of a pointer to an ast_dynamic_str which should
00311  *      have been retrieved using ast_dynamic_str_thread_get.  It will need to
00312  *      be updated in the case that the buffer has to be reallocated to
00313  *      accommodate a longer string than what it currently has space for.
00314  * \arg max_len This is the maximum length to allow the string buffer to grow
00315  *      to.  If this is set to 0, then there is no maximum length.
00316  * \arg ts This is a pointer to the thread storage structure declared by using
00317  *      the AST_THREADSTORAGE macro.  If declared with 
00318  *      AST_THREADSTORAGE(my_buf, my_buf_init), then this argument would be 
00319  *      (&my_buf).
00320  * \arg fmt This is the format string (printf style)
00321  * \arg ap This is the va_list
00322  *
00323  * \return The return value of this function is the same as that of the printf
00324  *         family of functions.
00325  *
00326  * Example usage:
00327  * \code
00328  * AST_THREADSTORAGE(my_str, my_str_init);
00329  * #define MY_STR_INIT_SIZE   128
00330  * ...
00331  * void my_func(const char *fmt, ...)
00332  * {
00333  *      struct ast_dynamic_str *buf;
00334  *      va_list ap;
00335  *
00336  *      if (!(buf = ast_dynamic_str_thread_get(&my_str, MY_STR_INIT_SIZE)))
00337  *           return;
00338  *      ...
00339  *      va_start(fmt, ap);
00340  *      ast_dynamic_str_thread_set_va(&buf, 0, &my_str, fmt, ap);
00341  *      va_end(ap);
00342  * 
00343  *      printf("This is the string we just built: %s\n", buf->str);
00344  *      ...
00345  * }
00346  * \endcode
00347  */
00348 #define ast_dynamic_str_thread_set_va(buf, max_len, ts, fmt, ap)                 \
00349    ({                                                                       \
00350       int __res;                                                       \
00351       while ((__res = ast_dynamic_str_thread_build_va(buf, max_len,    \
00352          ts, 0, fmt, ap)) == AST_DYNSTR_BUILD_RETRY) {            \
00353          va_end(ap);                                              \
00354          va_start(ap, fmt);                                       \
00355       }                                                                \
00356       (__res);                                                         \
00357    })
00358 
00359 /*!
00360  * \brief Append to a thread local dynamic string using a va_list
00361  *
00362  * The arguments, return values, and usage of this are the same as those for
00363  * ast_dynamic_str_thread_set_va().  However, instead of setting a new value
00364  * for the string, this will append to the current value.
00365  */
00366 #define ast_dynamic_str_thread_append_va(buf, max_len, ts, fmt, ap)              \
00367    ({                                                                       \
00368       int __res;                                                       \
00369       while ((__res = ast_dynamic_str_thread_build_va(buf, max_len,    \
00370          ts, 1, fmt, ap)) == AST_DYNSTR_BUILD_RETRY) {            \
00371          va_end(ap);                                              \
00372          va_start(ap, fmt);                                       \
00373       }                                                                \
00374       (__res);                                                         \
00375    })
00376 
00377 /*!
00378  * \brief Core functionality of ast_dynamic_str_thread_(set|append)_va
00379  *
00380  * The arguments to this function are the same as those described for
00381  * ast_dynamic_str_thread_set_va except for an addition argument, append.
00382  * If append is non-zero, this will append to the current string instead of
00383  * writing over it.
00384  *
00385  * In the case that this function is called and the buffer was not large enough
00386  * to hold the result, the partial write will be truncated, and the result
00387  * AST_DYNSTR_BUILD_RETRY will be returned to indicate that the buffer size
00388  * was increased, and the function should be called a second time.
00389  *
00390  * A return of AST_DYNSTR_BUILD_FAILED indicates a memory allocation error.
00391  *
00392  * A return value greater than or equal to zero indicates the number of
00393  * characters that have been written, not including the terminating '\0'.
00394  * In the append case, this only includes the number of characters appended.
00395  *
00396  * \note This function should never need to be called directly.  It should
00397  *       through calling one of the other functions or macros defined in this
00398  *       file.
00399  */
00400 int ast_dynamic_str_thread_build_va(struct ast_dynamic_str **buf, size_t max_len,
00401    struct ast_threadstorage *ts, int append, const char *fmt, va_list ap);
00402 
00403 /*!
00404  * \brief Set a thread locally stored dynamic string using variable arguments
00405  *
00406  * \arg buf This is the address of a pointer to an ast_dynamic_str which should
00407  *      have been retrieved using ast_dynamic_str_thread_get.  It will need to
00408  *      be updated in the case that the buffer has to be reallocated to
00409  *      accomodate a longer string than what it currently has space for.
00410  * \arg max_len This is the maximum length to allow the string buffer to grow
00411  *      to.  If this is set to 0, then there is no maximum length.
00412  * \arg ts This is a pointer to the thread storage structure declared by using
00413  *      the AST_THREADSTORAGE macro.  If declared with 
00414  *      AST_THREADSTORAGE(my_buf, my_buf_init), then this argument would be 
00415  *      (&my_buf).
00416  * \arg fmt This is the format string (printf style)
00417  *
00418  * \return The return value of this function is the same as that of the printf
00419  *         family of functions.
00420  *
00421  * Example usage:
00422  * \code
00423  * AST_THREADSTORAGE(my_str, my_str_init);
00424  * #define MY_STR_INIT_SIZE   128
00425  * ...
00426  * void my_func(int arg1, int arg2)
00427  * {
00428  *      struct ast_dynamic_str *buf;
00429  *      va_list ap;
00430  *
00431  *      if (!(buf = ast_dynamic_str_thread_get(&my_str, MY_STR_INIT_SIZE)))
00432  *           return;
00433  *      ...
00434  *      ast_dynamic_str_thread_set(&buf, 0, &my_str, "arg1: %d  arg2: %d\n",
00435  *           arg1, arg2);
00436  * 
00437  *      printf("This is the string we just built: %s\n", buf->str);
00438  *      ...
00439  * }
00440  * \endcode
00441  */
00442 AST_INLINE_API(
00443 int __attribute__ ((format (printf, 4, 5))) ast_dynamic_str_thread_set(
00444    struct ast_dynamic_str **buf, size_t max_len, 
00445    struct ast_threadstorage *ts, const char *fmt, ...),
00446 {
00447    int res;
00448    va_list ap;
00449 
00450    va_start(ap, fmt);
00451    res = ast_dynamic_str_thread_set_va(buf, max_len, ts, fmt, ap);
00452    va_end(ap);
00453 
00454    return res;
00455 }
00456 )
00457 
00458 /*!
00459  * \brief Append to a thread local dynamic string
00460  *
00461  * The arguments, return values, and usage of this function are the same as
00462  * ast_dynamic_str_thread_set().  However, instead of setting a new value for
00463  * the string, this function appends to the current value.
00464  */
00465 AST_INLINE_API(
00466 int __attribute__ ((format (printf, 4, 5))) ast_dynamic_str_thread_append(
00467    struct ast_dynamic_str **buf, size_t max_len, 
00468    struct ast_threadstorage *ts, const char *fmt, ...),
00469 {
00470    int res;
00471    va_list ap;
00472 
00473    va_start(ap, fmt);
00474    res = ast_dynamic_str_thread_append_va(buf, max_len, ts, fmt, ap);
00475    va_end(ap);
00476 
00477    return res;
00478 }
00479 )
00480 
00481 /*!
00482  * \brief Set a dynamic string
00483  *
00484  * \arg buf This is the address of a pointer to an ast_dynamic_str.  It will
00485  *      need to be updated in the case that the buffer has to be reallocated to
00486  *      accommodate a longer string than what it currently has space for.
00487  * \arg max_len This is the maximum length to allow the string buffer to grow
00488  *      to.  If this is set to 0, then there is no maximum length.
00489  *
00490  * \return The return value of this function is the same as that of the printf
00491  *         family of functions.
00492  */
00493 AST_INLINE_API(
00494 int __attribute__ ((format (printf, 3, 4))) ast_dynamic_str_set(
00495    struct ast_dynamic_str **buf, size_t max_len,
00496    const char *fmt, ...),
00497 {
00498    int res;
00499    va_list ap;
00500    
00501    va_start(ap, fmt);
00502    res = ast_dynamic_str_thread_set_va(buf, max_len, NULL, fmt, ap);
00503    va_end(ap);
00504 
00505    return res;
00506 }
00507 )
00508 
00509 /*!
00510  * \brief Append to a dynamic string
00511  *
00512  * The arguments, return values, and usage of this function are the same as
00513  * ast_dynamic_str_set().  However, this function appends to the string instead
00514  * of setting a new value.
00515  */
00516 AST_INLINE_API(
00517 int __attribute__ ((format (printf, 3, 4))) ast_dynamic_str_append(
00518    struct ast_dynamic_str **buf, size_t max_len,
00519    const char *fmt, ...),
00520 {
00521    int res;
00522    va_list ap;
00523    
00524    va_start(ap, fmt);
00525    res = ast_dynamic_str_thread_append_va(buf, max_len, NULL, fmt, ap);
00526    va_end(ap);
00527 
00528    return res;
00529 }
00530 )
00531 
00532 #endif /* ASTERISK_THREADSTORAGE_H */

Generated on Mon Mar 31 07:38:05 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.1