1219820Sjeff/*
2219820Sjeff * Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
3219820Sjeff *
4219820Sjeff * Licensed under the OpenSSL license (the "License").  You may not use
5219820Sjeff * this file except in compliance with the License.  You can obtain a copy
6219820Sjeff * in the file LICENSE in the source distribution or at
7219820Sjeff * https://www.openssl.org/source/license.html
8219820Sjeff */
9219820Sjeff
10219820Sjeff#if defined(_WIN32)
11219820Sjeff# include <windows.h>
12219820Sjeff#endif
13219820Sjeff
14219820Sjeff#include <openssl/crypto.h>
15219820Sjeff#include "testutil.h"
16219820Sjeff
17219820Sjeff#if !defined(OPENSSL_THREADS) || defined(CRYPTO_TDEBUG)
18219820Sjeff
19219820Sjefftypedef unsigned int thread_t;
20219820Sjeff
21219820Sjeffstatic int run_thread(thread_t *t, void (*f)(void))
22219820Sjeff{
23219820Sjeff    f();
24219820Sjeff    return 1;
25219820Sjeff}
26219820Sjeff
27219820Sjeffstatic int wait_for_thread(thread_t thread)
28219820Sjeff{
29219820Sjeff    return 1;
30219820Sjeff}
31219820Sjeff
32255932Salfred#elif defined(OPENSSL_SYS_WINDOWS)
33219820Sjeff
34255932Salfredtypedef HANDLE thread_t;
35219820Sjeff
36219820Sjeffstatic DWORD WINAPI thread_run(LPVOID arg)
37{
38    void (*f)(void);
39
40    *(void **) (&f) = arg;
41
42    f();
43    return 0;
44}
45
46static int run_thread(thread_t *t, void (*f)(void))
47{
48    *t = CreateThread(NULL, 0, thread_run, *(void **) &f, 0, NULL);
49    return *t != NULL;
50}
51
52static int wait_for_thread(thread_t thread)
53{
54    return WaitForSingleObject(thread, INFINITE) == 0;
55}
56
57#else
58
59typedef pthread_t thread_t;
60
61static void *thread_run(void *arg)
62{
63    void (*f)(void);
64
65    *(void **) (&f) = arg;
66
67    f();
68    return NULL;
69}
70
71static int run_thread(thread_t *t, void (*f)(void))
72{
73    return pthread_create(t, NULL, thread_run, *(void **) &f) == 0;
74}
75
76static int wait_for_thread(thread_t thread)
77{
78    return pthread_join(thread, NULL) == 0;
79}
80
81#endif
82
83static int test_lock(void)
84{
85    CRYPTO_RWLOCK *lock = CRYPTO_THREAD_lock_new();
86
87    if (!TEST_true(CRYPTO_THREAD_read_lock(lock))
88        || !TEST_true(CRYPTO_THREAD_unlock(lock)))
89        return 0;
90
91    CRYPTO_THREAD_lock_free(lock);
92
93    return 1;
94}
95
96static CRYPTO_ONCE once_run = CRYPTO_ONCE_STATIC_INIT;
97static unsigned once_run_count = 0;
98
99static void once_do_run(void)
100{
101    once_run_count++;
102}
103
104static void once_run_thread_cb(void)
105{
106    CRYPTO_THREAD_run_once(&once_run, once_do_run);
107}
108
109static int test_once(void)
110{
111    thread_t thread;
112
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))
117        return 0;
118    return 1;
119}
120
121static CRYPTO_THREAD_LOCAL thread_local_key;
122static unsigned destructor_run_count = 0;
123static int thread_local_thread_cb_ok = 0;
124
125static void thread_local_destructor(void *arg)
126{
127    unsigned *count;
128
129    if (arg == NULL)
130        return;
131
132    count = arg;
133
134    (*count)++;
135}
136
137static void thread_local_thread_cb(void)
138{
139    void *ptr;
140
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)))
145        return;
146
147    ptr = CRYPTO_THREAD_get_local(&thread_local_key);
148    if (!TEST_ptr_eq(ptr, &destructor_run_count))
149        return;
150
151    thread_local_thread_cb_ok = 1;
152}
153
154static int test_thread_local(void)
155{
156    thread_t thread;
157    void *ptr = NULL;
158
159    if (!TEST_true(CRYPTO_THREAD_init_local(&thread_local_key,
160                                            thread_local_destructor)))
161        return 0;
162
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))
168        return 0;
169
170#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
171
172    ptr = CRYPTO_THREAD_get_local(&thread_local_key);
173    if (!TEST_ptr_null(ptr))
174        return 0;
175
176# if !defined(OPENSSL_SYS_WINDOWS)
177    if (!TEST_int_eq(destructor_run_count, 1))
178        return 0;
179# endif
180#endif
181
182    if (!TEST_true(CRYPTO_THREAD_cleanup_local(&thread_local_key)))
183        return 0;
184    return 1;
185}
186
187int setup_tests(void)
188{
189    ADD_TEST(test_lock);
190    ADD_TEST(test_once);
191    ADD_TEST(test_thread_local);
192    return 1;
193}
194