1 /* Linuxthreads - a simple clone()-based implementation of Posix */
2 /* threads for Linux. */
3 /* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */
4 /* */
5 /* This program is free software; you can redistribute it and/or */
6 /* modify it under the terms of the GNU Library General Public License */
7 /* as published by the Free Software Foundation; either version 2 */
8 /* of the License, or (at your option) any later version. */
9 /* */
10 /* This program is distributed in the hope that it will be useful, */
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
13 /* GNU Library General Public License for more details. */
14
15 /* Thread-specific data */
16
17 #include <errno.h>
18 #include <stddef.h>
19 #include <stdlib.h>
20 #include "pthread.h"
21 #include "internals.h"
22 #include "spinlock.h"
23 #include "restart.h"
24 #include <bits/libc-lock.h>
25
26 #include <stdio.h>
27
28 /* Table of keys. */
29
30 static struct pthread_key_struct pthread_keys[PTHREAD_KEYS_MAX] =
31 { { 0, NULL } };
32
33 /* For debugging purposes put the maximum number of keys in a variable. */
34 const int __linuxthreads_pthread_keys_max = PTHREAD_KEYS_MAX;
35 const int __linuxthreads_pthread_key_2ndlevel_size = PTHREAD_KEY_2NDLEVEL_SIZE;
36
37 /* Mutex to protect access to pthread_keys */
38
39 static pthread_mutex_t pthread_keys_mutex = PTHREAD_MUTEX_INITIALIZER;
40
41 /* Create a new key */
42
43 int
44 attribute_hidden
__pthread_key_create(pthread_key_t * key,destr_function destr)45 __pthread_key_create(pthread_key_t * key, destr_function destr)
46 {
47 int i;
48
49 pthread_mutex_lock(&pthread_keys_mutex);
50 for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
51 if (! pthread_keys[i].in_use) {
52 /* Mark key in use */
53 pthread_keys[i].in_use = 1;
54 pthread_keys[i].destr = destr;
55 pthread_mutex_unlock(&pthread_keys_mutex);
56 *key = i;
57 return 0;
58 }
59 }
60 pthread_mutex_unlock(&pthread_keys_mutex);
61 return EAGAIN;
62 }
63 strong_alias (__pthread_key_create, pthread_key_create)
64
65 /* Reset deleted key's value to NULL in each live thread.
66 * NOTE: this executes in the context of the thread manager! */
67
68 struct pthread_key_delete_helper_args {
69 /* Damn, we need lexical closures in C! ;) */
70 unsigned int idx1st, idx2nd;
71 pthread_descr self;
72 };
73
pthread_key_delete_helper(void * arg,pthread_descr th)74 static void pthread_key_delete_helper(void *arg, pthread_descr th)
75 {
76 struct pthread_key_delete_helper_args *args = arg;
77 unsigned int idx1st = args->idx1st;
78 unsigned int idx2nd = args->idx2nd;
79 pthread_descr self = args->self;
80
81 if (self == 0)
82 self = args->self = thread_self();
83
84 if (!th->p_terminated) {
85 /* pthread_exit() may try to free th->p_specific[idx1st] concurrently. */
86 __pthread_lock(th->p_lock, self);
87 if (th->p_specific[idx1st] != NULL)
88 th->p_specific[idx1st][idx2nd] = NULL;
89 __pthread_unlock(th->p_lock);
90 }
91 }
92
93 /* Delete a key */
pthread_key_delete(pthread_key_t key)94 int pthread_key_delete(pthread_key_t key)
95 {
96 pthread_descr self = thread_self();
97
98 pthread_mutex_lock(&pthread_keys_mutex);
99 if (key >= PTHREAD_KEYS_MAX || !pthread_keys[key].in_use) {
100 pthread_mutex_unlock(&pthread_keys_mutex);
101 return EINVAL;
102 }
103 pthread_keys[key].in_use = 0;
104 pthread_keys[key].destr = NULL;
105
106 /* Set the value of the key to NULL in all running threads, so
107 that if the key is reallocated later by pthread_key_create, its
108 associated values will be NULL in all threads.
109
110 If no threads have been created yet, or if we are exiting, clear
111 it just in the current thread. */
112
113 struct pthread_key_delete_helper_args args;
114 args.idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE;
115 args.idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE;
116 if (!l4_is_invalid_cap(__pthread_manager_request)
117 && !(__builtin_expect (__pthread_exit_requested, 0)))
118 {
119 struct pthread_request request;
120
121 args.self = 0;
122
123 request.req_thread = self;
124 request.req_kind = REQ_FOR_EACH_THREAD;
125 request.req_args.for_each.arg = &args;
126 request.req_args.for_each.fn = pthread_key_delete_helper;
127 #if 1
128 __pthread_send_manager_rq(&request, 1);
129 #else
130 TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request,
131 (char *) &request, sizeof(request)));
132 #endif
133 suspend(self);
134 }
135 else
136 {
137 if (self->p_specific[args.idx1st] != NULL)
138 self->p_specific[args.idx1st][args.idx2nd] = NULL;
139 }
140
141 pthread_mutex_unlock(&pthread_keys_mutex);
142 return 0;
143 }
144
145 /* Set the value of a key */
146
147 int
148 attribute_hidden
__pthread_setspecific(pthread_key_t key,const void * pointer)149 __pthread_setspecific(pthread_key_t key, const void * pointer)
150 {
151 pthread_descr self = thread_self();
152 unsigned int idx1st, idx2nd;
153
154 if (key >= PTHREAD_KEYS_MAX || !pthread_keys[key].in_use)
155 return EINVAL;
156 idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE;
157 idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE;
158 if (THREAD_GETMEM_NC(self, p_specific, idx1st) == NULL) {
159 void *newp = calloc(PTHREAD_KEY_2NDLEVEL_SIZE, sizeof (void *));
160 if (newp == NULL)
161 return ENOMEM;
162 THREAD_SETMEM_NC(self, p_specific ,idx1st, newp);
163 }
164 THREAD_GETMEM_NC(self, p_specific, idx1st)[idx2nd] = (void *) pointer;
165 return 0;
166 }
strong_alias(__pthread_setspecific,pthread_setspecific)167 strong_alias (__pthread_setspecific, pthread_setspecific)
168
169 /* Get the value of a key */
170
171 attribute_hidden
172 void *
173 __pthread_getspecific(pthread_key_t key)
174 {
175 pthread_descr self = thread_self();
176 unsigned int idx1st, idx2nd;
177
178 if (key >= PTHREAD_KEYS_MAX)
179 return NULL;
180 idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE;
181 idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE;
182 if (THREAD_GETMEM_NC(self, p_specific, idx1st) == NULL
183 || !pthread_keys[key].in_use)
184 return NULL;
185 return THREAD_GETMEM_NC(self, p_specific, idx1st)[idx2nd];
186 }
strong_alias(__pthread_getspecific,pthread_getspecific)187 strong_alias (__pthread_getspecific, pthread_getspecific)
188
189 /* Call the destruction routines on all keys */
190
191 void
192 attribute_hidden
193 __pthread_destroy_specifics()
194 {
195 pthread_descr self = thread_self();
196 int i, j, round, found_nonzero;
197 destr_function destr;
198 void * data;
199
200 for (round = 0, found_nonzero = 1;
201 found_nonzero && round < PTHREAD_DESTRUCTOR_ITERATIONS;
202 round++) {
203 found_nonzero = 0;
204 for (i = 0; i < PTHREAD_KEY_1STLEVEL_SIZE; i++)
205 if (THREAD_GETMEM_NC(self, p_specific, i) != NULL)
206 for (j = 0; j < PTHREAD_KEY_2NDLEVEL_SIZE; j++) {
207 destr = pthread_keys[i * PTHREAD_KEY_2NDLEVEL_SIZE + j].destr;
208 data = THREAD_GETMEM_NC(self, p_specific, i)[j];
209 if (destr != NULL && data != NULL) {
210 THREAD_GETMEM_NC(self, p_specific, i)[j] = NULL;
211 destr(data);
212 found_nonzero = 1;
213 }
214 }
215 }
216 __pthread_lock(THREAD_GETMEM(self, p_lock), self);
217 for (i = 0; i < PTHREAD_KEY_1STLEVEL_SIZE; i++) {
218 if (THREAD_GETMEM_NC(self, p_specific, i) != NULL) {
219 void *p = THREAD_GETMEM_NC(self, p_specific, i);
220 THREAD_SETMEM_NC(self, p_specific, i, NULL);
221 free(p);
222 }
223 }
224 __pthread_unlock(THREAD_GETMEM(self, p_lock));
225 }
226
227 #if !(USE_TLS && HAVE___THREAD)
228
229 /* Thread-specific data for libc. */
230
231 int
232 attribute_hidden
__pthread_internal_tsd_set(int key,const void * pointer)233 __pthread_internal_tsd_set (int key, const void * pointer)
234 {
235 pthread_descr self = thread_self();
236
237 THREAD_SETMEM_NC(self, p_libc_specific, key, (void *) pointer);
238 return 0;
239 }
240
241 void *
242 attribute_hidden
__pthread_internal_tsd_get(int key)243 __pthread_internal_tsd_get (int key)
244 {
245 pthread_descr self = thread_self();
246
247 return THREAD_GETMEM_NC(self, p_libc_specific, key);
248 }
249
250 void ** __attribute__ ((__const__))
251 attribute_hidden
__pthread_internal_tsd_address(int key)252 __pthread_internal_tsd_address (int key)
253 {
254 pthread_descr self = thread_self();
255 return &self->p_libc_specific[key];
256 }
257
258 #endif
259