Mon May 14 04:43:01 2007

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 
00066 #if defined(DEBUG_THREADLOCALS)
00067 void __ast_threadstorage_object_add(void *key, size_t len, const char *file, const char *function, unsigned int line);
00068 void __ast_threadstorage_object_remove(void *key);
00069 void __ast_threadstorage_object_replace(void *key_old, void *key_new, size_t len);
00070 #endif /* defined(DEBUG_THREADLOCALS) */
00071 
00072 /*!
00073  * \brief Define a thread storage variable
00074  *
00075  * \arg name The name of the thread storage
00076  * \arg name_init This is a name used to create the function that gets called
00077  *      to initialize this thread storage. It can be anything since it will not
00078  *      be referred to anywhere else
00079  *
00080  * This macro would be used to declare an instance of thread storage in a file.
00081  *
00082  * Example usage:
00083  * \code
00084  * AST_THREADSTORAGE(my_buf, my_buf_init);
00085  * \endcode
00086  */
00087 #define AST_THREADSTORAGE(name, name_init) \
00088    AST_THREADSTORAGE_CUSTOM(name, name_init, ast_free) 
00089 
00090 #if !defined(DEBUG_THREADLOCALS)
00091 #define AST_THREADSTORAGE_CUSTOM(name, name_init, cleanup)  \
00092 static void name_init(void);                                \
00093 static struct ast_threadstorage name = {                    \
00094    .once = PTHREAD_ONCE_INIT,                          \
00095    .key_init = name_init,                              \
00096 };                                                          \
00097 static void name_init(void)                                 \
00098 {                                                           \
00099    pthread_key_create(&(name).key, cleanup);           \
00100 }
00101 #else /* defined(DEBUG_THREADLOCALS) */
00102 #define AST_THREADSTORAGE_CUSTOM(name, name_init, cleanup)  \
00103 static void name_init(void);                                \
00104 static struct ast_threadstorage name = {                    \
00105    .once = PTHREAD_ONCE_INIT,                          \
00106    .key_init = name_init,                              \
00107 };                                                          \
00108 static void __cleanup_##name(void *data)         \
00109 {                        \
00110    __ast_threadstorage_object_remove(data);      \
00111    cleanup(data);                 \
00112 }                        \
00113 static void name_init(void)                                 \
00114 {                                                           \
00115    pthread_key_create(&(name).key, __cleanup_##name);  \
00116 }
00117 #endif /* defined(DEBUG_THREADLOCALS) */
00118 
00119 /*!
00120  * \brief Retrieve thread storage
00121  *
00122  * \arg ts This is a pointer to the thread storage structure declared by using
00123  *      the AST_THREADSTORAGE macro.  If declared with 
00124  *      AST_THREADSTORAGE(my_buf, my_buf_init), then this argument would be 
00125  *      (&my_buf).
00126  * \arg init_size This is the amount of space to be allocated the first time
00127  *      this thread requests its data. Thus, this should be the size that the
00128  *      code accessing this thread storage is assuming the size to be.
00129  *
00130  * \return This function will return the thread local storage associated with
00131  *         the thread storage management variable passed as the first argument.
00132  *         The result will be NULL in the case of a memory allocation error.
00133  *
00134  * Example usage:
00135  * \code
00136  * AST_THREADSTORAGE(my_buf, my_buf_init);
00137  * #define MY_BUF_SIZE   128
00138  * ...
00139  * void my_func(const char *fmt, ...)
00140  * {
00141  *      void *buf;
00142  *
00143  *      if (!(buf = ast_threadstorage_get(&my_buf, MY_BUF_SIZE)))
00144  *           return;
00145  *      ...
00146  * }
00147  * \endcode
00148  */
00149 #if !defined(DEBUG_THREADLOCALS)
00150 AST_INLINE_API(
00151 void *ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size),
00152 {
00153    void *buf;
00154 
00155    pthread_once(&ts->once, ts->key_init);
00156    if (!(buf = pthread_getspecific(ts->key))) {
00157       if (!(buf = ast_calloc(1, init_size)))
00158          return NULL;
00159       pthread_setspecific(ts->key, buf);
00160    }
00161 
00162    return buf;
00163 }
00164 )
00165 #else /* defined(DEBUG_THREADLOCALS) */
00166 AST_INLINE_API(
00167 void *__ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size, const char *file, const char *function, unsigned int line),
00168 {
00169    void *buf;
00170 
00171    pthread_once(&ts->once, ts->key_init);
00172    if (!(buf = pthread_getspecific(ts->key))) {
00173       if (!(buf = ast_calloc(1, init_size)))
00174          return NULL;
00175       pthread_setspecific(ts->key, buf);
00176       __ast_threadstorage_object_add(buf, init_size, file, function, line);
00177    }
00178 
00179    return buf;
00180 }
00181 )
00182 
00183 #define ast_threadstorage_get(ts, init_size) __ast_threadstorage_get(ts, init_size, __FILE__, __PRETTY_FUNCTION__, __LINE__)
00184 #endif /* defined(DEBUG_THREADLOCALS) */
00185 
00186 /*!
00187  * \brief A dynamic length string
00188  */
00189 struct ast_dynamic_str {
00190    /* The current maximum length of the string */
00191    size_t len;
00192    /* The string buffer */
00193    char str[0];
00194 };
00195 
00196 /*!
00197  * \brief Create a dynamic length string
00198  *
00199  * \arg init_len This is the initial length of the string buffer
00200  *
00201  * \return This function returns a pointer to the dynamic string length.  The
00202  *         result will be NULL in the case of a memory allocation error.
00203  *
00204  * /note The result of this function is dynamically allocated memory, and must
00205  *       be free()'d after it is no longer needed.
00206  */
00207 AST_INLINE_API(
00208 struct ast_dynamic_str * attribute_malloc ast_dynamic_str_create(size_t init_len),
00209 {
00210    struct ast_dynamic_str *buf;
00211 
00212    if (!(buf = ast_calloc(1, sizeof(*buf) + init_len)))
00213       return NULL;
00214    
00215    buf->len = init_len;
00216 
00217    return buf;
00218 }
00219 )
00220 
00221 /*!
00222  * \brief Retrieve a thread locally stored dynamic string
00223  *
00224  * \arg ts This is a pointer to the thread storage structure declared by using
00225  *      the AST_THREADSTORAGE macro.  If declared with 
00226  *      AST_THREADSTORAGE(my_buf, my_buf_init), then this argument would be 
00227  *      (&my_buf).
00228  * \arg init_len This is the initial length of the thread's dynamic string. The
00229  *      current length may be bigger if previous operations in this thread have
00230  *      caused it to increase.
00231  *
00232  * \return This function will return the thread locally stored dynamic string
00233  *         associated with the thread storage management variable passed as the
00234  *         first argument.
00235  *         The result will be NULL in the case of a memory allocation error.
00236  *
00237  * Example usage:
00238  * \code
00239  * AST_THREADSTORAGE(my_str, my_str_init);
00240  * #define MY_STR_INIT_SIZE   128
00241  * ...
00242  * void my_func(const char *fmt, ...)
00243  * {
00244  *      struct ast_dynamic_str *buf;
00245  *
00246  *      if (!(buf = ast_dynamic_str_thread_get(&my_str, MY_STR_INIT_SIZE)))
00247  *           return;
00248  *      ...
00249  * }
00250  * \endcode
00251  */
00252 #if !defined(DEBUG_THREADLOCALS)
00253 AST_INLINE_API(
00254 struct ast_dynamic_str *ast_dynamic_str_thread_get(struct ast_threadstorage *ts,
00255    size_t init_len),
00256 {
00257    struct ast_dynamic_str *buf;
00258 
00259    if (!(buf = ast_threadstorage_get(ts, sizeof(*buf) + init_len)))
00260       return NULL;
00261    
00262    if (!buf->len)
00263       buf->len = init_len;
00264 
00265    return buf;
00266 }
00267 )
00268 #else /* defined(DEBUG_THREADLOCALS) */
00269 AST_INLINE_API(
00270 struct ast_dynamic_str *__ast_dynamic_str_thread_get(struct ast_threadstorage *ts,
00271    size_t init_len, const char *file, const char *function, unsigned int line),
00272 {
00273    struct ast_dynamic_str *buf;
00274 
00275    if (!(buf = __ast_threadstorage_get(ts, sizeof(*buf) + init_len, file, function, line)))
00276       return NULL;
00277    
00278    if (!buf->len)
00279       buf->len = init_len;
00280 
00281    return buf;
00282 }
00283 )
00284 
00285 #define ast_dynamic_str_thread_get(ts, init_len) __ast_dynamic_str_thread_get(ts, init_len, __FILE__, __PRETTY_FUNCTION__, __LINE__)
00286 #endif /* defined(DEBUG_THREADLOCALS) */ 
00287 
00288 /*!
00289  * \brief Error codes from ast_dynamic_str_thread_build_va()
00290  */
00291 enum {
00292    /*! An error has occured and the contents of the dynamic string
00293     *  are undefined */
00294    AST_DYNSTR_BUILD_FAILED = -1,
00295    /*! The buffer size for the dynamic string had to be increased, and
00296     *  ast_dynamic_str_thread_build_va() needs to be called again after
00297     *  a va_end() and va_start().
00298     */
00299    AST_DYNSTR_BUILD_RETRY = -2
00300 };
00301 
00302 /*!
00303  * \brief Set a thread locally stored dynamic string from a va_list
00304  *
00305  * \arg buf This is the address of a pointer to an ast_dynamic_str which should
00306  *      have been retrieved using ast_dynamic_str_thread_get.  It will need to
00307  *      be updated in the case that the buffer has to be reallocated to
00308  *      accommodate a longer string than what it currently has space for.
00309  * \arg max_len This is the maximum length to allow the string buffer to grow
00310  *      to.  If this is set to 0, then there is no maximum length.
00311  * \arg ts This is a pointer to the thread storage structure declared by using
00312  *      the AST_THREADSTORAGE macro.  If declared with 
00313  *      AST_THREADSTORAGE(my_buf, my_buf_init), then this argument would be 
00314  *      (&my_buf).
00315  * \arg fmt This is the format string (printf style)
00316  * \arg ap This is the va_list
00317  *
00318  * \return The return value of this function is the same as that of the printf
00319  *         family of functions.
00320  *
00321  * Example usage:
00322  * \code
00323  * AST_THREADSTORAGE(my_str, my_str_init);
00324  * #define MY_STR_INIT_SIZE   128
00325  * ...
00326  * void my_func(const char *fmt, ...)
00327  * {
00328  *      struct ast_dynamic_str *buf;
00329  *      va_list ap;
00330  *
00331  *      if (!(buf = ast_dynamic_str_thread_get(&my_str, MY_STR_INIT_SIZE)))
00332  *           return;
00333  *      ...
00334  *      va_start(fmt, ap);
00335  *      ast_dynamic_str_thread_set_va(&buf, 0, &my_str, fmt, ap);
00336  *      va_end(ap);
00337  * 
00338  *      printf("This is the string we just built: %s\n", buf->str);
00339  *      ...
00340  * }
00341  * \endcode
00342  */
00343 #define ast_dynamic_str_thread_set_va(buf, max_len, ts, fmt, ap)                 \
00344    ({                                                                       \
00345       int __res;                                                       \
00346       while ((__res = ast_dynamic_str_thread_build_va(buf, max_len,    \
00347          ts, 0, fmt, ap)) == AST_DYNSTR_BUILD_RETRY) {            \
00348          va_end(ap);                                              \
00349          va_start(ap, fmt);                                       \
00350       }                                                                \
00351       (__res);                                                         \
00352    })
00353 
00354 /*!
00355  * \brief Append to a thread local dynamic string using a va_list
00356  *
00357  * The arguments, return values, and usage of this are the same as those for
00358  * ast_dynamic_str_thread_set_va().  However, instead of setting a new value
00359  * for the string, this will append to the current value.
00360  */
00361 #define ast_dynamic_str_thread_append_va(buf, max_len, ts, fmt, ap)              \
00362    ({                                                                       \
00363       int __res;                                                       \
00364       while ((__res = ast_dynamic_str_thread_build_va(buf, max_len,    \
00365          ts, 1, fmt, ap)) == AST_DYNSTR_BUILD_RETRY) {            \
00366          va_end(ap);                                              \
00367          va_start(ap, fmt);                                       \
00368       }                                                                \
00369       (__res);                                                         \
00370    })
00371 
00372 /*!
00373  * \brief Core functionality of ast_dynamic_str_thread_(set|append)_va
00374  *
00375  * The arguments to this function are the same as those described for
00376  * ast_dynamic_str_thread_set_va except for an addition argument, append.
00377  * If append is non-zero, this will append to the current string instead of
00378  * writing over it.
00379  *
00380  * In the case that this function is called and the buffer was not large enough
00381  * to hold the result, the partial write will be truncated, and the result
00382  * AST_DYNSTR_BUILD_RETRY will be returned to indicate that the buffer size
00383  * was increased, and the function should be called a second time.
00384  *
00385  * A return of AST_DYNSTR_BUILD_FAILED indicates a memory allocation error.
00386  *
00387  * A return value greater than or equal to zero indicates the number of
00388  * characters that have been written, not including the terminating '\0'.
00389  * In the append case, this only includes the number of characters appended.
00390  *
00391  * \note This function should never need to be called directly.  It should
00392  *       through calling one of the other functions or macros defined in this
00393  *       file.
00394  */
00395 int ast_dynamic_str_thread_build_va(struct ast_dynamic_str **buf, size_t max_len,
00396    struct ast_threadstorage *ts, int append, const char *fmt, va_list ap);
00397 
00398 /*!
00399  * \brief Set a thread locally stored dynamic string using variable arguments
00400  *
00401  * \arg buf This is the address of a pointer to an ast_dynamic_str which should
00402  *      have been retrieved using ast_dynamic_str_thread_get.  It will need to
00403  *      be updated in the case that the buffer has to be reallocated to
00404  *      accomodate a longer string than what it currently has space for.
00405  * \arg max_len This is the maximum length to allow the string buffer to grow
00406  *      to.  If this is set to 0, then there is no maximum length.
00407  * \arg ts This is a pointer to the thread storage structure declared by using
00408  *      the AST_THREADSTORAGE macro.  If declared with 
00409  *      AST_THREADSTORAGE(my_buf, my_buf_init), then this argument would be 
00410  *      (&my_buf).
00411  * \arg fmt This is the format string (printf style)
00412  *
00413  * \return The return value of this function is the same as that of the printf
00414  *         family of functions.
00415  *
00416  * Example usage:
00417  * \code
00418  * AST_THREADSTORAGE(my_str, my_str_init);
00419  * #define MY_STR_INIT_SIZE   128
00420  * ...
00421  * void my_func(int arg1, int arg2)
00422  * {
00423  *      struct ast_dynamic_str *buf;
00424  *      va_list ap;
00425  *
00426  *      if (!(buf = ast_dynamic_str_thread_get(&my_str, MY_STR_INIT_SIZE)))
00427  *           return;
00428  *      ...
00429  *      ast_dynamic_str_thread_set(&buf, 0, &my_str, "arg1: %d  arg2: %d\n",
00430  *           arg1, arg2);
00431  * 
00432  *      printf("This is the string we just built: %s\n", buf->str);
00433  *      ...
00434  * }
00435  * \endcode
00436  */
00437 AST_INLINE_API(
00438 int __attribute__ ((format (printf, 4, 5))) ast_dynamic_str_thread_set(
00439    struct ast_dynamic_str **buf, size_t max_len, 
00440    struct ast_threadstorage *ts, const char *fmt, ...),
00441 {
00442    int res;
00443    va_list ap;
00444 
00445    va_start(ap, fmt);
00446    res = ast_dynamic_str_thread_set_va(buf, max_len, ts, fmt, ap);
00447    va_end(ap);
00448 
00449    return res;
00450 }
00451 )
00452 
00453 /*!
00454  * \brief Append to a thread local dynamic string
00455  *
00456  * The arguments, return values, and usage of this function are the same as
00457  * ast_dynamic_str_thread_set().  However, instead of setting a new value for
00458  * the string, this function appends to the current value.
00459  */
00460 AST_INLINE_API(
00461 int __attribute__ ((format (printf, 4, 5))) ast_dynamic_str_thread_append(
00462    struct ast_dynamic_str **buf, size_t max_len, 
00463    struct ast_threadstorage *ts, const char *fmt, ...),
00464 {
00465    int res;
00466    va_list ap;
00467 
00468    va_start(ap, fmt);
00469    res = ast_dynamic_str_thread_append_va(buf, max_len, ts, fmt, ap);
00470    va_end(ap);
00471 
00472    return res;
00473 }
00474 )
00475 
00476 /*!
00477  * \brief Set a dynamic string
00478  *
00479  * \arg buf This is the address of a pointer to an ast_dynamic_str.  It will
00480  *      need to be updated in the case that the buffer has to be reallocated to
00481  *      accommodate a longer string than what it currently has space for.
00482  * \arg max_len This is the maximum length to allow the string buffer to grow
00483  *      to.  If this is set to 0, then there is no maximum length.
00484  *
00485  * \return The return value of this function is the same as that of the printf
00486  *         family of functions.
00487  */
00488 AST_INLINE_API(
00489 int __attribute__ ((format (printf, 3, 4))) ast_dynamic_str_set(
00490    struct ast_dynamic_str **buf, size_t max_len,
00491    const char *fmt, ...),
00492 {
00493    int res;
00494    va_list ap;
00495    
00496    va_start(ap, fmt);
00497    res = ast_dynamic_str_thread_set_va(buf, max_len, NULL, fmt, ap);
00498    va_end(ap);
00499 
00500    return res;
00501 }
00502 )
00503 
00504 /*!
00505  * \brief Append to a dynamic string
00506  *
00507  * The arguments, return values, and usage of this function are the same as
00508  * ast_dynamic_str_set().  However, this function appends to the string instead
00509  * of setting a new value.
00510  */
00511 AST_INLINE_API(
00512 int __attribute__ ((format (printf, 3, 4))) ast_dynamic_str_append(
00513    struct ast_dynamic_str **buf, size_t max_len,
00514    const char *fmt, ...),
00515 {
00516    int res;
00517    va_list ap;
00518    
00519    va_start(ap, fmt);
00520    res = ast_dynamic_str_thread_append_va(buf, max_len, NULL, fmt, ap);
00521    va_end(ap);
00522 
00523    return res;
00524 }
00525 )
00526 
00527 #endif /* ASTERISK_THREADSTORAGE_H */

Generated on Mon May 14 04:43:01 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1