]> git.saurik.com Git - apple/libpthread.git/blob - src/pthread_tsd.c
libpthread-105.10.1.tar.gz
[apple/libpthread.git] / src / pthread_tsd.c
1 /*
2 * Copyright (c) 2000-2003, 2007, 2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /*
24 * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
25 * All Rights Reserved
26 *
27 * Permission to use, copy, modify, and distribute this software and
28 * its documentation for any purpose and without fee is hereby granted,
29 * provided that the above copyright notice appears in all copies and
30 * that both the copyright notice and this permission notice appear in
31 * supporting documentation.
32 *
33 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
34 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
35 * FOR A PARTICULAR PURPOSE.
36 *
37 * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
38 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
39 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
40 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
41 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
42 *
43 */
44 /*
45 * MkLinux
46 */
47
48 /*
49 * POSIX Pthread Library
50 * Thread Specific Data support
51 * NB: pthread_getspecific() is in a separate assembly file
52 */
53
54 #include "internal.h"
55 #include <TargetConditionals.h>
56
57 #if !VARIANT_DYLD
58 // __pthread_tsd_first is first static key managed by libpthread.
59 // __pthread_tsd_max is the (observed) end of static key destructors.
60 // __pthread_tsd_start is the start of dynamic keys.
61 // __pthread_tsd_end is the end of dynamic keys.
62
63 static const int __pthread_tsd_first = __TSD_RESERVED_MAX + 1;
64 static int __pthread_tsd_max = __pthread_tsd_first;
65 static const int __pthread_tsd_start = _INTERNAL_POSIX_THREAD_KEYS_MAX;
66 static const int __pthread_tsd_end = _INTERNAL_POSIX_THREAD_KEYS_END;
67
68 // Omit support for pthread key destructors in the static archive for dyld.
69 // dyld does not create and destroy threads so these are not necessary.
70 //
71 // We store the bit-wise negation of the destructor so that a quick non-zero
72 // test can be used to determine if the destructor has been set, even if it is
73 // NULL. This means that a destructor of value ~0x0ull cannot be used. That
74 // shouldn't be a problem in practice since it isn't a valid function address.
75
76 static struct {
77 uintptr_t destructor;
78 } _pthread_keys[_INTERNAL_POSIX_THREAD_KEYS_END];
79
80 static pthread_lock_t tsd_lock = LOCK_INITIALIZER;
81
82 // Returns true if successful, false if destructor was already set.
83 static bool
84 _pthread_key_set_destructor(pthread_key_t key, void (*destructor)(void *))
85 {
86 uintptr_t *ptr = &_pthread_keys[key].destructor;
87 uintptr_t value = ~(uintptr_t)destructor;
88 if (*ptr == 0) {
89 *ptr = value;
90 return true;
91 }
92 return false;
93 }
94
95 // Returns true if successful, false if the destructor was not set.
96 static bool
97 _pthread_key_unset_destructor(pthread_key_t key)
98 {
99 uintptr_t *ptr = &_pthread_keys[key].destructor;
100 if (*ptr != 0) {
101 *ptr = 0;
102 return true;
103 }
104 return false;
105 }
106
107 // Returns true if successful, false if the destructor was not set.
108 static bool
109 _pthread_key_get_destructor(pthread_key_t key, void (**destructor)(void *))
110 {
111 uintptr_t value = _pthread_keys[key].destructor;
112 if (destructor) {
113 *destructor = (void (*)(void *))(~value);
114 }
115 return (value != 0);
116 }
117
118 int
119 pthread_key_create(pthread_key_t *key, void (*destructor)(void *))
120 {
121 int res = EAGAIN; // Returns EAGAIN if key cannot be allocated.
122 pthread_key_t k;
123
124 LOCK(tsd_lock);
125 for (k = __pthread_tsd_start; k < __pthread_tsd_end; k++) {
126 if (_pthread_key_set_destructor(k, destructor)) {
127 *key = k;
128 res = 0;
129 break;
130 }
131 }
132 UNLOCK(tsd_lock);
133
134 return res;
135 }
136
137 int
138 pthread_key_delete(pthread_key_t key)
139 {
140 int res = EINVAL; // Returns EINVAL if key is not allocated.
141
142 LOCK(tsd_lock);
143 if (key >= __pthread_tsd_start && key < __pthread_tsd_end) {
144 if (_pthread_key_unset_destructor(key)) {
145 struct _pthread *p;
146 LOCK(_pthread_list_lock);
147 TAILQ_FOREACH(p, &__pthread_head, plist) {
148 // No lock for word-sized write.
149 p->tsd[key] = 0;
150 }
151 UNLOCK(_pthread_list_lock);
152 res = 0;
153 }
154 }
155 UNLOCK(tsd_lock);
156
157 return res;
158 }
159 #endif // !VARIANT_DYLD
160
161 int
162 pthread_setspecific(pthread_key_t key, const void *value)
163 {
164 int res = EINVAL;
165
166 #if !VARIANT_DYLD
167 if (key >= __pthread_tsd_first && key < __pthread_tsd_end) {
168 bool created = _pthread_key_get_destructor(key, NULL);
169 if (key < __pthread_tsd_start || created) {
170 struct _pthread *self = pthread_self();
171 self->tsd[key] = (void *)value;
172 res = 0;
173
174 if (key < __pthread_tsd_start) {
175 // XXX: is this really necessary?
176 _pthread_key_set_destructor(key, NULL);
177 }
178 if (key > self->max_tsd_key) {
179 self->max_tsd_key = (int)key;
180 }
181 }
182 }
183 #endif // !VARIANT_DYLD
184
185 return res;
186 }
187
188 void*
189 pthread_getspecific(pthread_key_t key)
190 {
191 return _pthread_getspecific_direct(key);
192 }
193
194 #if !VARIANT_DYLD
195 static void
196 _pthread_tsd_cleanup_key(pthread_t self, pthread_key_t key)
197 {
198 void (*destructor)(void *);
199 if (_pthread_key_get_destructor(key, &destructor)) {
200 void **ptr = &self->tsd[key];
201 void *value = *ptr;
202 if (value) {
203 *ptr = NULL;
204 if (destructor) {
205 destructor(value);
206 }
207 }
208 }
209 }
210 #endif // !VARIANT_DYLD
211
212 void
213 _pthread_tsd_cleanup(pthread_t self)
214 {
215 #if !VARIANT_DYLD
216 int j;
217
218 // clean up dynamic keys first
219 for (j = 0; j < PTHREAD_DESTRUCTOR_ITERATIONS; j++) {
220 pthread_key_t k;
221 for (k = __pthread_tsd_start; k <= self->max_tsd_key; k++) {
222 _pthread_tsd_cleanup_key(self, k);
223 }
224 }
225
226 self->max_tsd_key = 0;
227
228 // clean up static keys
229 for (j = 0; j < PTHREAD_DESTRUCTOR_ITERATIONS; j++) {
230 pthread_key_t k;
231 for (k = __pthread_tsd_first; k <= __pthread_tsd_max; k++) {
232 _pthread_tsd_cleanup_key(self, k);
233 }
234 }
235 #endif // !VARIANT_DYLD
236 }
237
238 #if !VARIANT_DYLD
239 // XXX: key should be pthread_key_t
240 int
241 pthread_key_init_np(int key, void (*destructor)(void *))
242 {
243 int res = EINVAL; // Returns EINVAL if key is out of range.
244 if (key >= __pthread_tsd_first && key < __pthread_tsd_start) {
245 LOCK(tsd_lock);
246 _pthread_key_set_destructor(key, destructor);
247 if (key > __pthread_tsd_max) {
248 __pthread_tsd_max = key;
249 }
250 UNLOCK(tsd_lock);
251 res = 0;
252 }
253 return res;
254 }
255 #endif // !VARIANT_DYLD
256
257 #undef pthread_self
258 pthread_t
259 pthread_self(void)
260 {
261 return _pthread_getspecific_direct(_PTHREAD_TSD_SLOT_PTHREAD_SELF);
262 }