* Copyright (c) 2000-2003, 2007, 2012 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
- *
+ *
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
- *
+ *
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
- *
+ *
* @APPLE_LICENSE_HEADER_END@
*/
/*
- * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
- * All Rights Reserved
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose and without fee is hereby granted,
- * provided that the above copyright notice appears in all copies and
- * that both the copyright notice and this permission notice appear in
- * supporting documentation.
- *
- * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE.
- *
- * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
- * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
+ * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
*/
/*
* MkLinux
*/
#include "internal.h"
-#include <TargetConditionals.h>
+
+#ifndef PTHREAD_KEY_LEGACY_SUPPORT
+#if TARGET_OS_DRIVERKIT
+#define PTHREAD_KEY_LEGACY_SUPPORT 0
+#else
+#define PTHREAD_KEY_LEGACY_SUPPORT 1
+#endif // TARGET_OS_DRIVERKIT
+#endif // PTHREAD_KEY_LEGACY_SUPPORT
#if !VARIANT_DYLD
// __pthread_tsd_first is first static key managed by libpthread.
// __pthread_tsd_end is the end of dynamic keys.
static const int __pthread_tsd_first = __TSD_RESERVED_MAX + 1;
-static int __pthread_tsd_max = __pthread_tsd_first;
static const int __pthread_tsd_start = _INTERNAL_POSIX_THREAD_KEYS_MAX;
static const int __pthread_tsd_end = _INTERNAL_POSIX_THREAD_KEYS_END;
-static int __pthread_key_legacy_behaviour = 0;
-static int __pthread_key_legacy_behaviour_log = 0;
+static int __pthread_tsd_max = __pthread_tsd_first;
+static _pthread_lock __pthread_tsd_lock = _PTHREAD_LOCK_INITIALIZER;
+#if PTHREAD_KEY_LEGACY_SUPPORT
+static bool __pthread_key_legacy_behaviour = 0;
+static bool __pthread_key_legacy_behaviour_log = 0;
+#else
+#define __pthread_key_legacy_behaviour 0
+#define _pthread_tsd_cleanup_legacy(...)
+#endif // PTHREAD_KEY_LEGACY_SUPPORT
// Omit support for pthread key destructors in the static archive for dyld.
// dyld does not create and destroy threads so these are not necessary.
uintptr_t destructor;
} _pthread_keys[_INTERNAL_POSIX_THREAD_KEYS_END];
-static pthread_lock_t tsd_lock = LOCK_INITIALIZER;
-
// The pthread_tsd destruction order can be reverted to the old (pre-10.11) order
// by setting this environment variable.
void
_pthread_key_global_init(const char *envp[])
{
- __pthread_key_legacy_behaviour = _simple_getenv(envp, "PTHREAD_KEY_LEGACY_DESTRUCTOR_ORDER") ? 1 : 0;
- __pthread_key_legacy_behaviour_log = _simple_getenv(envp, "PTHREAD_KEY_LEGACY_DESTRUCTOR_ORDER_LOG") ? 1 : 0;
+#if PTHREAD_KEY_LEGACY_SUPPORT
+ if (_simple_getenv(envp, "PTHREAD_KEY_LEGACY_DESTRUCTOR_ORDER")) {
+ __pthread_key_legacy_behaviour = true;
+ }
+ if (_simple_getenv(envp, "PTHREAD_KEY_LEGACY_DESTRUCTOR_ORDER_LOG")) {
+ __pthread_key_legacy_behaviour_log = true;
+ }
+#endif // PTHREAD_KEY_LEGACY_SUPPORT
}
// Returns true if successful, false if destructor was already set.
int res = EAGAIN; // Returns EAGAIN if key cannot be allocated.
pthread_key_t k;
- LOCK(tsd_lock);
+ _pthread_lock_lock(&__pthread_tsd_lock);
for (k = __pthread_tsd_start; k < __pthread_tsd_end; k++) {
if (_pthread_key_set_destructor(k, destructor)) {
*key = k;
break;
}
}
- UNLOCK(tsd_lock);
+ _pthread_lock_unlock(&__pthread_tsd_lock);
return res;
}
{
int res = EINVAL; // Returns EINVAL if key is not allocated.
- LOCK(tsd_lock);
+ _pthread_lock_lock(&__pthread_tsd_lock);
if (key >= __pthread_tsd_start && key < __pthread_tsd_end) {
if (_pthread_key_unset_destructor(key)) {
- struct _pthread *p;
- LOCK(_pthread_list_lock);
- TAILQ_FOREACH(p, &__pthread_head, plist) {
+ pthread_t p;
+ _pthread_lock_lock(&_pthread_list_lock);
+ TAILQ_FOREACH(p, &__pthread_head, tl_plist) {
// No lock for word-sized write.
p->tsd[key] = 0;
}
- UNLOCK(_pthread_list_lock);
+ _pthread_lock_unlock(&_pthread_list_lock);
res = 0;
}
}
- UNLOCK(tsd_lock);
+ _pthread_lock_unlock(&__pthread_tsd_lock);
return res;
}
-#endif // !VARIANT_DYLD
-int
-pthread_setspecific(pthread_key_t key, const void *value)
+static inline int
+_pthread_setspecific(pthread_t thread, pthread_key_t key, const void *value)
{
int res = EINVAL;
-#if !VARIANT_DYLD
if (key >= __pthread_tsd_first && key < __pthread_tsd_end) {
bool created = _pthread_key_get_destructor(key, NULL);
if (key < __pthread_tsd_start || created) {
- struct _pthread *self = pthread_self();
- self->tsd[key] = (void *)value;
+ thread->tsd[key] = (void *)value;
res = 0;
if (key < __pthread_tsd_start) {
// XXX: is this really necessary?
_pthread_key_set_destructor(key, NULL);
}
- if (key > self->max_tsd_key) {
- self->max_tsd_key = (int)key;
+ if (key > thread->max_tsd_key) {
+ thread->max_tsd_key = (uint16_t)key;
}
}
}
+
+ return res;
+}
+#endif // !VARIANT_DYLD
+
+int
+pthread_setspecific(pthread_key_t key, const void *value)
+{
+#if VARIANT_DYLD
+ return ENOTSUP;
+#else
+ return _pthread_setspecific(pthread_self(), key, value);
+#endif // !VARIANT_DYLD
+}
+
+int
+_pthread_setspecific_static(pthread_key_t key, void *value)
+{
+ int res = EINVAL;
+
+#if !VARIANT_DYLD
+ if (key < __pthread_tsd_start) {
+ _pthread_setspecific_direct(key, value);
+ res = 0;
+ }
#endif // !VARIANT_DYLD
return res;
}
#if !VARIANT_DYLD
+int
+pthread_introspection_setspecific_np(pthread_t thread,
+ pthread_key_t key, const void *value)
+{
+ pthread_t self = _pthread_self();
+ if (os_unlikely(self->introspection != PTHREAD_INTROSPECTION_THREAD_CREATE)) {
+ PTHREAD_CLIENT_CRASH(0, "Calling pthread_introspection_setspecific_np "
+ "outside of a CREATE introspection hook");
+ }
+ return _pthread_setspecific(thread, key, value);
+
+}
+
+void *
+pthread_introspection_getspecific_np(pthread_t thread, pthread_key_t key)
+{
+ pthread_t self = _pthread_self();
+ if (os_unlikely(self->introspection != PTHREAD_INTROSPECTION_THREAD_DESTROY)) {
+ PTHREAD_CLIENT_CRASH(0, "Calling pthread_introspection_getspecific_np "
+ "outside of a DESTROY introspection hook");
+ }
+ return thread->tsd[key];
+}
+
static void
_pthread_tsd_cleanup_key(pthread_t self, pthread_key_t key)
{
}
}
}
-#endif // !VARIANT_DYLD
-
-#import <_simple.h>
-#import <dlfcn.h>
-#if !VARIANT_DYLD
static void
_pthread_tsd_cleanup_new(pthread_t self)
{
int j;
- // clean up all keys except the garbage collection key
+ // clean up all keys
for (j = 0; j < PTHREAD_DESTRUCTOR_ITERATIONS; j++) {
pthread_key_t k;
for (k = __pthread_tsd_start; k <= self->max_tsd_key; k++) {
}
for (k = __pthread_tsd_first; k <= __pthread_tsd_max; k++) {
- if (k >= __PTK_FRAMEWORK_GC_KEY0 && k <= __PTK_FRAMEWORK_GC_KEY9) {
- // GC must be cleaned up last
- continue;
- }
_pthread_tsd_cleanup_key(self, k);
}
}
self->max_tsd_key = 0;
-
- // clean up all the GC keys
- for (j = 0; j < PTHREAD_DESTRUCTOR_ITERATIONS; j++) {
- pthread_key_t k;
- for (k = __PTK_FRAMEWORK_GC_KEY0; k <= __PTK_FRAMEWORK_GC_KEY9; k++) {
- _pthread_tsd_cleanup_key(self, k);
- }
- }
}
+#if PTHREAD_KEY_LEGACY_SUPPORT
+#import <_simple.h>
+#import <dlfcn.h>
static void
_pthread_tsd_behaviour_check(pthread_t self)
{
// Iterate from dynamic-key start to dynamic-key end, if the key has both
// a desctructor and a value then _pthread_tsd_cleanup_key would cause
// us to re-trigger the destructor.
- Dl_info i;
pthread_key_t k;
- for (k = __pthread_tsd_start; k <= __pthread_tsd_end; k++) {
+ for (k = __pthread_tsd_start; k < __pthread_tsd_end; k++) {
void (*destructor)(void *);
if (_pthread_key_get_destructor(k, &destructor)) {
void **ptr = &self->tsd[k];
if (value && destructor) {
_simple_asl_log(ASL_LEVEL_ERR, "pthread_tsd",
"warning: dynamic tsd keys dirty after static key cleanup loop.");
-
+#if 0
+ // enable this for debugging
+ Dl_info i;
if (dladdr(destructor, &i) == 0) {
_simple_asl_log(ASL_LEVEL_ERR, "pthread_tsd", i.dli_fname);
_simple_asl_log(ASL_LEVEL_ERR, "pthread_tsd", i.dli_saddr);
}
+#endif
}
}
}
}
}
}
+#endif // PTHREAD_KEY_LEGACY_SUPPORT
#endif // !VARIANT_DYLD
void
{
int res = EINVAL; // Returns EINVAL if key is out of range.
if (key >= __pthread_tsd_first && key < __pthread_tsd_start) {
- LOCK(tsd_lock);
+ _pthread_lock_lock(&__pthread_tsd_lock);
_pthread_key_set_destructor(key, destructor);
if (key > __pthread_tsd_max) {
__pthread_tsd_max = key;
}
- UNLOCK(tsd_lock);
+ _pthread_lock_unlock(&__pthread_tsd_lock);
res = 0;
}
return res;
pthread_t
pthread_self(void)
{
- return _pthread_getspecific_direct(_PTHREAD_TSD_SLOT_PTHREAD_SELF);
+ pthread_t self = _pthread_self_direct();
+ _pthread_validate_signature(self);
+ return self;
+}
+
+// rdar://57406917
+pthread_t
+_pthread_self(void)
+{
+ return pthread_self();
}