e15f2c31ae78928eb54d159088e5f68e9810b781
[openssl.git] / test / threadstest.c
1 /* ====================================================================
2  * Copyright (c) 2016 The OpenSSL Project.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in
13  *    the documentation and/or other materials provided with the
14  *    distribution.
15  *
16  * 3. All advertising materials mentioning features or use of this
17  *    software must display the following acknowledgment:
18  *    "This product includes software developed by the OpenSSL Project
19  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
20  *
21  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
22  *    endorse or promote products derived from this software without
23  *    prior written permission. For written permission, please contact
24  *    openssl-core@openssl.org.
25  *
26  * 5. Products derived from this software may not be called "OpenSSL"
27  *    nor may "OpenSSL" appear in their names without prior written
28  *    permission of the OpenSSL Project.
29  *
30  * 6. Redistributions of any form whatsoever must retain the following
31  *    acknowledgment:
32  *    "This product includes software developed by the OpenSSL Project
33  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
34  *
35  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
36  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
38  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
41  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
44  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
45  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
46  * OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  */
49
50 #include <stdio.h>
51
52 #include <openssl/crypto.h>
53
54 #if !defined(OPENSSL_THREADS) || defined(CRYPTO_TDEBUG)
55
56 typedef unsigned int thread_t;
57
58 static int run_thread(thread_t *t, void (*f)(void))
59 {
60     f();
61     return 1;
62 }
63
64 static int wait_for_thread(thread_t thread)
65 {
66     return 1;
67 }
68
69 #elif defined(OPENSSL_SYS_WINDOWS)
70
71 typedef HANDLE thread_t;
72
73 static DWORD WINAPI thread_run(LPVOID arg)
74 {
75     void (*f)(void);
76
77     *(void **) (&f) = arg;
78
79     f();
80     return 0;
81 }
82
83 static int run_thread(thread_t *t, void (*f)(void))
84 {
85     *t = CreateThread(NULL, 0, thread_run, *(void **) &f, 0, NULL);
86     return *t != NULL;
87 }
88
89 static int wait_for_thread(thread_t thread)
90 {
91     return WaitForSingleObject(thread, INFINITE) == 0;
92 }
93
94 #else
95
96 typedef pthread_t thread_t;
97
98 static void *thread_run(void *arg)
99 {
100     void (*f)(void);
101
102     *(void **) (&f) = arg;
103
104     f();
105     return NULL;
106 }
107
108 static int run_thread(thread_t *t, void (*f)(void))
109 {
110     return pthread_create(t, NULL, thread_run, *(void **) &f) == 0;
111 }
112
113 static int wait_for_thread(thread_t thread)
114 {
115     return pthread_join(thread, NULL) == 0;
116 }
117
118 #endif
119
120 static int test_lock(void)
121 {
122     CRYPTO_RWLOCK *lock = CRYPTO_THREAD_lock_new();
123
124     if (!CRYPTO_THREAD_read_lock(lock)) {
125         fprintf(stderr, "CRYPTO_THREAD_read_lock() failed\n");
126         return 0;
127     }
128
129     if (!CRYPTO_THREAD_unlock(lock)) {
130         fprintf(stderr, "CRYPTO_THREAD_unlock() failed\n");
131         return 0;
132     }
133
134     CRYPTO_THREAD_lock_free(lock);
135
136     return 1;
137 }
138
139 static CRYPTO_ONCE once_run = CRYPTO_ONCE_STATIC_INIT;
140 static unsigned once_run_count = 0;
141
142 static void once_do_run(void)
143 {
144     once_run_count++;
145 }
146
147 static void once_run_thread_cb(void)
148 {
149     CRYPTO_THREAD_run_once(&once_run, once_do_run);
150 }
151
152 static int test_once(void)
153 {
154     thread_t thread;
155     if (!run_thread(&thread, once_run_thread_cb) ||
156         !wait_for_thread(thread))
157     {
158         fprintf(stderr, "run_thread() failed\n");
159         return 0;
160     }
161
162     if (!CRYPTO_THREAD_run_once(&once_run, once_do_run)) {
163         fprintf(stderr, "CRYPTO_THREAD_run_once() failed\n");
164         return 0;
165     }
166
167     if (once_run_count != 1) {
168         fprintf(stderr, "once run %u times\n", once_run_count);
169         return 0;
170     }
171
172     return 1;
173 }
174
175 static CRYPTO_THREAD_LOCAL thread_local_key;
176 static unsigned destructor_run_count = 0;
177 static int thread_local_thread_cb_ok = 0;
178
179 static void thread_local_destructor(void *arg)
180 {
181     unsigned *count;
182
183     if (arg == NULL)
184         return;
185
186     count = arg;
187
188     (*count)++;
189 }
190
191 static void thread_local_thread_cb(void)
192 {
193     void *ptr;
194
195     ptr = CRYPTO_THREAD_get_local(&thread_local_key);
196     if (ptr != NULL) {
197         fprintf(stderr, "ptr not NULL\n");
198         return;
199     }
200
201     if (!CRYPTO_THREAD_set_local(&thread_local_key, &destructor_run_count)) {
202         fprintf(stderr, "CRYPTO_THREAD_set_local() failed\n");
203         return;
204     }
205
206     ptr = CRYPTO_THREAD_get_local(&thread_local_key);
207     if (ptr != &destructor_run_count) {
208         fprintf(stderr, "invalid ptr\n");
209         return;
210     }
211
212     thread_local_thread_cb_ok = 1;
213 }
214
215 static int test_thread_local(void)
216 {
217     thread_t thread;
218     void *ptr = NULL;
219
220     if (!CRYPTO_THREAD_init_local(&thread_local_key, thread_local_destructor)) {
221         fprintf(stderr, "CRYPTO_THREAD_init_local() failed\n");
222         return 0;
223     }
224
225     ptr = CRYPTO_THREAD_get_local(&thread_local_key);
226     if (ptr != NULL) {
227         fprintf(stderr, "ptr not NULL\n");
228         return 0;
229     }
230
231     if (!run_thread(&thread, thread_local_thread_cb) ||
232         !wait_for_thread(thread))
233     {
234         fprintf(stderr, "run_thread() failed\n");
235         return 0;
236     }
237
238     if (thread_local_thread_cb_ok != 1) {
239         fprintf(stderr, "thread-local thread callback failed\n");
240         return 0;
241     }
242
243 #if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
244
245     ptr = CRYPTO_THREAD_get_local(&thread_local_key);
246     if (ptr != NULL) {
247         fprintf(stderr, "ptr not NULL\n");
248         return 0;
249     }
250
251 # if !defined(OPENSSL_SYS_WINDOWS)
252     if (destructor_run_count != 1) {
253         fprintf(stderr, "thread-local destructor run %u times\n",
254                 destructor_run_count);
255         return 0;
256     }
257 # endif
258
259 #endif
260
261     if (!CRYPTO_THREAD_cleanup_local(&thread_local_key)) {
262         fprintf(stderr, "CRYPTO_THREAD_cleanup_local() failed\n");
263         return 0;
264     }
265
266     return 1;
267 }
268
269 int main(int argc, char **argv)
270 {
271     if (!test_lock())
272       return 1;
273
274     if (!test_once())
275       return 1;
276
277     if (!test_thread_local())
278       return 1;
279
280     printf("PASS\n");
281     return 0;
282 }