2 * Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
4 * Licensed under the Apache License 2.0 (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
14 #include <openssl/crypto.h>
17 #if !defined(OPENSSL_THREADS) || defined(CRYPTO_TDEBUG)
19 typedef unsigned int thread_t
;
21 static int run_thread(thread_t
*t
, void (*f
)(void))
27 static int wait_for_thread(thread_t thread
)
32 #elif defined(OPENSSL_SYS_WINDOWS)
34 typedef HANDLE thread_t
;
36 static DWORD WINAPI
thread_run(LPVOID arg
)
40 *(void **) (&f
) = arg
;
46 static int run_thread(thread_t
*t
, void (*f
)(void))
48 *t
= CreateThread(NULL
, 0, thread_run
, *(void **) &f
, 0, NULL
);
52 static int wait_for_thread(thread_t thread
)
54 return WaitForSingleObject(thread
, INFINITE
) == 0;
59 typedef pthread_t thread_t
;
61 static void *thread_run(void *arg
)
65 *(void **) (&f
) = arg
;
71 static int run_thread(thread_t
*t
, void (*f
)(void))
73 return pthread_create(t
, NULL
, thread_run
, *(void **) &f
) == 0;
76 static int wait_for_thread(thread_t thread
)
78 return pthread_join(thread
, NULL
) == 0;
83 static int test_lock(void)
85 CRYPTO_RWLOCK
*lock
= CRYPTO_THREAD_lock_new();
87 if (!TEST_true(CRYPTO_THREAD_read_lock(lock
))
88 || !TEST_true(CRYPTO_THREAD_unlock(lock
)))
91 CRYPTO_THREAD_lock_free(lock
);
96 static CRYPTO_ONCE once_run
= CRYPTO_ONCE_STATIC_INIT
;
97 static unsigned once_run_count
= 0;
99 static void once_do_run(void)
104 static void once_run_thread_cb(void)
106 CRYPTO_THREAD_run_once(&once_run
, once_do_run
);
109 static int test_once(void)
113 if (!TEST_true(run_thread(&thread
, once_run_thread_cb
))
114 || !TEST_true(wait_for_thread(thread
))
115 || !CRYPTO_THREAD_run_once(&once_run
, once_do_run
)
116 || !TEST_int_eq(once_run_count
, 1))
121 static CRYPTO_THREAD_LOCAL thread_local_key
;
122 static unsigned destructor_run_count
= 0;
123 static int thread_local_thread_cb_ok
= 0;
125 static void thread_local_destructor(void *arg
)
137 static void thread_local_thread_cb(void)
141 ptr
= CRYPTO_THREAD_get_local(&thread_local_key
);
142 if (!TEST_ptr_null(ptr
)
143 || !TEST_true(CRYPTO_THREAD_set_local(&thread_local_key
,
144 &destructor_run_count
)))
147 ptr
= CRYPTO_THREAD_get_local(&thread_local_key
);
148 if (!TEST_ptr_eq(ptr
, &destructor_run_count
))
151 thread_local_thread_cb_ok
= 1;
154 static int test_thread_local(void)
159 if (!TEST_true(CRYPTO_THREAD_init_local(&thread_local_key
,
160 thread_local_destructor
)))
163 ptr
= CRYPTO_THREAD_get_local(&thread_local_key
);
164 if (!TEST_ptr_null(ptr
)
165 || !TEST_true(run_thread(&thread
, thread_local_thread_cb
))
166 || !TEST_true(wait_for_thread(thread
))
167 || !TEST_int_eq(thread_local_thread_cb_ok
, 1))
170 #if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
172 ptr
= CRYPTO_THREAD_get_local(&thread_local_key
);
173 if (!TEST_ptr_null(ptr
))
176 # if !defined(OPENSSL_SYS_WINDOWS)
177 if (!TEST_int_eq(destructor_run_count
, 1))
182 if (!TEST_true(CRYPTO_THREAD_cleanup_local(&thread_local_key
)))
187 static int test_atomic(void)
189 int val
= 0, ret
= 0, testresult
= 0;
190 uint64_t val64
= 1, ret64
= 0;
191 CRYPTO_RWLOCK
*lock
= CRYPTO_THREAD_lock_new();
196 if (CRYPTO_atomic_add(&val
, 1, &ret
, NULL
)) {
197 /* This succeeds therefore we're on a platform with lockless atomics */
198 if (!TEST_int_eq(val
, 1) || !TEST_int_eq(val
, ret
))
201 /* This failed therefore we're on a platform without lockless atomics */
202 if (!TEST_int_eq(val
, 0) || !TEST_int_eq(val
, ret
))
208 if (!TEST_true(CRYPTO_atomic_add(&val
, 1, &ret
, lock
)))
210 if (!TEST_int_eq(val
, 1) || !TEST_int_eq(val
, ret
))
213 if (CRYPTO_atomic_or(&val64
, 2, &ret64
, NULL
)) {
214 /* This succeeds therefore we're on a platform with lockless atomics */
215 if (!TEST_uint_eq((unsigned int)val64
, 3)
216 || !TEST_uint_eq((unsigned int)val64
, (unsigned int)ret64
))
219 /* This failed therefore we're on a platform without lockless atomics */
220 if (!TEST_uint_eq((unsigned int)val64
, 1)
221 || !TEST_int_eq((unsigned int)ret64
, 0))
227 if (!TEST_true(CRYPTO_atomic_or(&val64
, 2, &ret64
, lock
)))
230 if (!TEST_uint_eq((unsigned int)val64
, 3)
231 || !TEST_uint_eq((unsigned int)val64
, (unsigned int)ret64
))
235 if (CRYPTO_atomic_load(&val64
, &ret64
, NULL
)) {
236 /* This succeeds therefore we're on a platform with lockless atomics */
237 if (!TEST_uint_eq((unsigned int)val64
, 3)
238 || !TEST_uint_eq((unsigned int)val64
, (unsigned int)ret64
))
241 /* This failed therefore we're on a platform without lockless atomics */
242 if (!TEST_uint_eq((unsigned int)val64
, 3)
243 || !TEST_int_eq((unsigned int)ret64
, 0))
248 if (!TEST_true(CRYPTO_atomic_load(&val64
, &ret64
, lock
)))
251 if (!TEST_uint_eq((unsigned int)val64
, 3)
252 || !TEST_uint_eq((unsigned int)val64
, (unsigned int)ret64
))
258 CRYPTO_THREAD_lock_free(lock
);
262 int setup_tests(void)
266 ADD_TEST(test_thread_local
);
267 ADD_TEST(test_atomic
);