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