]> git.ipfire.org Git - thirdparty/openssl.git/blob - test/threadstest.c
include/openssl: don't include <windows.h> in public headers.
[thirdparty/openssl.git] / test / threadstest.c
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 }