/src/openssl/crypto/thread/arch/thread_posix.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2019-2023 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_POSIX) |
13 | | # define _GNU_SOURCE |
14 | | # include <errno.h> |
15 | | # include <sys/types.h> |
16 | | # include <unistd.h> |
17 | | |
18 | | static void *thread_start_thunk(void *vthread) |
19 | 0 | { |
20 | 0 | CRYPTO_THREAD *thread; |
21 | 0 | CRYPTO_THREAD_RETVAL ret; |
22 | |
|
23 | 0 | thread = (CRYPTO_THREAD *)vthread; |
24 | |
|
25 | 0 | ret = thread->routine(thread->data); |
26 | 0 | ossl_crypto_mutex_lock(thread->statelock); |
27 | 0 | CRYPTO_THREAD_SET_STATE(thread, CRYPTO_THREAD_FINISHED); |
28 | 0 | thread->retval = ret; |
29 | 0 | ossl_crypto_condvar_broadcast(thread->condvar); |
30 | 0 | ossl_crypto_mutex_unlock(thread->statelock); |
31 | |
|
32 | 0 | return NULL; |
33 | 0 | } |
34 | | |
35 | | int ossl_crypto_thread_native_spawn(CRYPTO_THREAD *thread) |
36 | 0 | { |
37 | 0 | int ret; |
38 | 0 | pthread_attr_t attr; |
39 | 0 | pthread_t *handle; |
40 | |
|
41 | 0 | handle = OPENSSL_zalloc(sizeof(*handle)); |
42 | 0 | if (handle == NULL) |
43 | 0 | goto fail; |
44 | | |
45 | 0 | pthread_attr_init(&attr); |
46 | 0 | if (!thread->joinable) |
47 | 0 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); |
48 | 0 | ret = pthread_create(handle, &attr, thread_start_thunk, thread); |
49 | 0 | pthread_attr_destroy(&attr); |
50 | |
|
51 | 0 | if (ret != 0) |
52 | 0 | goto fail; |
53 | | |
54 | 0 | thread->handle = handle; |
55 | 0 | return 1; |
56 | | |
57 | 0 | fail: |
58 | 0 | thread->handle = NULL; |
59 | 0 | OPENSSL_free(handle); |
60 | 0 | return 0; |
61 | 0 | } |
62 | | |
63 | | int ossl_crypto_thread_native_perform_join(CRYPTO_THREAD *thread, CRYPTO_THREAD_RETVAL *retval) |
64 | 0 | { |
65 | 0 | void *thread_retval; |
66 | 0 | pthread_t *handle; |
67 | |
|
68 | 0 | if (thread == NULL || thread->handle == NULL) |
69 | 0 | return 0; |
70 | | |
71 | 0 | handle = (pthread_t *) thread->handle; |
72 | 0 | if (pthread_join(*handle, &thread_retval) != 0) |
73 | 0 | return 0; |
74 | | |
75 | | /* |
76 | | * Join return value may be non-NULL when the thread has been cancelled, |
77 | | * as indicated by thread_retval set to PTHREAD_CANCELLED. |
78 | | */ |
79 | 0 | if (thread_retval != NULL) |
80 | 0 | return 0; |
81 | | |
82 | 0 | return 1; |
83 | 0 | } |
84 | | |
85 | | int ossl_crypto_thread_native_exit(void) |
86 | 0 | { |
87 | 0 | pthread_exit(NULL); |
88 | 0 | return 1; |
89 | 0 | } |
90 | | |
91 | | int ossl_crypto_thread_native_is_self(CRYPTO_THREAD *thread) |
92 | 0 | { |
93 | 0 | return pthread_equal(*(pthread_t *)thread->handle, pthread_self()); |
94 | 0 | } |
95 | | |
96 | | CRYPTO_MUTEX *ossl_crypto_mutex_new(void) |
97 | 4 | { |
98 | 4 | pthread_mutex_t *mutex; |
99 | | |
100 | 4 | if ((mutex = OPENSSL_zalloc(sizeof(*mutex))) == NULL) |
101 | 0 | return NULL; |
102 | 4 | if (pthread_mutex_init(mutex, NULL) != 0) { |
103 | 0 | OPENSSL_free(mutex); |
104 | 0 | return NULL; |
105 | 0 | } |
106 | 4 | return (CRYPTO_MUTEX *)mutex; |
107 | 4 | } |
108 | | |
109 | | int ossl_crypto_mutex_try_lock(CRYPTO_MUTEX *mutex) |
110 | 0 | { |
111 | 0 | pthread_mutex_t *mutex_p; |
112 | |
|
113 | 0 | mutex_p = (pthread_mutex_t *)mutex; |
114 | |
|
115 | 0 | if (pthread_mutex_trylock(mutex_p) == EBUSY) |
116 | 0 | return 0; |
117 | | |
118 | 0 | return 1; |
119 | 0 | } |
120 | | |
121 | | void ossl_crypto_mutex_lock(CRYPTO_MUTEX *mutex) |
122 | 0 | { |
123 | 0 | int rc; |
124 | 0 | pthread_mutex_t *mutex_p; |
125 | |
|
126 | 0 | mutex_p = (pthread_mutex_t *)mutex; |
127 | 0 | rc = pthread_mutex_lock(mutex_p); |
128 | 0 | OPENSSL_assert(rc == 0); |
129 | 0 | } |
130 | | |
131 | | void ossl_crypto_mutex_unlock(CRYPTO_MUTEX *mutex) |
132 | 0 | { |
133 | 0 | int rc; |
134 | 0 | pthread_mutex_t *mutex_p; |
135 | |
|
136 | 0 | mutex_p = (pthread_mutex_t *)mutex; |
137 | 0 | rc = pthread_mutex_unlock(mutex_p); |
138 | 0 | OPENSSL_assert(rc == 0); |
139 | 0 | } |
140 | | |
141 | | void ossl_crypto_mutex_free(CRYPTO_MUTEX **mutex) |
142 | 2 | { |
143 | 2 | pthread_mutex_t **mutex_p; |
144 | | |
145 | 2 | if (mutex == NULL) |
146 | 0 | return; |
147 | | |
148 | 2 | mutex_p = (pthread_mutex_t **)mutex; |
149 | 2 | if (*mutex_p != NULL) |
150 | 2 | pthread_mutex_destroy(*mutex_p); |
151 | 2 | OPENSSL_free(*mutex_p); |
152 | 2 | *mutex = NULL; |
153 | 2 | } |
154 | | |
155 | | CRYPTO_CONDVAR *ossl_crypto_condvar_new(void) |
156 | 4 | { |
157 | 4 | pthread_cond_t *cv_p; |
158 | | |
159 | 4 | if ((cv_p = OPENSSL_zalloc(sizeof(*cv_p))) == NULL) |
160 | 0 | return NULL; |
161 | 4 | if (pthread_cond_init(cv_p, NULL) != 0) { |
162 | 0 | OPENSSL_free(cv_p); |
163 | 0 | return NULL; |
164 | 0 | } |
165 | 4 | return (CRYPTO_CONDVAR *) cv_p; |
166 | 4 | } |
167 | | |
168 | | void ossl_crypto_condvar_wait(CRYPTO_CONDVAR *cv, CRYPTO_MUTEX *mutex) |
169 | 0 | { |
170 | 0 | pthread_cond_t *cv_p; |
171 | 0 | pthread_mutex_t *mutex_p; |
172 | |
|
173 | 0 | cv_p = (pthread_cond_t *)cv; |
174 | 0 | mutex_p = (pthread_mutex_t *)mutex; |
175 | 0 | pthread_cond_wait(cv_p, mutex_p); |
176 | 0 | } |
177 | | |
178 | | void ossl_crypto_condvar_wait_timeout(CRYPTO_CONDVAR *cv, CRYPTO_MUTEX *mutex, |
179 | | OSSL_TIME deadline) |
180 | 0 | { |
181 | 0 | pthread_cond_t *cv_p = (pthread_cond_t *)cv; |
182 | 0 | pthread_mutex_t *mutex_p = (pthread_mutex_t *)mutex; |
183 | |
|
184 | 0 | if (ossl_time_is_infinite(deadline)) { |
185 | | /* |
186 | | * No deadline. Some pthread implementations allow |
187 | | * pthread_cond_timedwait to work the same as pthread_cond_wait when |
188 | | * abstime is NULL, but it is unclear whether this is POSIXly correct. |
189 | | */ |
190 | 0 | pthread_cond_wait(cv_p, mutex_p); |
191 | 0 | } else { |
192 | 0 | struct timespec deadline_ts; |
193 | |
|
194 | 0 | deadline_ts.tv_sec |
195 | 0 | = ossl_time2seconds(deadline); |
196 | 0 | deadline_ts.tv_nsec |
197 | 0 | = (ossl_time2ticks(deadline) % OSSL_TIME_SECOND) / OSSL_TIME_NS; |
198 | |
|
199 | 0 | pthread_cond_timedwait(cv_p, mutex_p, &deadline_ts); |
200 | 0 | } |
201 | 0 | } |
202 | | |
203 | | void ossl_crypto_condvar_broadcast(CRYPTO_CONDVAR *cv) |
204 | 0 | { |
205 | 0 | pthread_cond_t *cv_p; |
206 | |
|
207 | 0 | cv_p = (pthread_cond_t *)cv; |
208 | 0 | pthread_cond_broadcast(cv_p); |
209 | 0 | } |
210 | | |
211 | | void ossl_crypto_condvar_signal(CRYPTO_CONDVAR *cv) |
212 | 0 | { |
213 | 0 | pthread_cond_t *cv_p; |
214 | |
|
215 | 0 | cv_p = (pthread_cond_t *)cv; |
216 | 0 | pthread_cond_signal(cv_p); |
217 | 0 | } |
218 | | |
219 | | void ossl_crypto_condvar_free(CRYPTO_CONDVAR **cv) |
220 | 2 | { |
221 | 2 | pthread_cond_t **cv_p; |
222 | | |
223 | 2 | if (cv == NULL) |
224 | 0 | return; |
225 | | |
226 | 2 | cv_p = (pthread_cond_t **)cv; |
227 | 2 | if (*cv_p != NULL) |
228 | 2 | pthread_cond_destroy(*cv_p); |
229 | 2 | OPENSSL_free(*cv_p); |
230 | 2 | *cv_p = NULL; |
231 | 2 | } |
232 | | |
233 | | #endif |