rthread_tls.c revision 1.2
138032Speter/* $OpenBSD: rthread_tls.c,v 1.2 2017/08/15 06:38:41 guenther Exp $ */ 238032Speter/* 364562Sgshapiro * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org> 464562Sgshapiro * All Rights Reserved. 538032Speter * 638032Speter * Permission to use, copy, modify, and distribute this software for any 738032Speter * purpose with or without fee is hereby granted, provided that the above 838032Speter * copyright notice and this permission notice appear in all copies. 938032Speter * 1038032Speter * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1138032Speter * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1238032Speter * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1338032Speter * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1438032Speter * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1538032Speter * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1638032Speter * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1738032Speter */ 1838032Speter/* 1938032Speter * thread specific storage 2038032Speter */ 2138032Speter 2238032Speter#include <errno.h> 2364562Sgshapiro#include <pthread.h> 2438032Speter#include <stdlib.h> 2538032Speter 2638032Speter#include "rthread.h" 2738032Speter 28static struct rthread_key rkeys[PTHREAD_KEYS_MAX]; 29static _atomic_lock_t rkeyslock = _SPINLOCK_UNLOCKED; 30 31int 32pthread_key_create(pthread_key_t *key, void (*destructor)(void*)) 33{ 34 static int hint; 35 int i; 36 37 _spinlock(&rkeyslock); 38 if (rkeys[hint].used) { 39 for (i = 0; i < PTHREAD_KEYS_MAX; i++) { 40 if (!rkeys[i].used) 41 break; 42 } 43 if (i == PTHREAD_KEYS_MAX) { 44 _spinunlock(&rkeyslock); 45 return (EAGAIN); 46 } 47 hint = i; 48 } 49 rkeys[hint].used = 1; 50 rkeys[hint].destructor = destructor; 51 52 *key = hint++; 53 if (hint >= PTHREAD_KEYS_MAX) 54 hint = 0; 55 _spinunlock(&rkeyslock); 56 57 return (0); 58} 59DEF_STD(pthread_key_create); 60 61int 62pthread_key_delete(pthread_key_t key) 63{ 64 pthread_t thread; 65 struct rthread_storage *rs; 66 int rv = 0; 67 68 if (key < 0 || key >= PTHREAD_KEYS_MAX) 69 return (EINVAL); 70 71 _spinlock(&rkeyslock); 72 if (!rkeys[key].used) { 73 rv = EINVAL; 74 goto out; 75 } 76 77 rkeys[key].used = 0; 78 rkeys[key].destructor = NULL; 79 _spinlock(&_thread_lock); 80 LIST_FOREACH(thread, &_thread_list, threads) { 81 for (rs = thread->local_storage; rs; rs = rs->next) { 82 if (rs->keyid == key) 83 rs->data = NULL; 84 } 85 } 86 _spinunlock(&_thread_lock); 87 88out: 89 _spinunlock(&rkeyslock); 90 return (rv); 91} 92 93static struct rthread_storage * 94_rthread_findstorage(pthread_key_t key) 95{ 96 struct rthread_storage *rs; 97 pthread_t self; 98 99 if (!rkeys[key].used) { 100 rs = NULL; 101 goto out; 102 } 103 104 self = pthread_self(); 105 106 for (rs = self->local_storage; rs; rs = rs->next) { 107 if (rs->keyid == key) 108 break; 109 } 110 if (!rs) { 111 rs = calloc(1, sizeof(*rs)); 112 if (!rs) 113 goto out; 114 rs->keyid = key; 115 rs->data = NULL; 116 rs->next = self->local_storage; 117 self->local_storage = rs; 118 } 119 120out: 121 return (rs); 122} 123 124void * 125pthread_getspecific(pthread_key_t key) 126{ 127 struct rthread_storage *rs; 128 129 if (key < 0 || key >= PTHREAD_KEYS_MAX) 130 return (NULL); 131 132 rs = _rthread_findstorage(key); 133 if (!rs) 134 return (NULL); 135 136 return (rs->data); 137} 138DEF_STD(pthread_getspecific); 139 140int 141pthread_setspecific(pthread_key_t key, const void *data) 142{ 143 struct rthread_storage *rs; 144 145 if (key < 0 || key >= PTHREAD_KEYS_MAX) 146 return (EINVAL); 147 148 rs = _rthread_findstorage(key); 149 if (!rs) 150 return (ENOMEM); 151 rs->data = (void *)data; 152 153 return (0); 154} 155DEF_STD(pthread_setspecific); 156 157void 158_rthread_tls_destructors(pthread_t thread) 159{ 160 struct rthread_storage *rs; 161 int i; 162 163 _spinlock(&rkeyslock); 164 for (i = 0; i < PTHREAD_DESTRUCTOR_ITERATIONS; i++) { 165 for (rs = thread->local_storage; rs; rs = rs->next) { 166 if (!rs->data) 167 continue; 168 if (rkeys[rs->keyid].destructor) { 169 void (*destructor)(void *) = 170 rkeys[rs->keyid].destructor; 171 void *data = rs->data; 172 rs->data = NULL; 173 _spinunlock(&rkeyslock); 174 destructor(data); 175 _spinlock(&rkeyslock); 176 } 177 } 178 } 179 for (rs = thread->local_storage; rs; rs = thread->local_storage) { 180 thread->local_storage = rs->next; 181 free(rs); 182 } 183 _spinunlock(&rkeyslock); 184} 185