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