threadstorage.h 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2006, Digium, Inc.
  5. *
  6. * Russell Bryant <russell@digium.com>
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. */
  18. /*!
  19. * \file threadstorage.h
  20. * \author Russell Bryant <russell@digium.com>
  21. * \brief Definitions to aid in the use of thread local storage
  22. *
  23. * \arg \ref AstThreadStorage
  24. */
  25. /*!
  26. * \page AstThreadStorage The Asterisk Thread Storage API
  27. *
  28. *
  29. * The POSIX threads (pthreads) API provides the ability to define thread
  30. * specific data. The functions and structures defined here are intended
  31. * to centralize the code that is commonly used when using thread local
  32. * storage.
  33. *
  34. * The motivation for using this code in Asterisk is for situations where
  35. * storing data on a thread-specific basis can provide some amount of
  36. * performance benefit. For example, there are some call types in Asterisk
  37. * where ast_frame structures must be allocated very rapidly (easily 50, 100,
  38. * 200 times a second). Instead of doing the equivalent of that many calls
  39. * to malloc() and free() per second, thread local storage is used to keep a
  40. * list of unused frame structures so that they can be continuously reused.
  41. *
  42. * - \ref threadstorage.h
  43. */
  44. #ifndef ASTERISK_THREADSTORAGE_H
  45. #define ASTERISK_THREADSTORAGE_H
  46. #include "asterisk/utils.h"
  47. #include "asterisk/inline_api.h"
  48. /*!
  49. * \brief data for a thread locally stored variable
  50. */
  51. struct ast_threadstorage {
  52. pthread_once_t once; /*!< Ensure that the key is only initialized by one thread */
  53. pthread_key_t key; /*!< The key used to retrieve this thread's data */
  54. void (*key_init)(void); /*!< The function that initializes the key */
  55. int (*custom_init)(void *); /*!< Custom initialization function specific to the object */
  56. };
  57. #if defined(DEBUG_THREADLOCALS)
  58. void __ast_threadstorage_object_add(void *key, size_t len, const char *file, const char *function, unsigned int line);
  59. void __ast_threadstorage_object_remove(void *key);
  60. void __ast_threadstorage_object_replace(void *key_old, void *key_new, size_t len);
  61. #define THREADSTORAGE_RAW_CLEANUP(v) {}
  62. #else
  63. #define THREADSTORAGE_RAW_CLEANUP NULL
  64. #endif /* defined(DEBUG_THREADLOCALS) */
  65. /*!
  66. * \brief Define a thread storage variable
  67. *
  68. * \param name The name of the thread storage object
  69. *
  70. * This macro would be used to declare an instance of thread storage in a file.
  71. *
  72. * Example usage:
  73. * \code
  74. * AST_THREADSTORAGE(my_buf);
  75. * \endcode
  76. */
  77. #define AST_THREADSTORAGE(name) \
  78. AST_THREADSTORAGE_CUSTOM_SCOPE(name, NULL, ast_free_ptr, static)
  79. #define AST_THREADSTORAGE_PUBLIC(name) \
  80. AST_THREADSTORAGE_CUSTOM_SCOPE(name, NULL, ast_free_ptr,)
  81. #define AST_THREADSTORAGE_EXTERNAL(name) \
  82. extern struct ast_threadstorage name
  83. #define AST_THREADSTORAGE_RAW(name) \
  84. AST_THREADSTORAGE_CUSTOM_SCOPE(name, NULL, THREADSTORAGE_RAW_CLEANUP,)
  85. /*!
  86. * \brief Define a thread storage variable, with custom initialization and cleanup
  87. *
  88. * \param a The name of the thread storage object
  89. * \param b This is a custom function that will be called after each thread specific
  90. * object is allocated, with the allocated block of memory passed
  91. * as the argument.
  92. * \param c This is a custom function that will be called instead of ast_free
  93. * when the thread goes away. Note that if this is used, it *MUST*
  94. * call free on the allocated memory.
  95. *
  96. * Example usage:
  97. * \code
  98. * AST_THREADSTORAGE_CUSTOM(my_buf, my_init, my_cleanup);
  99. * \endcode
  100. */
  101. #define AST_THREADSTORAGE_CUSTOM(a,b,c) AST_THREADSTORAGE_CUSTOM_SCOPE(a,b,c,static)
  102. #if defined(PTHREAD_ONCE_INIT_NEEDS_BRACES)
  103. # define AST_PTHREAD_ONCE_INIT { PTHREAD_ONCE_INIT }
  104. #else
  105. # define AST_PTHREAD_ONCE_INIT PTHREAD_ONCE_INIT
  106. #endif
  107. #if !defined(DEBUG_THREADLOCALS)
  108. #define AST_THREADSTORAGE_CUSTOM_SCOPE(name, c_init, c_cleanup, scope) \
  109. static void __init_##name(void); \
  110. scope struct ast_threadstorage name = { \
  111. .once = AST_PTHREAD_ONCE_INIT, \
  112. .key_init = __init_##name, \
  113. .custom_init = c_init, \
  114. }; \
  115. static void __init_##name(void) \
  116. { \
  117. pthread_key_create(&(name).key, c_cleanup); \
  118. }
  119. #else /* defined(DEBUG_THREADLOCALS) */
  120. #define AST_THREADSTORAGE_CUSTOM_SCOPE(name, c_init, c_cleanup, scope) \
  121. static void __init_##name(void); \
  122. scope struct ast_threadstorage name = { \
  123. .once = AST_PTHREAD_ONCE_INIT, \
  124. .key_init = __init_##name, \
  125. .custom_init = c_init, \
  126. }; \
  127. static void __cleanup_##name(void *data) \
  128. { \
  129. __ast_threadstorage_object_remove(data); \
  130. c_cleanup(data); \
  131. } \
  132. static void __init_##name(void) \
  133. { \
  134. pthread_key_create(&(name).key, __cleanup_##name); \
  135. }
  136. #endif /* defined(DEBUG_THREADLOCALS) */
  137. /*!
  138. * \brief Retrieve thread storage
  139. *
  140. * \param ts This is a pointer to the thread storage structure declared by using
  141. * the AST_THREADSTORAGE macro. If declared with
  142. * AST_THREADSTORAGE(my_buf), then this argument would be (&my_buf).
  143. * \param init_size This is the amount of space to be allocated the first time
  144. * this thread requests its data. Thus, this should be the size that the
  145. * code accessing this thread storage is assuming the size to be.
  146. *
  147. * \return This function will return the thread local storage associated with
  148. * the thread storage management variable passed as the first argument.
  149. * The result will be NULL in the case of a memory allocation error.
  150. *
  151. * Example usage:
  152. * \code
  153. * AST_THREADSTORAGE(my_buf);
  154. * #define MY_BUF_SIZE 128
  155. * ...
  156. * void my_func(const char *fmt, ...)
  157. * {
  158. * void *buf;
  159. *
  160. * if (!(buf = ast_threadstorage_get(&my_buf, MY_BUF_SIZE)))
  161. * return;
  162. * ...
  163. * }
  164. * \endcode
  165. */
  166. #if !defined(DEBUG_THREADLOCALS)
  167. AST_INLINE_API(
  168. void *ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size),
  169. {
  170. void *buf;
  171. pthread_once(&ts->once, ts->key_init);
  172. if (!(buf = pthread_getspecific(ts->key))) {
  173. if (!(buf = ast_calloc(1, init_size))) {
  174. return NULL;
  175. }
  176. if (ts->custom_init && ts->custom_init(buf)) {
  177. ast_free(buf);
  178. return NULL;
  179. }
  180. pthread_setspecific(ts->key, buf);
  181. }
  182. return buf;
  183. }
  184. )
  185. #else /* defined(DEBUG_THREADLOCALS) */
  186. AST_INLINE_API(
  187. void *__ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size, const char *file, const char *function, unsigned int line),
  188. {
  189. void *buf;
  190. pthread_once(&ts->once, ts->key_init);
  191. if (!(buf = pthread_getspecific(ts->key))) {
  192. if (!(buf = ast_calloc(1, init_size))) {
  193. return NULL;
  194. }
  195. if (ts->custom_init && ts->custom_init(buf)) {
  196. ast_free(buf);
  197. return NULL;
  198. }
  199. pthread_setspecific(ts->key, buf);
  200. __ast_threadstorage_object_add(buf, init_size, file, function, line);
  201. }
  202. return buf;
  203. }
  204. )
  205. #define ast_threadstorage_get(ts, init_size) __ast_threadstorage_get(ts, init_size, __FILE__, __PRETTY_FUNCTION__, __LINE__)
  206. #endif /* defined(DEBUG_THREADLOCALS) */
  207. /*!
  208. * \brief Retrieve a raw pointer from threadstorage.
  209. * \param ts Threadstorage object to operate on.
  210. *
  211. * \return A pointer associated with the current thread, NULL
  212. * if no pointer is associated yet.
  213. *
  214. * \note This should only be used on threadstorage declared
  215. * by AST_THREADSTORAGE_RAW unless you really know what
  216. * you are doing.
  217. */
  218. AST_INLINE_API(
  219. void *ast_threadstorage_get_ptr(struct ast_threadstorage *ts),
  220. {
  221. pthread_once(&ts->once, ts->key_init);
  222. return pthread_getspecific(ts->key);
  223. }
  224. )
  225. /*!
  226. * \brief Set a raw pointer from threadstorage.
  227. * \param ts Threadstorage object to operate on.
  228. *
  229. * \retval 0 Success
  230. * \retval non-zero Failure
  231. *
  232. * \note This should only be used on threadstorage declared
  233. * by AST_THREADSTORAGE_RAW unless you really know what
  234. * you are doing.
  235. */
  236. AST_INLINE_API(
  237. int ast_threadstorage_set_ptr(struct ast_threadstorage *ts, void *ptr),
  238. {
  239. pthread_once(&ts->once, ts->key_init);
  240. return pthread_setspecific(ts->key, ptr);
  241. }
  242. )
  243. #endif /* ASTERISK_THREADSTORAGE_H */