2 * Copyright (c) 2000-2003, 2007, 2012 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
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.
33 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
34 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
35 * FOR A PARTICULAR PURPOSE.
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.
49 * POSIX Pthread Library
50 * Thread Specific Data support
51 * NB: pthread_getspecific() is in a separate assembly file
55 #include <TargetConditionals.h>
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.
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
;
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.
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.
78 } _pthread_keys
[_INTERNAL_POSIX_THREAD_KEYS_END
];
80 static pthread_lock_t tsd_lock
= LOCK_INITIALIZER
;
82 // Returns true if successful, false if destructor was already set.
84 _pthread_key_set_destructor(pthread_key_t key
, void (*destructor
)(void *))
86 uintptr_t *ptr
= &_pthread_keys
[key
].destructor
;
87 uintptr_t value
= ~(uintptr_t)destructor
;
95 // Returns true if successful, false if the destructor was not set.
97 _pthread_key_unset_destructor(pthread_key_t key
)
99 uintptr_t *ptr
= &_pthread_keys
[key
].destructor
;
107 // Returns true if successful, false if the destructor was not set.
109 _pthread_key_get_destructor(pthread_key_t key
, void (**destructor
)(void *))
111 uintptr_t value
= _pthread_keys
[key
].destructor
;
113 *destructor
= (void (*)(void *))(~value
);
119 pthread_key_create(pthread_key_t
*key
, void (*destructor
)(void *))
121 int res
= EAGAIN
; // Returns EAGAIN if key cannot be allocated.
125 for (k
= __pthread_tsd_start
; k
< __pthread_tsd_end
; k
++) {
126 if (_pthread_key_set_destructor(k
, destructor
)) {
138 pthread_key_delete(pthread_key_t key
)
140 int res
= EINVAL
; // Returns EINVAL if key is not allocated.
143 if (key
>= __pthread_tsd_start
&& key
< __pthread_tsd_end
) {
144 if (_pthread_key_unset_destructor(key
)) {
146 LOCK(_pthread_list_lock
);
147 TAILQ_FOREACH(p
, &__pthread_head
, plist
) {
148 // No lock for word-sized write.
151 UNLOCK(_pthread_list_lock
);
159 #endif // !VARIANT_DYLD
162 pthread_setspecific(pthread_key_t key
, const void *value
)
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
;
174 if (key
< __pthread_tsd_start
) {
175 // XXX: is this really necessary?
176 _pthread_key_set_destructor(key
, NULL
);
178 if (key
> self
->max_tsd_key
) {
179 self
->max_tsd_key
= (int)key
;
183 #endif // !VARIANT_DYLD
189 pthread_getspecific(pthread_key_t key
)
191 return _pthread_getspecific_direct(key
);
196 _pthread_tsd_cleanup_key(pthread_t self
, pthread_key_t key
)
198 void (*destructor
)(void *);
199 if (_pthread_key_get_destructor(key
, &destructor
)) {
200 void **ptr
= &self
->tsd
[key
];
210 #endif // !VARIANT_DYLD
213 _pthread_tsd_cleanup(pthread_t self
)
218 // clean up dynamic keys first
219 for (j
= 0; j
< PTHREAD_DESTRUCTOR_ITERATIONS
; j
++) {
221 for (k
= __pthread_tsd_start
; k
<= self
->max_tsd_key
; k
++) {
222 _pthread_tsd_cleanup_key(self
, k
);
226 self
->max_tsd_key
= 0;
228 // clean up static keys
229 for (j
= 0; j
< PTHREAD_DESTRUCTOR_ITERATIONS
; j
++) {
231 for (k
= __pthread_tsd_first
; k
<= __pthread_tsd_max
; k
++) {
232 _pthread_tsd_cleanup_key(self
, k
);
235 #endif // !VARIANT_DYLD
239 // XXX: key should be pthread_key_t
241 pthread_key_init_np(int key
, void (*destructor
)(void *))
243 int res
= EINVAL
; // Returns EINVAL if key is out of range.
244 if (key
>= __pthread_tsd_first
&& key
< __pthread_tsd_start
) {
246 _pthread_key_set_destructor(key
, destructor
);
247 if (key
> __pthread_tsd_max
) {
248 __pthread_tsd_max
= key
;
255 #endif // !VARIANT_DYLD
261 return _pthread_getspecific_direct(_PTHREAD_TSD_SLOT_PTHREAD_SELF
);