Convert more tests to framework
[openssl.git] / test / threadstest.c
1 /*
2  * Copyright 2016-2017 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 <openssl/crypto.h>
15 #include "test_main.h"
16 #include "testutil.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 (!TEST_true(CRYPTO_THREAD_read_lock(lock))
89         || !TEST_true(CRYPTO_THREAD_unlock(lock)))
90         return 0;
91
92     CRYPTO_THREAD_lock_free(lock);
93
94     return 1;
95 }
96
97 static CRYPTO_ONCE once_run = CRYPTO_ONCE_STATIC_INIT;
98 static unsigned once_run_count = 0;
99
100 static void once_do_run(void)
101 {
102     once_run_count++;
103 }
104
105 static void once_run_thread_cb(void)
106 {
107     CRYPTO_THREAD_run_once(&once_run, once_do_run);
108 }
109
110 static int test_once(void)
111 {
112     thread_t thread;
113
114     if (!TEST_true(run_thread(&thread, once_run_thread_cb))
115         || !TEST_true(wait_for_thread(thread))
116         || !CRYPTO_THREAD_run_once(&once_run, once_do_run)
117         || !TEST_int_eq(once_run_count, 1))
118         return 0;
119     return 1;
120 }
121
122 static CRYPTO_THREAD_LOCAL thread_local_key;
123 static unsigned destructor_run_count = 0;
124 static int thread_local_thread_cb_ok = 0;
125
126 static void thread_local_destructor(void *arg)
127 {
128     unsigned *count;
129
130     if (arg == NULL)
131         return;
132
133     count = arg;
134
135     (*count)++;
136 }
137
138 static void thread_local_thread_cb(void)
139 {
140     void *ptr;
141
142     ptr = CRYPTO_THREAD_get_local(&thread_local_key);
143     if (!TEST_ptr_null(ptr)
144         || !TEST_true(CRYPTO_THREAD_set_local(&thread_local_key,
145                                               &destructor_run_count)))
146         return;
147
148     ptr = CRYPTO_THREAD_get_local(&thread_local_key);
149     if (!TEST_ptr_eq(ptr, &destructor_run_count))
150         return;
151
152     thread_local_thread_cb_ok = 1;
153 }
154
155 static int test_thread_local(void)
156 {
157     thread_t thread;
158     void *ptr = NULL;
159
160     if (!TEST_true(CRYPTO_THREAD_init_local(&thread_local_key,
161                                             thread_local_destructor)))
162         return 0;
163
164     ptr = CRYPTO_THREAD_get_local(&thread_local_key);
165     if (!TEST_ptr_null(ptr)
166         || !TEST_true(run_thread(&thread, thread_local_thread_cb))
167         || !TEST_true(wait_for_thread(thread))
168         || !TEST_int_eq(thread_local_thread_cb_ok, 1))
169         return 0;
170
171 #if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
172
173     ptr = CRYPTO_THREAD_get_local(&thread_local_key);
174     if (!TEST_ptr_null(ptr))
175         return 0;
176
177 # if !defined(OPENSSL_SYS_WINDOWS)
178     if (!TEST_int_eq(destructor_run_count, 1))
179         return 0;
180 # endif
181 #endif
182
183     if (!TEST_true(CRYPTO_THREAD_cleanup_local(&thread_local_key)))
184         return 0;
185     return 1;
186 }
187
188 void register_tests(void)
189 {
190     ADD_TEST(test_lock);
191     ADD_TEST(test_once);
192     ADD_TEST(test_thread_local);
193 }