1e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley/* Copyright (c) 2015, Google Inc. 2e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley * 3e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley * Permission to use, copy, modify, and/or distribute this software for any 4e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley * purpose with or without fee is hereby granted, provided that the above 5e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley * copyright notice and this permission notice appear in all copies. 6e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley * 7e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 10e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 12e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 13e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ 14e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 15e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley#include "internal.h" 16e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 17e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley#if !defined(OPENSSL_WINDOWS) && !defined(OPENSSL_NO_THREADS) 18e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 19e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley#include <pthread.h> 20e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley#include <stdlib.h> 21e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley#include <string.h> 22e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 23e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley#include <openssl/mem.h> 24e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley#include <openssl/type_check.h> 25e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 26e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 27e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam LangleyOPENSSL_COMPILE_ASSERT(sizeof(CRYPTO_MUTEX) >= sizeof(pthread_rwlock_t), 28e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley CRYPTO_MUTEX_too_small); 29e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 30e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleyvoid CRYPTO_MUTEX_init(CRYPTO_MUTEX *lock) { 31e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley if (pthread_rwlock_init((pthread_rwlock_t *) lock, NULL) != 0) { 32e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley abort(); 33e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley } 34e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley} 35e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 36e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleyvoid CRYPTO_MUTEX_lock_read(CRYPTO_MUTEX *lock) { 37e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley if (pthread_rwlock_rdlock((pthread_rwlock_t *) lock) != 0) { 38e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley abort(); 39e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley } 40e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley} 41e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 42e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleyvoid CRYPTO_MUTEX_lock_write(CRYPTO_MUTEX *lock) { 43e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley if (pthread_rwlock_wrlock((pthread_rwlock_t *) lock) != 0) { 44e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley abort(); 45e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley } 46e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley} 47e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 48e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleyvoid CRYPTO_MUTEX_unlock(CRYPTO_MUTEX *lock) { 49e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley if (pthread_rwlock_unlock((pthread_rwlock_t *) lock) != 0) { 50e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley abort(); 51e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley } 52e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley} 53e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 54e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleyvoid CRYPTO_MUTEX_cleanup(CRYPTO_MUTEX *lock) { 55e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley pthread_rwlock_destroy((pthread_rwlock_t *) lock); 56e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley} 57e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 58e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleyvoid CRYPTO_STATIC_MUTEX_lock_read(struct CRYPTO_STATIC_MUTEX *lock) { 59e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley if (pthread_rwlock_rdlock(&lock->lock) != 0) { 60e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley abort(); 61e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley } 62e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley} 63e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 64e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleyvoid CRYPTO_STATIC_MUTEX_lock_write(struct CRYPTO_STATIC_MUTEX *lock) { 65e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley if (pthread_rwlock_wrlock(&lock->lock) != 0) { 66e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley abort(); 67e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley } 68e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley} 69e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 70e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleyvoid CRYPTO_STATIC_MUTEX_unlock(struct CRYPTO_STATIC_MUTEX *lock) { 71e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley if (pthread_rwlock_unlock(&lock->lock) != 0) { 72e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley abort(); 73e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley } 74e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley} 75e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 76e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleyvoid CRYPTO_once(CRYPTO_once_t *once, void (*init)(void)) { 77e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley pthread_once(once, init); 78e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley} 79e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 80e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleystatic pthread_mutex_t g_destructors_lock = PTHREAD_MUTEX_INITIALIZER; 81e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleystatic thread_local_destructor_t g_destructors[NUM_OPENSSL_THREAD_LOCALS]; 82e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 83e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleystatic void thread_local_destructor(void *arg) { 84e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley if (arg == NULL) { 85e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley return; 86e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley } 87e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 88e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley thread_local_destructor_t destructors[NUM_OPENSSL_THREAD_LOCALS]; 89e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley if (pthread_mutex_lock(&g_destructors_lock) != 0) { 90e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley return; 91e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley } 92e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley memcpy(destructors, g_destructors, sizeof(destructors)); 93e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley pthread_mutex_unlock(&g_destructors_lock); 94e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 95e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley unsigned i; 96e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley void **pointers = arg; 97e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley for (i = 0; i < NUM_OPENSSL_THREAD_LOCALS; i++) { 98e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley if (destructors[i] != NULL) { 99e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley destructors[i](pointers[i]); 100e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley } 101e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley } 102e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 103e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley OPENSSL_free(pointers); 104e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley} 105e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 106e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleystatic pthread_once_t g_thread_local_init_once = PTHREAD_ONCE_INIT; 107e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleystatic pthread_key_t g_thread_local_key; 108e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleystatic int g_thread_local_failed = 0; 109e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 110e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleystatic void thread_local_init(void) { 111e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley g_thread_local_failed = 112e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley pthread_key_create(&g_thread_local_key, thread_local_destructor) != 0; 113e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley} 114e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 115e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleyvoid *CRYPTO_get_thread_local(thread_local_data_t index) { 116e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley CRYPTO_once(&g_thread_local_init_once, thread_local_init); 117e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley if (g_thread_local_failed) { 118e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley return NULL; 119e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley } 120e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 121e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley void **pointers = pthread_getspecific(g_thread_local_key); 122e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley if (pointers == NULL) { 123e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley return NULL; 124e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley } 125e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley return pointers[index]; 126e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley} 127e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 128e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleyint CRYPTO_set_thread_local(thread_local_data_t index, void *value, 129e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley thread_local_destructor_t destructor) { 130e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley CRYPTO_once(&g_thread_local_init_once, thread_local_init); 131e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley if (g_thread_local_failed) { 132e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley destructor(value); 133e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley return 0; 134e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley } 135e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 136e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley void **pointers = pthread_getspecific(g_thread_local_key); 137e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley if (pointers == NULL) { 138e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley pointers = OPENSSL_malloc(sizeof(void *) * NUM_OPENSSL_THREAD_LOCALS); 139e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley if (pointers == NULL) { 140e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley destructor(value); 141e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley return 0; 142e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley } 143e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley memset(pointers, 0, sizeof(void *) * NUM_OPENSSL_THREAD_LOCALS); 144e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley if (pthread_setspecific(g_thread_local_key, pointers) != 0) { 145e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley OPENSSL_free(pointers); 146e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley destructor(value); 147e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley return 0; 148e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley } 149e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley } 150e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 151e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley if (pthread_mutex_lock(&g_destructors_lock) != 0) { 152e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley destructor(value); 153e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley return 0; 154e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley } 155e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley g_destructors[index] = destructor; 156e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley pthread_mutex_unlock(&g_destructors_lock); 157e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 158e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley pointers[index] = value; 159e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley return 1; 160e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley} 161e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 162e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley#endif /* !OPENSSL_WINDOWS && !OPENSSL_NO_THREADS */ 163