arch/async_posix.h: improve portability.
[oweals/openssl.git] / crypto / threads_pthread.c
1 /*
2  * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the OpenSSL license (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 <openssl/crypto.h>
11 #include "internal/cryptlib.h"
12
13 #if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG) && !defined(OPENSSL_SYS_WINDOWS)
14
15 # ifdef PTHREAD_RWLOCK_INITIALIZER
16 #  define USE_RWLOCK
17 # endif
18
19 CRYPTO_RWLOCK *CRYPTO_THREAD_lock_new(void)
20 {
21 # ifdef USE_RWLOCK
22     CRYPTO_RWLOCK *lock;
23
24     if ((lock = OPENSSL_zalloc(sizeof(pthread_rwlock_t))) == NULL) {
25         /* Don't set error, to avoid recursion blowup. */
26         return NULL;
27     }
28
29     if (pthread_rwlock_init(lock, NULL) != 0) {
30         OPENSSL_free(lock);
31         return NULL;
32     }
33 # else
34     pthread_mutexattr_t attr;
35     CRYPTO_RWLOCK *lock;
36
37     if ((lock = OPENSSL_zalloc(sizeof(pthread_mutex_t))) == NULL) {
38         /* Don't set error, to avoid recursion blowup. */
39         return NULL;
40     }
41
42     pthread_mutexattr_init(&attr);
43     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
44
45     if (pthread_mutex_init(lock, &attr) != 0) {
46         pthread_mutexattr_destroy(&attr);
47         OPENSSL_free(lock);
48         return NULL;
49     }
50
51     pthread_mutexattr_destroy(&attr);
52 # endif
53
54     return lock;
55 }
56
57 int CRYPTO_THREAD_read_lock(CRYPTO_RWLOCK *lock)
58 {
59 # ifdef USE_RWLOCK
60     if (pthread_rwlock_rdlock(lock) != 0)
61         return 0;
62 # else
63     if (pthread_mutex_lock(lock) != 0)
64         return 0;
65 # endif
66
67     return 1;
68 }
69
70 int CRYPTO_THREAD_write_lock(CRYPTO_RWLOCK *lock)
71 {
72 # ifdef USE_RWLOCK
73     if (pthread_rwlock_wrlock(lock) != 0)
74         return 0;
75 # else
76     if (pthread_mutex_lock(lock) != 0)
77         return 0;
78 # endif
79
80     return 1;
81 }
82
83 int CRYPTO_THREAD_unlock(CRYPTO_RWLOCK *lock)
84 {
85 # ifdef USE_RWLOCK
86     if (pthread_rwlock_unlock(lock) != 0)
87         return 0;
88 # else
89     if (pthread_mutex_unlock(lock) != 0)
90         return 0;
91 # endif
92
93     return 1;
94 }
95
96 void CRYPTO_THREAD_lock_free(CRYPTO_RWLOCK *lock)
97 {
98     if (lock == NULL)
99         return;
100
101 # ifdef USE_RWLOCK
102     pthread_rwlock_destroy(lock);
103 # else
104     pthread_mutex_destroy(lock);
105 # endif
106     OPENSSL_free(lock);
107
108     return;
109 }
110
111 int CRYPTO_THREAD_run_once(CRYPTO_ONCE *once, void (*init)(void))
112 {
113     if (pthread_once(once, init) != 0)
114         return 0;
115
116     return 1;
117 }
118
119 int CRYPTO_THREAD_init_local(CRYPTO_THREAD_LOCAL *key, void (*cleanup)(void *))
120 {
121     if (pthread_key_create(key, cleanup) != 0)
122         return 0;
123
124     return 1;
125 }
126
127 void *CRYPTO_THREAD_get_local(CRYPTO_THREAD_LOCAL *key)
128 {
129     return pthread_getspecific(*key);
130 }
131
132 int CRYPTO_THREAD_set_local(CRYPTO_THREAD_LOCAL *key, void *val)
133 {
134     if (pthread_setspecific(*key, val) != 0)
135         return 0;
136
137     return 1;
138 }
139
140 int CRYPTO_THREAD_cleanup_local(CRYPTO_THREAD_LOCAL *key)
141 {
142     if (pthread_key_delete(*key) != 0)
143         return 0;
144
145     return 1;
146 }
147
148 CRYPTO_THREAD_ID CRYPTO_THREAD_get_current_id(void)
149 {
150     return pthread_self();
151 }
152
153 int CRYPTO_THREAD_compare_id(CRYPTO_THREAD_ID a, CRYPTO_THREAD_ID b)
154 {
155     return pthread_equal(a, b);
156 }
157
158 int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock)
159 {
160 # if defined(__GNUC__) && defined(__ATOMIC_ACQ_REL)
161     if (__atomic_is_lock_free(sizeof(*val), val)) {
162         *ret = __atomic_add_fetch(val, amount, __ATOMIC_ACQ_REL);
163         return 1;
164     }
165 # endif
166     if (!CRYPTO_THREAD_write_lock(lock))
167         return 0;
168
169     *val += amount;
170     *ret  = *val;
171
172     if (!CRYPTO_THREAD_unlock(lock))
173         return 0;
174
175     return 1;
176 }
177
178 # ifdef OPENSSL_SYS_UNIX
179 static pthread_once_t fork_once_control = PTHREAD_ONCE_INIT;
180
181 static void fork_once_func(void)
182 {
183     pthread_atfork(OPENSSL_fork_prepare,
184                    OPENSSL_fork_parent, OPENSSL_fork_child);
185 }
186 # endif
187
188 int openssl_init_fork_handlers(void)
189 {
190 # ifdef OPENSSL_SYS_UNIX
191     if (pthread_once(&fork_once_control, fork_once_func) == 0)
192         return 1;
193 # endif
194     return 0;
195 }
196 #endif