]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/uclibc/lib/contrib/uclibc/libpthread/linuxthreads/specific.c
update
[l4.git] / l4 / pkg / uclibc / lib / contrib / uclibc / libpthread / linuxthreads / specific.c
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 #include <not-cancel.h>
26
27 /* Table of keys. */
28
29 static struct pthread_key_struct pthread_keys[PTHREAD_KEYS_MAX] =
30   { { 0, NULL } };
31
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;
35
36 /* Mutex to protect access to pthread_keys */
37
38 static pthread_mutex_t pthread_keys_mutex = PTHREAD_MUTEX_INITIALIZER;
39
40 /* Create a new key */
41
42 int __pthread_key_create(pthread_key_t * key, destr_function destr)
43 {
44   int i;
45
46   pthread_mutex_lock(&pthread_keys_mutex);
47   for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
48     if (! pthread_keys[i].in_use) {
49       /* Mark key in use */
50       pthread_keys[i].in_use = 1;
51       pthread_keys[i].destr = destr;
52       pthread_mutex_unlock(&pthread_keys_mutex);
53       *key = i;
54       return 0;
55     }
56   }
57   pthread_mutex_unlock(&pthread_keys_mutex);
58   return EAGAIN;
59 }
60 strong_alias (__pthread_key_create, pthread_key_create)
61
62 /* Reset deleted key's value to NULL in each live thread.
63  * NOTE: this executes in the context of the thread manager! */
64
65 struct pthread_key_delete_helper_args {
66   /* Damn, we need lexical closures in C! ;) */
67   unsigned int idx1st, idx2nd;
68   pthread_descr self;
69 };
70
71 static void pthread_key_delete_helper(void *arg, pthread_descr th)
72 {
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;
77
78   if (self == 0)
79     self = args->self = thread_self();
80
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);
87   }
88 }
89
90 /* Delete a key */
91 int pthread_key_delete(pthread_key_t key)
92 {
93   pthread_descr self = thread_self();
94
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);
98     return EINVAL;
99   }
100   pthread_keys[key].in_use = 0;
101   pthread_keys[key].destr = NULL;
102
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.
106
107      If no threads have been created yet, or if we are exiting, clear
108      it just in the current thread.  */
109
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)))
115     {
116       struct pthread_request request;
117
118       args.self = 0;
119
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;
124
125       TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request,
126                                           (char *) &request, sizeof(request)));
127       suspend(self);
128     }
129   else
130     {
131       if (self->p_specific[args.idx1st] != NULL)
132         self->p_specific[args.idx1st][args.idx2nd] = NULL;
133     }
134
135   pthread_mutex_unlock(&pthread_keys_mutex);
136   return 0;
137 }
138
139 /* Set the value of a key */
140
141 int __pthread_setspecific(pthread_key_t key, const void * pointer)
142 {
143   pthread_descr self = thread_self();
144   unsigned int idx1st, idx2nd;
145
146   if (key >= PTHREAD_KEYS_MAX || !pthread_keys[key].in_use)
147     return EINVAL;
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 *));
152     if (newp == NULL)
153       return ENOMEM;
154     THREAD_SETMEM_NC(self, p_specific[idx1st], newp);
155   }
156   THREAD_GETMEM_NC(self, p_specific[idx1st])[idx2nd] = (void *) pointer;
157   return 0;
158 }
159 strong_alias (__pthread_setspecific, pthread_setspecific)
160
161 /* Get the value of a key */
162
163 void * __pthread_getspecific(pthread_key_t key)
164 {
165   pthread_descr self = thread_self();
166   unsigned int idx1st, idx2nd;
167
168   if (key >= PTHREAD_KEYS_MAX)
169     return NULL;
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)
174     return NULL;
175   return THREAD_GETMEM_NC(self, p_specific[idx1st])[idx2nd];
176 }
177 strong_alias (__pthread_getspecific, pthread_getspecific)
178
179 /* Call the destruction routines on all keys */
180
181 void __pthread_destroy_specifics()
182 {
183   pthread_descr self = thread_self();
184   int i, j, round, found_nonzero;
185   destr_function destr;
186   void * data;
187
188   for (round = 0, found_nonzero = 1;
189        found_nonzero && round < PTHREAD_DESTRUCTOR_ITERATIONS;
190        round++) {
191     found_nonzero = 0;
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;
199             destr(data);
200             found_nonzero = 1;
201           }
202         }
203   }
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);
209       free(p);
210     }
211   }
212   __pthread_unlock(THREAD_GETMEM(self, p_lock));
213 }
214
215 #if !defined __UCLIBC_HAS_TLS__ && defined __UCLIBC_HAS_RPC__
216
217 /* Thread-specific data for libc. */
218
219 int
220 __pthread_internal_tsd_set (int key, const void * pointer)
221 {
222   pthread_descr self = thread_self();
223
224   THREAD_SETMEM_NC(self, p_libc_specific[key], (void *) pointer);
225   return 0;
226 }
227
228 void *
229 __pthread_internal_tsd_get (int key)
230 {
231   pthread_descr self = thread_self();
232
233   return THREAD_GETMEM_NC(self, p_libc_specific[key]);
234 }
235
236 void ** __attribute__ ((__const__))
237 __pthread_internal_tsd_address (int key)
238 {
239   pthread_descr self = thread_self();
240   return &self->p_libc_specific[key];
241 }
242
243 #endif