Skip to content

[5.5][Concurrency] Use pthread_specific for thread-local storage on Darwin. #38163

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 60 additions & 20 deletions include/swift/Runtime/ThreadLocal.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,15 @@
#ifndef SWIFT_RUNTIME_THREADLOCAL_H
#define SWIFT_RUNTIME_THREADLOCAL_H

#include <type_traits>
#include "ThreadLocalStorage.h"

/// SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL - Does the current configuration
/// allow the use of SWIFT_RUNTIME_ATTRIBUTE_THREAD_LOCAL?
#if defined(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME)
#if defined(__APPLE__)
// The pthread TLS APIs work better than C++ TLS on Apple platforms.
#define SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL 0
#elif defined(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME)
// We define SWIFT_RUNTIME_ATTRIBUTE_THREAD_LOCAL to nothing in this
// configuration and just use a global variable, so this is okay.
#define SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL 1
Expand Down Expand Up @@ -57,6 +63,17 @@
#endif

namespace swift {
// Validate a type stored in thread-local storage, using static asserts. Such
// types must fit in a pointer and be trivially copyable/destructible.
#define VALIDATE_THREAD_LOCAL_TYPE(T) \
static_assert(sizeof(T) <= sizeof(void *), \
"cannot store more than a pointer"); \
static_assert(std::is_trivially_copyable<T>::value, \
"ThreadLocal values must be trivially copyable"); \
static_assert(std::is_trivially_destructible<T>::value, \
"ThreadLocal cleanup is not supported, stored types must be " \
"trivially destructible");

// A wrapper class for thread-local storage.
//
// - On platforms that report SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL
Expand All @@ -72,50 +89,70 @@ namespace swift {
// - On platforms that don't report SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL,
// we have to simulate thread-local storage. Fortunately, all of
// these platforms (at least for now) support pthread_getspecific.
#if SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL
template <class T>
class ThreadLocal {
static_assert(sizeof(T) <= sizeof(void*), "cannot store more than a pointer");
VALIDATE_THREAD_LOCAL_TYPE(T)

#if SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL
T value;

public:
constexpr ThreadLocal() {}

T get() { return value; }

void set(T newValue) { value = newValue; }
};
#else
// A wrapper around a pthread_key_t that is lazily initialized using
// dispatch_once.
class ThreadLocalKey {
// We rely on the zero-initialization of objects with static storage
// duration.
dispatch_once_t once;
pthread_key_t key;

public:
pthread_key_t getKey() {
dispatch_once_f(&once, this, [](void *ctx) {
pthread_key_create(&reinterpret_cast<ThreadLocal*>(ctx)->key, nullptr);
dispatch_once_f(&once, &key, [](void *ctx) {
pthread_key_create(reinterpret_cast<pthread_key_t *>(ctx), nullptr);
});
return key;
}
#endif
};

// A type representing a constant pthread_key_t, for use on platforms that
// provide reserved keys.
template <pthread_key_t constantKey>
class ConstantThreadLocalKey {
public:
pthread_key_t getKey() { return constantKey; }
};

template <class T, class Key>
class ThreadLocal {
VALIDATE_THREAD_LOCAL_TYPE(T)

Key key;

public:
constexpr ThreadLocal() {}

T get() {
#if SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL
return value;
#else
void *storedValue = pthread_getspecific(getKey());
void *storedValue = SWIFT_THREAD_GETSPECIFIC(key.getKey());
T value;
memcpy(&value, &storedValue, sizeof(T));
return value;
#endif
}

void set(T newValue) {
#if SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL
value = newValue;
#else
void *storedValue;
memcpy(&storedValue, &newValue, sizeof(T));
pthread_setspecific(getKey(), storedValue);
#endif
SWIFT_THREAD_SETSPECIFIC(key.getKey(), storedValue);
}
};
#endif

} // end namespace swift

/// SWIFT_RUNTIME_DECLARE_THREAD_LOCAL(TYPE, NAME) - Declare a variable
Expand All @@ -124,13 +161,16 @@ class ThreadLocal {
///
/// Because of the fallback path, the default-initialization of the
/// type must be equivalent to a bitwise zero-initialization, and the
/// type must be small and trivially copyable.
/// type must be small and trivially copyable and destructible.
#if SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL
#define SWIFT_RUNTIME_DECLARE_THREAD_LOCAL(TYPE, NAME) \
#define SWIFT_RUNTIME_DECLARE_THREAD_LOCAL(TYPE, NAME, KEY) \
SWIFT_RUNTIME_ATTRIBUTE_THREAD_LOCAL swift::ThreadLocal<TYPE> NAME
#elif SWIFT_TLS_HAS_RESERVED_PTHREAD_SPECIFIC
#define SWIFT_RUNTIME_DECLARE_THREAD_LOCAL(TYPE, NAME, KEY) \
swift::ThreadLocal<TYPE, ConstantThreadLocalKey<KEY>> NAME
#else
#define SWIFT_RUNTIME_DECLARE_THREAD_LOCAL(TYPE, NAME) \
swift::ThreadLocal<TYPE> NAME
#define SWIFT_RUNTIME_DECLARE_THREAD_LOCAL(TYPE, NAME, KEY) \
swift::ThreadLocal<TYPE, ThreadLocalKey> NAME
#endif

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,33 @@ extern "C" int pthread_key_init_np(int key, void (*destructor)(void *));
# ifndef __PTK_FRAMEWORK_SWIFT_KEY3
# define __PTK_FRAMEWORK_SWIFT_KEY3 103
# endif
# ifndef __PTK_FRAMEWORK_SWIFT_KEY4
# define __PTK_FRAMEWORK_SWIFT_KEY4 104
# endif
# ifndef __PTK_FRAMEWORK_SWIFT_KEY5
# define __PTK_FRAMEWORK_SWIFT_KEY5 105
# endif
# ifndef __PTK_FRAMEWORK_SWIFT_KEY6
# define __PTK_FRAMEWORK_SWIFT_KEY6 106
# endif
# ifndef __PTK_FRAMEWORK_SWIFT_KEY7
# define __PTK_FRAMEWORK_SWIFT_KEY7 107
# endif
# ifndef __PTK_FRAMEWORK_SWIFT_KEY8
# define __PTK_FRAMEWORK_SWIFT_KEY8 108
# endif
# ifndef __PTK_FRAMEWORK_SWIFT_KEY9
# define __PTK_FRAMEWORK_SWIFT_KEY9 109
# endif


# define SWIFT_RUNTIME_TLS_KEY __PTK_FRAMEWORK_SWIFT_KEY0
# define SWIFT_STDLIB_TLS_KEY __PTK_FRAMEWORK_SWIFT_KEY1
# define SWIFT_COMPATIBILITY_50_TLS_KEY __PTK_FRAMEWORK_SWIFT_KEY2
# define SWIFT_CONCURRENCY_TASK_KEY __PTK_FRAMEWORK_SWIFT_KEY3
# define SWIFT_CONCURRENCY_EXECUTOR_TRACKING_INFO_KEY __PTK_FRAMEWORK_SWIFT_KEY4
# define SWIFT_CONCURRENCY_FALLBACK_TASK_LOCAL_STORAGE_KEY \
__PTK_FRAMEWORK_SWIFT_KEY5

#endif

Expand Down
29 changes: 11 additions & 18 deletions stdlib/public/Concurrency/Actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@
#endif

#include "../CompatibilityOverride/CompatibilityOverride.h"
#include "../runtime/ThreadLocalStorage.h"
#include "swift/Runtime/Atomic.h"
#include "swift/Runtime/Casting.h"
#include "swift/Runtime/Once.h"
#include "swift/Runtime/Mutex.h"
#include "swift/Runtime/ThreadLocal.h"
#include "swift/Runtime/ThreadLocalStorage.h"
#include "swift/ABI/Task.h"
#include "swift/ABI/Actor.h"
#include "llvm/ADT/PointerIntPair.h"
Expand Down Expand Up @@ -111,8 +111,9 @@ class ExecutorTrackingInfo {
/// the right executor. It would make sense for that to be a
/// separate thread-local variable (or whatever is most efficient
/// on the target platform).
static SWIFT_RUNTIME_DECLARE_THREAD_LOCAL(Pointer<ExecutorTrackingInfo>,
ActiveInfoInThread);
static SWIFT_RUNTIME_DECLARE_THREAD_LOCAL(
Pointer<ExecutorTrackingInfo>, ActiveInfoInThread,
SWIFT_CONCURRENCY_EXECUTOR_TRACKING_INFO_KEY);

/// The active executor.
ExecutorRef ActiveExecutor = ExecutorRef::generic();
Expand Down Expand Up @@ -186,21 +187,11 @@ class ExecutorTrackingInfo {
}
};

#ifdef SWIFT_TLS_HAS_RESERVED_PTHREAD_SPECIFIC
class ActiveTask {
public:
static void set(AsyncTask *task) {
SWIFT_THREAD_SETSPECIFIC(SWIFT_CONCURRENCY_TASK_KEY, task);
}
static AsyncTask *get() {
return (AsyncTask *)SWIFT_THREAD_GETSPECIFIC(SWIFT_CONCURRENCY_TASK_KEY);
}
};
#else
class ActiveTask {
/// A thread-local variable pointing to the active tracking
/// information about the current thread, if any.
static SWIFT_RUNTIME_DECLARE_THREAD_LOCAL(Pointer<AsyncTask>, Value);
static SWIFT_RUNTIME_DECLARE_THREAD_LOCAL(Pointer<AsyncTask>, Value,
SWIFT_CONCURRENCY_TASK_KEY);

public:
static void set(AsyncTask *task) { Value.set(task); }
Expand All @@ -210,11 +201,13 @@ class ActiveTask {
/// Define the thread-locals.
SWIFT_RUNTIME_DECLARE_THREAD_LOCAL(
Pointer<AsyncTask>,
ActiveTask::Value);
#endif
ActiveTask::Value,
SWIFT_CONCURRENCY_TASK_KEY);

SWIFT_RUNTIME_DECLARE_THREAD_LOCAL(
Pointer<ExecutorTrackingInfo>,
ExecutorTrackingInfo::ActiveInfoInThread);
ExecutorTrackingInfo::ActiveInfoInThread,
SWIFT_CONCURRENCY_EXECUTOR_TRACKING_INFO_KEY);

} // end anonymous namespace

Expand Down
10 changes: 5 additions & 5 deletions stdlib/public/Concurrency/TaskLocal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
//===----------------------------------------------------------------------===//

#include "../CompatibilityOverride/CompatibilityOverride.h"
#include "../runtime/ThreadLocalStorage.h"
#include "swift/Runtime/Atomic.h"
#include "swift/Runtime/Casting.h"
#include "swift/Runtime/Once.h"
#include "swift/Runtime/Mutex.h"
#include "swift/Runtime/Concurrency.h"
#include "swift/Runtime/ThreadLocal.h"
#include "swift/Runtime/ThreadLocalStorage.h"
#include "swift/ABI/TaskLocal.h"
#include "swift/ABI/Task.h"
#include "swift/ABI/Actor.h"
Expand Down Expand Up @@ -59,8 +59,8 @@ template <class T> struct Pointer {
/// THIS IS RUNTIME INTERNAL AND NOT ABI.
class FallbackTaskLocalStorage {
static SWIFT_RUNTIME_DECLARE_THREAD_LOCAL(
Pointer<TaskLocal::Storage>,
Value);
Pointer<TaskLocal::Storage>, Value,
SWIFT_CONCURRENCY_FALLBACK_TASK_LOCAL_STORAGE_KEY);

public:
static void set(TaskLocal::Storage *task) { Value.set(task); }
Expand All @@ -69,8 +69,8 @@ class FallbackTaskLocalStorage {

/// Define the thread-locals.
SWIFT_RUNTIME_DECLARE_THREAD_LOCAL(
Pointer<TaskLocal::Storage>,
FallbackTaskLocalStorage::Value);
Pointer<TaskLocal::Storage>, FallbackTaskLocalStorage::Value,
SWIFT_CONCURRENCY_FALLBACK_TASK_LOCAL_STORAGE_KEY);

// ==== ABI --------------------------------------------------------------------

Expand Down
2 changes: 1 addition & 1 deletion stdlib/public/runtime/Exclusivity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@

#include "swift/Runtime/Exclusivity.h"
#include "../SwiftShims/Visibility.h"
#include "ThreadLocalStorage.h"
#include "swift/Basic/Lazy.h"
#include "swift/Runtime/Config.h"
#include "swift/Runtime/Debug.h"
#include "swift/Runtime/Metadata.h"
#include "swift/Runtime/ThreadLocalStorage.h"
#include <memory>
#include <inttypes.h>
#include <stdio.h>
Expand Down
2 changes: 1 addition & 1 deletion stdlib/public/stubs/ThreadLocalStorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
#include <cstring>

#include "../SwiftShims/ThreadLocalStorage.h"
#include "../runtime/ThreadLocalStorage.h"
#include "swift/Basic/Lazy.h"
#include "swift/Runtime/Debug.h"
#include "swift/Runtime/ThreadLocalStorage.h"

SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
void _stdlib_destroyTLS(void *);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

#include "swift/Runtime/Once.h"
#include "swift/Runtime/Exclusivity.h"
#include "../../public/runtime/ThreadLocalStorage.h"
#include "swift/Runtime/ThreadLocalStorage.h"

using namespace swift;

Expand Down