thr_spec.c revision 283690
13584Ssos/* 23584Ssos * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. 3230132Suqs * All rights reserved. 411397Sswallace * 53584Ssos * Redistribution and use in source and binary forms, with or without 63584Ssos * modification, are permitted provided that the following conditions 73584Ssos * are met: 83584Ssos * 1. Redistributions of source code must retain the above copyright 93584Ssos * notice, this list of conditions and the following disclaimer. 103584Ssos * 2. Redistributions in binary form must reproduce the above copyright 113584Ssos * notice, this list of conditions and the following disclaimer in the 123584Ssos * documentation and/or other materials provided with the distribution. 133584Ssos * 3. Neither the name of the author nor the names of any co-contributors 143584Ssos * may be used to endorse or promote products derived from this software 153584Ssos * without specific prior written permission. 163584Ssos * 1797748Sschweikh * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 183584Ssos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 193584Ssos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 203584Ssos * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 213584Ssos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 223584Ssos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 233584Ssos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 243584Ssos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 253584Ssos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 263584Ssos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 273584Ssos * SUCH DAMAGE. 283584Ssos * 293584Ssos * $FreeBSD: stable/10/lib/libthr/thread/thr_spec.c 283690 2015-05-29 07:48:30Z kib $ 303584Ssos */ 31115684Sobrien 32115684Sobrien#include "namespace.h" 33115684Sobrien#include <sys/mman.h> 343584Ssos#include <signal.h> 3511397Sswallace#include <stdlib.h> 3614885Sswallace#include <string.h> 3711397Sswallace#include <errno.h> 38162954Sphk#include <pthread.h> 3991388Srobert#include "un-namespace.h" 4011397Sswallace#include "libc_private.h" 41141488Sjhb 4224205Sbde#include "thr_private.h" 4311397Sswallace 44141488Sjhbstruct pthread_key _thread_keytable[PTHREAD_KEYS_MAX]; 4511397Sswallace 46160241Sjhb__weak_reference(_pthread_key_create, pthread_key_create); 47141488Sjhb__weak_reference(_pthread_key_delete, pthread_key_delete); 4811397Sswallace__weak_reference(_pthread_getspecific, pthread_getspecific); 493584Ssos__weak_reference(_pthread_setspecific, pthread_setspecific); 503584Ssos 5111397Sswallace 5214885Sswallaceint 5311397Sswallace_pthread_key_create(pthread_key_t *key, void (*destructor)(void *)) 5411397Sswallace{ 5511397Sswallace struct pthread *curthread; 5611397Sswallace int i; 5711397Sswallace 583584Ssos _thr_check_init(); 5954655Seivind 6011397Sswallace curthread = _get_curthread(); 6111397Sswallace 6211397Sswallace THR_LOCK_ACQUIRE(curthread, &_keytable_lock); 6383366Sjulian for (i = 0; i < PTHREAD_KEYS_MAX; i++) { 643584Ssos 6583366Sjulian if (_thread_keytable[i].allocated == 0) { 6611397Sswallace _thread_keytable[i].allocated = 1; 67147820Sjhb _thread_keytable[i].destructor = destructor; 68147820Sjhb _thread_keytable[i].seqno++; 693584Ssos 7011397Sswallace THR_LOCK_RELEASE(curthread, &_keytable_lock); 7111397Sswallace *key = i + 1; 7211397Sswallace return (0); 73160798Sjhb } 74147820Sjhb 75160798Sjhb } 76147820Sjhb THR_LOCK_RELEASE(curthread, &_keytable_lock); 77147820Sjhb return (EAGAIN); 783584Ssos} 793584Ssos 8011397Sswallaceint 8183366Sjulian_pthread_key_delete(pthread_key_t userkey) 8283366Sjulian{ 8311397Sswallace struct pthread *curthread; 8411397Sswallace int key, ret; 85160192Sjhb 863584Ssos key = userkey - 1; 8711397Sswallace if ((unsigned int)key >= PTHREAD_KEYS_MAX) 88160192Sjhb return (EINVAL); 89160192Sjhb curthread = _get_curthread(); 90160192Sjhb THR_LOCK_ACQUIRE(curthread, &_keytable_lock); 91160192Sjhb if (_thread_keytable[key].allocated) { 92160192Sjhb _thread_keytable[key].allocated = 0; 93160192Sjhb ret = 0; 9411397Sswallace } else { 9511397Sswallace ret = EINVAL; 9611397Sswallace } 9783366Sjulian THR_LOCK_RELEASE(curthread, &_keytable_lock); 9883366Sjulian return (ret); 9911397Sswallace} 1003584Ssos 10111397Sswallacevoid 1023584Ssos_thread_cleanupspecific(void) 10311397Sswallace{ 104107849Salfred struct pthread *curthread; 105107849Salfred void (*destructor)(void *); 106225617Skmacy const void *data; 1073584Ssos int i, key; 1083584Ssos 1093584Ssos curthread = _get_curthread(); 11011397Sswallace if (curthread->specific == NULL) 11183366Sjulian return; 11283366Sjulian THR_LOCK_ACQUIRE(curthread, &_keytable_lock); 11311397Sswallace for (i = 0; i < PTHREAD_DESTRUCTOR_ITERATIONS && 1143584Ssos curthread->specific_data_count > 0; i++) { 11511397Sswallace for (key = 0; key < PTHREAD_KEYS_MAX && 11626819Ssef curthread->specific_data_count > 0; key++) { 117103870Salfred destructor = NULL; 11826819Ssef 11926819Ssef if (_thread_keytable[key].allocated && 12026819Ssef (curthread->specific[key].data != NULL)) { 12126819Ssef if (curthread->specific[key].seqno == 12211397Sswallace _thread_keytable[key].seqno) { 12311397Sswallace data = curthread->specific[key].data; 12411397Sswallace destructor = _thread_keytable[key]. 12511397Sswallace destructor; 12611397Sswallace } 127110299Sphk curthread->specific[key].data = NULL; 128110299Sphk curthread->specific_data_count--; 12911397Sswallace } else if (curthread->specific[key].data != NULL) { 130107849Salfred /* 13126819Ssef * This can happen if the key is 13211397Sswallace * deleted via pthread_key_delete 13311397Sswallace * without first setting the value to 13411397Sswallace * NULL in all threads. POSIX says 13583366Sjulian * that the destructor is not invoked 13611397Sswallace * in this case. 1373584Ssos */ 1383584Ssos curthread->specific[key].data = NULL; 139107849Salfred curthread->specific_data_count--; 140107849Salfred } 1413584Ssos 142167086Sjhb /* 1433584Ssos * If there is a destructor, call it with the 1443584Ssos * key table entry unlocked. 1453584Ssos */ 14611397Sswallace if (destructor != NULL) { 14783366Sjulian THR_LOCK_RELEASE(curthread, &_keytable_lock); 1483584Ssos destructor(__DECONST(void *, data)); 1493584Ssos THR_LOCK_ACQUIRE(curthread, &_keytable_lock); 1503584Ssos } 1513584Ssos } 1523584Ssos } 1533584Ssos THR_LOCK_RELEASE(curthread, &_keytable_lock); 1543584Ssos munmap(curthread->specific, PTHREAD_KEYS_MAX * sizeof(struct 1553584Ssos pthread_specific_elem)); 1563584Ssos curthread->specific = NULL; 1573584Ssos if (curthread->specific_data_count > 0) { 1583584Ssos stderr_debug("Thread %p has exited with leftover " 1593584Ssos "thread-specific data after %d destructor iterations\n", 1603584Ssos curthread, PTHREAD_DESTRUCTOR_ITERATIONS); 1613584Ssos } 1623584Ssos} 16311397Sswallace 1643584Ssosint 16541514Sarchie_pthread_setspecific(pthread_key_t userkey, const void *value) 16641514Sarchie{ 16791393Srobert struct pthread *pthread; 16891388Srobert void *tmp; 16941514Sarchie pthread_key_t key; 17041514Sarchie 17141514Sarchie key = userkey - 1; 17241514Sarchie if ((unsigned int)key >= PTHREAD_KEYS_MAX || 17341514Sarchie !_thread_keytable[key].allocated) 17441514Sarchie return (EINVAL); 17541514Sarchie 17641514Sarchie pthread = _get_curthread(); 17741514Sarchie if (pthread->specific == NULL) { 17841514Sarchie tmp = mmap(NULL, PTHREAD_KEYS_MAX * 17941514Sarchie sizeof(struct pthread_specific_elem), 18041514Sarchie PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 1813584Ssos if (tmp == MAP_FAILED) 1823584Ssos return (ENOMEM); 1833584Ssos pthread->specific = tmp; 18438354Sbde } 18538354Sbde if (pthread->specific[key].data == NULL) { 1863584Ssos if (value != NULL) 1873584Ssos pthread->specific_data_count++; 1883584Ssos } else if (value == NULL) 1893584Ssos pthread->specific_data_count--; 19083366Sjulian pthread->specific[key].data = value; 1913584Ssos pthread->specific[key].seqno = _thread_keytable[key].seqno; 19211397Sswallace return (0); 19383366Sjulian} 19411397Sswallace 1953584Ssosvoid * 19614885Sswallace_pthread_getspecific(pthread_key_t userkey) 19714885Sswallace{ 19883366Sjulian struct pthread *pthread; 19914885Sswallace const void *data; 200141488Sjhb pthread_key_t key; 201141488Sjhb 20214885Sswallace /* Check if there is specific data. */ 203141488Sjhb key = userkey - 1; 204141488Sjhb if ((unsigned int)key >= PTHREAD_KEYS_MAX) 205141488Sjhb return (NULL); 206141488Sjhb 207141488Sjhb pthread = _get_curthread(); 208141488Sjhb /* Check if this key has been used before. */ 209141488Sjhb if (_thread_keytable[key].allocated && pthread->specific != NULL && 21014885Sswallace pthread->specific[key].seqno == _thread_keytable[key].seqno) { 211141488Sjhb /* Return the value: */ 212155401Sjhb data = pthread->specific[key].data; 213141488Sjhb } else { 214141488Sjhb /* 21514885Sswallace * This key has not been used before, so return NULL 216 * instead. 217 */ 218 data = NULL; 219 } 220 return (__DECONST(void *, data)); 221} 222 223void 224_thr_tsd_unload(struct dl_phdr_info *phdr_info) 225{ 226 struct pthread *curthread; 227 void (*destructor)(void *); 228 int key; 229 230 curthread = _get_curthread(); 231 THR_LOCK_ACQUIRE(curthread, &_keytable_lock); 232 for (key = 0; key < PTHREAD_KEYS_MAX; key++) { 233 if (!_thread_keytable[key].allocated) 234 continue; 235 destructor = _thread_keytable[key].destructor; 236 if (destructor == NULL) 237 continue; 238 if (__elf_phdr_match_addr(phdr_info, destructor)) 239 _thread_keytable[key].destructor = NULL; 240 } 241 THR_LOCK_RELEASE(curthread, &_keytable_lock); 242} 243