80-test_ssl_new.t: Make 19-mac-then-encrypt.conf work without TLSv1.2
[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 }