xref: /openssl/crypto/thread/arch/thread_posix.c (revision da1c088f)
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 
thread_start_thunk(void * vthread)18 static void *thread_start_thunk(void *vthread)
19 {
20     CRYPTO_THREAD *thread;
21     CRYPTO_THREAD_RETVAL ret;
22 
23     thread = (CRYPTO_THREAD *)vthread;
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_broadcast(thread->condvar);
30     ossl_crypto_mutex_unlock(thread->statelock);
31 
32     return NULL;
33 }
34 
ossl_crypto_thread_native_spawn(CRYPTO_THREAD * thread)35 int ossl_crypto_thread_native_spawn(CRYPTO_THREAD *thread)
36 {
37     int ret;
38     pthread_attr_t attr;
39     pthread_t *handle;
40 
41     handle = OPENSSL_zalloc(sizeof(*handle));
42     if (handle == NULL)
43         goto fail;
44 
45     pthread_attr_init(&attr);
46     if (!thread->joinable)
47         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
48     ret = pthread_create(handle, &attr, thread_start_thunk, thread);
49     pthread_attr_destroy(&attr);
50 
51     if (ret != 0)
52         goto fail;
53 
54     thread->handle = handle;
55     return 1;
56 
57 fail:
58     thread->handle = NULL;
59     OPENSSL_free(handle);
60     return 0;
61 }
62 
ossl_crypto_thread_native_perform_join(CRYPTO_THREAD * thread,CRYPTO_THREAD_RETVAL * retval)63 int ossl_crypto_thread_native_perform_join(CRYPTO_THREAD *thread, CRYPTO_THREAD_RETVAL *retval)
64 {
65     void *thread_retval;
66     pthread_t *handle;
67 
68     if (thread == NULL || thread->handle == NULL)
69         return 0;
70 
71     handle = (pthread_t *) thread->handle;
72     if (pthread_join(*handle, &thread_retval) != 0)
73         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     if (thread_retval != NULL)
80         return 0;
81 
82     return 1;
83 }
84 
ossl_crypto_thread_native_exit(void)85 int ossl_crypto_thread_native_exit(void)
86 {
87     pthread_exit(NULL);
88     return 1;
89 }
90 
ossl_crypto_thread_native_is_self(CRYPTO_THREAD * thread)91 int ossl_crypto_thread_native_is_self(CRYPTO_THREAD *thread)
92 {
93     return pthread_equal(*(pthread_t *)thread->handle, pthread_self());
94 }
95 
ossl_crypto_mutex_new(void)96 CRYPTO_MUTEX *ossl_crypto_mutex_new(void)
97 {
98     pthread_mutex_t *mutex;
99 
100     if ((mutex = OPENSSL_zalloc(sizeof(*mutex))) == NULL)
101         return NULL;
102     if (pthread_mutex_init(mutex, NULL) != 0) {
103         OPENSSL_free(mutex);
104         return NULL;
105     }
106     return (CRYPTO_MUTEX *)mutex;
107 }
108 
ossl_crypto_mutex_try_lock(CRYPTO_MUTEX * mutex)109 int ossl_crypto_mutex_try_lock(CRYPTO_MUTEX *mutex)
110 {
111     pthread_mutex_t *mutex_p;
112 
113     mutex_p = (pthread_mutex_t *)mutex;
114 
115     if (pthread_mutex_trylock(mutex_p) == EBUSY)
116         return 0;
117 
118     return 1;
119 }
120 
ossl_crypto_mutex_lock(CRYPTO_MUTEX * mutex)121 void ossl_crypto_mutex_lock(CRYPTO_MUTEX *mutex)
122 {
123     int rc;
124     pthread_mutex_t *mutex_p;
125 
126     mutex_p = (pthread_mutex_t *)mutex;
127     rc = pthread_mutex_lock(mutex_p);
128     OPENSSL_assert(rc == 0);
129 }
130 
ossl_crypto_mutex_unlock(CRYPTO_MUTEX * mutex)131 void ossl_crypto_mutex_unlock(CRYPTO_MUTEX *mutex)
132 {
133     int rc;
134     pthread_mutex_t *mutex_p;
135 
136     mutex_p = (pthread_mutex_t *)mutex;
137     rc = pthread_mutex_unlock(mutex_p);
138     OPENSSL_assert(rc == 0);
139 }
140 
ossl_crypto_mutex_free(CRYPTO_MUTEX ** mutex)141 void ossl_crypto_mutex_free(CRYPTO_MUTEX **mutex)
142 {
143     pthread_mutex_t **mutex_p;
144 
145     if (mutex == NULL)
146         return;
147 
148     mutex_p = (pthread_mutex_t **)mutex;
149     if (*mutex_p != NULL)
150         pthread_mutex_destroy(*mutex_p);
151     OPENSSL_free(*mutex_p);
152     *mutex = NULL;
153 }
154 
ossl_crypto_condvar_new(void)155 CRYPTO_CONDVAR *ossl_crypto_condvar_new(void)
156 {
157     pthread_cond_t *cv_p;
158 
159     if ((cv_p = OPENSSL_zalloc(sizeof(*cv_p))) == NULL)
160         return NULL;
161     if (pthread_cond_init(cv_p, NULL) != 0) {
162         OPENSSL_free(cv_p);
163         return NULL;
164     }
165     return (CRYPTO_CONDVAR *) cv_p;
166 }
167 
ossl_crypto_condvar_wait(CRYPTO_CONDVAR * cv,CRYPTO_MUTEX * mutex)168 void ossl_crypto_condvar_wait(CRYPTO_CONDVAR *cv, CRYPTO_MUTEX *mutex)
169 {
170     pthread_cond_t *cv_p;
171     pthread_mutex_t *mutex_p;
172 
173     cv_p = (pthread_cond_t *)cv;
174     mutex_p = (pthread_mutex_t *)mutex;
175     pthread_cond_wait(cv_p, mutex_p);
176 }
177 
ossl_crypto_condvar_wait_timeout(CRYPTO_CONDVAR * cv,CRYPTO_MUTEX * mutex,OSSL_TIME deadline)178 void ossl_crypto_condvar_wait_timeout(CRYPTO_CONDVAR *cv, CRYPTO_MUTEX *mutex,
179                                       OSSL_TIME deadline)
180 {
181     pthread_cond_t *cv_p = (pthread_cond_t *)cv;
182     pthread_mutex_t *mutex_p = (pthread_mutex_t *)mutex;
183 
184     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         pthread_cond_wait(cv_p, mutex_p);
191     } else {
192         struct timespec deadline_ts;
193 
194         deadline_ts.tv_sec
195             = ossl_time2seconds(deadline);
196         deadline_ts.tv_nsec
197             = (ossl_time2ticks(deadline) % OSSL_TIME_SECOND) / OSSL_TIME_NS;
198 
199         pthread_cond_timedwait(cv_p, mutex_p, &deadline_ts);
200     }
201 }
202 
ossl_crypto_condvar_broadcast(CRYPTO_CONDVAR * cv)203 void ossl_crypto_condvar_broadcast(CRYPTO_CONDVAR *cv)
204 {
205     pthread_cond_t *cv_p;
206 
207     cv_p = (pthread_cond_t *)cv;
208     pthread_cond_broadcast(cv_p);
209 }
210 
ossl_crypto_condvar_signal(CRYPTO_CONDVAR * cv)211 void ossl_crypto_condvar_signal(CRYPTO_CONDVAR *cv)
212 {
213     pthread_cond_t *cv_p;
214 
215     cv_p = (pthread_cond_t *)cv;
216     pthread_cond_signal(cv_p);
217 }
218 
ossl_crypto_condvar_free(CRYPTO_CONDVAR ** cv)219 void ossl_crypto_condvar_free(CRYPTO_CONDVAR **cv)
220 {
221     pthread_cond_t **cv_p;
222 
223     if (cv == NULL)
224         return;
225 
226     cv_p = (pthread_cond_t **)cv;
227     if (*cv_p != NULL)
228         pthread_cond_destroy(*cv_p);
229     OPENSSL_free(*cv_p);
230     *cv_p = NULL;
231 }
232 
233 #endif
234