1 /* 2 * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the OpenSSL license (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 #if defined(_WIN32) 11 # include <windows.h> 12 #endif 13 14 #include <stdio.h> 15 16 #include <openssl/crypto.h> 17 18 #if !defined(OPENSSL_THREADS) || defined(CRYPTO_TDEBUG) 19 20 typedef unsigned int thread_t; 21 22 static int run_thread(thread_t *t, void (*f)(void)) 23 { 24 f(); 25 return 1; 26 } 27 28 static int wait_for_thread(thread_t thread) 29 { 30 return 1; 31 } 32 33 #elif defined(OPENSSL_SYS_WINDOWS) 34 35 typedef HANDLE thread_t; 36 37 static DWORD WINAPI thread_run(LPVOID arg) 38 { 39 void (*f)(void); 40 41 *(void **) (&f) = arg; 42 43 f(); 44 return 0; 45 } 46 47 static int run_thread(thread_t *t, void (*f)(void)) 48 { 49 *t = CreateThread(NULL, 0, thread_run, *(void **) &f, 0, NULL); 50 return *t != NULL; 51 } 52 53 static int wait_for_thread(thread_t thread) 54 { 55 return WaitForSingleObject(thread, INFINITE) == 0; 56 } 57 58 #else 59 60 typedef pthread_t thread_t; 61 62 static void *thread_run(void *arg) 63 { 64 void (*f)(void); 65 66 *(void **) (&f) = arg; 67 68 f(); 69 return NULL; 70 } 71 72 static int run_thread(thread_t *t, void (*f)(void)) 73 { 74 return pthread_create(t, NULL, thread_run, *(void **) &f) == 0; 75 } 76 77 static int wait_for_thread(thread_t thread) 78 { 79 return pthread_join(thread, NULL) == 0; 80 } 81 82 #endif 83 84 static int test_lock(void) 85 { 86 CRYPTO_RWLOCK *lock = CRYPTO_THREAD_lock_new(); 87 88 if (!CRYPTO_THREAD_read_lock(lock)) { 89 fprintf(stderr, "CRYPTO_THREAD_read_lock() failed\n"); 90 return 0; 91 } 92 93 if (!CRYPTO_THREAD_unlock(lock)) { 94 fprintf(stderr, "CRYPTO_THREAD_unlock() failed\n"); 95 return 0; 96 } 97 98 CRYPTO_THREAD_lock_free(lock); 99 100 return 1; 101 } 102 103 static CRYPTO_ONCE once_run = CRYPTO_ONCE_STATIC_INIT; 104 static unsigned once_run_count = 0; 105 106 static void once_do_run(void) 107 { 108 once_run_count++; 109 } 110 111 static void once_run_thread_cb(void) 112 { 113 CRYPTO_THREAD_run_once(&once_run, once_do_run); 114 } 115 116 static int test_once(void) 117 { 118 thread_t thread; 119 if (!run_thread(&thread, once_run_thread_cb) || 120 !wait_for_thread(thread)) 121 { 122 fprintf(stderr, "run_thread() failed\n"); 123 return 0; 124 } 125 126 if (!CRYPTO_THREAD_run_once(&once_run, once_do_run)) { 127 fprintf(stderr, "CRYPTO_THREAD_run_once() failed\n"); 128 return 0; 129 } 130 131 if (once_run_count != 1) { 132 fprintf(stderr, "once run %u times\n", once_run_count); 133 return 0; 134 } 135 136 return 1; 137 } 138 139 static CRYPTO_THREAD_LOCAL thread_local_key; 140 static unsigned destructor_run_count = 0; 141 static int thread_local_thread_cb_ok = 0; 142 143 static void thread_local_destructor(void *arg) 144 { 145 unsigned *count; 146 147 if (arg == NULL) 148 return; 149 150 count = arg; 151 152 (*count)++; 153 } 154 155 static void thread_local_thread_cb(void) 156 { 157 void *ptr; 158 159 ptr = CRYPTO_THREAD_get_local(&thread_local_key); 160 if (ptr != NULL) { 161 fprintf(stderr, "ptr not NULL\n"); 162 return; 163 } 164 165 if (!CRYPTO_THREAD_set_local(&thread_local_key, &destructor_run_count)) { 166 fprintf(stderr, "CRYPTO_THREAD_set_local() failed\n"); 167 return; 168 } 169 170 ptr = CRYPTO_THREAD_get_local(&thread_local_key); 171 if (ptr != &destructor_run_count) { 172 fprintf(stderr, "invalid ptr\n"); 173 return; 174 } 175 176 thread_local_thread_cb_ok = 1; 177 } 178 179 static int test_thread_local(void) 180 { 181 thread_t thread; 182 void *ptr = NULL; 183 184 if (!CRYPTO_THREAD_init_local(&thread_local_key, thread_local_destructor)) { 185 fprintf(stderr, "CRYPTO_THREAD_init_local() failed\n"); 186 return 0; 187 } 188 189 ptr = CRYPTO_THREAD_get_local(&thread_local_key); 190 if (ptr != NULL) { 191 fprintf(stderr, "ptr not NULL\n"); 192 return 0; 193 } 194 195 if (!run_thread(&thread, thread_local_thread_cb) || 196 !wait_for_thread(thread)) 197 { 198 fprintf(stderr, "run_thread() failed\n"); 199 return 0; 200 } 201 202 if (thread_local_thread_cb_ok != 1) { 203 fprintf(stderr, "thread-local thread callback failed\n"); 204 return 0; 205 } 206 207 #if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG) 208 209 ptr = CRYPTO_THREAD_get_local(&thread_local_key); 210 if (ptr != NULL) { 211 fprintf(stderr, "ptr not NULL\n"); 212 return 0; 213 } 214 215 # if !defined(OPENSSL_SYS_WINDOWS) 216 if (destructor_run_count != 1) { 217 fprintf(stderr, "thread-local destructor run %u times\n", 218 destructor_run_count); 219 return 0; 220 } 221 # endif 222 223 #endif 224 225 if (!CRYPTO_THREAD_cleanup_local(&thread_local_key)) { 226 fprintf(stderr, "CRYPTO_THREAD_cleanup_local() failed\n"); 227 return 0; 228 } 229 230 return 1; 231 } 232 233 int main(int argc, char **argv) 234 { 235 if (!test_lock()) 236 return 1; 237 238 if (!test_once()) 239 return 1; 240 241 if (!test_thread_local()) 242 return 1; 243 244 printf("PASS\n"); 245 return 0; 246 } 247