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