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