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