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 */
43 int __pthread_key_create(pthread_key_t * key, destr_function destr)
47 pthread_mutex_lock(&pthread_keys_mutex);
48 for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
49 if (! pthread_keys[i].in_use) {
51 pthread_keys[i].in_use = 1;
52 pthread_keys[i].destr = destr;
53 pthread_mutex_unlock(&pthread_keys_mutex);
58 pthread_mutex_unlock(&pthread_keys_mutex);
61 strong_alias (__pthread_key_create, pthread_key_create)
63 /* Reset deleted key's value to NULL in each live thread.
64 * NOTE: this executes in the context of the thread manager! */
66 struct pthread_key_delete_helper_args {
67 /* Damn, we need lexical closures in C! ;) */
68 unsigned int idx1st, idx2nd;
72 static void pthread_key_delete_helper(void *arg, pthread_descr th)
74 struct pthread_key_delete_helper_args *args = arg;
75 unsigned int idx1st = args->idx1st;
76 unsigned int idx2nd = args->idx2nd;
77 pthread_descr self = args->self;
80 self = args->self = thread_self();
82 if (!th->p_terminated) {
83 /* pthread_exit() may try to free th->p_specific[idx1st] concurrently. */
84 __pthread_lock(th->p_lock, self);
85 if (th->p_specific[idx1st] != NULL)
86 th->p_specific[idx1st][idx2nd] = NULL;
87 __pthread_unlock(th->p_lock);
92 int pthread_key_delete(pthread_key_t key)
94 pthread_descr self = thread_self();
96 pthread_mutex_lock(&pthread_keys_mutex);
97 if (key >= PTHREAD_KEYS_MAX || !pthread_keys[key].in_use) {
98 pthread_mutex_unlock(&pthread_keys_mutex);
101 pthread_keys[key].in_use = 0;
102 pthread_keys[key].destr = NULL;
104 /* Set the value of the key to NULL in all running threads, so
105 that if the key is reallocated later by pthread_key_create, its
106 associated values will be NULL in all threads.
108 If no threads have been created yet, or if we are exiting, clear
109 it just in the current thread. */
111 struct pthread_key_delete_helper_args args;
112 args.idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE;
113 args.idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE;
114 if (!l4_is_invalid_cap(__pthread_manager_request)
115 && !(__builtin_expect (__pthread_exit_requested, 0)))
117 struct pthread_request request;
121 request.req_thread = self;
122 request.req_kind = REQ_FOR_EACH_THREAD;
123 request.req_args.for_each.arg = &args;
124 request.req_args.for_each.fn = pthread_key_delete_helper;
126 __pthread_send_manager_rq(&request, 1);
128 TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request,
129 (char *) &request, sizeof(request)));
135 if (self->p_specific[args.idx1st] != NULL)
136 self->p_specific[args.idx1st][args.idx2nd] = NULL;
139 pthread_mutex_unlock(&pthread_keys_mutex);
143 /* Set the value of a key */
145 int __pthread_setspecific(pthread_key_t key, const void * pointer)
147 pthread_descr self = thread_self();
148 unsigned int idx1st, idx2nd;
150 if (key >= PTHREAD_KEYS_MAX || !pthread_keys[key].in_use)
152 idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE;
153 idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE;
154 if (THREAD_GETMEM_NC(self, p_specific[idx1st]) == NULL) {
155 void *newp = calloc(PTHREAD_KEY_2NDLEVEL_SIZE, sizeof (void *));
158 THREAD_SETMEM_NC(self, p_specific[idx1st], newp);
160 THREAD_GETMEM_NC(self, p_specific[idx1st])[idx2nd] = (void *) pointer;
163 strong_alias (__pthread_setspecific, pthread_setspecific)
165 /* Get the value of a key */
167 void * __pthread_getspecific(pthread_key_t key)
169 pthread_descr self = thread_self();
170 unsigned int idx1st, idx2nd;
172 if (key >= PTHREAD_KEYS_MAX)
174 idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE;
175 idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE;
176 if (THREAD_GETMEM_NC(self, p_specific[idx1st]) == NULL
177 || !pthread_keys[key].in_use)
179 return THREAD_GETMEM_NC(self, p_specific[idx1st])[idx2nd];
181 strong_alias (__pthread_getspecific, pthread_getspecific)
183 /* Call the destruction routines on all keys */
185 void __pthread_destroy_specifics()
187 pthread_descr self = thread_self();
188 int i, j, round, found_nonzero;
189 destr_function destr;
192 for (round = 0, found_nonzero = 1;
193 found_nonzero && round < PTHREAD_DESTRUCTOR_ITERATIONS;
196 for (i = 0; i < PTHREAD_KEY_1STLEVEL_SIZE; i++)
197 if (THREAD_GETMEM_NC(self, p_specific[i]) != NULL)
198 for (j = 0; j < PTHREAD_KEY_2NDLEVEL_SIZE; j++) {
199 destr = pthread_keys[i * PTHREAD_KEY_2NDLEVEL_SIZE + j].destr;
200 data = THREAD_GETMEM_NC(self, p_specific[i])[j];
201 if (destr != NULL && data != NULL) {
202 THREAD_GETMEM_NC(self, p_specific[i])[j] = NULL;
208 __pthread_lock(THREAD_GETMEM(self, p_lock), self);
209 for (i = 0; i < PTHREAD_KEY_1STLEVEL_SIZE; i++) {
210 if (THREAD_GETMEM_NC(self, p_specific[i]) != NULL) {
211 void *p = THREAD_GETMEM_NC(self, p_specific[i]);
212 THREAD_SETMEM_NC(self, p_specific[i], NULL);
216 __pthread_unlock(THREAD_GETMEM(self, p_lock));
219 #if !(USE_TLS && HAVE___THREAD)
221 /* Thread-specific data for libc. */
224 __pthread_internal_tsd_set (int key, const void * pointer)
226 pthread_descr self = thread_self();
228 THREAD_SETMEM_NC(self, p_libc_specific[key], (void *) pointer);
233 __pthread_internal_tsd_get (int key)
235 pthread_descr self = thread_self();
237 return THREAD_GETMEM_NC(self, p_libc_specific[key]);
240 void ** __attribute__ ((__const__))
241 __pthread_internal_tsd_address (int key)
243 pthread_descr self = thread_self();
244 return &self->p_libc_specific[key];