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