Files
swift-mirror/include/swift/Runtime/ThreadLocal.h
Alastair Houghton 0cf687aa2b [Build][Runtime] Replace SWIFT_STDLIB_SINGLE_THREADED_RUNTIME.
SWIFT_STDLIB_SINGLE_THREADED_RUNTIME is too much of a blunt instrument here.
It covers both the Concurrency runtime and the rest of the runtime, but we'd
like to be able to have e.g. a single-threaded Concurrency runtime while
the rest of the runtime is still thread safe (for instance).

So: rename it to SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY and make it just
control the Concurrency runtime, then add a SWIFT_STDLIB_THREADING_PACKAGE
setting at the CMake/build-script level, which defines
SWIFT_STDLIB_THREADING_xxx where xxx depends on the chosen threading package.

This is especially useful on systems where there may be a choice of threading
package that you could use.

rdar://90776105
2022-06-07 07:39:51 +01:00

179 lines
6.2 KiB
C++

//===--- ThreadLocal.h - Thread-local storage -------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Declarations and macros for working with thread-local storage in the
// Swift runtime.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_RUNTIME_THREADLOCAL_H
#define SWIFT_RUNTIME_THREADLOCAL_H
#include <type_traits>
#include "ThreadLocalStorage.h"
#include "Once.h"
/// SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL - Does the current configuration
/// allow the use of SWIFT_RUNTIME_ATTRIBUTE_THREAD_LOCAL?
#if SWIFT_STDLIB_THREADING_NONE
// 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
#elif SWIFT_STDLIB_THREADING_DARWIN
// The pthread TLS APIs work better than C++ TLS on Apple platforms.
#define SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL 0
#elif __has_feature(tls)
// If __has_feature reports that TLS is available, use it.
#define SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL 1
#elif !defined(__clang__)
// If we're not using Clang, assume that __has_feature is unreliable
// and that we can safely use TLS.
#else
// Otherwise we can't use TLS and have to fall back on something else.
#define SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL 0
#endif
/// SWIFT_RUNTIME_THREAD_LOCAL - Declare that something is a
/// thread-local variable in the runtime.
#if SWIFT_STDLIB_THREADING_NONE
// In a single-threaded runtime, thread-locals are global.
#define SWIFT_RUNTIME_ATTRIBUTE_THREAD_LOCAL
#elif defined(__GNUC__)
// In GCC-compatible compilers, we prefer __thread because it's understood
// to guarantee a constant initializer, which permits more efficient access
// patterns.
#define SWIFT_RUNTIME_ATTRIBUTE_THREAD_LOCAL __thread
#else
// Otherwise, just fall back on the standard C++ feature.
#define SWIFT_RUNTIME_ATTRIBUTE_THREAD_LOCAL thread_local
#endif
// Implementation of SWIFT_RUNTIME_DECLARE_THREAD_LOCAL
#if !SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL
#include <pthread.h>
#include <dispatch/dispatch.h>
#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
// above, an object of this type is declared with
// SWIFT_RUNTIME_ATTRIBUTE_THREAD_LOCAL. This makes the object
// itself thread-local, and no internal support is required.
//
// Note that this includes platforms that don't support threading,
// for which SWIFT_RUNTIME_ATTRIBUTE_THREAD_LOCAL is empty;
// thread-local declarations then create an ordinary global.
//
// - 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
// or similar.
#if SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL
template <class T>
class ThreadLocal {
VALIDATE_THREAD_LOCAL_TYPE(T)
T value;
public:
constexpr ThreadLocal() {}
T get() { return value; }
void set(T newValue) { value = newValue; }
};
#else
// A wrapper around a __swift_thread_key_t that is lazily initialized using
// dispatch_once.
class ThreadLocalKey {
// We rely on the zero-initialization of objects with static storage
// duration.
swift_once_t once;
__swift_thread_key_t key;
public:
__swift_thread_key_t getKey() {
swift_once(&once, [](void *ctx) {
SWIFT_THREAD_KEY_CREATE(reinterpret_cast<__swift_thread_key_t *>(ctx),
nullptr);
}, &key);
return key;
}
};
// A type representing a constant __swift_thread_key_t, for use on platforms
// that provide reserved keys.
template <__swift_thread_key_t constantKey>
class ConstantThreadLocalKey {
public:
__swift_thread_key_t getKey() { return constantKey; }
};
template <class T, class Key>
class ThreadLocal {
VALIDATE_THREAD_LOCAL_TYPE(T)
Key key;
public:
constexpr ThreadLocal() {}
T get() {
void *storedValue = SWIFT_THREAD_GETSPECIFIC(key.getKey());
T value;
memcpy(&value, &storedValue, sizeof(T));
return value;
}
void set(T newValue) {
void *storedValue;
memcpy(&storedValue, &newValue, sizeof(T));
SWIFT_THREAD_SETSPECIFIC(key.getKey(), storedValue);
}
};
#endif
} // end namespace swift
/// SWIFT_RUNTIME_DECLARE_THREAD_LOCAL(TYPE, NAME) - Declare a variable
/// to be a thread-local variable. The declaration must have static
/// storage duration; it may be prefixed with "static".
///
/// 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 and destructible.
#if SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL
#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, KEY) \
swift::ThreadLocal<TYPE, ThreadLocalKey> NAME
#endif
#endif