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

Collapse All | Expand All

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

Return to bug 200138