thr_spec.c revision 50476
1/*
2 * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by John Birrell.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * $FreeBSD: head/lib/libkse/thread/thr_spec.c 50476 1999-08-28 00:22:10Z peter $
33 */
34#include <signal.h>
35#include <stdlib.h>
36#include <string.h>
37#include <errno.h>
38#ifdef _THREAD_SAFE
39#include <pthread.h>
40#include "pthread_private.h"
41
42/* Static variables: */
43static	struct pthread_key key_table[PTHREAD_KEYS_MAX];
44
45int
46pthread_key_create(pthread_key_t * key, void (*destructor) (void *))
47{
48	for ((*key) = 0; (*key) < PTHREAD_KEYS_MAX; (*key)++) {
49		/* Lock the key table entry: */
50		_SPINLOCK(&key_table[*key].lock);
51
52		if (key_table[(*key)].allocated == 0) {
53			key_table[(*key)].allocated = 1;
54			key_table[(*key)].destructor = destructor;
55
56			/* Unlock the key table entry: */
57			_SPINUNLOCK(&key_table[*key].lock);
58			return (0);
59		}
60
61		/* Unlock the key table entry: */
62		_SPINUNLOCK(&key_table[*key].lock);
63	}
64	return (EAGAIN);
65}
66
67int
68pthread_key_delete(pthread_key_t key)
69{
70	int ret = 0;
71
72	if (key < PTHREAD_KEYS_MAX) {
73		/* Lock the key table entry: */
74		_SPINLOCK(&key_table[key].lock);
75
76		if (key_table[key].allocated)
77			key_table[key].allocated = 0;
78		else
79			ret = EINVAL;
80
81		/* Unlock the key table entry: */
82		_SPINUNLOCK(&key_table[key].lock);
83	} else
84		ret = EINVAL;
85	return (ret);
86}
87
88void
89_thread_cleanupspecific(void)
90{
91	void           *data;
92	int             key;
93	int             itr;
94	void		(*destructor)( void *);
95
96	for (itr = 0; itr < PTHREAD_DESTRUCTOR_ITERATIONS; itr++) {
97		for (key = 0; key < PTHREAD_KEYS_MAX; key++) {
98			if (_thread_run->specific_data_count) {
99				/* Lock the key table entry: */
100				_SPINLOCK(&key_table[key].lock);
101				destructor = NULL;
102
103				if (key_table[key].allocated) {
104					if (_thread_run->specific_data[key]) {
105						data = (void *) _thread_run->specific_data[key];
106						_thread_run->specific_data[key] = NULL;
107						_thread_run->specific_data_count--;
108						destructor = key_table[key].destructor;
109					}
110				}
111
112				/* Unlock the key table entry: */
113				_SPINUNLOCK(&key_table[key].lock);
114
115				/*
116				 * If there is a destructore, call it
117				 * with the key table entry unlocked:
118				 */
119				if (destructor)
120					destructor(data);
121			} else {
122				free(_thread_run->specific_data);
123				_thread_run->specific_data = NULL;
124				return;
125			}
126		}
127	}
128	free(_thread_run->specific_data);
129	_thread_run->specific_data = NULL;
130}
131
132static inline const void **
133pthread_key_allocate_data(void)
134{
135	const void    **new_data;
136	if ((new_data = (const void **) malloc(sizeof(void *) * PTHREAD_KEYS_MAX)) != NULL) {
137		memset((void *) new_data, 0, sizeof(void *) * PTHREAD_KEYS_MAX);
138	}
139	return (new_data);
140}
141
142int
143pthread_setspecific(pthread_key_t key, const void *value)
144{
145	pthread_t       pthread;
146	int             ret = 0;
147
148	/* Point to the running thread: */
149	pthread = _thread_run;
150
151	if ((pthread->specific_data) ||
152	    (pthread->specific_data = pthread_key_allocate_data())) {
153		if (key < PTHREAD_KEYS_MAX) {
154			if (key_table[key].allocated) {
155				if (pthread->specific_data[key] == NULL) {
156					if (value != NULL)
157						pthread->specific_data_count++;
158				} else {
159					if (value == NULL)
160						pthread->specific_data_count--;
161				}
162				pthread->specific_data[key] = value;
163				ret = 0;
164			} else
165				ret = EINVAL;
166		} else
167			ret = EINVAL;
168	} else
169		ret = ENOMEM;
170	return (ret);
171}
172
173void *
174pthread_getspecific(pthread_key_t key)
175{
176	pthread_t       pthread;
177	void		*data;
178
179	/* Point to the running thread: */
180	pthread = _thread_run;
181
182	/* Check if there is specific data: */
183	if (pthread->specific_data != NULL && key < PTHREAD_KEYS_MAX) {
184		/* Check if this key has been used before: */
185		if (key_table[key].allocated) {
186			/* Return the value: */
187			data = (void *) pthread->specific_data[key];
188		} else {
189			/*
190			 * This key has not been used before, so return NULL
191			 * instead:
192			 */
193			data = NULL;
194		}
195	} else
196		/* No specific data has been created, so just return NULL: */
197		data = NULL;
198	return (data);
199}
200#endif
201