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