Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 
 

218 строки
5.4 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. #include <stdio.h>
  16. #if !defined(OPENSSL_NO_THREADS)
  17. #if defined(OPENSSL_WINDOWS)
  18. OPENSSL_MSVC_PRAGMA(warning(push, 3))
  19. #include <windows.h>
  20. OPENSSL_MSVC_PRAGMA(warning(pop))
  21. typedef HANDLE thread_t;
  22. static DWORD WINAPI thread_run(LPVOID arg) {
  23. void (*thread_func)(void);
  24. /* VC really doesn't like casting between data and function pointers. */
  25. OPENSSL_memcpy(&thread_func, &arg, sizeof(thread_func));
  26. thread_func();
  27. return 0;
  28. }
  29. static int run_thread(thread_t *out_thread, void (*thread_func)(void)) {
  30. void *arg;
  31. /* VC really doesn't like casting between data and function pointers. */
  32. OPENSSL_memcpy(&arg, &thread_func, sizeof(arg));
  33. *out_thread = CreateThread(NULL /* security attributes */,
  34. 0 /* default stack size */, thread_run, arg,
  35. 0 /* run immediately */, NULL /* ignore id */);
  36. return *out_thread != NULL;
  37. }
  38. static int wait_for_thread(thread_t thread) {
  39. return WaitForSingleObject(thread, INFINITE) == 0;
  40. }
  41. #else
  42. #include <pthread.h>
  43. #include <string.h>
  44. #include <time.h>
  45. typedef pthread_t thread_t;
  46. static void *thread_run(void *arg) {
  47. void (*thread_func)(void) = arg;
  48. thread_func();
  49. return NULL;
  50. }
  51. static int run_thread(thread_t *out_thread, void (*thread_func)(void)) {
  52. return pthread_create(out_thread, NULL /* default attributes */, thread_run,
  53. thread_func) == 0;
  54. }
  55. static int wait_for_thread(thread_t thread) {
  56. return pthread_join(thread, NULL) == 0;
  57. }
  58. #endif /* OPENSSL_WINDOWS */
  59. static unsigned g_once_init_called = 0;
  60. static void once_init(void) {
  61. g_once_init_called++;
  62. /* Sleep briefly so one |call_once_thread| instance will call |CRYPTO_once|
  63. * while the other is running this function. */
  64. #if defined(OPENSSL_WINDOWS)
  65. Sleep(1 /* milliseconds */);
  66. #else
  67. struct timespec req;
  68. OPENSSL_memset(&req, 0, sizeof(req));
  69. req.tv_nsec = 1000000;
  70. nanosleep(&req, NULL);
  71. #endif
  72. }
  73. static CRYPTO_once_t g_test_once = CRYPTO_ONCE_INIT;
  74. static void call_once_thread(void) {
  75. CRYPTO_once(&g_test_once, once_init);
  76. }
  77. static int test_once(void) {
  78. if (g_once_init_called != 0) {
  79. fprintf(stderr, "g_once_init_called was non-zero at start.\n");
  80. return 0;
  81. }
  82. thread_t thread1, thread2;
  83. if (!run_thread(&thread1, call_once_thread) ||
  84. !run_thread(&thread2, call_once_thread) ||
  85. !wait_for_thread(thread1) ||
  86. !wait_for_thread(thread2)) {
  87. fprintf(stderr, "thread failed.\n");
  88. return 0;
  89. }
  90. CRYPTO_once(&g_test_once, once_init);
  91. if (g_once_init_called != 1) {
  92. fprintf(stderr, "Expected init function to be called once, but found %u.\n",
  93. g_once_init_called);
  94. return 0;
  95. }
  96. return 1;
  97. }
  98. static int g_test_thread_ok = 0;
  99. static unsigned g_destructor_called_count = 0;
  100. static void thread_local_destructor(void *arg) {
  101. if (arg == NULL) {
  102. return;
  103. }
  104. unsigned *count = arg;
  105. (*count)++;
  106. }
  107. static void thread_local_test_thread(void) {
  108. void *ptr = CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_TEST);
  109. if (ptr != NULL) {
  110. return;
  111. }
  112. if (!CRYPTO_set_thread_local(OPENSSL_THREAD_LOCAL_TEST,
  113. &g_destructor_called_count,
  114. thread_local_destructor)) {
  115. return;
  116. }
  117. if (CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_TEST) !=
  118. &g_destructor_called_count) {
  119. return;
  120. }
  121. g_test_thread_ok = 1;
  122. }
  123. static void thread_local_test2_thread(void) {}
  124. static int test_thread_local(void) {
  125. void *ptr = CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_TEST);
  126. if (ptr != NULL) {
  127. fprintf(stderr, "Thread-local data was non-NULL at start.\n");
  128. }
  129. thread_t thread;
  130. if (!run_thread(&thread, thread_local_test_thread) ||
  131. !wait_for_thread(thread)) {
  132. fprintf(stderr, "thread failed.\n");
  133. return 0;
  134. }
  135. if (!g_test_thread_ok) {
  136. fprintf(stderr, "Thread-local data didn't work in thread.\n");
  137. return 0;
  138. }
  139. if (g_destructor_called_count != 1) {
  140. fprintf(stderr,
  141. "Destructor should have been called once, but actually called %u "
  142. "times.\n",
  143. g_destructor_called_count);
  144. return 0;
  145. }
  146. /* thread_local_test2_thread doesn't do anything, but it tests that the
  147. * thread destructor function works even if thread-local storage wasn't used
  148. * for a thread. */
  149. if (!run_thread(&thread, thread_local_test2_thread) ||
  150. !wait_for_thread(thread)) {
  151. fprintf(stderr, "thread failed.\n");
  152. return 0;
  153. }
  154. return 1;
  155. }
  156. int main(int argc, char **argv) {
  157. if (!test_once() ||
  158. !test_thread_local()) {
  159. return 1;
  160. }
  161. printf("PASS\n");
  162. return 0;
  163. }
  164. #else /* OPENSSL_NO_THREADS */
  165. int main(int argc, char **argv) {
  166. printf("PASS\n");
  167. return 0;
  168. }
  169. #endif