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 !(defined(__arm__) && __ARM_ARCH < 6) 162 if (__atomic_is_lock_free(sizeof(*val), val)) { 163 *ret = __atomic_add_fetch(val, amount, __ATOMIC_ACQ_REL); 164 return 1; 165 } 166 # endif 167 if (!CRYPTO_THREAD_write_lock(lock)) 168 return 0; 169 170 *val += amount; 171 *ret = *val; 172 173 if (!CRYPTO_THREAD_unlock(lock)) 174 return 0; 175 176 return 1; 177 } 178 179 # ifdef OPENSSL_SYS_UNIX 180 static pthread_once_t fork_once_control = PTHREAD_ONCE_INIT; 181 182 static void fork_once_func(void) 183 { 184 pthread_atfork(OPENSSL_fork_prepare, 185 OPENSSL_fork_parent, OPENSSL_fork_child); 186 } 187 # endif 188 189 int openssl_init_fork_handlers(void) 190 { 191 # ifdef OPENSSL_SYS_UNIX 192 if (pthread_once(&fork_once_control, fork_once_func) == 0) 193 return 1; 194 # endif 195 return 0; 196 } 197 #endif 198