key.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. /*++
  2. Copyright (c) 2015 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. key.c
  9. Abstract:
  10. This module implements support for POSIX thread keys, which are the POSIX
  11. notion of thread-local storage.
  12. Author:
  13. Evan Green 1-May-2015
  14. Environment:
  15. User Mode C Library
  16. --*/
  17. //
  18. // ------------------------------------------------------------------- Includes
  19. //
  20. #include "pthreadp.h"
  21. #include <assert.h>
  22. #include <limits.h>
  23. //
  24. // --------------------------------------------------------------------- Macros
  25. //
  26. //
  27. // This macro returns non-zero if the given key is valid.
  28. //
  29. #define PTHREAD_VALID_KEY(_Key) \
  30. ((((_Key) & PTHREAD_KEY_VALID) != 0) && \
  31. (((_Key) & ~PTHREAD_KEY_VALID) < PTHREAD_KEYS_MAX))
  32. //
  33. // ---------------------------------------------------------------- Definitions
  34. //
  35. //
  36. // This bit is set when the key is in use.
  37. //
  38. #define PTHREAD_KEY_IN_USE 0x00000001
  39. //
  40. // This is the increment for the sequence number. It both toggles the in-use
  41. // bit and acts as part of the sequence number.
  42. //
  43. #define PTHREAD_KEY_SEQUENCE_INCREMENT 1
  44. //
  45. // This bit is part of what is returned to the user.
  46. //
  47. #define PTHREAD_KEY_VALID 0x80000000
  48. //
  49. // ------------------------------------------------------ Data Type Definitions
  50. //
  51. typedef
  52. void
  53. (*PPTHREAD_KEY_DESTRUCTOR) (
  54. void *Value
  55. );
  56. /*++
  57. Routine Description:
  58. This routine is called when a thread with thread-local storage for a
  59. particular key exits.
  60. Arguments:
  61. Value - Supplies the thread-local key value.
  62. Return Value:
  63. None.
  64. --*/
  65. /*++
  66. Structure Description:
  67. This structure stores information for a thread key (thread local storage).
  68. Members:
  69. Sequence - Stores the sequence number of the key. The first bit is used
  70. to determine if the key is in use.
  71. Destructor - Stores the pointer to the optional destructor function called
  72. when the key is deleted.
  73. --*/
  74. typedef struct _PTHREAD_KEY {
  75. UINTN Sequence;
  76. UINTN Destructor;
  77. } PTHREAD_KEY, *PPTHREAD_KEY;
  78. //
  79. // ----------------------------------------------- Internal Function Prototypes
  80. //
  81. //
  82. // -------------------------------------------------------------------- Globals
  83. //
  84. //
  85. // Define the dynamically allocated thread key map.
  86. //
  87. PPTHREAD_KEY ClThreadKeys;
  88. //
  89. // ------------------------------------------------------------------ Functions
  90. //
  91. PTHREAD_API
  92. int
  93. pthread_key_create (
  94. pthread_key_t *Key,
  95. void (*KeyDestructorRoutine)(void *)
  96. )
  97. /*++
  98. Routine Description:
  99. This routine attempts to create and reserve a new thread key.
  100. Arguments:
  101. Key - Supplies a pointer where the key information will be returned.
  102. KeyDestructorRoutine - Supplies an optional pointer to a routine to call
  103. when the key is destroyed on a particular thread. This routine will
  104. be called with a pointer to the thread-specific value for the key.
  105. Return Value:
  106. 0 on success.
  107. EAGAIN if the system lacked the resources to create a new key slot, or
  108. there are too many keys.
  109. ENOMEM if insufficient memory exists to create the key.
  110. --*/
  111. {
  112. UINTN KeyIndex;
  113. PPTHREAD_KEY Keys;
  114. UINTN NewOldValue;
  115. UINTN NewValue;
  116. UINTN OldValue;
  117. //
  118. // Allocate the key structure if needed. This may race with other threads
  119. // trying to do the same, so be prepared to lose and back out.
  120. //
  121. if (ClThreadKeys == NULL) {
  122. Keys = malloc(sizeof(PTHREAD_KEY) * PTHREAD_KEYS_MAX);
  123. if (Keys == NULL) {
  124. return ENOMEM;
  125. }
  126. memset(Keys, 0, sizeof(PTHREAD_KEY) * PTHREAD_KEYS_MAX);
  127. //
  128. // Try to make this the official array.
  129. //
  130. OldValue = RtlAtomicCompareExchange((PUINTN)&ClThreadKeys,
  131. (UINTN)Keys,
  132. (UINTN)NULL);
  133. if (OldValue != (UINTN)NULL) {
  134. //
  135. // Someone else beat this thread to the punch. Use their array.
  136. //
  137. free(Keys);
  138. }
  139. }
  140. assert(ClThreadKeys != NULL);
  141. //
  142. // Loop trying to find a free key.
  143. //
  144. for (KeyIndex = 0; KeyIndex < PTHREAD_KEYS_MAX; KeyIndex += 1) {
  145. OldValue = ClThreadKeys[KeyIndex].Sequence;
  146. while ((OldValue & PTHREAD_KEY_IN_USE) == 0) {
  147. //
  148. // Try to jam in an incremented sequence number that will have the
  149. // in-use bit set.
  150. //
  151. NewValue = OldValue + PTHREAD_KEY_SEQUENCE_INCREMENT;
  152. NewOldValue = RtlAtomicCompareExchange(
  153. &(ClThreadKeys[KeyIndex].Sequence),
  154. NewValue,
  155. OldValue);
  156. if (NewOldValue == OldValue) {
  157. *Key = KeyIndex | PTHREAD_KEY_VALID;
  158. ClThreadKeys[KeyIndex].Destructor =
  159. (UINTN)(KeyDestructorRoutine);
  160. return 0;
  161. }
  162. OldValue = NewOldValue;
  163. }
  164. }
  165. *Key = -1;
  166. //
  167. // No keys could be located.
  168. //
  169. return EAGAIN;
  170. }
  171. PTHREAD_API
  172. int
  173. pthread_key_delete (
  174. pthread_key_t Key
  175. )
  176. /*++
  177. Routine Description:
  178. This routine releases a thread key. It is the responsibility of the
  179. application to release any thread-specific data associated with the old key.
  180. No destructors are called from this function.
  181. Arguments:
  182. Key - Supplies a pointer to the key to delete.
  183. Return Value:
  184. 0 on success.
  185. EINVAL if the key is invalid.
  186. --*/
  187. {
  188. UINTN Index;
  189. UINTN NewValue;
  190. UINTN OldValue;
  191. if (!PTHREAD_VALID_KEY(Key)) {
  192. return EINVAL;
  193. }
  194. Index = Key & ~PTHREAD_KEY_VALID;
  195. OldValue = ClThreadKeys[Index].Sequence;
  196. if ((OldValue & PTHREAD_KEY_IN_USE) == 0) {
  197. return EINVAL;
  198. }
  199. //
  200. // Try to increment the sequence number and clear the in-use bit.
  201. //
  202. NewValue = RtlAtomicCompareExchange(
  203. &(ClThreadKeys[Index].Sequence),
  204. OldValue + PTHREAD_KEY_SEQUENCE_INCREMENT,
  205. OldValue);
  206. if (NewValue == OldValue) {
  207. return 0;
  208. }
  209. //
  210. // The sequence number changed out from underneath this function. The
  211. // caller is double deleting somewhere.
  212. //
  213. return EINVAL;
  214. }
  215. PTHREAD_API
  216. void *
  217. pthread_getspecific (
  218. pthread_key_t Key
  219. )
  220. /*++
  221. Routine Description:
  222. This routine returns the thread-specific value for the given key.
  223. Arguments:
  224. Key - Supplies a pointer to the key whose value should be returned.
  225. Return Value:
  226. Returns the last value set for the current thread and key combination, or
  227. NULL if no value has been set or the key is not valid.
  228. --*/
  229. {
  230. UINTN Index;
  231. PPTHREAD Thread;
  232. if ((!PTHREAD_VALID_KEY(Key)) || (ClThreadKeys == NULL)) {
  233. return NULL;
  234. }
  235. Index = Key & ~PTHREAD_KEY_VALID;
  236. Thread = (PPTHREAD)pthread_self();
  237. if (Thread->KeyData[Index].Sequence == ClThreadKeys[Index].Sequence) {
  238. return Thread->KeyData[Index].Value;
  239. }
  240. //
  241. // The caller passed us a key that has since been deleted.
  242. //
  243. return NULL;
  244. }
  245. PTHREAD_API
  246. int
  247. pthread_setspecific (
  248. pthread_key_t Key,
  249. const void *Value
  250. )
  251. /*++
  252. Routine Description:
  253. This routine sets the thread-specific value for the given key and current
  254. thread.
  255. Arguments:
  256. Key - Supplies the key whose value should be set.
  257. Value - Supplies the value to set.
  258. Return Value:
  259. 0 on success.
  260. EINVAL if the key passed was invalid.
  261. --*/
  262. {
  263. UINTN Index;
  264. PPTHREAD_KEY_DATA KeyData;
  265. UINTN Sequence;
  266. PPTHREAD Thread;
  267. if (!PTHREAD_VALID_KEY(Key)) {
  268. return EINVAL;
  269. }
  270. Index = Key & ~PTHREAD_KEY_VALID;
  271. assert(Index < PTHREAD_KEYS_MAX);
  272. assert(ClThreadKeys != NULL);
  273. Thread = (PPTHREAD)pthread_self();
  274. KeyData = &(Thread->KeyData[Index]);
  275. Sequence = ClThreadKeys[Index].Sequence;
  276. if ((Sequence & PTHREAD_KEY_IN_USE) != 0) {
  277. KeyData->Sequence = Sequence;
  278. KeyData->Value = (PVOID)Value;
  279. return 0;
  280. }
  281. //
  282. // The caller asked to set a key that is not in use.
  283. //
  284. return EINVAL;
  285. }
  286. VOID
  287. ClpDestroyThreadKeyData (
  288. PPTHREAD Thread
  289. )
  290. /*++
  291. Routine Description:
  292. This routine destroys the thread key data for the given thread and calls
  293. all destructor routines.
  294. Arguments:
  295. Thread - Supplies a pointer to the thread that is exiting.
  296. Return Value:
  297. None.
  298. --*/
  299. {
  300. PPTHREAD_KEY_DESTRUCTOR Destructor;
  301. UINTN DestructorsCalled;
  302. UINTN DestructorValue;
  303. UINTN Index;
  304. UINTN Round;
  305. UINTN Sequence;
  306. void *Value;
  307. if (ClThreadKeys == NULL) {
  308. Thread->KeyData = NULL;
  309. return;
  310. }
  311. for (Round = 0; Round < PTHREAD_DESTRUCTOR_ITERATIONS; Round += 1) {
  312. DestructorsCalled = 0;
  313. for (Index = 0; Index < PTHREAD_KEYS_MAX; Index += 1) {
  314. Sequence = ClThreadKeys[Index].Sequence;
  315. DestructorValue = ClThreadKeys[Index].Destructor;
  316. //
  317. // If the key is in use and the thread-local value is valid, the
  318. // destructor needs to be called.
  319. //
  320. if (((Sequence & PTHREAD_KEY_IN_USE) != 0) &&
  321. (Sequence == Thread->KeyData[Index].Sequence) &&
  322. (Thread->KeyData[Index].Value != NULL)) {
  323. Destructor = (PPTHREAD_KEY_DESTRUCTOR)(DestructorValue);
  324. if (Destructor == NULL) {
  325. continue;
  326. }
  327. //
  328. // Clear out the value (so this only happens once) and call
  329. // the destructor routine.
  330. //
  331. Value = Thread->KeyData[Index].Value;
  332. Thread->KeyData[Index].Value = NULL;
  333. Destructor(Value);
  334. DestructorsCalled += 1;
  335. }
  336. }
  337. //
  338. // If no destructors were called, then stop doing rounds of looping.
  339. //
  340. if (DestructorsCalled == 0) {
  341. break;
  342. }
  343. }
  344. Thread->KeyData = NULL;
  345. return;
  346. }
  347. //
  348. // --------------------------------------------------------- Internal Functions
  349. //