1 /* Linuxthreads - a simple clone()-based implementation of Posix */
2 /* threads for Linux. */
3 /* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */
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. */
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. */
15 /* Thread-specific data */
21 #include "internals.h"
24 #include <bits/libc-lock.h>
30 static struct pthread_key_struct pthread_keys[PTHREAD_KEYS_MAX] =
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;
37 /* Mutex to protect access to pthread_keys */
39 static pthread_mutex_t pthread_keys_mutex = PTHREAD_MUTEX_INITIALIZER;
41 /* Create a new key */
45 __pthread_key_create(pthread_key_t * key, destr_function destr)
49 pthread_mutex_lock(&pthread_keys_mutex);
50 for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
51 if (! pthread_keys[i].in_use) {
53 pthread_keys[i].in_use = 1;
54 pthread_keys[i].destr = destr;
55 pthread_mutex_unlock(&pthread_keys_mutex);
60 pthread_mutex_unlock(&pthread_keys_mutex);
63 strong_alias (__pthread_key_create, pthread_key_create)
65 /* Reset deleted key's value to NULL in each live thread.
66 * NOTE: this executes in the context of the thread manager! */
68 struct pthread_key_delete_helper_args {
69 /* Damn, we need lexical closures in C! ;) */
70 unsigned int idx1st, idx2nd;
74 static void pthread_key_delete_helper(void *arg, pthread_descr th)
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;
82 self = args->self = thread_self();
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);
94 int pthread_key_delete(pthread_key_t key)
96 pthread_descr self = thread_self();
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);
103 pthread_keys[key].in_use = 0;
104 pthread_keys[key].destr = NULL;
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.
110 If no threads have been created yet, or if we are exiting, clear
111 it just in the current thread. */
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)))
119 struct pthread_request request;
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;
128 __pthread_send_manager_rq(&request, 1);
130 TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request,
131 (char *) &request, sizeof(request)));
137 if (self->p_specific[args.idx1st] != NULL)
138 self->p_specific[args.idx1st][args.idx2nd] = NULL;
141 pthread_mutex_unlock(&pthread_keys_mutex);
145 /* Set the value of a key */
149 __pthread_setspecific(pthread_key_t key, const void * pointer)
151 pthread_descr self = thread_self();
152 unsigned int idx1st, idx2nd;
154 if (key >= PTHREAD_KEYS_MAX || !pthread_keys[key].in_use)
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 *));
162 THREAD_SETMEM_NC(self, p_specific ,idx1st, newp);
164 THREAD_GETMEM_NC(self, p_specific, idx1st)[idx2nd] = (void *) pointer;
167 strong_alias (__pthread_setspecific, pthread_setspecific)
169 /* Get the value of a key */
173 __pthread_getspecific(pthread_key_t key)
175 pthread_descr self = thread_self();
176 unsigned int idx1st, idx2nd;
178 if (key >= PTHREAD_KEYS_MAX)
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)
185 return THREAD_GETMEM_NC(self, p_specific, idx1st)[idx2nd];
187 strong_alias (__pthread_getspecific, pthread_getspecific)
189 /* Call the destruction routines on all keys */
193 __pthread_destroy_specifics()
195 pthread_descr self = thread_self();
196 int i, j, round, found_nonzero;
197 destr_function destr;
200 for (round = 0, found_nonzero = 1;
201 found_nonzero && round < PTHREAD_DESTRUCTOR_ITERATIONS;
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;
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);
224 __pthread_unlock(THREAD_GETMEM(self, p_lock));
227 #if !(USE_TLS && HAVE___THREAD)
229 /* Thread-specific data for libc. */
233 __pthread_internal_tsd_set (int key, const void * pointer)
235 pthread_descr self = thread_self();
237 THREAD_SETMEM_NC(self, p_libc_specific, key, (void *) pointer);
243 __pthread_internal_tsd_get (int key)
245 pthread_descr self = thread_self();
247 return THREAD_GETMEM_NC(self, p_libc_specific, key);
250 void ** __attribute__ ((__const__))
252 __pthread_internal_tsd_address (int key)
254 pthread_descr self = thread_self();
255 return &self->p_libc_specific[key];