thr_spec.c revision 17706
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		if (key_table[(*key)].count == 0) {
49			key_table[(*key)].count++;
50			key_table[(*key)].destructor = destructor;
51			return (0);
52		}
53	}
54	return (EAGAIN);
55}
56
57int
58pthread_key_delete(pthread_key_t key)
59{
60	int             ret;
61	int             status;
62
63	/* Block signals: */
64	_thread_kern_sig_block(&status);
65
66	if (key < PTHREAD_KEYS_MAX) {
67		switch (key_table[key].count) {
68		case 1:
69			key_table[key].destructor = NULL;
70			key_table[key].count = 0;
71		case 0:
72			ret = 0;
73			break;
74		default:
75			ret = EBUSY;
76		}
77	} else {
78		ret = EINVAL;
79	}
80
81	/* Unblock signals: */
82	_thread_kern_sig_unblock(status);
83	return (ret);
84}
85
86void
87_thread_cleanupspecific(void)
88{
89	void           *data;
90	int             key;
91	int             itr;
92	int             status;
93
94	/* Block signals: */
95	_thread_kern_sig_block(&status);
96
97	for (itr = 0; itr < PTHREAD_DESTRUCTOR_ITERATIONS; itr++) {
98		for (key = 0; key < PTHREAD_KEYS_MAX; key++) {
99			if (_thread_run->specific_data_count) {
100				if (_thread_run->specific_data[key]) {
101					data = (void *) _thread_run->specific_data[key];
102					_thread_run->specific_data[key] = NULL;
103					_thread_run->specific_data_count--;
104					if (key_table[key].destructor) {
105						key_table[key].destructor(data);
106					}
107					key_table[key].count--;
108				}
109			} else {
110				free(_thread_run->specific_data);
111
112				/* Unblock signals: */
113				_thread_kern_sig_unblock(status);
114				return;
115			}
116		}
117	}
118	free(_thread_run->specific_data);
119
120	/* Unblock signals: */
121	_thread_kern_sig_unblock(status);
122}
123
124static inline const void **
125pthread_key_allocate_data(void)
126{
127	const void    **new_data;
128	if ((new_data = (const void **) malloc(sizeof(void *) * PTHREAD_KEYS_MAX)) != NULL) {
129		memset((void *) new_data, 0, sizeof(void *) * PTHREAD_KEYS_MAX);
130	}
131	return (new_data);
132}
133
134int
135pthread_setspecific(pthread_key_t key, const void *value)
136{
137	pthread_t       pthread;
138	int             ret = 0;
139	int             status;
140
141	/* Block signals: */
142	_thread_kern_sig_block(&status);
143
144	/* Point to the running thread: */
145	pthread = _thread_run;
146
147	/*
148	 * Enter a loop for signal handler threads to find the parent thread
149	 * which has the specific data associated with it:
150	 */
151	while (pthread->parent_thread != NULL) {
152		/* Point to the parent thread: */
153		pthread = pthread->parent_thread;
154	}
155
156	if ((pthread->specific_data) || (pthread->specific_data = pthread_key_allocate_data())) {
157		if ((key < PTHREAD_KEYS_MAX) && (key_table)) {
158			if (key_table[key].count) {
159				if (pthread->specific_data[key] == NULL) {
160					if (value != NULL) {
161						pthread->specific_data_count++;
162						key_table[key].count++;
163					}
164				} else {
165					if (value == NULL) {
166						pthread->specific_data_count--;
167						key_table[key].count--;
168					}
169				}
170				pthread->specific_data[key] = value;
171				ret = 0;
172			} else {
173				ret = EINVAL;
174			}
175		} else {
176			ret = EINVAL;
177		}
178	} else {
179		ret = ENOMEM;
180	}
181
182	/* Unblock signals: */
183	_thread_kern_sig_unblock(status);
184	return (ret);
185}
186
187int
188pthread_getspecific(pthread_key_t key, void **p_data)
189{
190	pthread_t       pthread;
191	int             rval = 0;
192	int             status;
193
194	/* Block signals: */
195	_thread_kern_sig_block(&status);
196
197	/* Point to the running thread: */
198	pthread = _thread_run;
199
200	/*
201	 * Enter a loop for signal handler threads to find the parent thread
202	 * which has the specific data associated with it:
203	 */
204	while (pthread->parent_thread != NULL) {
205		/* Point to the parent thread: */
206		pthread = pthread->parent_thread;
207	}
208
209	/* Check for errors: */
210	if (pthread == NULL || p_data == NULL) {
211		/* Return an invalid argument error: */
212		_thread_seterrno(_thread_run, EINVAL);
213		rval = -1;
214	}
215	/* Check if there is specific data: */
216	else if (pthread->specific_data != NULL && (key < PTHREAD_KEYS_MAX) && (key_table)) {
217		/* Check if this key has been used before: */
218		if (key_table[key].count) {
219			/* Return the value: */
220			*p_data = (void *) pthread->specific_data[key];
221		} else {
222			/*
223			 * This key has not been used before, so return NULL
224			 * instead:
225			 */
226			*p_data = NULL;
227		}
228	} else {
229		/* No specific data has been created, so just return NULL: */
230		*p_data = NULL;
231	}
232
233	/* Unblock signals: */
234	_thread_kern_sig_unblock(status);
235	return (rval);
236}
237#endif
238