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
56 #ifndef PTHREAD_KEY_LEGACY_SUPPORT
57 #if TARGET_OS_DRIVERKIT
58 #define PTHREAD_KEY_LEGACY_SUPPORT 0
60 #define PTHREAD_KEY_LEGACY_SUPPORT 1
61 #endif // TARGET_OS_DRIVERKIT
62 #endif // PTHREAD_KEY_LEGACY_SUPPORT
65 // __pthread_tsd_first is first static key managed by libpthread.
66 // __pthread_tsd_max is the (observed) end of static key destructors.
67 // __pthread_tsd_start is the start of dynamic keys.
68 // __pthread_tsd_end is the end of dynamic keys.
70 static const int __pthread_tsd_first
= __TSD_RESERVED_MAX
+ 1;
71 static const int __pthread_tsd_start
= _INTERNAL_POSIX_THREAD_KEYS_MAX
;
72 static const int __pthread_tsd_end
= _INTERNAL_POSIX_THREAD_KEYS_END
;
74 static int __pthread_tsd_max
= __pthread_tsd_first
;
75 static _pthread_lock __pthread_tsd_lock
= _PTHREAD_LOCK_INITIALIZER
;
76 #if PTHREAD_KEY_LEGACY_SUPPORT
77 static bool __pthread_key_legacy_behaviour
= 0;
78 static bool __pthread_key_legacy_behaviour_log
= 0;
80 #define __pthread_key_legacy_behaviour 0
81 #define _pthread_tsd_cleanup_legacy(...)
82 #endif // PTHREAD_KEY_LEGACY_SUPPORT
84 // Omit support for pthread key destructors in the static archive for dyld.
85 // dyld does not create and destroy threads so these are not necessary.
87 // We store the bit-wise negation of the destructor so that a quick non-zero
88 // test can be used to determine if the destructor has been set, even if it is
89 // NULL. This means that a destructor of value ~0x0ull cannot be used. That
90 // shouldn't be a problem in practice since it isn't a valid function address.
94 } _pthread_keys
[_INTERNAL_POSIX_THREAD_KEYS_END
];
96 // The pthread_tsd destruction order can be reverted to the old (pre-10.11) order
97 // by setting this environment variable.
99 _pthread_key_global_init(const char *envp
[])
101 #if PTHREAD_KEY_LEGACY_SUPPORT
102 if (_simple_getenv(envp
, "PTHREAD_KEY_LEGACY_DESTRUCTOR_ORDER")) {
103 __pthread_key_legacy_behaviour
= true;
105 if (_simple_getenv(envp
, "PTHREAD_KEY_LEGACY_DESTRUCTOR_ORDER_LOG")) {
106 __pthread_key_legacy_behaviour_log
= true;
108 #endif // PTHREAD_KEY_LEGACY_SUPPORT
111 // Returns true if successful, false if destructor was already set.
113 _pthread_key_set_destructor(pthread_key_t key
, void (*destructor
)(void *))
115 uintptr_t *ptr
= &_pthread_keys
[key
].destructor
;
116 uintptr_t value
= ~(uintptr_t)destructor
;
124 // Returns true if successful, false if the destructor was not set.
126 _pthread_key_unset_destructor(pthread_key_t key
)
128 uintptr_t *ptr
= &_pthread_keys
[key
].destructor
;
136 // Returns true if successful, false if the destructor was not set.
138 _pthread_key_get_destructor(pthread_key_t key
, void (**destructor
)(void *))
140 uintptr_t value
= _pthread_keys
[key
].destructor
;
142 *destructor
= (void (*)(void *))(~value
);
148 pthread_key_create(pthread_key_t
*key
, void (*destructor
)(void *))
150 int res
= EAGAIN
; // Returns EAGAIN if key cannot be allocated.
153 _pthread_lock_lock(&__pthread_tsd_lock
);
154 for (k
= __pthread_tsd_start
; k
< __pthread_tsd_end
; k
++) {
155 if (_pthread_key_set_destructor(k
, destructor
)) {
161 _pthread_lock_unlock(&__pthread_tsd_lock
);
167 pthread_key_delete(pthread_key_t key
)
169 int res
= EINVAL
; // Returns EINVAL if key is not allocated.
171 _pthread_lock_lock(&__pthread_tsd_lock
);
172 if (key
>= __pthread_tsd_start
&& key
< __pthread_tsd_end
) {
173 if (_pthread_key_unset_destructor(key
)) {
175 _pthread_lock_lock(&_pthread_list_lock
);
176 TAILQ_FOREACH(p
, &__pthread_head
, tl_plist
) {
177 // No lock for word-sized write.
180 _pthread_lock_unlock(&_pthread_list_lock
);
184 _pthread_lock_unlock(&__pthread_tsd_lock
);
190 _pthread_setspecific(pthread_t thread
, pthread_key_t key
, const void *value
)
194 if (key
>= __pthread_tsd_first
&& key
< __pthread_tsd_end
) {
195 bool created
= _pthread_key_get_destructor(key
, NULL
);
196 if (key
< __pthread_tsd_start
|| created
) {
197 thread
->tsd
[key
] = (void *)value
;
200 if (key
< __pthread_tsd_start
) {
201 // XXX: is this really necessary?
202 _pthread_key_set_destructor(key
, NULL
);
204 if (key
> thread
->max_tsd_key
) {
205 thread
->max_tsd_key
= (uint16_t)key
;
212 #endif // !VARIANT_DYLD
215 pthread_setspecific(pthread_key_t key
, const void *value
)
220 return _pthread_setspecific(pthread_self(), key
, value
);
221 #endif // !VARIANT_DYLD
225 _pthread_setspecific_static(pthread_key_t key
, void *value
)
230 if (key
< __pthread_tsd_start
) {
231 _pthread_setspecific_direct(key
, value
);
234 #endif // !VARIANT_DYLD
240 pthread_getspecific(pthread_key_t key
)
242 return _pthread_getspecific_direct(key
);
247 pthread_introspection_setspecific_np(pthread_t thread
,
248 pthread_key_t key
, const void *value
)
250 pthread_t self
= _pthread_self();
251 if (os_unlikely(self
->introspection
!= PTHREAD_INTROSPECTION_THREAD_CREATE
)) {
252 PTHREAD_CLIENT_CRASH(0, "Calling pthread_introspection_setspecific_np "
253 "outside of a CREATE introspection hook");
255 return _pthread_setspecific(thread
, key
, value
);
260 pthread_introspection_getspecific_np(pthread_t thread
, pthread_key_t key
)
262 pthread_t self
= _pthread_self();
263 if (os_unlikely(self
->introspection
!= PTHREAD_INTROSPECTION_THREAD_DESTROY
)) {
264 PTHREAD_CLIENT_CRASH(0, "Calling pthread_introspection_getspecific_np "
265 "outside of a DESTROY introspection hook");
267 return thread
->tsd
[key
];
271 _pthread_tsd_cleanup_key(pthread_t self
, pthread_key_t key
)
273 void (*destructor
)(void *);
274 if (_pthread_key_get_destructor(key
, &destructor
)) {
275 void **ptr
= &self
->tsd
[key
];
287 _pthread_tsd_cleanup_new(pthread_t self
)
292 for (j
= 0; j
< PTHREAD_DESTRUCTOR_ITERATIONS
; j
++) {
294 for (k
= __pthread_tsd_start
; k
<= self
->max_tsd_key
; k
++) {
295 _pthread_tsd_cleanup_key(self
, k
);
298 for (k
= __pthread_tsd_first
; k
<= __pthread_tsd_max
; k
++) {
299 _pthread_tsd_cleanup_key(self
, k
);
303 self
->max_tsd_key
= 0;
306 #if PTHREAD_KEY_LEGACY_SUPPORT
310 _pthread_tsd_behaviour_check(pthread_t self
)
312 // Iterate from dynamic-key start to dynamic-key end, if the key has both
313 // a desctructor and a value then _pthread_tsd_cleanup_key would cause
314 // us to re-trigger the destructor.
317 for (k
= __pthread_tsd_start
; k
< __pthread_tsd_end
; k
++) {
318 void (*destructor
)(void *);
319 if (_pthread_key_get_destructor(k
, &destructor
)) {
320 void **ptr
= &self
->tsd
[k
];
322 if (value
&& destructor
) {
323 _simple_asl_log(ASL_LEVEL_ERR
, "pthread_tsd",
324 "warning: dynamic tsd keys dirty after static key cleanup loop.");
326 // enable this for debugging
328 if (dladdr(destructor
, &i
) == 0) {
329 _simple_asl_log(ASL_LEVEL_ERR
, "pthread_tsd", i
.dli_fname
);
330 _simple_asl_log(ASL_LEVEL_ERR
, "pthread_tsd", i
.dli_saddr
);
340 _pthread_tsd_cleanup_legacy(pthread_t self
)
344 // clean up dynamic keys first
345 for (j
= 0; j
< PTHREAD_DESTRUCTOR_ITERATIONS
; j
++) {
347 for (k
= __pthread_tsd_start
; k
<= self
->max_tsd_key
; k
++) {
348 _pthread_tsd_cleanup_key(self
, k
);
352 self
->max_tsd_key
= 0;
354 // clean up static keys
355 for (j
= 0; j
< PTHREAD_DESTRUCTOR_ITERATIONS
; j
++) {
357 for (k
= __pthread_tsd_first
; k
<= __pthread_tsd_max
; k
++) {
358 _pthread_tsd_cleanup_key(self
, k
);
361 if (__pthread_key_legacy_behaviour_log
!= 0 && self
->max_tsd_key
!= 0) {
362 // max_tsd_key got dirtied, either by static or dynamic keys being
363 // reset. check for any dirty dynamic keys.
364 _pthread_tsd_behaviour_check(self
);
368 #endif // PTHREAD_KEY_LEGACY_SUPPORT
369 #endif // !VARIANT_DYLD
372 _pthread_tsd_cleanup(pthread_t self
)
376 // unless __pthread_key_legacy_behaviour == 1, use the new pthread key
377 // destructor order: (dynamic -> static) x5 -> (GC x5)
379 if (__pthread_key_legacy_behaviour
== 0) {
380 _pthread_tsd_cleanup_new(self
);
382 _pthread_tsd_cleanup_legacy(self
);
384 #endif // !VARIANT_DYLD
388 // XXX: key should be pthread_key_t
390 pthread_key_init_np(int key
, void (*destructor
)(void *))
392 int res
= EINVAL
; // Returns EINVAL if key is out of range.
393 if (key
>= __pthread_tsd_first
&& key
< __pthread_tsd_start
) {
394 _pthread_lock_lock(&__pthread_tsd_lock
);
395 _pthread_key_set_destructor(key
, destructor
);
396 if (key
> __pthread_tsd_max
) {
397 __pthread_tsd_max
= key
;
399 _pthread_lock_unlock(&__pthread_tsd_lock
);
404 #endif // !VARIANT_DYLD
410 pthread_t self
= _pthread_self_direct();
411 _pthread_validate_signature(self
);
419 return pthread_self();