Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 
 
 
 

221 wiersze
6.9 KiB

  1. /* Copyright (c) 2015, Google Inc.
  2. *
  3. * Permission to use, copy, modify, and/or distribute this software for any
  4. * purpose with or without fee is hereby granted, provided that the above
  5. * copyright notice and this permission notice appear in all copies.
  6. *
  7. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  8. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  9. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  10. * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  11. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  12. * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  13. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
  14. #include "internal.h"
  15. #if defined(OPENSSL_WINDOWS)
  16. #pragma warning(push, 3)
  17. #include <windows.h>
  18. #pragma warning(pop)
  19. #include <assert.h>
  20. #include <string.h>
  21. #include <openssl/mem.h>
  22. void CRYPTO_once(CRYPTO_once_t *in_once, void (*init)(void)) {
  23. volatile LONG *once = (LONG*) in_once;
  24. assert(sizeof(LONG) == sizeof(CRYPTO_once_t));
  25. /* Values must be aligned. */
  26. assert((((uintptr_t) once) & 3) == 0);
  27. /* This assumes that reading *once has acquire semantics. This should be true
  28. * on x86 and x86-64, where we expect Windows to run. */
  29. #if !defined(OPENSSL_X86) && !defined(OPENSSL_X86_64)
  30. #error "Windows once code may not work on other platforms." \
  31. "You can use InitOnceBeginInitialize on >=Vista"
  32. #endif
  33. if (*once == 1) {
  34. return;
  35. }
  36. for (;;) {
  37. switch (InterlockedCompareExchange(once, 2, 0)) {
  38. case 0:
  39. /* The value was zero so we are the first thread to call |CRYPTO_once|
  40. * on it. */
  41. init();
  42. /* Write one to indicate that initialisation is complete. */
  43. InterlockedExchange(once, 1);
  44. return;
  45. case 1:
  46. /* Another thread completed initialisation between our fast-path check
  47. * and |InterlockedCompareExchange|. */
  48. return;
  49. case 2:
  50. /* Another thread is running the initialisation. Switch to it then try
  51. * again. */
  52. SwitchToThread();
  53. break;
  54. default:
  55. abort();
  56. }
  57. }
  58. }
  59. static CRITICAL_SECTION g_destructors_lock;
  60. static thread_local_destructor_t g_destructors[NUM_OPENSSL_THREAD_LOCALS];
  61. static CRYPTO_once_t g_thread_local_init_once = CRYPTO_ONCE_INIT;
  62. static DWORD g_thread_local_key;
  63. static int g_thread_local_failed;
  64. static void thread_local_init(void) {
  65. if (!InitializeCriticalSectionAndSpinCount(&g_destructors_lock, 0x400)) {
  66. g_thread_local_failed = 1;
  67. return;
  68. }
  69. g_thread_local_key = TlsAlloc();
  70. g_thread_local_failed = (g_thread_local_key == TLS_OUT_OF_INDEXES);
  71. }
  72. static void NTAPI thread_local_destructor(PVOID module,
  73. DWORD reason, PVOID reserved) {
  74. if (DLL_THREAD_DETACH != reason && DLL_PROCESS_DETACH != reason) {
  75. return;
  76. }
  77. CRYPTO_once(&g_thread_local_init_once, thread_local_init);
  78. if (g_thread_local_failed) {
  79. return;
  80. }
  81. void **pointers = (void**) TlsGetValue(g_thread_local_key);
  82. if (pointers == NULL) {
  83. return;
  84. }
  85. thread_local_destructor_t destructors[NUM_OPENSSL_THREAD_LOCALS];
  86. EnterCriticalSection(&g_destructors_lock);
  87. memcpy(destructors, g_destructors, sizeof(destructors));
  88. LeaveCriticalSection(&g_destructors_lock);
  89. unsigned i;
  90. for (i = 0; i < NUM_OPENSSL_THREAD_LOCALS; i++) {
  91. if (destructors[i] != NULL) {
  92. destructors[i](pointers[i]);
  93. }
  94. }
  95. OPENSSL_free(pointers);
  96. }
  97. /* Thread Termination Callbacks.
  98. *
  99. * Windows doesn't support a per-thread destructor with its TLS primitives.
  100. * So, we build it manually by inserting a function to be called on each
  101. * thread's exit. This magic is from http://www.codeproject.com/threads/tls.asp
  102. * and it works for VC++ 7.0 and later.
  103. *
  104. * Force a reference to _tls_used to make the linker create the TLS directory
  105. * if it's not already there. (E.g. if __declspec(thread) is not used). Force
  106. * a reference to p_thread_callback_boringssl to prevent whole program
  107. * optimization from discarding the variable. */
  108. #ifdef _WIN64
  109. #pragma comment(linker, "/INCLUDE:_tls_used")
  110. #pragma comment(linker, "/INCLUDE:p_thread_callback_boringssl")
  111. #else
  112. #pragma comment(linker, "/INCLUDE:__tls_used")
  113. #pragma comment(linker, "/INCLUDE:_p_thread_callback_boringssl")
  114. #endif
  115. /* .CRT$XLA to .CRT$XLZ is an array of PIMAGE_TLS_CALLBACK pointers that are
  116. * called automatically by the OS loader code (not the CRT) when the module is
  117. * loaded and on thread creation. They are NOT called if the module has been
  118. * loaded by a LoadLibrary() call. It must have implicitly been loaded at
  119. * process startup.
  120. *
  121. * By implicitly loaded, I mean that it is directly referenced by the main EXE
  122. * or by one of its dependent DLLs. Delay-loaded DLL doesn't count as being
  123. * implicitly loaded.
  124. *
  125. * See VC\crt\src\tlssup.c for reference. */
  126. /* The linker must not discard p_thread_callback_boringssl. (We force a reference
  127. * to this variable with a linker /INCLUDE:symbol pragma to ensure that.) If
  128. * this variable is discarded, the OnThreadExit function will never be
  129. * called. */
  130. #ifdef _WIN64
  131. /* .CRT section is merged with .rdata on x64 so it must be constant data. */
  132. #pragma const_seg(".CRT$XLC")
  133. /* When defining a const variable, it must have external linkage to be sure the
  134. * linker doesn't discard it. */
  135. extern const PIMAGE_TLS_CALLBACK p_thread_callback_boringssl;
  136. const PIMAGE_TLS_CALLBACK p_thread_callback_boringssl = thread_local_destructor;
  137. /* Reset the default section. */
  138. #pragma const_seg()
  139. #else
  140. #pragma data_seg(".CRT$XLC")
  141. PIMAGE_TLS_CALLBACK p_thread_callback_boringssl = thread_local_destructor;
  142. /* Reset the default section. */
  143. #pragma data_seg()
  144. #endif /* _WIN64 */
  145. void *CRYPTO_get_thread_local(thread_local_data_t index) {
  146. CRYPTO_once(&g_thread_local_init_once, thread_local_init);
  147. if (g_thread_local_failed) {
  148. return NULL;
  149. }
  150. void **pointers = TlsGetValue(g_thread_local_key);
  151. if (pointers == NULL) {
  152. return NULL;
  153. }
  154. return pointers[index];
  155. }
  156. int CRYPTO_set_thread_local(thread_local_data_t index, void *value,
  157. thread_local_destructor_t destructor) {
  158. CRYPTO_once(&g_thread_local_init_once, thread_local_init);
  159. if (g_thread_local_failed) {
  160. destructor(value);
  161. return 0;
  162. }
  163. void **pointers = TlsGetValue(g_thread_local_key);
  164. if (pointers == NULL) {
  165. pointers = OPENSSL_malloc(sizeof(void *) * NUM_OPENSSL_THREAD_LOCALS);
  166. if (pointers == NULL) {
  167. destructor(value);
  168. return 0;
  169. }
  170. memset(pointers, 0, sizeof(void *) * NUM_OPENSSL_THREAD_LOCALS);
  171. if (TlsSetValue(g_thread_local_key, pointers) == 0) {
  172. OPENSSL_free(pointers);
  173. destructor(value);
  174. return 0;
  175. }
  176. }
  177. EnterCriticalSection(&g_destructors_lock);
  178. g_destructors[index] = destructor;
  179. LeaveCriticalSection(&g_destructors_lock);
  180. pointers[index] = value;
  181. return 1;
  182. }
  183. #endif /* OPENSSL_WINDOWS */