1 /* 2 * Copyright 2022-2024 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (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 #include <string.h> 11 #include <internal/cryptlib.h> 12 #include <internal/thread_arch.h> 13 #include <internal/thread.h> 14 #include <openssl/thread.h> 15 #include "testutil.h" 16 17 static int test_thread_reported_flags(void) 18 { 19 uint32_t flags = OSSL_get_thread_support_flags(); 20 21 #if !defined(OPENSSL_THREADS) 22 if (!TEST_int_eq(flags, 0)) 23 return 0; 24 #endif 25 26 #if defined(OPENSSL_NO_THREAD_POOL) 27 if (!TEST_int_eq(flags & OSSL_THREAD_SUPPORT_FLAG_THREAD_POOL, 0)) 28 return 0; 29 #else 30 if (!TEST_int_eq(flags & OSSL_THREAD_SUPPORT_FLAG_THREAD_POOL, 31 OSSL_THREAD_SUPPORT_FLAG_THREAD_POOL)) 32 return 0; 33 #endif 34 35 #if defined(OPENSSL_NO_DEFAULT_THREAD_POOL) 36 if (!TEST_int_eq(flags & OSSL_THREAD_SUPPORT_FLAG_DEFAULT_SPAWN, 0)) 37 return 0; 38 #else 39 if (!TEST_int_eq(flags & OSSL_THREAD_SUPPORT_FLAG_DEFAULT_SPAWN, 40 OSSL_THREAD_SUPPORT_FLAG_DEFAULT_SPAWN)) 41 return 0; 42 #endif 43 44 return 1; 45 } 46 47 #ifndef OPENSSL_NO_THREAD_POOL 48 49 # define TEST_THREAD_NATIVE_FN_SET_VALUE 1 50 static uint32_t test_thread_native_fn(void *data) 51 { 52 uint32_t *ldata = (uint32_t*) data; 53 *ldata = *ldata + 1; 54 return *ldata - 1; 55 } 56 /* Tests of native threads */ 57 58 static int test_thread_native(void) 59 { 60 uint32_t retval; 61 uint32_t local; 62 CRYPTO_THREAD *t; 63 64 /* thread spawn, join */ 65 66 local = 1; 67 t = ossl_crypto_thread_native_start(test_thread_native_fn, &local, 1); 68 if (!TEST_ptr(t)) 69 return 0; 70 71 /* 72 * pthread_join results in undefined behaviour if called on a joined 73 * thread. We do not impose such restrictions, so it's up to us to 74 * ensure that this does not happen (thread sanitizer will warn us 75 * if we do). 76 */ 77 if (!TEST_int_eq(ossl_crypto_thread_native_join(t, &retval), 1)) 78 return 0; 79 if (!TEST_int_eq(ossl_crypto_thread_native_join(t, &retval), 1)) 80 return 0; 81 82 if (!TEST_int_eq(retval, 1) || !TEST_int_eq(local, 2)) 83 return 0; 84 85 if (!TEST_int_eq(ossl_crypto_thread_native_clean(t), 1)) 86 return 0; 87 t = NULL; 88 89 if (!TEST_int_eq(ossl_crypto_thread_native_clean(t), 0)) 90 return 0; 91 92 return 1; 93 } 94 95 # if !defined(OPENSSL_NO_DEFAULT_THREAD_POOL) 96 static int test_thread_internal(void) 97 { 98 uint32_t retval[3]; 99 uint32_t local[3] = { 0 }; 100 uint32_t threads_supported; 101 size_t i; 102 void *t[3]; 103 int status = 0; 104 OSSL_LIB_CTX *cust_ctx = OSSL_LIB_CTX_new(); 105 106 threads_supported = OSSL_get_thread_support_flags(); 107 threads_supported &= OSSL_THREAD_SUPPORT_FLAG_DEFAULT_SPAWN; 108 109 if (threads_supported == 0) { 110 if (!TEST_uint64_t_eq(OSSL_get_max_threads(NULL), 0)) 111 goto cleanup; 112 if (!TEST_uint64_t_eq(OSSL_get_max_threads(cust_ctx), 0)) 113 goto cleanup; 114 115 if (!TEST_int_eq(OSSL_set_max_threads(NULL, 1), 0)) 116 goto cleanup; 117 if (!TEST_int_eq(OSSL_set_max_threads(cust_ctx, 1), 0)) 118 goto cleanup; 119 120 if (!TEST_uint64_t_eq(OSSL_get_max_threads(NULL), 0)) 121 goto cleanup; 122 if (!TEST_uint64_t_eq(OSSL_get_max_threads(cust_ctx), 0)) 123 goto cleanup; 124 125 t[0] = ossl_crypto_thread_start(NULL, test_thread_native_fn, &local[0]); 126 if (!TEST_ptr_null(t[0])) 127 goto cleanup; 128 129 status = 1; 130 goto cleanup; 131 } 132 133 /* fail when not allowed to use threads */ 134 135 if (!TEST_uint64_t_eq(OSSL_get_max_threads(NULL), 0)) 136 goto cleanup; 137 t[0] = ossl_crypto_thread_start(NULL, test_thread_native_fn, &local[0]); 138 if (!TEST_ptr_null(t[0])) 139 goto cleanup; 140 141 /* fail when enabled on a different context */ 142 if (!TEST_uint64_t_eq(OSSL_get_max_threads(cust_ctx), 0)) 143 goto cleanup; 144 if (!TEST_int_eq(OSSL_set_max_threads(cust_ctx, 1), 1)) 145 goto cleanup; 146 if (!TEST_uint64_t_eq(OSSL_get_max_threads(NULL), 0)) 147 goto cleanup; 148 if (!TEST_uint64_t_eq(OSSL_get_max_threads(cust_ctx), 1)) 149 goto cleanup; 150 t[0] = ossl_crypto_thread_start(NULL, test_thread_native_fn, &local[0]); 151 if (!TEST_ptr_null(t[0])) 152 goto cleanup; 153 if (!TEST_int_eq(OSSL_set_max_threads(cust_ctx, 0), 1)) 154 goto cleanup; 155 156 /* sequential startup */ 157 158 if (!TEST_int_eq(OSSL_set_max_threads(NULL, 1), 1)) 159 goto cleanup; 160 if (!TEST_uint64_t_eq(OSSL_get_max_threads(NULL), 1)) 161 goto cleanup; 162 if (!TEST_uint64_t_eq(OSSL_get_max_threads(cust_ctx), 0)) 163 goto cleanup; 164 165 for (i = 0; i < OSSL_NELEM(t); ++i) { 166 local[0] = i + 1; 167 168 t[i] = ossl_crypto_thread_start(NULL, test_thread_native_fn, &local[0]); 169 if (!TEST_ptr(t[i])) 170 goto cleanup; 171 172 /* 173 * pthread_join results in undefined behaviour if called on a joined 174 * thread. We do not impose such restrictions, so it's up to us to 175 * ensure that this does not happen (thread sanitizer will warn us 176 * if we do). 177 */ 178 if (!TEST_int_eq(ossl_crypto_thread_join(t[i], &retval[0]), 1)) 179 goto cleanup; 180 if (!TEST_int_eq(ossl_crypto_thread_join(t[i], &retval[0]), 1)) 181 goto cleanup; 182 183 if (!TEST_int_eq(retval[0], i + 1) || !TEST_int_eq(local[0], i + 2)) 184 goto cleanup; 185 186 if (!TEST_int_eq(ossl_crypto_thread_clean(t[i]), 1)) 187 goto cleanup; 188 t[i] = NULL; 189 190 if (!TEST_int_eq(ossl_crypto_thread_clean(t[i]), 0)) 191 goto cleanup; 192 } 193 194 /* parallel startup */ 195 196 if (!TEST_int_eq(OSSL_set_max_threads(NULL, OSSL_NELEM(t)), 1)) 197 goto cleanup; 198 199 for (i = 0; i < OSSL_NELEM(t); ++i) { 200 local[i] = i + 1; 201 t[i] = ossl_crypto_thread_start(NULL, test_thread_native_fn, &local[i]); 202 if (!TEST_ptr(t[i])) 203 goto cleanup; 204 } 205 for (i = 0; i < OSSL_NELEM(t); ++i) { 206 if (!TEST_int_eq(ossl_crypto_thread_join(t[i], &retval[i]), 1)) 207 goto cleanup; 208 } 209 for (i = 0; i < OSSL_NELEM(t); ++i) { 210 if (!TEST_int_eq(retval[i], i + 1) || !TEST_int_eq(local[i], i + 2)) 211 goto cleanup; 212 if (!TEST_int_eq(ossl_crypto_thread_clean(t[i]), 1)) 213 goto cleanup; 214 } 215 216 /* parallel startup, bottleneck */ 217 218 if (!TEST_int_eq(OSSL_set_max_threads(NULL, OSSL_NELEM(t) - 1), 1)) 219 goto cleanup; 220 221 for (i = 0; i < OSSL_NELEM(t); ++i) { 222 local[i] = i + 1; 223 t[i] = ossl_crypto_thread_start(NULL, test_thread_native_fn, &local[i]); 224 if (!TEST_ptr(t[i])) 225 goto cleanup; 226 } 227 for (i = 0; i < OSSL_NELEM(t); ++i) { 228 if (!TEST_int_eq(ossl_crypto_thread_join(t[i], &retval[i]), 1)) 229 goto cleanup; 230 } 231 for (i = 0; i < OSSL_NELEM(t); ++i) { 232 if (!TEST_int_eq(retval[i], i + 1) || !TEST_int_eq(local[i], i + 2)) 233 goto cleanup; 234 if (!TEST_int_eq(ossl_crypto_thread_clean(t[i]), 1)) 235 goto cleanup; 236 } 237 238 if (!TEST_int_eq(OSSL_set_max_threads(NULL, 0), 1)) 239 goto cleanup; 240 241 status = 1; 242 cleanup: 243 OSSL_LIB_CTX_free(cust_ctx); 244 return status; 245 } 246 # endif 247 248 static uint32_t test_thread_native_multiple_joins_fn1(void *data) 249 { 250 return 0; 251 } 252 253 static uint32_t test_thread_native_multiple_joins_fn2(void *data) 254 { 255 ossl_crypto_thread_native_join((CRYPTO_THREAD *)data, NULL); 256 return 0; 257 } 258 259 static uint32_t test_thread_native_multiple_joins_fn3(void *data) 260 { 261 ossl_crypto_thread_native_join((CRYPTO_THREAD *)data, NULL); 262 return 0; 263 } 264 265 static int test_thread_native_multiple_joins(void) 266 { 267 CRYPTO_THREAD *t, *t1, *t2; 268 269 t = ossl_crypto_thread_native_start(test_thread_native_multiple_joins_fn1, NULL, 1); 270 t1 = ossl_crypto_thread_native_start(test_thread_native_multiple_joins_fn2, t, 1); 271 t2 = ossl_crypto_thread_native_start(test_thread_native_multiple_joins_fn3, t, 1); 272 273 if (!TEST_ptr(t) || !TEST_ptr(t1) || !TEST_ptr(t2)) 274 return 0; 275 276 if (!TEST_int_eq(ossl_crypto_thread_native_join(t2, NULL), 1)) 277 return 0; 278 if (!TEST_int_eq(ossl_crypto_thread_native_join(t1, NULL), 1)) 279 return 0; 280 281 if (!TEST_int_eq(ossl_crypto_thread_native_clean(t2), 1)) 282 return 0; 283 284 if (!TEST_int_eq(ossl_crypto_thread_native_clean(t1), 1)) 285 return 0; 286 287 if (!TEST_int_eq(ossl_crypto_thread_native_clean(t), 1)) 288 return 0; 289 290 return 1; 291 } 292 293 #endif 294 295 int setup_tests(void) 296 { 297 ADD_TEST(test_thread_reported_flags); 298 #if !defined(OPENSSL_NO_THREAD_POOL) 299 ADD_TEST(test_thread_native); 300 ADD_TEST(test_thread_native_multiple_joins); 301 # if !defined(OPENSSL_NO_DEFAULT_THREAD_POOL) 302 ADD_TEST(test_thread_internal); 303 # endif 304 #endif 305 306 return 1; 307 } 308