thr_spec.c revision 35509
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];
43static	long	key_table_lock	= 0;
44
45int
46pthread_key_create(pthread_key_t * key, void (*destructor) (void *))
47{
48	/* Lock the key table: */
49	_spinlock(&key_table_lock);
50
51	for ((*key) = 0; (*key) < PTHREAD_KEYS_MAX; (*key)++) {
52		if (key_table[(*key)].count == 0) {
53			key_table[(*key)].count++;
54			key_table[(*key)].destructor = destructor;
55
56			/* Unlock the key table: */
57			_atomic_unlock(&key_table_lock);
58			return (0);
59		}
60	}
61
62	/* Unlock the key table: */
63	_atomic_unlock(&key_table_lock);
64	return (EAGAIN);
65}
66
67int
68pthread_key_delete(pthread_key_t key)
69{
70	int ret;
71
72	/* Lock the key table: */
73	_spinlock(&key_table_lock);
74
75	if (key < PTHREAD_KEYS_MAX) {
76		switch (key_table[key].count) {
77		case 1:
78			key_table[key].destructor = NULL;
79			key_table[key].count = 0;
80		case 0:
81			ret = 0;
82			break;
83		default:
84			ret = EBUSY;
85		}
86	} else
87		ret = EINVAL;
88
89	/* Unlock the key table: */
90	_atomic_unlock(&key_table_lock);
91	return (ret);
92}
93
94void
95_thread_cleanupspecific(void)
96{
97	void           *data;
98	int             key;
99	int             itr;
100
101	for (itr = 0; itr < PTHREAD_DESTRUCTOR_ITERATIONS; itr++) {
102		for (key = 0; key < PTHREAD_KEYS_MAX; key++) {
103			if (_thread_run->specific_data_count) {
104				/* Lock the key table entry: */
105				_spinlock(&key_table[key].access_lock);
106
107				if (_thread_run->specific_data[key]) {
108					data = (void *) _thread_run->specific_data[key];
109					_thread_run->specific_data[key] = NULL;
110					_thread_run->specific_data_count--;
111					if (key_table[key].destructor) {
112						key_table[key].destructor(data);
113					}
114					key_table[key].count--;
115				}
116
117				/* Unlock the key table entry: */
118				_atomic_unlock(&key_table[key].access_lock);
119			} else {
120				free(_thread_run->specific_data);
121				return;
122			}
123		}
124	}
125	free(_thread_run->specific_data);
126}
127
128static inline const void **
129pthread_key_allocate_data(void)
130{
131	const void    **new_data;
132	if ((new_data = (const void **) malloc(sizeof(void *) * PTHREAD_KEYS_MAX)) != NULL) {
133		memset((void *) new_data, 0, sizeof(void *) * PTHREAD_KEYS_MAX);
134	}
135	return (new_data);
136}
137
138int
139pthread_setspecific(pthread_key_t key, const void *value)
140{
141	pthread_t       pthread;
142	int             ret = 0;
143
144	/* Point to the running thread: */
145	pthread = _thread_run;
146
147	if ((pthread->specific_data) ||
148	    (pthread->specific_data = pthread_key_allocate_data())) {
149		if ((key < PTHREAD_KEYS_MAX) && (key_table)) {
150			/* Lock the key table entry: */
151			_spinlock(&key_table[key].access_lock);
152
153			if (key_table[key].count) {
154				if (pthread->specific_data[key] == NULL) {
155					if (value != NULL) {
156						pthread->specific_data_count++;
157						key_table[key].count++;
158					}
159				} else {
160					if (value == NULL) {
161						pthread->specific_data_count--;
162						key_table[key].count--;
163					}
164				}
165				pthread->specific_data[key] = value;
166				ret = 0;
167			} else
168				ret = EINVAL;
169
170			/* Unlock the key table entry: */
171			_atomic_unlock(&key_table[key].access_lock);
172
173		} else
174			ret = EINVAL;
175	} else
176		ret = ENOMEM;
177	return (ret);
178}
179
180void *
181pthread_getspecific(pthread_key_t key)
182{
183	pthread_t       pthread;
184	void		*data;
185
186	/* Point to the running thread: */
187	pthread = _thread_run;
188
189	/* Check if there is specific data: */
190	if (pthread->specific_data != NULL &&
191	    (key < PTHREAD_KEYS_MAX) && (key_table)) {
192		/* Lock the key table entry: */
193		_spinlock(&key_table[key].access_lock);
194
195		/* Check if this key has been used before: */
196		if (key_table[key].count) {
197			/* Return the value: */
198			data = (void *) pthread->specific_data[key];
199		} else {
200			/*
201			 * This key has not been used before, so return NULL
202			 * instead:
203			 */
204			data = NULL;
205		}
206
207		/* Unlock the key table entry: */
208		_atomic_unlock(&key_table[key].access_lock);
209	} else
210		/* No specific data has been created, so just return NULL: */
211		data = NULL;
212	return (data);
213}
214#endif
215