thr_spec.c revision 36830
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 REGENTS 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 */
33#include <signal.h>
34#include <stdlib.h>
35#include <string.h>
36#include <errno.h>
37#ifdef _THREAD_SAFE
38#include <pthread.h>
39#include "pthread_private.h"
40
41/* Static variables: */
42static	struct pthread_key key_table[PTHREAD_KEYS_MAX];
43
44int
45pthread_key_create(pthread_key_t * key, void (*destructor) (void *))
46{
47	for ((*key) = 0; (*key) < PTHREAD_KEYS_MAX; (*key)++) {
48		/* Lock the key table entry: */
49		_SPINLOCK(&key_table[*key].lock);
50
51		if (key_table[(*key)].allocated == 0) {
52			key_table[(*key)].allocated = 1;
53			key_table[(*key)].destructor = destructor;
54
55			/* Unlock the key table entry: */
56			_SPINUNLOCK(&key_table[*key].lock);
57			return (0);
58		}
59
60		/* Unlock the key table entry: */
61		_SPINUNLOCK(&key_table[*key].lock);
62	}
63	return (EAGAIN);
64}
65
66int
67pthread_key_delete(pthread_key_t key)
68{
69	int ret = 0;
70
71	if (key < PTHREAD_KEYS_MAX) {
72		/* Lock the key table entry: */
73		_SPINLOCK(&key_table[key].lock);
74
75		if (key_table[key].allocated)
76			key_table[key].allocated = 0;
77		else
78			ret = EINVAL;
79
80		/* Unlock the key table entry: */
81		_SPINUNLOCK(&key_table[key].lock);
82	} else
83		ret = EINVAL;
84	return (ret);
85}
86
87void
88_thread_cleanupspecific(void)
89{
90	void           *data;
91	int             key;
92	int             itr;
93	void		(*destructor)( void *);
94
95	for (itr = 0; itr < PTHREAD_DESTRUCTOR_ITERATIONS; itr++) {
96		for (key = 0; key < PTHREAD_KEYS_MAX; key++) {
97			if (_thread_run->specific_data_count) {
98				/* Lock the key table entry: */
99				_SPINLOCK(&key_table[key].lock);
100				destructor = NULL;
101
102				if (key_table[key].allocated) {
103					if (_thread_run->specific_data[key]) {
104						data = (void *) _thread_run->specific_data[key];
105						_thread_run->specific_data[key] = NULL;
106						_thread_run->specific_data_count--;
107						destructor = key_table[key].destructor;
108					}
109				}
110
111				/* Unlock the key table entry: */
112				_SPINUNLOCK(&key_table[key].lock);
113
114				/*
115				 * If there is a destructore, call it
116				 * with the key table entry unlocked:
117				 */
118				if (destructor)
119					destructor(data);
120			} else {
121				free(_thread_run->specific_data);
122				return;
123			}
124		}
125	}
126	free(_thread_run->specific_data);
127}
128
129static inline const void **
130pthread_key_allocate_data(void)
131{
132	const void    **new_data;
133	if ((new_data = (const void **) malloc(sizeof(void *) * PTHREAD_KEYS_MAX)) != NULL) {
134		memset((void *) new_data, 0, sizeof(void *) * PTHREAD_KEYS_MAX);
135	}
136	return (new_data);
137}
138
139int
140pthread_setspecific(pthread_key_t key, const void *value)
141{
142	pthread_t       pthread;
143	int             ret = 0;
144
145	/* Point to the running thread: */
146	pthread = _thread_run;
147
148	if ((pthread->specific_data) ||
149	    (pthread->specific_data = pthread_key_allocate_data())) {
150		if (key < PTHREAD_KEYS_MAX) {
151			if (key_table[key].allocated) {
152				if (pthread->specific_data[key] == NULL) {
153					if (value != NULL)
154						pthread->specific_data_count++;
155				} else {
156					if (value == NULL)
157						pthread->specific_data_count--;
158				}
159				pthread->specific_data[key] = value;
160				ret = 0;
161			} else
162				ret = EINVAL;
163		} else
164			ret = EINVAL;
165	} else
166		ret = ENOMEM;
167	return (ret);
168}
169
170void *
171pthread_getspecific(pthread_key_t key)
172{
173	pthread_t       pthread;
174	void		*data;
175
176	/* Point to the running thread: */
177	pthread = _thread_run;
178
179	/* Check if there is specific data: */
180	if (pthread->specific_data != NULL && key < PTHREAD_KEYS_MAX) {
181		/* Check if this key has been used before: */
182		if (key_table[key].allocated) {
183			/* Return the value: */
184			data = (void *) pthread->specific_data[key];
185		} else {
186			/*
187			 * This key has not been used before, so return NULL
188			 * instead:
189			 */
190			data = NULL;
191		}
192	} else
193		/* No specific data has been created, so just return NULL: */
194		data = NULL;
195	return (data);
196}
197#endif
198