View | Details | Raw Unified | Return to bug 200138 | Differences between
and this patch

Collapse All | Expand All

(-)b/lib/libthr/thread/thr_spec.c (-110 / +91 lines)
Lines 30-35 Link Here
30
 */
30
 */
31
31
32
#include "namespace.h"
32
#include "namespace.h"
33
#include <sys/mman.h>
33
#include <signal.h>
34
#include <signal.h>
34
#include <stdlib.h>
35
#include <stdlib.h>
35
#include <string.h>
36
#include <string.h>
Lines 40-46 Link Here
40
41
41
#include "thr_private.h"
42
#include "thr_private.h"
42
43
43
/* Static variables: */
44
struct pthread_key _thread_keytable[PTHREAD_KEYS_MAX];
44
struct pthread_key _thread_keytable[PTHREAD_KEYS_MAX];
45
45
46
__weak_reference(_pthread_key_create, pthread_key_create);
46
__weak_reference(_pthread_key_create, pthread_key_create);
Lines 50-56 __weak_reference(_pthread_setspecific, pthread_setspecific); Link Here
50
50
51
51
52
int
52
int
53
_pthread_key_create(pthread_key_t *key, void (*destructor) (void *))
53
_pthread_key_create(pthread_key_t *key, void (*destructor)(void *))
54
{
54
{
55
	struct pthread *curthread;
55
	struct pthread *curthread;
56
	int i;
56
	int i;
Lines 59-65 _pthread_key_create(pthread_key_t *key, void (*destructor) (void *)) Link Here
59
59
60
	curthread = _get_curthread();
60
	curthread = _get_curthread();
61
61
62
	/* Lock the key table: */
63
	THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
62
	THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
64
	for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
63
	for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
65
64
Lines 68-81 _pthread_key_create(pthread_key_t *key, void (*destructor) (void *)) Link Here
68
			_thread_keytable[i].destructor = destructor;
67
			_thread_keytable[i].destructor = destructor;
69
			_thread_keytable[i].seqno++;
68
			_thread_keytable[i].seqno++;
70
69
71
			/* Unlock the key table: */
72
			THR_LOCK_RELEASE(curthread, &_keytable_lock);
70
			THR_LOCK_RELEASE(curthread, &_keytable_lock);
73
			*key = i + 1;
71
			*key = i + 1;
74
			return (0);
72
			return (0);
75
		}
73
		}
76
74
77
	}
75
	}
78
	/* Unlock the key table: */
79
	THR_LOCK_RELEASE(curthread, &_keytable_lock);
76
	THR_LOCK_RELEASE(curthread, &_keytable_lock);
80
	return (EAGAIN);
77
	return (EAGAIN);
