Wed Oct 14 15:01:58 2009

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

Generated on Wed Oct 14 15:01:58 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7