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