tls.h 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. /* Thread-local storage in multithreaded situations.
  2. Copyright (C) 2005, 2007-2013 Free Software Foundation, Inc.
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 3 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  13. /* Written by Bruno Haible <bruno@clisp.org>, 2005. */
  14. /* This file contains thread-local storage primitives for use with a given
  15. thread library. It does not contain primitives for creating threads or
  16. for other multithreading primitives.
  17. Type: gl_tls_key_t
  18. Initialization: gl_tls_key_init (name, destructor);
  19. Getting per-thread value: gl_tls_get (name)
  20. Setting per-thread value: gl_tls_set (name, pointer);
  21. De-initialization: gl_tls_key_destroy (name);
  22. Equivalent functions with control of error handling:
  23. Initialization: err = glthread_tls_key_init (&name, destructor);
  24. Setting per-thread value: err = glthread_tls_set (&name, pointer);
  25. De-initialization: err = glthread_tls_key_destroy (&name);
  26. A per-thread value is of type 'void *'.
  27. A destructor is a function pointer of type 'void (*) (void *)', called
  28. when a thread exits, and taking the last per-thread value as argument. It
  29. is unspecified whether the destructor function is called when the last
  30. per-thread value is NULL. On some platforms, the destructor function is
  31. not called at all.
  32. */
  33. #ifndef _TLS_H
  34. #define _TLS_H
  35. #include <errno.h>
  36. #include <stdlib.h>
  37. /* ========================================================================= */
  38. #if USE_POSIX_THREADS
  39. /* Use the POSIX threads library. */
  40. # include <pthread.h>
  41. # if PTHREAD_IN_USE_DETECTION_HARD
  42. /* The pthread_in_use() detection needs to be done at runtime. */
  43. # define pthread_in_use() \
  44. glthread_in_use ()
  45. extern int glthread_in_use (void);
  46. # endif
  47. # if USE_POSIX_THREADS_WEAK
  48. /* Use weak references to the POSIX threads library. */
  49. # pragma weak pthread_key_create
  50. # pragma weak pthread_getspecific
  51. # pragma weak pthread_setspecific
  52. # pragma weak pthread_key_delete
  53. # ifndef pthread_self
  54. # pragma weak pthread_self
  55. # endif
  56. # if !PTHREAD_IN_USE_DETECTION_HARD
  57. # pragma weak pthread_cancel
  58. # define pthread_in_use() (pthread_cancel != NULL)
  59. # endif
  60. # else
  61. # if !PTHREAD_IN_USE_DETECTION_HARD
  62. # define pthread_in_use() 1
  63. # endif
  64. # endif
  65. /* ------------------------- gl_tls_key_t datatype ------------------------- */
  66. typedef union
  67. {
  68. void *singlethread_value;
  69. pthread_key_t key;
  70. }
  71. gl_tls_key_t;
  72. # define glthread_tls_key_init(KEY, DESTRUCTOR) \
  73. (pthread_in_use () \
  74. ? pthread_key_create (&(KEY)->key, DESTRUCTOR) \
  75. : ((KEY)->singlethread_value = NULL, 0))
  76. # define gl_tls_get(NAME) \
  77. (pthread_in_use () \
  78. ? pthread_getspecific ((NAME).key) \
  79. : (NAME).singlethread_value)
  80. # define glthread_tls_set(KEY, POINTER) \
  81. (pthread_in_use () \
  82. ? pthread_setspecific ((KEY)->key, (POINTER)) \
  83. : ((KEY)->singlethread_value = (POINTER), 0))
  84. # define glthread_tls_key_destroy(KEY) \
  85. (pthread_in_use () ? pthread_key_delete ((KEY)->key) : 0)
  86. #endif
  87. /* ========================================================================= */
  88. #if USE_PTH_THREADS
  89. /* Use the GNU Pth threads library. */
  90. # include <pth.h>
  91. # if USE_PTH_THREADS_WEAK
  92. /* Use weak references to the GNU Pth threads library. */
  93. # pragma weak pth_key_create
  94. # pragma weak pth_key_getdata
  95. # pragma weak pth_key_setdata
  96. # pragma weak pth_key_delete
  97. # pragma weak pth_cancel
  98. # define pth_in_use() (pth_cancel != NULL)
  99. # else
  100. # define pth_in_use() 1
  101. # endif
  102. /* ------------------------- gl_tls_key_t datatype ------------------------- */
  103. typedef union
  104. {
  105. void *singlethread_value;
  106. pth_key_t key;
  107. }
  108. gl_tls_key_t;
  109. # define glthread_tls_key_init(KEY, DESTRUCTOR) \
  110. (pth_in_use () \
  111. ? (!pth_key_create (&(KEY)->key, DESTRUCTOR) ? errno : 0) \
  112. : ((KEY)->singlethread_value = NULL, 0))
  113. # define gl_tls_get(NAME) \
  114. (pth_in_use () \
  115. ? pth_key_getdata ((NAME).key) \
  116. : (NAME).singlethread_value)
  117. # define glthread_tls_set(KEY, POINTER) \
  118. (pth_in_use () \
  119. ? (!pth_key_setdata ((KEY)->key, (POINTER)) ? errno : 0) \
  120. : ((KEY)->singlethread_value = (POINTER), 0))
  121. # define glthread_tls_key_destroy(KEY) \
  122. (pth_in_use () \
  123. ? (!pth_key_delete ((KEY)->key) ? errno : 0) \
  124. : 0)
  125. #endif
  126. /* ========================================================================= */
  127. #if USE_SOLARIS_THREADS
  128. /* Use the old Solaris threads library. */
  129. # include <thread.h>
  130. # if USE_SOLARIS_THREADS_WEAK
  131. /* Use weak references to the old Solaris threads library. */
  132. # pragma weak thr_keycreate
  133. # pragma weak thr_getspecific
  134. # pragma weak thr_setspecific
  135. # pragma weak thr_suspend
  136. # define thread_in_use() (thr_suspend != NULL)
  137. # else
  138. # define thread_in_use() 1
  139. # endif
  140. /* ------------------------- gl_tls_key_t datatype ------------------------- */
  141. typedef union
  142. {
  143. void *singlethread_value;
  144. thread_key_t key;
  145. }
  146. gl_tls_key_t;
  147. # define glthread_tls_key_init(KEY, DESTRUCTOR) \
  148. (thread_in_use () \
  149. ? thr_keycreate (&(KEY)->key, DESTRUCTOR) \
  150. : ((KEY)->singlethread_value = NULL, 0))
  151. # define gl_tls_get(NAME) \
  152. (thread_in_use () \
  153. ? glthread_tls_get_multithreaded ((NAME).key) \
  154. : (NAME).singlethread_value)
  155. extern void *glthread_tls_get_multithreaded (thread_key_t key);
  156. # define glthread_tls_set(KEY, POINTER) \
  157. (thread_in_use () \
  158. ? thr_setspecific ((KEY)->key, (POINTER)) \
  159. : ((KEY)->singlethread_value = (POINTER), 0))
  160. # define glthread_tls_key_destroy(KEY) \
  161. /* Unsupported. */ \
  162. 0
  163. #endif
  164. /* ========================================================================= */
  165. #if USE_WINDOWS_THREADS
  166. # define WIN32_LEAN_AND_MEAN /* avoid including junk */
  167. # include <windows.h>
  168. /* ------------------------- gl_tls_key_t datatype ------------------------- */
  169. typedef DWORD gl_tls_key_t;
  170. # define glthread_tls_key_init(KEY, DESTRUCTOR) \
  171. /* The destructor is unsupported. */ \
  172. ((*(KEY) = TlsAlloc ()) == (DWORD)-1 ? EAGAIN : ((void) (DESTRUCTOR), 0))
  173. # define gl_tls_get(NAME) \
  174. TlsGetValue (NAME)
  175. # define glthread_tls_set(KEY, POINTER) \
  176. (!TlsSetValue (*(KEY), POINTER) ? EINVAL : 0)
  177. # define glthread_tls_key_destroy(KEY) \
  178. (!TlsFree (*(KEY)) ? EINVAL : 0)
  179. #endif
  180. /* ========================================================================= */
  181. #if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WINDOWS_THREADS)
  182. /* Provide dummy implementation if threads are not supported. */
  183. /* ------------------------- gl_tls_key_t datatype ------------------------- */
  184. typedef struct
  185. {
  186. void *singlethread_value;
  187. }
  188. gl_tls_key_t;
  189. # define glthread_tls_key_init(KEY, DESTRUCTOR) \
  190. ((KEY)->singlethread_value = NULL, \
  191. (void) (DESTRUCTOR), \
  192. 0)
  193. # define gl_tls_get(NAME) \
  194. (NAME).singlethread_value
  195. # define glthread_tls_set(KEY, POINTER) \
  196. ((KEY)->singlethread_value = (POINTER), 0)
  197. # define glthread_tls_key_destroy(KEY) \
  198. 0
  199. #endif
  200. /* ========================================================================= */
  201. /* Macros with built-in error handling. */
  202. /* ------------------------- gl_tls_key_t datatype ------------------------- */
  203. #define gl_tls_key_init(NAME, DESTRUCTOR) \
  204. do \
  205. { \
  206. if (glthread_tls_key_init (&NAME, DESTRUCTOR)) \
  207. abort (); \
  208. } \
  209. while (0)
  210. #define gl_tls_set(NAME, POINTER) \
  211. do \
  212. { \
  213. if (glthread_tls_set (&NAME, POINTER)) \
  214. abort (); \
  215. } \
  216. while (0)
  217. #define gl_tls_key_destroy(NAME) \
  218. do \
  219. { \
  220. if (glthread_tls_key_destroy (&NAME)) \
  221. abort (); \
  222. } \
  223. while (0)
  224. /* ========================================================================= */
  225. #endif /* _TLS_H */