81
}
78
}
Lines 83-126 _pthread_key_create(pthread_key_t *key, void (*destructor) (void *)) Link Here
83
int
80
int
84
_pthread_key_delete(pthread_key_t userkey)
81
_pthread_key_delete(pthread_key_t userkey)
85
{
82
{
86
	struct pthread *curthread = _get_curthread();
83
	struct pthread *curthread;
87
	int key = userkey - 1;
84
	int key, ret;
88
	int ret = 0;
89
90
	if ((unsigned int)key < PTHREAD_KEYS_MAX) {
91
		/* Lock the key table: */
92
		THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
93
94
		if (_thread_keytable[key].allocated)
95
			_thread_keytable[key].allocated = 0;
96
		else
97
			ret = EINVAL;
98
85
99
		/* Unlock the key table: */
86
	key = userkey - 1;
100
		THR_LOCK_RELEASE(curthread, &_keytable_lock);
87
	if ((unsigned int)key >= PTHREAD_KEYS_MAX)
101
	} else
88
		return (EINVAL);
89
	curthread = _get_curthread();
90
	THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
91
	if (_thread_keytable[key].allocated) {
92
		_thread_keytable[key].allocated = 0;
93
		ret = 0;
94
	} else {
102
		ret = EINVAL;
95
		ret = EINVAL;
96
	}
97
	THR_LOCK_RELEASE(curthread, &_keytable_lock);
103
	return (ret);
98
	return (ret);
104
}
99
}
105
100
106
void 
101
void 
107
_thread_cleanupspecific(void)
102
_thread_cleanupspecific(void)
108
{
103
{
109
	struct pthread	*curthread = _get_curthread();
104
	struct pthread *curthread;
110
	void		(*destructor)( void *);
105
	void (*destructor)(void *);
111
	const void	*data = NULL;
106
	const void *data;
112
	int		key;
107
	int i, key;
113
	int		i;
114
108
109
	curthread = _get_curthread();
115
	if (curthread->specific == NULL)
110
	if (curthread->specific == NULL)
116
		return;
111
		return;
117
118
	/* Lock the key table: */
119
	THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
112
	THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
120
	for (i = 0; (i < PTHREAD_DESTRUCTOR_ITERATIONS) &&
113
	for (i = 0; i < PTHREAD_DESTRUCTOR_ITERATIONS &&
121
	    (curthread->specific_data_count > 0); i++) {
114
	    curthread->specific_data_count > 0; i++) {
122
		for (key = 0; (key < PTHREAD_KEYS_MAX) &&
115
		for (key = 0; key < PTHREAD_KEYS_MAX &&
123
		    (curthread->specific_data_count > 0); key++) {
116
		    curthread->specific_data_count > 0; key++) {
124
			destructor = NULL;
117
			destructor = NULL;
125
118
126
			if (_thread_keytable[key].allocated &&
119
			if (_thread_keytable[key].allocated &&
Lines 128-158 _thread_cleanupspecific(void) Link Here
128
				if (curthread->specific[key].seqno ==
121
				if (curthread->specific[key].seqno ==
129
				    _thread_keytable[key].seqno) {
122
				    _thread_keytable[key].seqno) {
130
					data = curthread->specific[key].data;
123
					data = curthread->specific[key].data;
131
					destructor = _thread_keytable[key].destructor;
124
					destructor = _thread_keytable[key].
125
					    destructor;
132
				}
126
				}
133
				curthread->specific[key].data = NULL;
127
				curthread->specific[key].data = NULL;
134
				curthread->specific_data_count--;
128
				curthread->specific_data_count--;
135
			}
129
			} else if (curthread->specific[key].data != NULL) {
136
			else if (curthread->specific[key].data != NULL) {
137
				/* 
130
				/* 
138
				 * This can happen if the key is deleted via
131
				 * This can happen if the key is
139
				 * pthread_key_delete without first setting the value
132
				 * deleted via pthread_key_delete
140
				 * to NULL in all threads.  POSIX says that the
133
				 * without first setting the value to
141
				 * destructor is not invoked in this case.
134
				 * NULL in all threads.  POSIX says
135
				 * that the destructor is not invoked
136
				 * in this case.
142
				 */
137
				 */
143
				curthread->specific[key].data = NULL;
138
				curthread->specific[key].data = NULL;
144
				curthread->specific_data_count--;
139
				curthread->specific_data_count--;
145
			}
140
			}
146
141
147
			/*
142
			/*
148
			 * If there is a destructor, call it
143
			 * If there is a destructor, call it with the
149
			 * with the key table entry unlocked:
144
			 * key table entry unlocked.
150
			 */
145
			 */
151
			if (destructor != NULL) {
146
			if (destructor != NULL) {
152
				/*
153
				 * Don't hold the lock while calling the
154
				 * destructor:
155
				 */
156
				THR_LOCK_RELEASE(curthread, &_keytable_lock);
147
				THR_LOCK_RELEASE(curthread, &_keytable_lock);
157
				destructor(__DECONST(void *, data));
148
				destructor(__DECONST(void *, data));
158
				THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
149
				THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
Lines 160-261 _thread_cleanupspecific(void) Link Here
160
		}
151
		}
161
	}
152
	}
162
	THR_LOCK_RELEASE(curthread, &_keytable_lock);
153
	THR_LOCK_RELEASE(curthread, &_keytable_lock);
163
	free(curthread->specific);
154
	munmap(curthread->specific, PTHREAD_KEYS_MAX * sizeof(struct
155
	    pthread_specific_elem));
164
	curthread->specific = NULL;
156
	curthread->specific = NULL;
165
	if (curthread->specific_data_count > 0)
157
	if (curthread->specific_data_count > 0) {
166
		stderr_debug("Thread %p has exited with leftover "
158
		stderr_debug("Thread %p has exited with leftover "
167
		    "thread-specific data after %d destructor iterations\n",
159
		    "thread-specific data after %d destructor iterations\n",
168
		    curthread, PTHREAD_DESTRUCTOR_ITERATIONS);
160
		    curthread, PTHREAD_DESTRUCTOR_ITERATIONS);
169
}
161
	}
170
171
static inline struct pthread_specific_elem *
172
pthread_key_allocate_data(void)
173
{
174
	struct pthread_specific_elem *new_data;
175
176
	new_data = (struct pthread_specific_elem *)
177
	    calloc(1, sizeof(struct pthread_specific_elem) * PTHREAD_KEYS_MAX);
178
	return (new_data);
179
}
162
}
180
163
181
int 
164
int 
182
_pthread_setspecific(pthread_key_t userkey, const void *value)
165
_pthread_setspecific(pthread_key_t userkey, const void *value)
183
{
166
{
184
	struct pthread	*pthread;
167
	struct pthread *pthread;
185
	pthread_key_t	key = userkey - 1;
168
	void *tmp;
186
	int		ret = 0;
169
	pthread_key_t key;
187
170
188
	/* Point to the running thread: */
171
	key = userkey - 1;
189
	pthread = _get_curthread();
172
	if ((unsigned int)key >= PTHREAD_KEYS_MAX ||
173
	    !_thread_keytable[key].allocated)
174
		return (EINVAL);
190
175
191
	if ((pthread->specific) ||
176
	pthread = _get_curthread();
192
	    (pthread->specific = pthread_key_allocate_data())) {
177
	if (pthread->specific == NULL) {
193
		if ((unsigned int)key < PTHREAD_KEYS_MAX) {
178
		tmp = mmap(NULL, PTHREAD_KEYS_MAX *
194
			if (_thread_keytable[key].allocated) {
179
		    sizeof(struct pthread_specific_elem),
195
				if (pthread->specific[key].data == NULL) {
180
		    PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
196
					if (value != NULL)
181
		if (tmp == MAP_FAILED)
197
						pthread->specific_data_count++;
182
			return (ENOMEM);
198
				} else if (value == NULL)
183
		pthread->specific = tmp;
199
					pthread->specific_data_count--;
184
	}
200
				pthread->specific[key].data = value;
185
	if (pthread->specific[key].data == NULL) {
201
				pthread->specific[key].seqno =
186
		if (value != NULL)
202
				    _thread_keytable[key].seqno;
187
			pthread->specific_data_count++;
203
				ret = 0;
188
	} else if (value == NULL)
204
			} else
189
		pthread->specific_data_count--;
205
				ret = EINVAL;
190
	pthread->specific[key].data = value;
206
		} else
191
	pthread->specific[key].seqno = _thread_keytable[key].seqno;
207
			ret = EINVAL;
192
	return (0);
208
	} else
209
		ret = ENOMEM;
210
	return (ret);
211
}
193
}
212
194
213
void *
195
void *
214
_pthread_getspecific(pthread_key_t userkey)
196
_pthread_getspecific(pthread_key_t userkey)
215
{
197
{
216
	struct pthread	*pthread;
198
	struct pthread *pthread;
217
	pthread_key_t	key = userkey - 1;
199
	const void *data;
218
	const void	*data;
200
	pthread_key_t key;
219
201
220
	/* Point to the running thread: */
202
	/* Check if there is specific data. */
221
	pthread = _get_curthread();
203
	key = userkey - 1;
204
	if ((unsigned int)key >= PTHREAD_KEYS_MAX)
205
		return (NULL);
222
206
223
	/* Check if there is specific data: */
207
	pthread = _get_curthread();
224
	if (pthread->specific != NULL && (unsigned int)key < PTHREAD_KEYS_MAX) {
208
	/* Check if this key has been used before. */
225
		/* Check if this key has been used before: */
209
	if (_thread_keytable[key].allocated && pthread->specific != NULL &&
226
		if (_thread_keytable[key].allocated &&
210
	    pthread->specific[key].seqno == _thread_keytable[key].seqno) {
227
		    (pthread->specific[key].seqno == _thread_keytable[key].seqno)) {
211
		/* Return the value: */
228
			/* Return the value: */
212
		data = pthread->specific[key].data;
229
			data = pthread->specific[key].data;
213
	} else {
230
		} else {
214
		/*
231
			/*
215
		 * This key has not been used before, so return NULL
232
			 * This key has not been used before, so return NULL
216
		 * instead.
233
			 * instead: 
217
		 */
234
			 */
235
			data = NULL;
236
		}
237
	} else
238
		/* No specific data has been created, so just return NULL: */
239
		data = NULL;
218
		data = NULL;
219
	}
240
	return (__DECONST(void *, data));
220
	return (__DECONST(void *, data));
241
}
221
}
242
222
243
void
223
void
244
_thr_tsd_unload(struct dl_phdr_info *phdr_info)
224
_thr_tsd_unload(struct dl_phdr_info *phdr_info)
245
{
225
{
246
	struct pthread *curthread = _get_curthread();
226
	struct pthread *curthread;
247
	void (*destructor)(void *);
227
	void (*destructor)(void *);
248
	int key;
228
	int key;
249
229
230
	curthread = _get_curthread();
250
	THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
231
	THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
251
	for (key = 0; key < PTHREAD_KEYS_MAX; key++) {
232
	for (key = 0; key < PTHREAD_KEYS_MAX; key++) {
252
		if (_thread_keytable[key].allocated) {
233
		if (!_thread_keytable[key].allocated)
253
			destructor = _thread_keytable[key].destructor;
234
			continue;
254
			if (destructor != NULL) {
235
		destructor = _thread_keytable[key].destructor;
255
				if (__elf_phdr_match_addr(phdr_info, destructor))
236
		if (destructor == NULL)
256
					_thread_keytable[key].destructor = NULL;
237
			continue;
257
			}
238
		if (__elf_phdr_match_addr(phdr_info, destructor))
258
		}
239
			_thread_keytable[key].destructor = NULL;
259
	}
240
	}
260
	THR_LOCK_RELEASE(curthread, &_keytable_lock);
241
	THR_LOCK_RELEASE(curthread, &_keytable_lock);
261
}
242
}

Return to bug 200138