tls.h 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. /* Thread-local storage in multithreaded situations.
  2. Copyright (C) 2005, 2007-2020 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 <https://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. #if !defined c11_threads_in_use
  38. # if HAVE_THREADS_H && USE_POSIX_THREADS_WEAK
  39. # include <threads.h>
  40. # pragma weak thrd_exit
  41. # define c11_threads_in_use() (thrd_exit != NULL)
  42. # else
  43. # define c11_threads_in_use() 0
  44. # endif
  45. #endif
  46. /* ========================================================================= */
  47. #if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS
  48. /* Use the ISO C threads library. */
  49. # include <threads.h>
  50. /* ------------------------- gl_tls_key_t datatype ------------------------- */
  51. typedef tss_t gl_tls_key_t;
  52. # define glthread_tls_key_init(KEY, DESTRUCTOR) \
  53. (tss_create (KEY, DESTRUCTOR) != thrd_success ? EAGAIN : 0)
  54. # define gl_tls_get(NAME) \
  55. tss_get (NAME)
  56. # define glthread_tls_set(KEY, POINTER) \
  57. (tss_set (*(KEY), (POINTER)) != thrd_success ? ENOMEM : 0)
  58. # define glthread_tls_key_destroy(KEY) \
  59. (tss_delete (*(KEY)), 0)
  60. #endif
  61. /* ========================================================================= */
  62. #if USE_POSIX_THREADS
  63. /* Use the POSIX threads library. */
  64. # include <pthread.h>
  65. # if PTHREAD_IN_USE_DETECTION_HARD
  66. /* The pthread_in_use() detection needs to be done at runtime. */
  67. # define pthread_in_use() \
  68. glthread_in_use ()
  69. extern int glthread_in_use (void);
  70. # endif
  71. # if USE_POSIX_THREADS_WEAK
  72. /* Use weak references to the POSIX threads library. */
  73. # pragma weak pthread_key_create
  74. # pragma weak pthread_getspecific
  75. # pragma weak pthread_setspecific
  76. # pragma weak pthread_key_delete
  77. # ifndef pthread_self
  78. # pragma weak pthread_self
  79. # endif
  80. # if !PTHREAD_IN_USE_DETECTION_HARD
  81. # pragma weak pthread_mutexattr_gettype
  82. # define pthread_in_use() \
  83. (pthread_mutexattr_gettype != NULL || c11_threads_in_use ())
  84. # endif
  85. # else
  86. # if !PTHREAD_IN_USE_DETECTION_HARD
  87. # define pthread_in_use() 1
  88. # endif
  89. # endif
  90. /* ------------------------- gl_tls_key_t datatype ------------------------- */
  91. typedef union
  92. {
  93. void *singlethread_value;
  94. pthread_key_t key;
  95. }
  96. gl_tls_key_t;
  97. # define glthread_tls_key_init(KEY, DESTRUCTOR) \
  98. (pthread_in_use () \
  99. ? pthread_key_create (&(KEY)->key, DESTRUCTOR) \
  100. : ((KEY)->singlethread_value = NULL, 0))
  101. # define gl_tls_get(NAME) \
  102. (pthread_in_use () \
  103. ? pthread_getspecific ((NAME).key) \
  104. : (NAME).singlethread_value)
  105. # define glthread_tls_set(KEY, POINTER) \
  106. (pthread_in_use () \
  107. ? pthread_setspecific ((KEY)->key, (POINTER)) \
  108. : ((KEY)->singlethread_value = (POINTER), 0))
  109. # define glthread_tls_key_destroy(KEY) \
  110. (pthread_in_use () ? pthread_key_delete ((KEY)->key) : 0)
  111. #endif
  112. /* ========================================================================= */
  113. #if USE_WINDOWS_THREADS
  114. # define WIN32_LEAN_AND_MEAN /* avoid including junk */
  115. # include <windows.h>
  116. # include "windows-tls.h"
  117. /* ------------------------- gl_tls_key_t datatype ------------------------- */
  118. typedef glwthread_tls_key_t gl_tls_key_t;
  119. # define glthread_tls_key_init(KEY, DESTRUCTOR) \
  120. glwthread_tls_key_create (KEY, DESTRUCTOR)
  121. # define gl_tls_get(NAME) \
  122. TlsGetValue (NAME)
  123. # define glthread_tls_set(KEY, POINTER) \
  124. (!TlsSetValue (*(KEY), POINTER) ? EINVAL : 0)
  125. # define glthread_tls_key_destroy(KEY) \
  126. glwthread_tls_key_delete (*(KEY))
  127. #endif
  128. /* ========================================================================= */
  129. #if !(USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS)
  130. /* Provide dummy implementation if threads are not supported. */
  131. /* ------------------------- gl_tls_key_t datatype ------------------------- */
  132. typedef struct
  133. {
  134. void *singlethread_value;
  135. }
  136. gl_tls_key_t;
  137. # define glthread_tls_key_init(KEY, DESTRUCTOR) \
  138. ((KEY)->singlethread_value = NULL, \
  139. (void) (DESTRUCTOR), \
  140. 0)
  141. # define gl_tls_get(NAME) \
  142. (NAME).singlethread_value
  143. # define glthread_tls_set(KEY, POINTER) \
  144. ((KEY)->singlethread_value = (POINTER), 0)
  145. # define glthread_tls_key_destroy(KEY) \
  146. 0
  147. #endif
  148. /* ========================================================================= */
  149. /* Macros with built-in error handling. */
  150. /* ------------------------- gl_tls_key_t datatype ------------------------- */
  151. #define gl_tls_key_init(NAME, DESTRUCTOR) \
  152. do \
  153. { \
  154. if (glthread_tls_key_init (&NAME, DESTRUCTOR)) \
  155. abort (); \
  156. } \
  157. while (0)
  158. #define gl_tls_set(NAME, POINTER) \
  159. do \
  160. { \
  161. if (glthread_tls_set (&NAME, POINTER)) \
  162. abort (); \
  163. } \
  164. while (0)
  165. #define gl_tls_key_destroy(NAME) \
  166. do \
  167. { \
  168. if (glthread_tls_key_destroy (&NAME)) \
  169. abort (); \
  170. } \
  171. while (0)
  172. /* ========================================================================= */
  173. #endif /* _TLS_H */