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 */