Defined out MUTEX attributes not available on NonStop SPT Threads.
[openssl.git] / crypto / threads_pthread.c
1 /*
2  * Copyright 2016-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 /* We need to use the OPENSSL_fork_*() deprecated APIs */
11 #define OPENSSL_SUPPRESS_DEPRECATED
12
13 #include <openssl/crypto.h>
14 #include "internal/cryptlib.h"
15
16 #if defined(__sun)
17 # include <atomic.h>
18 #endif
19
20 #if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG) && !defined(OPENSSL_SYS_WINDOWS)
21
22 # if defined(OPENSSL_SYS_UNIX)
23 #  include <sys/types.h>
24 #  include <unistd.h>
25 #endif
26
27 # include <assert.h>
28
29 # ifdef PTHREAD_RWLOCK_INITIALIZER
30 #  define USE_RWLOCK
31 # endif
32
33 CRYPTO_RWLOCK *CRYPTO_THREAD_lock_new(void)
34 {
35 # ifdef USE_RWLOCK
36     CRYPTO_RWLOCK *lock;
37
38     if ((lock = OPENSSL_zalloc(sizeof(pthread_rwlock_t))) == NULL) {
39         /* Don't set error, to avoid recursion blowup. */
40         return NULL;
41     }
42
43     if (pthread_rwlock_init(lock, NULL) != 0) {
44         OPENSSL_free(lock);
45         return NULL;
46     }
47 # else
48     pthread_mutexattr_t attr;
49     CRYPTO_RWLOCK *lock;
50
51     if ((lock = OPENSSL_zalloc(sizeof(pthread_mutex_t))) == NULL) {
52         /* Don't set error, to avoid recursion blowup. */
53         return NULL;
54     }
55
56     /*
57      * We don't use recursive mutexes, but try to catch errors if we do.
58      */
59     pthread_mutexattr_init(&attr);
60 #  if !defined (__TANDEM) && !defined (_SPT_MODEL_)
61 #   if !defined(NDEBUG) && !defined(OPENSSL_NO_MUTEX_ERRORCHECK)
62     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
63 #   else
64     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
65 #   endif
66 #  else
67     /* The SPT Thread Library does not define MUTEX attributes. */
68 #  endif
69
70     if (pthread_mutex_init(lock, &attr) != 0) {
71         pthread_mutexattr_destroy(&attr);
72         OPENSSL_free(lock);
73         return NULL;
74     }
75
76     pthread_mutexattr_destroy(&attr);
77 # endif
78
79     return lock;
80 }
81
82 __owur int CRYPTO_THREAD_read_lock(CRYPTO_RWLOCK *lock)
83 {
84 # ifdef USE_RWLOCK
85     if (pthread_rwlock_rdlock(lock) != 0)
86         return 0;
87 # else
88     if (pthread_mutex_lock(lock) != 0) {
89         assert(errno != EDEADLK && errno != EBUSY);
90         return 0;
91     }
92 # endif
93
94     return 1;
95 }
96
97 __owur int CRYPTO_THREAD_write_lock(CRYPTO_RWLOCK *lock)
98 {
99 # ifdef USE_RWLOCK
100     if (pthread_rwlock_wrlock(lock) != 0)
101         return 0;
102 # else
103     if (pthread_mutex_lock(lock) != 0) {
104         assert(errno != EDEADLK && errno != EBUSY);
105         return 0;
106     }
107 # endif
108
109     return 1;
110 }
111
112 int CRYPTO_THREAD_unlock(CRYPTO_RWLOCK *lock)
113 {
114 # ifdef USE_RWLOCK
115     if (pthread_rwlock_unlock(lock) != 0)
116         return 0;
117 # else
118     if (pthread_mutex_unlock(lock) != 0) {
119         assert(errno != EPERM);
120         return 0;
121     }
122 # endif
123
124     return 1;
125 }
126
127 void CRYPTO_THREAD_lock_free(CRYPTO_RWLOCK *lock)
128 {
129     if (lock == NULL)
130         return;
131
132 # ifdef USE_RWLOCK
133     pthread_rwlock_destroy(lock);
134 # else
135     pthread_mutex_destroy(lock);
136 # endif
137     OPENSSL_free(lock);
138
139     return;
140 }
141
142 int CRYPTO_THREAD_run_once(CRYPTO_ONCE *once, void (*init)(void))
143 {
144     if (pthread_once(once, init) != 0)
145         return 0;
146
147     return 1;
148 }
149
150 int CRYPTO_THREAD_init_local(CRYPTO_THREAD_LOCAL *key, void (*cleanup)(void *))
151 {
152     if (pthread_key_create(key, cleanup) != 0)
153         return 0;
154
155     return 1;
156 }
157
158 void *CRYPTO_THREAD_get_local(CRYPTO_THREAD_LOCAL *key)
159 {
160     return pthread_getspecific(*key);
161 }
162
163 int CRYPTO_THREAD_set_local(CRYPTO_THREAD_LOCAL *key, void *val)
164 {
165     if (pthread_setspecific(*key, val) != 0)
166         return 0;
167
168     return 1;
169 }
170
171 int CRYPTO_THREAD_cleanup_local(CRYPTO_THREAD_LOCAL *key)
172 {
173     if (pthread_key_delete(*key) != 0)
174         return 0;
175
176     return 1;
177 }
178
179 CRYPTO_THREAD_ID CRYPTO_THREAD_get_current_id(void)
180 {
181     return pthread_self();
182 }
183
184 int CRYPTO_THREAD_compare_id(CRYPTO_THREAD_ID a, CRYPTO_THREAD_ID b)
185 {
186     return pthread_equal(a, b);
187 }
188
189 int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock)
190 {
191 # if defined(__GNUC__) && defined(__ATOMIC_ACQ_REL)
192     if (__atomic_is_lock_free(sizeof(*val), val)) {
193         *ret = __atomic_add_fetch(val, amount, __ATOMIC_ACQ_REL);
194         return 1;
195     }
196 # elif defined(__sun) && (defined(__SunOS_5_10) || defined(__SunOS_5_11))
197     /* This will work for all future Solaris versions. */
198     if (ret != NULL) {
199         *ret = atomic_add_int_nv((volatile unsigned int *)val, amount);
200         return 1;
201     }
202 # endif
203     if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
204         return 0;
205
206     *val += amount;
207     *ret  = *val;
208
209     if (!CRYPTO_THREAD_unlock(lock))
210         return 0;
211
212     return 1;
213 }
214
215 int CRYPTO_atomic_or(uint64_t *val, uint64_t op, uint64_t *ret,
216                      CRYPTO_RWLOCK *lock)
217 {
218 # if defined(__GNUC__) && defined(__ATOMIC_ACQ_REL)
219     if (__atomic_is_lock_free(sizeof(*val), val)) {
220         *ret = __atomic_or_fetch(val, op, __ATOMIC_ACQ_REL);
221         return 1;
222     }
223 # elif defined(__sun) && (defined(__SunOS_5_10) || defined(__SunOS_5_11))
224     /* This will work for all future Solaris versions. */
225     if (ret != NULL) {
226         *ret = atomic_or_64_nv(val, op);
227         return 1;
228     }
229 # endif
230     if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
231         return 0;
232     *val |= op;
233     *ret  = *val;
234
235     if (!CRYPTO_THREAD_unlock(lock))
236         return 0;
237
238     return 1;
239 }
240
241 int CRYPTO_atomic_load(uint64_t *val, uint64_t *ret, CRYPTO_RWLOCK *lock)
242 {
243 # if defined(__GNUC__) && defined(__ATOMIC_ACQUIRE)
244     if (__atomic_is_lock_free(sizeof(*val), val)) {
245         __atomic_load(val, ret, __ATOMIC_ACQUIRE);
246         return 1;
247     }
248 # elif defined(__sun) && (defined(__SunOS_5_10) || defined(__SunOS_5_11))
249     /* This will work for all future Solaris versions. */
250     if (ret != NULL) {
251         *ret = atomic_or_64_nv(val, 0);
252         return 1;
253     }
254 # endif
255     if (lock == NULL || !CRYPTO_THREAD_read_lock(lock))
256         return 0;
257     *ret  = *val;
258     if (!CRYPTO_THREAD_unlock(lock))
259         return 0;
260
261     return 1;
262 }
263 # ifndef FIPS_MODULE
264 #  ifdef OPENSSL_SYS_UNIX
265
266 static pthread_once_t fork_once_control = PTHREAD_ONCE_INIT;
267
268 static void fork_once_func(void)
269 {
270 #   ifndef OPENSSL_NO_DEPRECATED_3_0
271     pthread_atfork(OPENSSL_fork_prepare,
272                    OPENSSL_fork_parent, OPENSSL_fork_child);
273 #   endif
274 }
275 #  endif
276
277 int openssl_init_fork_handlers(void)
278 {
279 #  ifdef OPENSSL_SYS_UNIX
280     if (pthread_once(&fork_once_control, fork_once_func) == 0)
281         return 1;
282 #  endif
283     return 0;
284 }
285 # endif /* FIPS_MODULE */
286
287 int openssl_get_fork_id(void)
288 {
289     return getpid();
290 }
291 #endif