113546Sjulian/*
213546Sjulian * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
313546Sjulian * All rights reserved.
413546Sjulian *
513546Sjulian * Redistribution and use in source and binary forms, with or without
613546Sjulian * modification, are permitted provided that the following conditions
713546Sjulian * are met:
813546Sjulian * 1. Redistributions of source code must retain the above copyright
913546Sjulian *    notice, this list of conditions and the following disclaimer.
1013546Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1113546Sjulian *    notice, this list of conditions and the following disclaimer in the
1213546Sjulian *    documentation and/or other materials provided with the distribution.
13165967Simp * 3. Neither the name of the author nor the names of any co-contributors
1413546Sjulian *    may be used to endorse or promote products derived from this software
1513546Sjulian *    without specific prior written permission.
1613546Sjulian *
1713546Sjulian * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
1813546Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1913546Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2049439Sdeischen * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2113546Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2213546Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2313546Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2413546Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2513546Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2613546Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2713546Sjulian * SUCH DAMAGE.
2813546Sjulian *
2950476Speter * $FreeBSD: releng/10.3/lib/libkse/thread/thr_spec.c 174689 2007-12-16 23:29:57Z deischen $
3013546Sjulian */
31174112Sdeischen
32174112Sdeischen#include "namespace.h"
3313546Sjulian#include <signal.h>
3413546Sjulian#include <stdlib.h>
3513546Sjulian#include <string.h>
3613546Sjulian#include <errno.h>
3713546Sjulian#include <pthread.h>
38174112Sdeischen#include "un-namespace.h"
39103388Smini#include "thr_private.h"
4013546Sjulian
41156611Sdeischen
42132120Sdavidxustruct pthread_key _thread_keytable[PTHREAD_KEYS_MAX];
4313546Sjulian
4475369Sdeischen__weak_reference(_pthread_key_create, pthread_key_create);
4575369Sdeischen__weak_reference(_pthread_key_delete, pthread_key_delete);
4675369Sdeischen__weak_reference(_pthread_getspecific, pthread_getspecific);
4775369Sdeischen__weak_reference(_pthread_setspecific, pthread_setspecific);
4871581Sdeischen
4971581Sdeischen
5013546Sjulianint
51113658Sdeischen_pthread_key_create(pthread_key_t *key, void (*destructor) (void *))
5213546Sjulian{
53173921Sdavidxu	struct pthread *curthread;
54118984Sdavidxu	int i;
55113658Sdeischen
56173921Sdavidxu	if (_thr_initial == NULL)
57173921Sdavidxu		_libpthread_init(NULL);
58173921Sdavidxu	curthread = _get_curthread();
59173921Sdavidxu
60113658Sdeischen	/* Lock the key table: */
61113658Sdeischen	THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
62118984Sdavidxu	for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
6335509Sjb
64132120Sdavidxu		if (_thread_keytable[i].allocated == 0) {
65132120Sdavidxu			_thread_keytable[i].allocated = 1;
66132120Sdavidxu			_thread_keytable[i].destructor = destructor;
67132120Sdavidxu			_thread_keytable[i].seqno++;
6835509Sjb
69113658Sdeischen			/* Unlock the key table: */
70113658Sdeischen			THR_LOCK_RELEASE(curthread, &_keytable_lock);
71118984Sdavidxu			*key = i;
7213546Sjulian			return (0);
7313546Sjulian		}
7436697Sjb
7513546Sjulian	}
76113658Sdeischen	/* Unlock the key table: */
77113658Sdeischen	THR_LOCK_RELEASE(curthread, &_keytable_lock);
7813546Sjulian	return (EAGAIN);
7913546Sjulian}
8013546Sjulian
8113546Sjulianint
8271581Sdeischen_pthread_key_delete(pthread_key_t key)
8313546Sjulian{
84173921Sdavidxu	struct pthread *curthread = _get_curthread();
8536697Sjb	int ret = 0;
8613546Sjulian
87118984Sdavidxu	if ((unsigned int)key < PTHREAD_KEYS_MAX) {
88113658Sdeischen		/* Lock the key table: */
89113658Sdeischen		THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
9013546Sjulian
91132120Sdavidxu		if (_thread_keytable[key].allocated)
92132120Sdavidxu			_thread_keytable[key].allocated = 0;
9336697Sjb		else
9436697Sjb			ret = EINVAL;
9536697Sjb
96113658Sdeischen		/* Unlock the key table: */
97113658Sdeischen		THR_LOCK_RELEASE(curthread, &_keytable_lock);
9835509Sjb	} else
9913546Sjulian		ret = EINVAL;
10013546Sjulian	return (ret);
10113546Sjulian}
10213546Sjulian
10313546Sjulianvoid
10413546Sjulian_thread_cleanupspecific(void)
10513546Sjulian{
10671581Sdeischen	struct pthread	*curthread = _get_curthread();
107174112Sdeischen	const_key_destructor_t destructor;
108174112Sdeischen	const void	*data = NULL;
10971581Sdeischen	int		key;
110119154Sdeischen	int		i;
11113546Sjulian
112119154Sdeischen	if (curthread->specific == NULL)
113119154Sdeischen		return;
114119154Sdeischen
115119154Sdeischen	/* Lock the key table: */
116119154Sdeischen	THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
117119154Sdeischen	for (i = 0; (i < PTHREAD_DESTRUCTOR_ITERATIONS) &&
118119154Sdeischen	    (curthread->specific_data_count > 0); i++) {
119113658Sdeischen		for (key = 0; (key < PTHREAD_KEYS_MAX) &&
120113658Sdeischen		    (curthread->specific_data_count > 0); key++) {
121113658Sdeischen			destructor = NULL;
12235509Sjb
123132120Sdavidxu			if (_thread_keytable[key].allocated &&
124113658Sdeischen			    (curthread->specific[key].data != NULL)) {
125113658Sdeischen				if (curthread->specific[key].seqno ==
126132120Sdavidxu				    _thread_keytable[key].seqno) {
127174112Sdeischen					data = curthread->specific[key].data;
128174112Sdeischen					destructor = (const_key_destructor_t)
129174112Sdeischen					    _thread_keytable[key].destructor;
13013546Sjulian				}
131113658Sdeischen				curthread->specific[key].data = NULL;
132113658Sdeischen				curthread->specific_data_count--;
133113658Sdeischen			}
13435509Sjb
135113658Sdeischen			/*
136113658Sdeischen			 * If there is a destructore, call it
137113658Sdeischen			 * with the key table entry unlocked:
138113658Sdeischen			 */
139113658Sdeischen			if (destructor != NULL) {
14036830Sjb				/*
141113658Sdeischen				 * Don't hold the lock while calling the
142113658Sdeischen				 * destructor:
14336830Sjb				 */
144113658Sdeischen				THR_LOCK_RELEASE(curthread, &_keytable_lock);
145113658Sdeischen				destructor(data);
146113658Sdeischen				THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
14713546Sjulian			}
14813546Sjulian		}
14992730Sdeischen	}
150119154Sdeischen	THR_LOCK_RELEASE(curthread, &_keytable_lock);
151119154Sdeischen	free(curthread->specific);
152119154Sdeischen	curthread->specific = NULL;
153119154Sdeischen	if (curthread->specific_data_count > 0)
154119154Sdeischen		stderr_debug("Thread %p has exited with leftover "
155119154Sdeischen		    "thread-specific data after %d destructor iterations\n",
156119154Sdeischen		    curthread, PTHREAD_DESTRUCTOR_ITERATIONS);
15713546Sjulian}
15813546Sjulian
15992730Sdeischenstatic inline struct pthread_specific_elem *
16013546Sjulianpthread_key_allocate_data(void)
16113546Sjulian{
16292730Sdeischen	struct pthread_specific_elem *new_data;
16392730Sdeischen
16492730Sdeischen	new_data = (struct pthread_specific_elem *)
16592730Sdeischen	    malloc(sizeof(struct pthread_specific_elem) * PTHREAD_KEYS_MAX);
16692730Sdeischen	if (new_data != NULL) {
16792730Sdeischen		memset((void *) new_data, 0,
16892730Sdeischen		    sizeof(struct pthread_specific_elem) * PTHREAD_KEYS_MAX);
16913546Sjulian	}
17013546Sjulian	return (new_data);
17113546Sjulian}
17213546Sjulian
17313546Sjulianint
17471581Sdeischen_pthread_setspecific(pthread_key_t key, const void *value)
17513546Sjulian{
17671581Sdeischen	struct pthread	*pthread;
17771581Sdeischen	int		ret = 0;
17813546Sjulian
17913546Sjulian	/* Point to the running thread: */
18071581Sdeischen	pthread = _get_curthread();
18113546Sjulian
18292730Sdeischen	if ((pthread->specific) ||
18392730Sdeischen	    (pthread->specific = pthread_key_allocate_data())) {
184118984Sdavidxu		if ((unsigned int)key < PTHREAD_KEYS_MAX) {
185132120Sdavidxu			if (_thread_keytable[key].allocated) {
18692730Sdeischen				if (pthread->specific[key].data == NULL) {
18736697Sjb					if (value != NULL)
18813546Sjulian						pthread->specific_data_count++;
189119154Sdeischen				} else if (value == NULL)
190119154Sdeischen					pthread->specific_data_count--;
191174112Sdeischen				*(const void **)&pthread->specific[key].data = value;
19292730Sdeischen				pthread->specific[key].seqno =
193132120Sdavidxu				    _thread_keytable[key].seqno;
19413546Sjulian				ret = 0;
19535509Sjb			} else
19613546Sjulian				ret = EINVAL;
19735509Sjb		} else
19813546Sjulian			ret = EINVAL;
19935509Sjb	} else
20013546Sjulian		ret = ENOMEM;
20113546Sjulian	return (ret);
20213546Sjulian}
20313546Sjulian
20419630Shsuvoid *
20571581Sdeischen_pthread_getspecific(pthread_key_t key)
20613546Sjulian{
20771581Sdeischen	struct pthread	*pthread;
20819630Shsu	void		*data;
20913546Sjulian
21013546Sjulian	/* Point to the running thread: */
21171581Sdeischen	pthread = _get_curthread();
21213546Sjulian
21335509Sjb	/* Check if there is specific data: */
214118984Sdavidxu	if (pthread->specific != NULL && (unsigned int)key < PTHREAD_KEYS_MAX) {
21513546Sjulian		/* Check if this key has been used before: */
216132120Sdavidxu		if (_thread_keytable[key].allocated &&
217132120Sdavidxu		    (pthread->specific[key].seqno == _thread_keytable[key].seqno)) {
21813546Sjulian			/* Return the value: */
219174112Sdeischen			data = pthread->specific[key].data;
22013546Sjulian		} else {
22113546Sjulian			/*
22213546Sjulian			 * This key has not been used before, so return NULL
22313546Sjulian			 * instead:
22413546Sjulian			 */
22519630Shsu			data = NULL;
22613546Sjulian		}
22735509Sjb	} else
22813546Sjulian		/* No specific data has been created, so just return NULL: */
22919630Shsu		data = NULL;
23019630Shsu	return (data);
23113546Sjulian}
232