1331722Seadler/* 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 */ 29144518Sdavidxu 30297706Skib#include <sys/cdefs.h> 31297706Skib__FBSDID("$FreeBSD: stable/11/lib/libthr/thread/thr_spec.c 319430 2017-06-01 14:49:53Z vangyzen $"); 32297706Skib 33157457Sdavidxu#include "namespace.h" 34282948Skib#include <sys/mman.h> 35112918Sjeff#include <signal.h> 36112918Sjeff#include <stdlib.h> 37112918Sjeff#include <string.h> 38112918Sjeff#include <errno.h> 39112918Sjeff#include <pthread.h> 40157457Sdavidxu#include "un-namespace.h" 41211860Sdavidxu#include "libc_private.h" 42144518Sdavidxu 43112918Sjeff#include "thr_private.h" 44112918Sjeff 45319430Svangyzenstatic struct pthread_key _thread_keytable[PTHREAD_KEYS_MAX]; 46112918Sjeff 47112918Sjeff__weak_reference(_pthread_key_create, pthread_key_create); 48112918Sjeff__weak_reference(_pthread_key_delete, pthread_key_delete); 49112918Sjeff__weak_reference(_pthread_getspecific, pthread_getspecific); 50112918Sjeff__weak_reference(_pthread_setspecific, pthread_setspecific); 51112918Sjeff 52112918Sjeff 53112918Sjeffint 54282948Skib_pthread_key_create(pthread_key_t *key, void (*destructor)(void *)) 55112918Sjeff{ 56173394Smarius struct pthread *curthread; 57144518Sdavidxu int i; 58112918Sjeff 59173394Smarius _thr_check_init(); 60173394Smarius 61173394Smarius curthread = _get_curthread(); 62173394Smarius 63144518Sdavidxu THR_LOCK_ACQUIRE(curthread, &_keytable_lock); 64144518Sdavidxu for (i = 0; i < PTHREAD_KEYS_MAX; i++) { 65112918Sjeff 66144518Sdavidxu if (_thread_keytable[i].allocated == 0) { 67144518Sdavidxu _thread_keytable[i].allocated = 1; 68144518Sdavidxu _thread_keytable[i].destructor = destructor; 69144518Sdavidxu _thread_keytable[i].seqno++; 70144518Sdavidxu 71144518Sdavidxu THR_LOCK_RELEASE(curthread, &_keytable_lock); 72250691Sdavidxu *key = i + 1; 73112918Sjeff return (0); 74112918Sjeff } 75112918Sjeff 76112918Sjeff } 77144518Sdavidxu THR_LOCK_RELEASE(curthread, &_keytable_lock); 78112918Sjeff return (EAGAIN); 79112918Sjeff} 80112918Sjeff 81112918Sjeffint 82250691Sdavidxu_pthread_key_delete(pthread_key_t userkey) 83112918Sjeff{ 84282948Skib struct pthread *curthread; 85282948Skib int key, ret; 86112918Sjeff 87282948Skib key = userkey - 1; 88282948Skib if ((unsigned int)key >= PTHREAD_KEYS_MAX) 89282948Skib return (EINVAL); 90282948Skib curthread = _get_curthread(); 91282948Skib THR_LOCK_ACQUIRE(curthread, &_keytable_lock); 92282948Skib if (_thread_keytable[key].allocated) { 93282948Skib _thread_keytable[key].allocated = 0; 94282948Skib ret = 0; 95282948Skib } else { 96112918Sjeff ret = EINVAL; 97282948Skib } 98282948Skib THR_LOCK_RELEASE(curthread, &_keytable_lock); 99112918Sjeff return (ret); 100112918Sjeff} 101112918Sjeff 102112918Sjeffvoid 103112918Sjeff_thread_cleanupspecific(void) 104112918Sjeff{ 105282948Skib struct pthread *curthread; 106282948Skib void (*destructor)(void *); 107282948Skib const void *data; 108282948Skib int i, key; 109112918Sjeff 110282948Skib curthread = _get_curthread(); 111144518Sdavidxu if (curthread->specific == NULL) 112144518Sdavidxu return; 113144518Sdavidxu THR_LOCK_ACQUIRE(curthread, &_keytable_lock); 114282948Skib for (i = 0; i < PTHREAD_DESTRUCTOR_ITERATIONS && 115282948Skib curthread->specific_data_count > 0; i++) { 116282948Skib for (key = 0; key < PTHREAD_KEYS_MAX && 117282948Skib curthread->specific_data_count > 0; key++) { 118144518Sdavidxu destructor = NULL; 119144518Sdavidxu 120144518Sdavidxu if (_thread_keytable[key].allocated && 121144518Sdavidxu (curthread->specific[key].data != NULL)) { 122144518Sdavidxu if (curthread->specific[key].seqno == 123144518Sdavidxu _thread_keytable[key].seqno) { 124157457Sdavidxu data = curthread->specific[key].data; 125282948Skib destructor = _thread_keytable[key]. 126282948Skib destructor; 127112918Sjeff } 128144518Sdavidxu curthread->specific[key].data = NULL; 129144518Sdavidxu curthread->specific_data_count--; 130282948Skib } else if (curthread->specific[key].data != NULL) { 131197477Sdavidxu /* 132282948Skib * This can happen if the key is 133282948Skib * deleted via pthread_key_delete 134282948Skib * without first setting the value to 135282948Skib * NULL in all threads. POSIX says 136282948Skib * that the destructor is not invoked 137282948Skib * in this case. 138197477Sdavidxu */ 139197477Sdavidxu curthread->specific[key].data = NULL; 140197477Sdavidxu curthread->specific_data_count--; 141197477Sdavidxu } 142112918Sjeff 143144518Sdavidxu /* 144282948Skib * If there is a destructor, call it with the 145282948Skib * key table entry unlocked. 146144518Sdavidxu */ 147144518Sdavidxu if (destructor != NULL) { 148144518Sdavidxu THR_LOCK_RELEASE(curthread, &_keytable_lock); 149157457Sdavidxu destructor(__DECONST(void *, data)); 150144518Sdavidxu THR_LOCK_ACQUIRE(curthread, &_keytable_lock); 151112918Sjeff } 152112918Sjeff } 153112918Sjeff } 154144518Sdavidxu THR_LOCK_RELEASE(curthread, &_keytable_lock); 155282948Skib munmap(curthread->specific, PTHREAD_KEYS_MAX * sizeof(struct 156282948Skib pthread_specific_elem)); 157144518Sdavidxu curthread->specific = NULL; 158282948Skib if (curthread->specific_data_count > 0) { 159144518Sdavidxu stderr_debug("Thread %p has exited with leftover " 160144518Sdavidxu "thread-specific data after %d destructor iterations\n", 161144518Sdavidxu curthread, PTHREAD_DESTRUCTOR_ITERATIONS); 162282948Skib } 163112918Sjeff} 164112918Sjeff 165112918Sjeffint 166250691Sdavidxu_pthread_setspecific(pthread_key_t userkey, const void *value) 167112918Sjeff{ 168282948Skib struct pthread *pthread; 169282948Skib void *tmp; 170282948Skib pthread_key_t key; 171112918Sjeff 172282948Skib key = userkey - 1; 173282948Skib if ((unsigned int)key >= PTHREAD_KEYS_MAX || 174282948Skib !_thread_keytable[key].allocated) 175282948Skib return (EINVAL); 176282948Skib 177144518Sdavidxu pthread = _get_curthread(); 178282948Skib if (pthread->specific == NULL) { 179282948Skib tmp = mmap(NULL, PTHREAD_KEYS_MAX * 180282948Skib sizeof(struct pthread_specific_elem), 181282948Skib PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 182282948Skib if (tmp == MAP_FAILED) 183282948Skib return (ENOMEM); 184282948Skib pthread->specific = tmp; 185282948Skib } 186282948Skib if (pthread->specific[key].data == NULL) { 187282948Skib if (value != NULL) 188282948Skib pthread->specific_data_count++; 189282948Skib } else if (value == NULL) 190282948Skib pthread->specific_data_count--; 191282948Skib pthread->specific[key].data = value; 192282948Skib pthread->specific[key].seqno = _thread_keytable[key].seqno; 193282948Skib return (0); 194112918Sjeff} 195112918Sjeff 196112918Sjeffvoid * 197250691Sdavidxu_pthread_getspecific(pthread_key_t userkey) 198112918Sjeff{ 199282948Skib struct pthread *pthread; 200282948Skib const void *data; 201282948Skib pthread_key_t key; 202112918Sjeff 203282948Skib /* Check if there is specific data. */ 204282948Skib key = userkey - 1; 205282948Skib if ((unsigned int)key >= PTHREAD_KEYS_MAX) 206282948Skib return (NULL); 207282948Skib 208144518Sdavidxu pthread = _get_curthread(); 209282948Skib /* Check if this key has been used before. */ 210282948Skib if (_thread_keytable[key].allocated && pthread->specific != NULL && 211282948Skib pthread->specific[key].seqno == _thread_keytable[key].seqno) { 212282948Skib /* Return the value: */ 213282948Skib data = pthread->specific[key].data; 214282948Skib } else { 215282948Skib /* 216282948Skib * This key has not been used before, so return NULL 217282948Skib * instead. 218282948Skib */ 219112918Sjeff data = NULL; 220282948Skib } 221157457Sdavidxu return (__DECONST(void *, data)); 222112918Sjeff} 223211860Sdavidxu 224211860Sdavidxuvoid 225211860Sdavidxu_thr_tsd_unload(struct dl_phdr_info *phdr_info) 226211860Sdavidxu{ 227282948Skib struct pthread *curthread; 228211860Sdavidxu void (*destructor)(void *); 229211860Sdavidxu int key; 230211860Sdavidxu 231282948Skib curthread = _get_curthread(); 232211860Sdavidxu THR_LOCK_ACQUIRE(curthread, &_keytable_lock); 233211860Sdavidxu for (key = 0; key < PTHREAD_KEYS_MAX; key++) { 234282948Skib if (!_thread_keytable[key].allocated) 235282948Skib continue; 236282948Skib destructor = _thread_keytable[key].destructor; 237282948Skib if (destructor == NULL) 238282948Skib continue; 239282948Skib if (__elf_phdr_match_addr(phdr_info, destructor)) 240282948Skib _thread_keytable[key].destructor = NULL; 241211860Sdavidxu } 242211860Sdavidxu THR_LOCK_RELEASE(curthread, &_keytable_lock); 243211860Sdavidxu} 244