]> git.ipfire.org Git - thirdparty/openssl.git/blob - crypto/thread/arch/thread_win.c
QUIC Thread Assisted Mode: Support Windows XP
[thirdparty/openssl.git] / crypto / thread / arch / thread_win.c
1 /*
2 * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
3 *
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
8 */
9
10 #include <internal/thread_arch.h>
11
12 #if defined(OPENSSL_THREADS_WINNT)
13 # include <process.h>
14 # include <windows.h>
15
16 static DWORD __stdcall thread_start_thunk(LPVOID vthread)
17 {
18 CRYPTO_THREAD *thread;
19 CRYPTO_THREAD_RETVAL ret;
20
21 thread = (CRYPTO_THREAD *)vthread;
22
23 thread->thread_id = GetCurrentThreadId();
24
25 ret = thread->routine(thread->data);
26 ossl_crypto_mutex_lock(thread->statelock);
27 CRYPTO_THREAD_SET_STATE(thread, CRYPTO_THREAD_FINISHED);
28 thread->retval = ret;
29 ossl_crypto_condvar_signal(thread->condvar);
30 ossl_crypto_mutex_unlock(thread->statelock);
31
32 return 0;
33 }
34
35 int ossl_crypto_thread_native_spawn(CRYPTO_THREAD *thread)
36 {
37 HANDLE *handle;
38
39 handle = OPENSSL_zalloc(sizeof(*handle));
40 if (handle == NULL)
41 goto fail;
42
43 *handle = (HANDLE)_beginthreadex(NULL, 0, &thread_start_thunk, thread, 0, NULL);
44 if (*handle == NULL)
45 goto fail;
46
47 thread->handle = handle;
48 return 1;
49
50 fail:
51 thread->handle = NULL;
52 OPENSSL_free(handle);
53 return 0;
54 }
55
56 int ossl_crypto_thread_native_perform_join(CRYPTO_THREAD *thread, CRYPTO_THREAD_RETVAL *retval)
57 {
58 DWORD thread_retval;
59 HANDLE *handle;
60
61 if (thread == NULL || thread->handle == NULL)
62 return 0;
63
64 handle = (HANDLE *) thread->handle;
65 if (WaitForSingleObject(*handle, INFINITE) != WAIT_OBJECT_0)
66 return 0;
67
68 if (GetExitCodeThread(*handle, &thread_retval) == 0)
69 return 0;
70
71 /*
72 * GetExitCodeThread call followed by this check is to make sure that
73 * the thread exitted properly. In particular, thread_retval may be
74 * non-zero when exitted via explicit ExitThread/TerminateThread or
75 * if the thread is still active (returns STILL_ACTIVE (259)).
76 */
77 if (thread_retval != 0)
78 return 0;
79
80 if (CloseHandle(*handle) == 0)
81 return 0;
82
83 return 1;
84 }
85
86 int ossl_crypto_thread_native_exit(void)
87 {
88 _endthreadex(0);
89 return 1;
90 }
91
92 int ossl_crypto_thread_native_is_self(CRYPTO_THREAD *thread)
93 {
94 return thread->thread_id == GetCurrentThreadId();
95 }
96
97 CRYPTO_MUTEX *ossl_crypto_mutex_new(void)
98 {
99 CRITICAL_SECTION *mutex;
100
101 if ((mutex = OPENSSL_zalloc(sizeof(*mutex))) == NULL)
102 return NULL;
103 InitializeCriticalSection(mutex);
104 return (CRYPTO_MUTEX *)mutex;
105 }
106
107 void ossl_crypto_mutex_lock(CRYPTO_MUTEX *mutex)
108 {
109 CRITICAL_SECTION *mutex_p;
110
111 mutex_p = (CRITICAL_SECTION *)mutex;
112 EnterCriticalSection(mutex_p);
113 }
114
115 int ossl_crypto_mutex_try_lock(CRYPTO_MUTEX *mutex)
116 {
117 CRITICAL_SECTION *mutex_p;
118
119 mutex_p = (CRITICAL_SECTION *)mutex;
120 if (TryEnterCriticalSection(mutex_p))
121 return 1;
122
123 return 0;
124 }
125
126 void ossl_crypto_mutex_unlock(CRYPTO_MUTEX *mutex)
127 {
128 CRITICAL_SECTION *mutex_p;
129
130 mutex_p = (CRITICAL_SECTION *)mutex;
131 LeaveCriticalSection(mutex_p);
132 }
133
134 void ossl_crypto_mutex_free(CRYPTO_MUTEX **mutex)
135 {
136 CRITICAL_SECTION **mutex_p;
137
138 mutex_p = (CRITICAL_SECTION **)mutex;
139 if (*mutex_p != NULL)
140 DeleteCriticalSection(*mutex_p);
141 OPENSSL_free(*mutex_p);
142 *mutex = NULL;
143 }
144
145 static int determine_timeout(OSSL_TIME deadline, DWORD *w_timeout_p)
146 {
147 OSSL_TIME now, delta;
148 uint64_t ms;
149
150 if (ossl_time_is_infinite(deadline)) {
151 *w_timeout_p = INFINITE;
152 return 1;
153 }
154
155 now = ossl_time_now();
156 delta = ossl_time_subtract(deadline, now);
157
158 if (ossl_time_is_zero(delta))
159 return 0;
160
161 ms = ossl_time2ms(delta);
162
163
164 /*
165 * Amount of time we want to wait is too long for the 32-bit argument to
166 * the Win32 API, so just wait as long as possible.
167 */
168 if (ms > (uint64_t)(INFINITE - 1))
169 *w_timeout_p = INFINITE - 1;
170 else
171 *w_timeout_p = (DWORD)ms;
172
173 return 1;
174 }
175
176 # if defined(OPENSSL_THREADS_WINNT_LEGACY)
177
178 CRYPTO_CONDVAR *ossl_crypto_condvar_new(void)
179 {
180 HANDLE h;
181
182 if ((h = CreateEventA(NULL, FALSE, FALSE, NULL)) == NULL)
183 return NULL;
184
185 return (CRYPTO_CONDVAR *)h;
186 }
187
188 void ossl_crypto_condvar_wait(CRYPTO_CONDVAR *cv, CRYPTO_MUTEX *mutex)
189 {
190 ossl_crypto_mutex_unlock(mutex);
191 WaitForSingleObject((HANDLE)cv, INFINITE);
192 ossl_crypto_mutex_lock(mutex);
193 }
194
195 void ossl_crypto_condvar_wait_timeout(CRYPTO_CONDVAR *cv, CRYPTO_MUTEX *mutex,
196 OSSL_TIME deadline)
197 {
198 DWORD timeout;
199
200 fprintf(stderr, "# wt\n"); fflush(stderr);
201 if (!determine_timeout(deadline, &timeout))
202 timeout = 1;
203
204 ossl_crypto_mutex_unlock(mutex);
205 WaitForSingleObject((HANDLE)cv, timeout);
206 fprintf(stderr, "# wtd\n"); fflush(stderr);
207 ossl_crypto_mutex_lock(mutex);
208 fprintf(stderr, "# wtd2\n"); fflush(stderr);
209 }
210
211 void ossl_crypto_condvar_broadcast(CRYPTO_CONDVAR *cv)
212 {
213 /* Not supported */
214 }
215
216 void ossl_crypto_condvar_signal(CRYPTO_CONDVAR *cv)
217 {
218 HANDLE *cv_p = (HANDLE *)cv;
219
220 SetEvent(cv_p);
221 }
222
223 void ossl_crypto_condvar_free(CRYPTO_CONDVAR **cv)
224 {
225 HANDLE **cv_p;
226
227 cv_p = (HANDLE **)cv;
228 if (*cv_p != NULL)
229 CloseHandle(*cv_p);
230
231 *cv_p = NULL;
232 }
233
234 # else
235
236 CRYPTO_CONDVAR *ossl_crypto_condvar_new(void)
237 {
238 CONDITION_VARIABLE *cv_p;
239
240 if ((cv_p = OPENSSL_zalloc(sizeof(*cv_p))) == NULL)
241 return NULL;
242 InitializeConditionVariable(cv_p);
243 return (CRYPTO_CONDVAR *)cv_p;
244 }
245
246 void ossl_crypto_condvar_wait(CRYPTO_CONDVAR *cv, CRYPTO_MUTEX *mutex)
247 {
248 CONDITION_VARIABLE *cv_p;
249 CRITICAL_SECTION *mutex_p;
250
251 cv_p = (CONDITION_VARIABLE *)cv;
252 mutex_p = (CRITICAL_SECTION *)mutex;
253 SleepConditionVariableCS(cv_p, mutex_p, INFINITE);
254 }
255
256 void ossl_crypto_condvar_wait_timeout(CRYPTO_CONDVAR *cv, CRYPTO_MUTEX *mutex,
257 OSSL_TIME deadline)
258 {
259 DWORD timeout;
260 CONDITION_VARIABLE *cv_p = (CONDITION_VARIABLE *)cv;
261 CRITICAL_SECTION *mutex_p = (CRITICAL_SECTION *)mutex;
262
263 if (!determine_timeout(deadline, &timeout))
264 timeout = 1;
265
266 SleepConditionVariableCS(cv_p, mutex_p, timeout);
267 }
268
269 void ossl_crypto_condvar_broadcast(CRYPTO_CONDVAR *cv)
270 {
271 CONDITION_VARIABLE *cv_p;
272
273 cv_p = (CONDITION_VARIABLE *)cv;
274 WakeAllConditionVariable(cv_p);
275 }
276
277 void ossl_crypto_condvar_signal(CRYPTO_CONDVAR *cv)
278 {
279 CONDITION_VARIABLE *cv_p;
280
281 cv_p = (CONDITION_VARIABLE *)cv;
282 WakeConditionVariable(cv_p);
283 }
284
285 void ossl_crypto_condvar_free(CRYPTO_CONDVAR **cv)
286 {
287 CONDITION_VARIABLE **cv_p;
288
289 cv_p = (CONDITION_VARIABLE **)cv;
290 OPENSSL_free(*cv_p);
291 *cv_p = NULL;
292 }
293
294 #endif
295
296 void ossl_crypto_mem_barrier(void)
297 {
298 MemoryBarrier();
299 }
300
301 #endif