1112918Sjeff/* 2112918Sjeff * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. 3112918Sjeff * All rights reserved. 4112918Sjeff * 5112918Sjeff * Redistribution and use in source and binary forms, with or without 6112918Sjeff * modification, are permitted provided that the following conditions 7112918Sjeff * are met: 8112918Sjeff * 1. Redistributions of source code must retain the above copyright 9112918Sjeff * notice, this list of conditions and the following disclaimer. 10112918Sjeff * 2. Redistributions in binary form must reproduce the above copyright 11112918Sjeff * notice, this list of conditions and the following disclaimer in the 12112918Sjeff * documentation and/or other materials provided with the distribution. 13165967Simp * 3. Neither the name of the author nor the names of any co-contributors 14112918Sjeff * may be used to endorse or promote products derived from this software 15112918Sjeff * without specific prior written permission. 16112918Sjeff * 17112918Sjeff * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 18112918Sjeff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19112918Sjeff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20112918Sjeff * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21112918Sjeff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22112918Sjeff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23112918Sjeff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24112918Sjeff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25112918Sjeff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26112918Sjeff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27112918Sjeff * SUCH DAMAGE. 28112918Sjeff * 29112918Sjeff * $FreeBSD$ 30112918Sjeff */ 31144518Sdavidxu 32157457Sdavidxu#include "namespace.h" 33283690Skib#include <sys/mman.h> 34112918Sjeff#include <signal.h> 35112918Sjeff#include <stdlib.h> 36112918Sjeff#include <string.h> 37112918Sjeff#include <errno.h> 38112918Sjeff#include <pthread.h> 39157457Sdavidxu#include "un-namespace.h" 40211860Sdavidxu#include "libc_private.h" 41144518Sdavidxu 42112918Sjeff#include "thr_private.h" 43112918Sjeff 44144518Sdavidxustruct pthread_key _thread_keytable[PTHREAD_KEYS_MAX]; 45112918Sjeff 46112918Sjeff__weak_reference(_pthread_key_create, pthread_key_create); 47112918Sjeff__weak_reference(_pthread_key_delete, pthread_key_delete); 48112918Sjeff__weak_reference(_pthread_getspecific, pthread_getspecific); 49112918Sjeff__weak_reference(_pthread_setspecific, pthread_setspecific); 50112918Sjeff 51112918Sjeff 52112918Sjeffint 53283690Skib_pthread_key_create(pthread_key_t *key, void (*destructor)(void *)) 54112918Sjeff{ 55173394Smarius struct pthread *curthread; 56144518Sdavidxu int i; 57112918Sjeff 58173394Smarius _thr_check_init(); 59173394Smarius 60173394Smarius curthread = _get_curthread(); 61173394Smarius 62144518Sdavidxu THR_LOCK_ACQUIRE(curthread, &_keytable_lock); 63144518Sdavidxu for (i = 0; i < PTHREAD_KEYS_MAX; i++) { 64112918Sjeff 65144518Sdavidxu if (_thread_keytable[i].allocated == 0) { 66144518Sdavidxu _thread_keytable[i].allocated = 1; 67144518Sdavidxu _thread_keytable[i].destructor = destructor; 68144518Sdavidxu _thread_keytable[i].seqno++; 69144518Sdavidxu 70144518Sdavidxu THR_LOCK_RELEASE(curthread, &_keytable_lock); 71250691Sdavidxu *key = i + 1; 72112918Sjeff return (0); 73112918Sjeff } 74112918Sjeff 75112918Sjeff } 76144518Sdavidxu THR_LOCK_RELEASE(curthread, &_keytable_lock); 77112918Sjeff return (EAGAIN); 78112918Sjeff} 79112918Sjeff 80112918Sjeffint 81250691Sdavidxu_pthread_key_delete(pthread_key_t userkey) 82112918Sjeff{ 83283690Skib struct pthread *curthread; 84283690Skib int key, ret; 85112918Sjeff 86283690Skib key = userkey - 1; 87283690Skib if ((unsigned int)key >= PTHREAD_KEYS_MAX) 88283690Skib return (EINVAL); 89283690Skib curthread = _get_curthread(); 90283690Skib THR_LOCK_ACQUIRE(curthread, &_keytable_lock); 91283690Skib if (_thread_keytable[key].allocated) { 92283690Skib _thread_keytable[key].allocated = 0; 93283690Skib ret = 0; 94283690Skib } else { 95112918Sjeff ret = EINVAL; 96283690Skib } 97283690Skib THR_LOCK_RELEASE(curthread, &_keytable_lock); 98112918Sjeff return (ret); 99112918Sjeff} 100112918Sjeff 101112918Sjeffvoid 102112918Sjeff_thread_cleanupspecific(void) 103112918Sjeff{ 104283690Skib struct pthread *curthread; 105283690Skib void (*destructor)(void *); 106283690Skib const void *data; 107283690Skib int i, key; 108112918Sjeff 109283690Skib curthread = _get_curthread(); 110144518Sdavidxu if (curthread->specific == NULL) 111144518Sdavidxu return; 112144518Sdavidxu THR_LOCK_ACQUIRE(curthread, &_keytable_lock); 113283690Skib for (i = 0; i < PTHREAD_DESTRUCTOR_ITERATIONS && 114283690Skib curthread->specific_data_count > 0; i++) { 115283690Skib for (key = 0; key < PTHREAD_KEYS_MAX && 116283690Skib curthread->specific_data_count > 0; key++) { 117144518Sdavidxu destructor = NULL; 118144518Sdavidxu 119144518Sdavidxu if (_thread_keytable[key].allocated && 120144518Sdavidxu (curthread->specific[key].data != NULL)) { 121144518Sdavidxu if (curthread->specific[key].seqno == 122144518Sdavidxu _thread_keytable[key].seqno) { 123157457Sdavidxu data = curthread->specific[key].data; 124283690Skib destructor = _thread_keytable[key]. 125283690Skib destructor; 126112918Sjeff } 127144518Sdavidxu curthread->specific[key].data = NULL; 128144518Sdavidxu curthread->specific_data_count--; 129283690Skib } else if (curthread->specific[key].data != NULL) { 130197477Sdavidxu /* 131283690Skib * This can happen if the key is 132283690Skib * deleted via pthread_key_delete 133283690Skib * without first setting the value to 134283690Skib * NULL in all threads. POSIX says 135283690Skib * that the destructor is not invoked 136283690Skib * in this case. 137197477Sdavidxu */ 138197477Sdavidxu curthread->specific[key].data = NULL; 139197477Sdavidxu curthread->specific_data_count--; 140197477Sdavidxu } 141112918Sjeff 142144518Sdavidxu /* 143283690Skib * If there is a destructor, call it with the 144283690Skib * key table entry unlocked. 145144518Sdavidxu */ 146144518Sdavidxu if (destructor != NULL) { 147144518Sdavidxu THR_LOCK_RELEASE(curthread, &_keytable_lock); 148157457Sdavidxu destructor(__DECONST(void *, data)); 149144518Sdavidxu THR_LOCK_ACQUIRE(curthread, &_keytable_lock); 150112918Sjeff } 151112918Sjeff } 152112918Sjeff } 153144518Sdavidxu THR_LOCK_RELEASE(curthread, &_keytable_lock); 154283690Skib munmap(curthread->specific, PTHREAD_KEYS_MAX * sizeof(struct 155283690Skib pthread_specific_elem)); 156144518Sdavidxu curthread->specific = NULL; 157283690Skib if (curthread->specific_data_count > 0) { 158144518Sdavidxu stderr_debug("Thread %p has exited with leftover " 159144518Sdavidxu "thread-specific data after %d destructor iterations\n", 160144518Sdavidxu curthread, PTHREAD_DESTRUCTOR_ITERATIONS); 161283690Skib } 162112918Sjeff} 163112918Sjeff 164112918Sjeffint 165250691Sdavidxu_pthread_setspecific(pthread_key_t userkey, const void *value) 166112918Sjeff{ 167283690Skib struct pthread *pthread; 168283690Skib void *tmp; 169283690Skib pthread_key_t key; 170112918Sjeff 171283690Skib key = userkey - 1; 172283690Skib if ((unsigned int)key >= PTHREAD_KEYS_MAX || 173283690Skib !_thread_keytable[key].allocated) 174283690Skib return (EINVAL); 175283690Skib 176144518Sdavidxu pthread = _get_curthread(); 177283690Skib if (pthread->specific == NULL) { 178283690Skib tmp = mmap(NULL, PTHREAD_KEYS_MAX * 179283690Skib sizeof(struct pthread_specific_elem), 180283690Skib PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 181283690Skib if (tmp == MAP_FAILED) 182283690Skib return (ENOMEM); 183283690Skib pthread->specific = tmp; 184283690Skib } 185283690Skib if (pthread->specific[key].data == NULL) { 186283690Skib if (value != NULL) 187283690Skib pthread->specific_data_count++; 188283690Skib } else if (value == NULL) 189283690Skib pthread->specific_data_count--; 190283690Skib pthread->specific[key].data = value; 191283690Skib pthread->specific[key].seqno = _thread_keytable[key].seqno; 192283690Skib return (0); 193112918Sjeff} 194112918Sjeff 195112918Sjeffvoid * 196250691Sdavidxu_pthread_getspecific(pthread_key_t userkey) 197112918Sjeff{ 198283690Skib struct pthread *pthread; 199283690Skib const void *data; 200283690Skib pthread_key_t key; 201112918Sjeff 202283690Skib /* Check if there is specific data. */ 203283690Skib key = userkey - 1; 204283690Skib if ((unsigned int)key >= PTHREAD_KEYS_MAX) 205283690Skib return (NULL); 206283690Skib 207144518Sdavidxu pthread = _get_curthread(); 208283690Skib /* Check if this key has been used before. */ 209283690Skib if (_thread_keytable[key].allocated && pthread->specific != NULL && 210283690Skib pthread->specific[key].seqno == _thread_keytable[key].seqno) { 211283690Skib /* Return the value: */ 212283690Skib data = pthread->specific[key].data; 213283690Skib } else { 214283690Skib /* 215283690Skib * This key has not been used before, so return NULL 216283690Skib * instead. 217283690Skib */ 218112918Sjeff data = NULL; 219283690Skib } 220157457Sdavidxu return (__DECONST(void *, data)); 221112918Sjeff} 222211860Sdavidxu 223211860Sdavidxuvoid 224211860Sdavidxu_thr_tsd_unload(struct dl_phdr_info *phdr_info) 225211860Sdavidxu{ 226283690Skib struct pthread *curthread; 227211860Sdavidxu void (*destructor)(void *); 228211860Sdavidxu int key; 229211860Sdavidxu 230283690Skib curthread = _get_curthread(); 231211860Sdavidxu THR_LOCK_ACQUIRE(curthread, &_keytable_lock); 232211860Sdavidxu for (key = 0; key < PTHREAD_KEYS_MAX; key++) { 233283690Skib if (!_thread_keytable[key].allocated) 234283690Skib continue; 235283690Skib destructor = _thread_keytable[key].destructor; 236283690Skib if (destructor == NULL) 237283690Skib continue; 238283690Skib if (__elf_phdr_match_addr(phdr_info, destructor)) 239283690Skib _thread_keytable[key].destructor = NULL; 240211860Sdavidxu } 241211860Sdavidxu THR_LOCK_RELEASE(curthread, &_keytable_lock); 242211860Sdavidxu} 243