thr_spec.c revision 31402
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]; 43 44int 45pthread_key_create(pthread_key_t * key, void (*destructor) (void *)) 46{ 47 for ((*key) = 0; (*key) < PTHREAD_KEYS_MAX; (*key)++) { 48 if (key_table[(*key)].count == 0) { 49 key_table[(*key)].count++; 50 key_table[(*key)].destructor = destructor; 51 return (0); 52 } 53 } 54 return (EAGAIN); 55} 56 57int 58pthread_key_delete(pthread_key_t key) 59{ 60 int ret; 61 int status; 62 63 /* Block signals: */ 64 _thread_kern_sig_block(&status); 65 66 if (key < PTHREAD_KEYS_MAX) { 67 switch (key_table[key].count) { 68 case 1: 69 key_table[key].destructor = NULL; 70 key_table[key].count = 0; 71 case 0: 72 ret = 0; 73 break; 74 default: 75 ret = EBUSY; 76 } 77 } else { 78 ret = EINVAL; 79 } 80 81 /* Unblock signals: */ 82 _thread_kern_sig_unblock(status); 83 return (ret); 84} 85 86void 87_thread_cleanupspecific(void) 88{ 89 void *data; 90 int key; 91 int itr; 92 int status; 93 94 /* Block signals: */ 95 _thread_kern_sig_block(&status); 96 97 for (itr = 0; itr < PTHREAD_DESTRUCTOR_ITERATIONS; itr++) { 98 for (key = 0; key < PTHREAD_KEYS_MAX; key++) { 99 if (_thread_run->specific_data_count) { 100 if (_thread_run->specific_data[key]) { 101 data = (void *) _thread_run->specific_data[key]; 102 _thread_run->specific_data[key] = NULL; 103 _thread_run->specific_data_count--; 104 if (key_table[key].destructor) { 105 key_table[key].destructor(data); 106 } 107 key_table[key].count--; 108 } 109 } else { 110 free(_thread_run->specific_data); 111 112 /* Unblock signals: */ 113 _thread_kern_sig_unblock(status); 114 return; 115 } 116 } 117 } 118 free(_thread_run->specific_data); 119 120 /* Unblock signals: */ 121 _thread_kern_sig_unblock(status); 122} 123 124static inline const void ** 125pthread_key_allocate_data(void) 126{ 127 const void **new_data; 128 if ((new_data = (const void **) malloc(sizeof(void *) * PTHREAD_KEYS_MAX)) != NULL) { 129 memset((void *) new_data, 0, sizeof(void *) * PTHREAD_KEYS_MAX); 130 } 131 return (new_data); 132} 133 134int 135pthread_setspecific(pthread_key_t key, const void *value) 136{ 137 pthread_t pthread; 138 int ret = 0; 139 int status; 140 141 /* Block signals: */ 142 _thread_kern_sig_block(&status); 143 144 /* Point to the running thread: */ 145 pthread = _thread_run; 146 147 /* 148 * Enter a loop for signal handler threads to find the parent thread 149 * which has the specific data associated with it: 150 */ 151 while (pthread->parent_thread != NULL) { 152 /* Point to the parent thread: */ 153 pthread = pthread->parent_thread; 154 } 155 156 if ((pthread->specific_data) || (pthread->specific_data = pthread_key_allocate_data())) { 157 if ((key < PTHREAD_KEYS_MAX) && (key_table)) { 158 if (key_table[key].count) { 159 if (pthread->specific_data[key] == NULL) { 160 if (value != NULL) { 161 pthread->specific_data_count++; 162 key_table[key].count++; 163 } 164 } else { 165 if (value == NULL) { 166 pthread->specific_data_count--; 167 key_table[key].count--; 168 } 169 } 170 pthread->specific_data[key] = value; 171 ret = 0; 172 } else { 173 ret = EINVAL; 174 } 175 } else { 176 ret = EINVAL; 177 } 178 } else { 179 ret = ENOMEM; 180 } 181 182 /* Unblock signals: */ 183 _thread_kern_sig_unblock(status); 184 return (ret); 185} 186 187void * 188pthread_getspecific(pthread_key_t key) 189{ 190 pthread_t pthread; 191 int status; 192 void *data; 193 194 /* Block signals: */ 195 _thread_kern_sig_block(&status); 196 197 /* Point to the running thread: */ 198 pthread = _thread_run; 199 200 /* 201 * Enter a loop for signal handler threads to find the parent thread 202 * which has the specific data associated with it: 203 */ 204 while (pthread->parent_thread != NULL) { 205 /* Point to the parent thread: */ 206 pthread = pthread->parent_thread; 207 } 208 209 /* Check for errors: */ 210 if (pthread == NULL) { 211 /* Return an invalid argument error: */ 212 data = NULL; 213 } 214 /* Check if there is specific data: */ 215 else if (pthread->specific_data != NULL && (key < PTHREAD_KEYS_MAX) && (key_table)) { 216 /* Check if this key has been used before: */ 217 if (key_table[key].count) { 218 /* Return the value: */ 219 data = (void *) pthread->specific_data[key]; 220 } else { 221 /* 222 * This key has not been used before, so return NULL 223 * instead: 224 */ 225 data = NULL; 226 } 227 } else { 228 /* No specific data has been created, so just return NULL: */ 229 data = NULL; 230 } 231 232 /* Unblock signals: */ 233 _thread_kern_sig_unblock(status); 234 return (data); 235} 236#endif 237