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