thr_spec.c revision 36549
1/* 2 * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by John Birrell. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 */ 33#include <signal.h> 34#include <stdlib.h> 35#include <string.h> 36#include <errno.h> 37#ifdef _THREAD_SAFE 38#include <pthread.h> 39#include "pthread_private.h" 40 41/* Static variables: */ 42static struct pthread_key key_table[PTHREAD_KEYS_MAX]; 43static long key_table_lock = 0; 44 45int 46pthread_key_create(pthread_key_t * key, void (*destructor) (void *)) 47{ 48 /* Lock the key table: */ 49 _spinlock(&key_table_lock); 50 51 for ((*key) = 0; (*key) < PTHREAD_KEYS_MAX; (*key)++) { 52 if (key_table[(*key)].count == 0) { 53 key_table[(*key)].count++; 54 key_table[(*key)].destructor = destructor; 55 56 /* Unlock the key table: */ 57 _atomic_unlock(&key_table_lock); 58 return (0); 59 } 60 } 61 62 /* Unlock the key table: */ 63 _atomic_unlock(&key_table_lock); 64 return (EAGAIN); 65} 66 67int 68pthread_key_delete(pthread_key_t key) 69{ 70 int ret; 71 72 /* Lock the key table: */ 73 _spinlock(&key_table_lock); 74 75 if (key < PTHREAD_KEYS_MAX) { 76 switch (key_table[key].count) { 77 case 1: 78 key_table[key].destructor = NULL; 79 key_table[key].count = 0; 80 case 0: 81 ret = 0; 82 break; 83 default: 84 ret = EBUSY; 85 } 86 } else 87 ret = EINVAL; 88 89 /* Unlock the key table: */ 90 _atomic_unlock(&key_table_lock); 91 return (ret); 92} 93 94void 95_thread_cleanupspecific(void) 96{ 97 void *data; 98 int key; 99 int itr; 100 101 for (itr = 0; itr < PTHREAD_DESTRUCTOR_ITERATIONS; itr++) { 102 for (key = 0; key < PTHREAD_KEYS_MAX; key++) { 103 if (_thread_run->specific_data_count) { 104 /* Lock the key table entry: */ 105 _spinlock(&key_table[key].access_lock); 106 107 if (_thread_run->specific_data[key]) { 108 data = (void *) _thread_run->specific_data[key]; 109 _thread_run->specific_data[key] = NULL; 110 _thread_run->specific_data_count--; 111 if (key_table[key].destructor) { 112 key_table[key].destructor(data); 113 } 114 key_table[key].count--; 115 } 116 117 /* Unlock the key table entry: */ 118 _atomic_unlock(&key_table[key].access_lock); 119 } else { 120 free(_thread_run->specific_data); 121 return; 122 } 123 } 124 } 125 free(_thread_run->specific_data); 126} 127 128static inline const void ** 129pthread_key_allocate_data(void) 130{ 131 const void **new_data; 132 if ((new_data = (const void **) malloc(sizeof(void *) * PTHREAD_KEYS_MAX)) != NULL) { 133 memset((void *) new_data, 0, sizeof(void *) * PTHREAD_KEYS_MAX); 134 } 135 return (new_data); 136} 137 138int 139pthread_setspecific(pthread_key_t key, const void *value) 140{ 141 pthread_t pthread; 142 int ret = 0; 143 144 /* Point to the running thread: */ 145 pthread = _thread_run; 146 147 if ((pthread->specific_data) || 148 (pthread->specific_data = pthread_key_allocate_data())) { 149 if (key < PTHREAD_KEYS_MAX) { 150 /* Lock the key table entry: */ 151 _spinlock(&key_table[key].access_lock); 152 153 if (key_table[key].count) { 154 if (pthread->specific_data[key] == NULL) { 155 if (value != NULL) { 156 pthread->specific_data_count++; 157 key_table[key].count++; 158 } 159 } else { 160 if (value == NULL) { 161 pthread->specific_data_count--; 162 key_table[key].count--; 163 } 164 } 165 pthread->specific_data[key] = value; 166 ret = 0; 167 } else 168 ret = EINVAL; 169 170 /* Unlock the key table entry: */ 171 _atomic_unlock(&key_table[key].access_lock); 172 173 } else 174 ret = EINVAL; 175 } else 176 ret = ENOMEM; 177 return (ret); 178} 179 180void * 181pthread_getspecific(pthread_key_t key) 182{ 183 pthread_t pthread; 184 void *data; 185 186 /* Point to the running thread: */ 187 pthread = _thread_run; 188 189 /* Check if there is specific data: */ 190 if (pthread->specific_data != NULL && 191 (key < PTHREAD_KEYS_MAX) && (key_table)) { 192 /* Lock the key table entry: */ 193 _spinlock(&key_table[key].access_lock); 194 195 /* Check if this key has been used before: */ 196 if (key_table[key].count) { 197 /* Return the value: */ 198 data = (void *) pthread->specific_data[key]; 199 } else { 200 /* 201 * This key has not been used before, so return NULL 202 * instead: 203 */ 204 data = NULL; 205 } 206 207 /* Unlock the key table entry: */ 208 _atomic_unlock(&key_table[key].access_lock); 209 } else 210 /* No specific data has been created, so just return NULL: */ 211 data = NULL; 212 return (data); 213} 214#endif 215