]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/uclibc/lib/libpthread/src/specific.c
Inital import
[l4.git] / l4 / pkg / uclibc / lib / libpthread / src / 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
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 __pthread_key_create(pthread_key_t * key, destr_function destr)
44 {
45   int i;
46
47   pthread_mutex_lock(&pthread_keys_mutex);
48   for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
49     if (! pthread_keys[i].in_use) {
50       /* Mark key in use */
51       pthread_keys[i].in_use = 1;
52       pthread_keys[i].destr = destr;
53       pthread_mutex_unlock(&pthread_keys_mutex);
54       *key = i;
55       return 0;
56     }
57   }
58   pthread_mutex_unlock(&pthread_keys_mutex);
59   return EAGAIN;
60 }
61 strong_alias (__pthread_key_create, pthread_key_create)
62
63 /* Reset deleted key's value to NULL in each live thread.
64  * NOTE: this executes in the context of the thread manager! */
65
66 struct pthread_key_delete_helper_args {
67   /* Damn, we need lexical closures in C! ;) */
68   unsigned int idx1st, idx2nd;
69   pthread_descr self;
70 };
71
72 static void pthread_key_delete_helper(void *arg, pthread_descr th)
73 {
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;
78
79   if (self == 0)
80     self = args->self = thread_self();
81
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);
88   }
89 }
90
91 /* Delete a key */
92 int pthread_key_delete(pthread_key_t key)
93 {
94   pthread_descr self = thread_self();
95
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);
99     return EINVAL;
100   }
101   pthread_keys[key].in_use = 0;
102   pthread_keys[key].destr = NULL;
103
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.
107
108      If no threads have been created yet, or if we are exiting, clear
109      it just in the current thread.  */
110
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)))
116     {
117       struct pthread_request request;
118
119       args.self = 0;
120
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;
125 #if 1
126       __pthread_send_manager_rq(&request, 1);
127 #else
128       TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request,
129                                           (char *) &request, sizeof(request)));
130 #endif
131       suspend(self);
132     }
133   else
134     {
135       if (self->p_specific[args.idx1st] != NULL)
136         self->p_specific[args.idx1st][args.idx2nd] = NULL;
137     }
138
139   pthread_mutex_unlock(&pthread_keys_mutex);
140   return 0;
141 }
142
143 /* Set the value of a key */
144
145 int __pthread_setspecific(pthread_key_t key, const void * pointer)
146 {
147   pthread_descr self = thread_self();
148   unsigned int idx1st, idx2nd;
149
150   if (key >= PTHREAD_KEYS_MAX || !pthread_keys[key].in_use)
151     return EINVAL;
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 *));
156     if (newp == NULL)
157       return ENOMEM;
158     THREAD_SETMEM_NC(self, p_specific[idx1st], newp);
159   }
160   THREAD_GETMEM_NC(self, p_specific[idx1st])[idx2nd] = (void *) pointer;
161   return 0;
162 }
163 strong_alias (__pthread_setspecific, pthread_setspecific)
164
165 /* Get the value of a key */
166
167 void * __pthread_getspecific(pthread_key_t key)
168 {
169   pthread_descr self = thread_self();
170   unsigned int idx1st, idx2nd;
171
172   if (key >= PTHREAD_KEYS_MAX)
173     return NULL;
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)
178     return NULL;
179   return THREAD_GETMEM_NC(self, p_specific[idx1st])[idx2nd];
180 }
181 strong_alias (__pthread_getspecific, pthread_getspecific)
182
183 /* Call the destruction routines on all keys */
184
185 void __pthread_destroy_specifics()
186 {
187   pthread_descr self = thread_self();
188   int i, j, round, found_nonzero;
189   destr_function destr;
190   void * data;
191
192   for (round = 0, found_nonzero = 1;
193        found_nonzero && round < PTHREAD_DESTRUCTOR_ITERATIONS;
194        round++) {
195     found_nonzero = 0;
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;
203             destr(data);
204             found_nonzero = 1;
205           }
206         }
207   }
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);
213       free(p);
214     }
215   }
216   __pthread_unlock(THREAD_GETMEM(self, p_lock));
217 }
218
219 #if !(USE_TLS && HAVE___THREAD)
220
221 /* Thread-specific data for libc. */
222
223 int
224 __pthread_internal_tsd_set (int key, const void * pointer)
225 {
226   pthread_descr self = thread_self();
227
228   THREAD_SETMEM_NC(self, p_libc_specific[key], (void *) pointer);
229   return 0;
230 }
231
232 void *
233 __pthread_internal_tsd_get (int key)
234 {
235   pthread_descr self = thread_self();
236
237   return THREAD_GETMEM_NC(self, p_libc_specific[key]);
238 }
239
240 void ** __attribute__ ((__const__))
241 __pthread_internal_tsd_address (int key)
242 {
243   pthread_descr self = thread_self();
244   return &self->p_libc_specific[key];
245 }
246
247 #endif