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
test_thread_reported_flags(void)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
test_thread_native_fn(void * data)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
test_thread_native(void)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)
test_thread_internal(void)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
test_thread_native_multiple_joins_fn1(void * data)248 static uint32_t test_thread_native_multiple_joins_fn1(void *data)
249 {
250 return 0;
251 }
252
test_thread_native_multiple_joins_fn2(void * data)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
test_thread_native_multiple_joins_fn3(void * data)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
test_thread_native_multiple_joins(void)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
setup_tests(void)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