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>
25 #include <not-cancel.h>
29 static struct pthread_key_struct pthread_keys[PTHREAD_KEYS_MAX] =
32 /* For debugging purposes put the maximum number of keys in a variable. */
33 const int __linuxthreads_pthread_keys_max = PTHREAD_KEYS_MAX;
34 const int __linuxthreads_pthread_key_2ndlevel_size = PTHREAD_KEY_2NDLEVEL_SIZE;
36 /* Mutex to protect access to pthread_keys */
38 static pthread_mutex_t pthread_keys_mutex = PTHREAD_MUTEX_INITIALIZER;
40 /* Create a new key */
42 int __pthread_key_create(pthread_key_t * key, destr_function destr)
46 pthread_mutex_lock(&pthread_keys_mutex);
47 for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
48 if (! pthread_keys[i].in_use) {
50 pthread_keys[i].in_use = 1;
51 pthread_keys[i].destr = destr;
52 pthread_mutex_unlock(&pthread_keys_mutex);
57 pthread_mutex_unlock(&pthread_keys_mutex);
60 strong_alias (__pthread_key_create, pthread_key_create)
62 /* Reset deleted key's value to NULL in each live thread.
63 * NOTE: this executes in the context of the thread manager! */
65 struct pthread_key_delete_helper_args {
66 /* Damn, we need lexical closures in C! ;) */
67 unsigned int idx1st, idx2nd;
71 static void pthread_key_delete_helper(void *arg, pthread_descr th)
73 struct pthread_key_delete_helper_args *args = arg;
74 unsigned int idx1st = args->idx1st;
75 unsigned int idx2nd = args->idx2nd;
76 pthread_descr self = args->self;
79 self = args->self = thread_self();
81 if (!th->p_terminated) {
82 /* pthread_exit() may try to free th->p_specific[idx1st] concurrently. */
83 __pthread_lock(th->p_lock, self);
84 if (th->p_specific[idx1st] != NULL)
85 th->p_specific[idx1st][idx2nd] = NULL;
86 __pthread_unlock(th->p_lock);
91 int pthread_key_delete(pthread_key_t key)
93 pthread_descr self = thread_self();
95 pthread_mutex_lock(&pthread_keys_mutex);
96 if (key >= PTHREAD_KEYS_MAX || !pthread_keys[key].in_use) {
97 pthread_mutex_unlock(&pthread_keys_mutex);
100 pthread_keys[key].in_use = 0;
101 pthread_keys[key].destr = NULL;
103 /* Set the value of the key to NULL in all running threads, so
104 that if the key is reallocated later by pthread_key_create, its
105 associated values will be NULL in all threads.
107 If no threads have been created yet, or if we are exiting, clear
108 it just in the current thread. */
110 struct pthread_key_delete_helper_args args;
111 args.idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE;
112 args.idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE;
113 if (__pthread_manager_request != -1
114 && !(__builtin_expect (__pthread_exit_requested, 0)))
116 struct pthread_request request;
120 request.req_thread = self;
121 request.req_kind = REQ_FOR_EACH_THREAD;
122 request.req_args.for_each.arg = &args;
123 request.req_args.for_each.fn = pthread_key_delete_helper;
125 TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request,
126 (char *) &request, sizeof(request)));
131 if (self->p_specific[args.idx1st] != NULL)
132 self->p_specific[args.idx1st][args.idx2nd] = NULL;
135 pthread_mutex_unlock(&pthread_keys_mutex);
139 /* Set the value of a key */
141 int __pthread_setspecific(pthread_key_t key, const void * pointer)
143 pthread_descr self = thread_self();
144 unsigned int idx1st, idx2nd;
146 if (key >= PTHREAD_KEYS_MAX || !pthread_keys[key].in_use)
148 idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE;
149 idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE;
150 if (THREAD_GETMEM_NC(self, p_specific[idx1st]) == NULL) {
151 void *newp = calloc(PTHREAD_KEY_2NDLEVEL_SIZE, sizeof (void *));
154 THREAD_SETMEM_NC(self, p_specific[idx1st], newp);
156 THREAD_GETMEM_NC(self, p_specific[idx1st])[idx2nd] = (void *) pointer;
159 strong_alias (__pthread_setspecific, pthread_setspecific)
161 /* Get the value of a key */
163 void * __pthread_getspecific(pthread_key_t key)
165 pthread_descr self = thread_self();
166 unsigned int idx1st, idx2nd;
168 if (key >= PTHREAD_KEYS_MAX)
170 idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE;
171 idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE;
172 if (THREAD_GETMEM_NC(self, p_specific[idx1st]) == NULL
173 || !pthread_keys[key].in_use)
175 return THREAD_GETMEM_NC(self, p_specific[idx1st])[idx2nd];
177 strong_alias (__pthread_getspecific, pthread_getspecific)
179 /* Call the destruction routines on all keys */
181 void __pthread_destroy_specifics()
183 pthread_descr self = thread_self();
184 int i, j, round, found_nonzero;
185 destr_function destr;
188 for (round = 0, found_nonzero = 1;
189 found_nonzero && round < PTHREAD_DESTRUCTOR_ITERATIONS;
192 for (i = 0; i < PTHREAD_KEY_1STLEVEL_SIZE; i++)
193 if (THREAD_GETMEM_NC(self, p_specific[i]) != NULL)
194 for (j = 0; j < PTHREAD_KEY_2NDLEVEL_SIZE; j++) {
195 destr = pthread_keys[i * PTHREAD_KEY_2NDLEVEL_SIZE + j].destr;
196 data = THREAD_GETMEM_NC(self, p_specific[i])[j];
197 if (destr != NULL && data != NULL) {
198 THREAD_GETMEM_NC(self, p_specific[i])[j] = NULL;
204 __pthread_lock(THREAD_GETMEM(self, p_lock), self);
205 for (i = 0; i < PTHREAD_KEY_1STLEVEL_SIZE; i++) {
206 if (THREAD_GETMEM_NC(self, p_specific[i]) != NULL) {
207 void *p = THREAD_GETMEM_NC(self, p_specific[i]);
208 THREAD_SETMEM_NC(self, p_specific[i], NULL);
212 __pthread_unlock(THREAD_GETMEM(self, p_lock));
215 #if !(USE_TLS && HAVE___THREAD)
217 /* Thread-specific data for libc. */
220 __pthread_internal_tsd_set (int key, const void * pointer)
222 pthread_descr self = thread_self();
224 THREAD_SETMEM_NC(self, p_libc_specific[key], (void *) pointer);
229 __pthread_internal_tsd_get (int key)
231 pthread_descr self = thread_self();
233 return THREAD_GETMEM_NC(self, p_libc_specific[key]);
236 void ** __attribute__ ((__const__))
237 __pthread_internal_tsd_address (int key)
239 pthread_descr self = thread_self();
240 return &self->p_libc_specific[key];