mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Threading] Create new threading library and use it.
Moved all the threading code to one place. Added explicit support for Darwin, Linux, Pthreads, C11 threads and Win32 threads, including new implementations of Once for Linux, Pthreads, C11 and Win32. rdar://90776105
This commit is contained in:
35
include/swift/Threading/Errors.h
Normal file
35
include/swift/Threading/Errors.h
Normal file
@@ -0,0 +1,35 @@
|
||||
//==--- Errors.h - Threading implementation error handling ----- -*-C++ -*-===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2022 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Declares some support routines for error handling in the threading code
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SWIFT_THREADING_ERRORS_H
|
||||
#define SWIFT_THREADING_ERRORS_H
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "swift/Basic/Compiler.h"
|
||||
|
||||
namespace swift {
|
||||
namespace threading {
|
||||
|
||||
// Users of the threading library are expected to provide this function.
|
||||
SWIFT_ATTRIBUTE_NORETURN
|
||||
SWIFT_FORMAT(1, 2)
|
||||
void fatal(const char *msg, ...);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SWIFT_THREADING_ERRORS_H
|
||||
37
include/swift/Threading/Impl.h
Normal file
37
include/swift/Threading/Impl.h
Normal file
@@ -0,0 +1,37 @@
|
||||
//===--- Impl.h - Threading abstraction implementation -------- -*- C++ -*-===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2022 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Includes the relevant implementation file based on the selected threading
|
||||
// package.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SWIFT_THREADING_IMPL_H
|
||||
#define SWIFT_THREADING_IMPL_H
|
||||
|
||||
#if SWIFT_THREADING_NONE
|
||||
#include "Impl/Nothreads.h"
|
||||
#elif SWIFT_THREADING_DARWIN
|
||||
#include "Impl/Darwin.h"
|
||||
#elif SWIFT_THREADING_LINUX
|
||||
#include "Impl/Linux.h"
|
||||
#elif SWIFT_THREADING_PTHREADS
|
||||
#include "Impl/Pthreads.h"
|
||||
#elif SWIFT_THREADING_C11
|
||||
#include "Impl/C11.h"
|
||||
#elif SWIFT_THREADING_WIN32
|
||||
#include "Impl/Win32.h"
|
||||
#else
|
||||
#error You need to implement Threading/Impl.h for your threading package.
|
||||
#endif
|
||||
|
||||
#endif // SWIFT_THREADING_IMPL_H
|
||||
180
include/swift/Threading/Impl/C11.h
Normal file
180
include/swift/Threading/Impl/C11.h
Normal file
@@ -0,0 +1,180 @@
|
||||
//==--- C11.h - Threading abstraction implementation ----------- -*-C++ -*-===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2022 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Implements threading support for C11 threads
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SWIFT_THREADING_IMPL_C11_H
|
||||
#define SWIFT_THREADING_IMPL_C11_H
|
||||
|
||||
#include <threads.h>
|
||||
#include <stdatomic.h>
|
||||
|
||||
namespace swift {
|
||||
namespace threading_impl {
|
||||
|
||||
#define SWIFT_C11THREADS_CHECK(expr) \
|
||||
do { \
|
||||
int res_ = (expr); \
|
||||
if (res_ != thrd_success) \
|
||||
swift::threading::fatal(#expr " failed with error %d\n", res_); \
|
||||
} while (0)
|
||||
|
||||
#define SWIFT_C11THREADS_RETURN_TRUE_OR_FALSE(expr) \
|
||||
do { \
|
||||
int res_ = (expr); \
|
||||
switch (res_) { \
|
||||
case thrd_success: \
|
||||
return true; \
|
||||
case thrd_busy: \
|
||||
return false; \
|
||||
default: \
|
||||
swift::threading::fatal(#expr " failed with error (%d)\n", res_); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
// .. Thread related things ..................................................
|
||||
|
||||
using thread_id = ::thrd_t;
|
||||
|
||||
inline thread_id thread_get_current() { return ::thrd_current(); }
|
||||
thread_id thread_get_main();
|
||||
bool thread_is_main();
|
||||
inline bool threads_same(thread_id a, thread_id b) {
|
||||
return ::thrd_equal(a, b);
|
||||
}
|
||||
|
||||
// .. Mutex support ..........................................................
|
||||
|
||||
using mutex_handle = ::mtx_t;
|
||||
|
||||
inline void mutex_init(mutex_handle &handle, bool checked=false) {
|
||||
SWIFT_C11THREADS_CHECK(::mtx_init(&handle), ::mtx_plain);
|
||||
}
|
||||
inline void mutex_destroy(mutex_handle &handle) {
|
||||
SWIFT_C11THREADS_CHECK(::mtx_destroy(&handle));
|
||||
}
|
||||
|
||||
inline void mutex_lock(mutex_handle &handle) {
|
||||
SWIFT_C11THREADS_CHECK(::mtx_lock(&handle));
|
||||
}
|
||||
inline void mutex_unlock(mutex_handle &handle) {
|
||||
SWIFT_C11THREADS_CHECK(::mtx_unlock(&handle));
|
||||
}
|
||||
inline bool mutex_try_lock(mutex_handle &handle) {
|
||||
SWIFT_C11THREADS_RETURN_TRUE_OR_FALSE(::mtx_trylock(&handle));
|
||||
}
|
||||
|
||||
inline void mutex_unsafe_lock(mutex_handle &handle) {
|
||||
(void)::mtx_lock(&handle);
|
||||
}
|
||||
inline void mutex_unsafe_unlock(mutex_handle &handle) {
|
||||
(void)::mtx_unlock(&handle);
|
||||
}
|
||||
|
||||
struct lazy_mutex_handle {
|
||||
::mtx_t mutex;
|
||||
::atomic_int once; // -1 = initialized, 0 = uninitialized, 1 = initializing
|
||||
};
|
||||
|
||||
inline constexpr lazy_mutex_handle lazy_mutex_initializer() {
|
||||
return (lazy_mutex_handle){0};
|
||||
}
|
||||
inline void lazy_mutex_init(lazy_mutex_handle &handle) {
|
||||
// Sadly, we can't use call_once() for this as it doesn't have a context
|
||||
if (::atomic_load_explicit(&handle.once, ::memory_order_acquire) < 0)
|
||||
return;
|
||||
|
||||
if (::atomic_compare_exchange_strong_explicit(&handle.once,
|
||||
&(int){ 0 },
|
||||
1,
|
||||
::memory_order_relaxed,
|
||||
::memory_order_relaxed)) {
|
||||
SWIFT_C11THREADS_CHECK(::mtx_init(&handle.mutex, ::mtx_plain));
|
||||
::atomic_store_explicit(&handle.once, -1, ::memory_order_release);
|
||||
return;
|
||||
}
|
||||
|
||||
while (::atomic_load_explicit(&handle.once, memory_order_acquire) >= 0) {
|
||||
// Just spin; ::mtx_init() is very likely to be fast
|
||||
}
|
||||
}
|
||||
|
||||
inline void lazy_mutex_destroy(lazy_mutex_handle &handle) {
|
||||
if (::atomic_load_explicit(&handle.once, ::memory_order_acquire) < 0)
|
||||
SWIFT_C11THREADS_CHECK(::mtx_destroy(&handle.mutex));
|
||||
}
|
||||
|
||||
inline void lazy_mutex_lock(lazy_mutex_handle &handle) {
|
||||
lazy_mutex_init(handle);
|
||||
SWIFT_C11THREADS_CHECK(::mtx_lock(&handle.mutex));
|
||||
}
|
||||
inline void lazy_mutex_unlock(lazy_mutex_handle &handle) {
|
||||
lazy_mutex_init(handle);
|
||||
SWIFT_C11THREADS_CHECK(::mtx_unlock(&handle.mutex));
|
||||
}
|
||||
inline bool lazy_mutex_try_lock(lazy_mutex_handle &handle) {
|
||||
lazy_mutex_init(handle);
|
||||
SWIFT_C11THREADS_RETURN_TRUE_OR_FALSE(::mtx_trylock(&handle.mutex));
|
||||
}
|
||||
|
||||
inline void lazy_mutex_unsafe_lock(lazy_mutex_handle &handle) {
|
||||
lazy_mutex_init(handle);
|
||||
(void)::mtx_lock(&handle.mutex);
|
||||
}
|
||||
inline void lazy_mutex_unsafe_unlock(lazy_mutex_handle &handle) {
|
||||
lazy_mutex_init(handle);
|
||||
(void)::mtx_unlock(&handle.mutex);
|
||||
}
|
||||
|
||||
// .. Once ...................................................................
|
||||
|
||||
typedef ::atomic_int once_t;
|
||||
|
||||
void once_slow(once_t &predicate, void (*fn)(void *), void *context);
|
||||
|
||||
inline void once(once_t &predicate, void (*fn)(void *), void *context) {
|
||||
// Sadly we can't use call_once() for this (no context)
|
||||
if (::atomic_load_explicit(&predicate, ::memory_order_acquire) < 0)
|
||||
return;
|
||||
|
||||
once_slow(predicate, fn, context);
|
||||
}
|
||||
|
||||
// .. Thread local storage ...................................................
|
||||
|
||||
#if __cplusplus >= 201103L || __has_feature(cxx_thread_local)
|
||||
#define SWIFT_THREAD_LOCAL thread_local
|
||||
#endif
|
||||
|
||||
using tls_key = ::tss_t;
|
||||
using tls_dtor = void (*)(void *);
|
||||
|
||||
inline bool tls_alloc(tls_key &key, tls_dtor dtor) {
|
||||
return ::tss_create(&key, dtor) == thrd_success;
|
||||
}
|
||||
|
||||
inline void *tls_get(tls_key key) {
|
||||
return ::tss_get(key);
|
||||
}
|
||||
|
||||
inline void tls_set(tls_key key, void *ptr) {
|
||||
::tss_set(key, ptr);
|
||||
}
|
||||
|
||||
} // namespace threading_impl
|
||||
|
||||
} // namespace swift
|
||||
|
||||
#endif // SWIFT_THREADING_IMPL_C11_H
|
||||
177
include/swift/Threading/Impl/Darwin.h
Normal file
177
include/swift/Threading/Impl/Darwin.h
Normal file
@@ -0,0 +1,177 @@
|
||||
//==--- Darwin.h - Threading abstraction implementation -------- -*-C++ -*-===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2022 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Implements threading support for Apple platforms
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SWIFT_THREADING_IMPL_DARWIN_H
|
||||
#define SWIFT_THREADING_IMPL_DARWIN_H
|
||||
|
||||
#include <pthread.h>
|
||||
#include <os/lock.h>
|
||||
#include <dispatch/dispatch.h>
|
||||
|
||||
#include "swift/Threading/Errors.h"
|
||||
|
||||
namespace swift {
|
||||
namespace threading_impl {
|
||||
|
||||
// .. Thread related things ..................................................
|
||||
|
||||
using thread_id = ::pthread_t;
|
||||
|
||||
inline thread_id thread_get_current() { return ::pthread_self(); }
|
||||
|
||||
thread_id thread_get_main();
|
||||
bool thread_is_main();
|
||||
|
||||
inline bool threads_same(thread_id a, thread_id b) {
|
||||
return ::pthread_equal(a, b);
|
||||
}
|
||||
|
||||
// .. Mutex support ..........................................................
|
||||
|
||||
using mutex_handle = ::os_unfair_lock;
|
||||
|
||||
inline void mutex_init(mutex_handle &handle, bool checked=false) {
|
||||
handle = OS_UNFAIR_LOCK_INIT;
|
||||
}
|
||||
inline void mutex_destroy(mutex_handle &handle) { }
|
||||
|
||||
inline void mutex_lock(mutex_handle &handle) {
|
||||
::os_unfair_lock_lock(&handle);
|
||||
}
|
||||
inline void mutex_unlock(mutex_handle &handle) {
|
||||
::os_unfair_lock_unlock(&handle);
|
||||
}
|
||||
inline bool mutex_try_lock(mutex_handle &handle) {
|
||||
return ::os_unfair_lock_trylock(&handle);
|
||||
}
|
||||
|
||||
inline void mutex_unsafe_lock(mutex_handle &handle) {
|
||||
::os_unfair_lock_lock(&handle);
|
||||
}
|
||||
inline void mutex_unsafe_unlock(mutex_handle &handle) {
|
||||
::os_unfair_lock_unlock(&handle);
|
||||
}
|
||||
|
||||
using lazy_mutex_handle = ::os_unfair_lock;
|
||||
|
||||
// We don't need to be lazy here because Darwin has OS_UNFAIR_LOCK_INIT.
|
||||
inline constexpr lazy_mutex_handle lazy_mutex_initializer() {
|
||||
return OS_UNFAIR_LOCK_INIT;
|
||||
}
|
||||
inline void lazy_mutex_destroy(lazy_mutex_handle &handle) { }
|
||||
|
||||
inline void lazy_mutex_lock(lazy_mutex_handle &handle) {
|
||||
::os_unfair_lock_lock(&handle);
|
||||
}
|
||||
inline void lazy_mutex_unlock(lazy_mutex_handle &handle) {
|
||||
::os_unfair_lock_unlock(&handle);
|
||||
}
|
||||
inline bool lazy_mutex_try_lock(lazy_mutex_handle &handle) {
|
||||
return ::os_unfair_lock_trylock(&handle);
|
||||
}
|
||||
|
||||
inline void lazy_mutex_unsafe_lock(lazy_mutex_handle &handle) {
|
||||
::os_unfair_lock_lock(&handle);
|
||||
}
|
||||
inline void lazy_mutex_unsafe_unlock(lazy_mutex_handle &handle) {
|
||||
::os_unfair_lock_unlock(&handle);
|
||||
}
|
||||
|
||||
// .. Once ...................................................................
|
||||
|
||||
using once_t = ::dispatch_once_t;
|
||||
|
||||
inline void once(once_t &predicate, void (*fn)(void *), void *context) {
|
||||
dispatch_once_f(&predicate, context, fn);
|
||||
}
|
||||
|
||||
// .. Thread local storage ...................................................
|
||||
|
||||
// On Darwin, we want to use the reserved keys
|
||||
#define SWIFT_THREADING_USE_RESERVED_TLS_KEYS 1
|
||||
|
||||
#if __has_include(<pthread/tsd_private.h>)
|
||||
#include <pthread/tsd_private.h>
|
||||
#else
|
||||
#define __PTK_FRAMEWORK_SWIFT_KEY0 100
|
||||
#define __PTK_FRAMEWORK_SWIFT_KEY1 101
|
||||
#define __PTK_FRAMEWORK_SWIFT_KEY2 102
|
||||
#define __PTK_FRAMEWORK_SWIFT_KEY3 103
|
||||
#define __PTK_FRAMEWORK_SWIFT_KEY4 104
|
||||
#define __PTK_FRAMEWORK_SWIFT_KEY5 105
|
||||
#define __PTK_FRAMEWORK_SWIFT_KEY6 106
|
||||
#define __PTK_FRAMEWORK_SWIFT_KEY7 107
|
||||
#define __PTK_FRAMEWORK_SWIFT_KEY8 108
|
||||
#define __PTK_FRAMEWORK_SWIFT_KEY9 109
|
||||
|
||||
extern "C" {
|
||||
|
||||
extern int pthread_key_init_np(int, void (*)(void *));
|
||||
|
||||
inline bool _pthread_has_direct_tsd() { return false; }
|
||||
inline void *_pthread_getspecific_direct(pthread_key_t k) {
|
||||
return pthread_getspecific(k);
|
||||
}
|
||||
inline void _pthread_setspecific_direct(pthread_key_t k, void *v) {
|
||||
pthread_setspecific(k, v);
|
||||
}
|
||||
|
||||
}
|
||||
#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
|
||||
#define SWIFT_RESERVED_TLS_KEY_6 __PTK_FRAMEWORK_SWIFT_KEY6
|
||||
#define SWIFT_RESERVED_TLS_KEY_7 __PTK_FRAMEWORK_SWIFT_KEY7
|
||||
#define SWIFT_RESERVED_TLS_KEY_8 __PTK_FRAMEWORK_SWIFT_KEY8
|
||||
#define SWIFT_RESERVED_TLS_KEY_9 __PTK_FRAMEWORK_SWIFT_KEY9
|
||||
|
||||
#define SWIFT_TLS_DECLARE_DTOR(name) void name(void *)
|
||||
|
||||
using tls_key = pthread_key_t;
|
||||
using tls_dtor = void (*)(void *);
|
||||
|
||||
inline bool tls_init(tls_key key, tls_dtor dtor) {
|
||||
return pthread_key_init_np(key, dtor) == 0;
|
||||
}
|
||||
|
||||
inline bool tls_alloc(tls_key &key, tls_dtor dtor) {
|
||||
return pthread_key_create(&key, dtor) == 0;
|
||||
}
|
||||
|
||||
inline void *tls_get(tls_key key) {
|
||||
if (_pthread_has_direct_tsd())
|
||||
return _pthread_getspecific_direct(key);
|
||||
else
|
||||
return pthread_getspecific(key);
|
||||
}
|
||||
|
||||
inline void tls_set(tls_key key, void *value) {
|
||||
if (_pthread_has_direct_tsd())
|
||||
_pthread_setspecific_direct(key, value);
|
||||
else
|
||||
pthread_setspecific(key, value);
|
||||
}
|
||||
|
||||
} // namespace threading_impl
|
||||
|
||||
} // namespace swift
|
||||
|
||||
#endif // SWIFT_THREADING_IMPL_DARWIN_H
|
||||
168
include/swift/Threading/Impl/Linux.h
Normal file
168
include/swift/Threading/Impl/Linux.h
Normal file
@@ -0,0 +1,168 @@
|
||||
//==--- Pthreads.h - Threading abstraction implementation ------ -*-C++ -*-===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2022 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Implements threading support for Linux
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SWIFT_THREADING_IMPL_LINUX_H
|
||||
#define SWIFT_THREADING_IMPL_LINUX_H
|
||||
|
||||
#include <pthread.h>
|
||||
#include <atomic>
|
||||
#include "swift/Threading/Errors.h"
|
||||
|
||||
#include "Linux/ulock.h"
|
||||
|
||||
namespace swift {
|
||||
namespace threading_impl {
|
||||
|
||||
#define SWIFT_LINUXTHREADS_CHECK(expr) \
|
||||
do { \
|
||||
int res_ = (expr); \
|
||||
if (res_ != 0) \
|
||||
swift::threading::fatal(#expr " failed with error %d\n", res_); \
|
||||
} while (0)
|
||||
|
||||
#define SWIFT_PTHREADS_RETURN_TRUE_OR_FALSE(expr) \
|
||||
do { \
|
||||
int res_ = (expr); \
|
||||
switch (res_) { \
|
||||
case 0: \
|
||||
return true; \
|
||||
case EBUSY: \
|
||||
return false; \
|
||||
default: \
|
||||
swift::threading::fatal(#expr " failed with error (%d)\n", res_); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// .. Thread related things ..................................................
|
||||
|
||||
using thread_id = ::pthread_t;
|
||||
|
||||
inline thread_id thread_get_current() { return ::pthread_self(); }
|
||||
|
||||
thread_id thread_get_main();
|
||||
bool thread_is_main();
|
||||
|
||||
inline bool threads_same(thread_id a, thread_id b) {
|
||||
return ::pthread_equal(a, b);
|
||||
}
|
||||
|
||||
// .. Mutex support ..........................................................
|
||||
|
||||
using mutex_handle = ::pthread_mutex_t;
|
||||
|
||||
inline void mutex_init(mutex_handle &handle, bool checked=false) {
|
||||
if (!checked) {
|
||||
handle = PTHREAD_MUTEX_INITIALIZER;
|
||||
} else {
|
||||
::pthread_mutexattr_t attr;
|
||||
SWIFT_LINUXTHREADS_CHECK(::pthread_mutexattr_init(&attr));
|
||||
SWIFT_LINUXTHREADS_CHECK(::pthread_mutexattr_settype(&attr,
|
||||
PTHREAD_MUTEX_ERRORCHECK));
|
||||
SWIFT_LINUXTHREADS_CHECK(::pthread_mutexattr_destroy(&attr));
|
||||
}
|
||||
}
|
||||
inline void mutex_destroy(mutex_handle &handle) {
|
||||
SWIFT_LINUXTHREADS_CHECK(::pthread_mutex_destroy(&handle));
|
||||
}
|
||||
|
||||
inline void mutex_lock(mutex_handle &handle) {
|
||||
SWIFT_LINUXTHREADS_CHECK(::pthread_mutex_lock(&handle));
|
||||
}
|
||||
inline void mutex_unlock(mutex_handle &handle) {
|
||||
SWIFT_LINUXTHREADS_CHECK(::pthread_mutex_unlock(&handle));
|
||||
}
|
||||
inline bool mutex_try_lock(mutex_handle &handle) {
|
||||
SWIFT_PTHREADS_RETURN_TRUE_OR_FALSE(::pthread_mutex_trylock(&handle));
|
||||
}
|
||||
|
||||
inline void mutex_unsafe_lock(mutex_handle &handle) {
|
||||
(void)::pthread_mutex_lock(&handle);
|
||||
}
|
||||
inline void mutex_unsafe_unlock(mutex_handle &handle) {
|
||||
(void)::pthread_mutex_unlock(&handle);
|
||||
}
|
||||
|
||||
using lazy_mutex_handle = ::pthread_mutex_t;
|
||||
|
||||
// We don't actually need to be lazy here because pthreads has
|
||||
// PTHREAD_MUTEX_INITIALIZER.
|
||||
inline constexpr lazy_mutex_handle lazy_mutex_initializer() {
|
||||
return PTHREAD_MUTEX_INITIALIZER;
|
||||
}
|
||||
inline void lazy_mutex_destroy(lazy_mutex_handle &handle) {
|
||||
SWIFT_LINUXTHREADS_CHECK(::pthread_mutex_destroy(&handle));
|
||||
}
|
||||
|
||||
inline void lazy_mutex_lock(lazy_mutex_handle &handle) {
|
||||
SWIFT_LINUXTHREADS_CHECK(::pthread_mutex_lock(&handle));
|
||||
}
|
||||
inline void lazy_mutex_unlock(lazy_mutex_handle &handle) {
|
||||
SWIFT_LINUXTHREADS_CHECK(::pthread_mutex_unlock(&handle));
|
||||
}
|
||||
inline bool lazy_mutex_try_lock(lazy_mutex_handle &handle) {
|
||||
SWIFT_PTHREADS_RETURN_TRUE_OR_FALSE(::pthread_mutex_trylock(&handle));
|
||||
}
|
||||
|
||||
inline void lazy_mutex_unsafe_lock(lazy_mutex_handle &handle) {
|
||||
(void)::pthread_mutex_lock(&handle);
|
||||
}
|
||||
inline void lazy_mutex_unsafe_unlock(lazy_mutex_handle &handle) {
|
||||
(void)::pthread_mutex_unlock(&handle);
|
||||
}
|
||||
|
||||
// .. Once ...................................................................
|
||||
|
||||
struct once_t {
|
||||
std::atomic<std::int32_t> flag;
|
||||
linux::ulock_t lock;
|
||||
};
|
||||
|
||||
using once_t = std::atomic<int>;
|
||||
|
||||
inline void once(once_t &predicate, void (*fn)(void *), void *context) {
|
||||
// Sadly we can't use ::pthread_once() for this (no context)
|
||||
if (predicate.load(std::memory_order_acquire) < 0)
|
||||
return;
|
||||
|
||||
once_slow(predicate, fn, context);
|
||||
}
|
||||
|
||||
// .. Thread local storage ...................................................
|
||||
|
||||
#if __cplusplus >= 201103L || __has_feature(cxx_thread_local)
|
||||
#define SWIFT_THREAD_LOCAL thread_local
|
||||
#endif
|
||||
|
||||
using tls_key = pthread_key_t;
|
||||
using tls_dtor = void (*)(void *);
|
||||
|
||||
inline bool tls_alloc(tls_key &key, tls_dtor dtor) {
|
||||
return pthread_key_create(&key, dtor) == 0;
|
||||
}
|
||||
|
||||
inline void *tls_get(tls_key key) {
|
||||
return pthread_getspecific(key);
|
||||
}
|
||||
|
||||
inline void tls_set(tls_key key, void *value) {
|
||||
pthread_setspecific(key, value);
|
||||
}
|
||||
|
||||
} // namespace threading_impl
|
||||
|
||||
} // namespace swift
|
||||
|
||||
#endif // SWIFT_THREADING_IMPL_PTHREADS_H
|
||||
99
include/swift/Threading/Impl/Linux/ulock.h
Normal file
99
include/swift/Threading/Impl/Linux/ulock.h
Normal file
@@ -0,0 +1,99 @@
|
||||
//==--- ulock.h - 32-bit futex-based lock for Linux ------------ -*-C++ -*-===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2022 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Implements a 32-bit futex-based locking primitive with priority inversion
|
||||
// support.
|
||||
//
|
||||
// This has comparable performance to pthread_mutex_t (on x86-64, it's slower
|
||||
// under contention, but not much different otherwise; other architectures may
|
||||
// vary), but it only takes up 32 bits instead of 40 *bytes*.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SWIFT_THREADING_IMPL_LINUX_ULOCK_H
|
||||
#define SWIFT_THREADING_IMPL_LINUX_ULOCK_H
|
||||
|
||||
// This file is specific to Linux; we're just going to assume we can use
|
||||
// various GCC/Clang extensions here.
|
||||
|
||||
#include <linux/futex.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
|
||||
namespace swift {
|
||||
namespace threading_impl {
|
||||
namespace linux {
|
||||
|
||||
typedef std::int32_t ulock_t;
|
||||
|
||||
#define ULOCK_INITIALIZER 0
|
||||
#define ulock_fastpath(x) __builtin_expect((x), true)
|
||||
|
||||
inline int ulock_get_tid(void) {
|
||||
static __thread int tid;
|
||||
if (tid == 0)
|
||||
tid = gettid();
|
||||
return tid;
|
||||
}
|
||||
|
||||
inline int ulock_futex(ulock_t *lock, int op) {
|
||||
return syscall(SYS_futex, lock, op | FUTEX_PRIVATE_FLAG,
|
||||
0, nullptr, nullptr, 0);
|
||||
}
|
||||
|
||||
inline void ulock_lock(ulock_t *lock) {
|
||||
const ulock_t tid = ulock_get_tid();
|
||||
do {
|
||||
ulock_t zero = 0;
|
||||
if (ulock_fastpath(__atomic_compare_exchange_n(lock, &zero,
|
||||
tid, true,
|
||||
__ATOMIC_ACQUIRE,
|
||||
__ATOMIC_RELAXED)))
|
||||
return;
|
||||
|
||||
} while (ulock_futex(lock, FUTEX_LOCK_PI) != 0);
|
||||
}
|
||||
|
||||
inline bool ulock_trylock(ulock_t *lock) {
|
||||
ulock_t zero = 0;
|
||||
if (ulock_fastpath(__atomic_compare_exchange_n(lock, &zero,
|
||||
ulock_get_tid(), true,
|
||||
__ATOMIC_ACQUIRE,
|
||||
__ATOMIC_RELAXED)))
|
||||
return true;
|
||||
|
||||
return ulock_futex(lock, FUTEX_TRYLOCK_PI) == 0;
|
||||
}
|
||||
|
||||
inline void ulock_unlock(ulock_t *lock) {
|
||||
const ulock_t tid = ulock_get_tid();
|
||||
do {
|
||||
ulock_t expected = tid;
|
||||
if (ulock_fastpath(__atomic_compare_exchange_n(lock, &expected,
|
||||
0, true,
|
||||
__ATOMIC_RELEASE,
|
||||
__ATOMIC_RELAXED)))
|
||||
return;
|
||||
|
||||
} while (ulock_futex(lock, FUTEX_UNLOCK_PI) != 0);
|
||||
}
|
||||
|
||||
} // namespace linux
|
||||
} // namespace threading_impl
|
||||
} // namespace swift
|
||||
|
||||
#endif // SWIFT_THREADING_IMPL_LINUX_ULOCK_H
|
||||
76
include/swift/Threading/Impl/Nothreads.h
Normal file
76
include/swift/Threading/Impl/Nothreads.h
Normal file
@@ -0,0 +1,76 @@
|
||||
//==--- Nothreads.h - Threading abstraction implementation ----- -*-C++ -*-===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2022 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Implements threading support for platforms without threading
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SWIFT_THREADING_IMPL_NOTHREADS_H
|
||||
#define SWIFT_THREADING_IMPL_NOTHREADS_H
|
||||
|
||||
namespace swift {
|
||||
namespace threading_impl {
|
||||
|
||||
// .. Thread related things ..................................................
|
||||
|
||||
using thread_id = unsigned;
|
||||
|
||||
inline thread_id thread_get_current() { return 0; }
|
||||
inline thread_id thread_get_main() { return 0; }
|
||||
inline bool thread_is_main() { return true; }
|
||||
inline bool threads_same(thread_id a, thread_id b) { return a == b; }
|
||||
|
||||
// .. Mutex support ..........................................................
|
||||
|
||||
using mutex_handle = unsigned;
|
||||
|
||||
inline void mutex_init(mutex_handle &handle, bool checked=false) {}
|
||||
inline void mutex_destroy(mutex_handle &handle) { }
|
||||
inline void mutex_lock(mutex_handle &handle) { }
|
||||
inline void mutex_unlock(mutex_handle &handle) { }
|
||||
inline bool mutex_try_lock(mutex_handle &handle) { return true; }
|
||||
|
||||
inline void mutex_unsafe_lock(mutex_handle &handle) { }
|
||||
inline void mutex_unsafe_unlock(mutex_handle &handle) { }
|
||||
|
||||
using lazy_mutex_handle = unsigned;
|
||||
|
||||
inline constexpr lazy_mutex_handle lazy_mutex_initializer() { return 0; }
|
||||
inline void lazy_mutex_destroy(lazy_mutex_handle &handle) { }
|
||||
inline void lazy_mutex_lock(lazy_mutex_handle &handle) { }
|
||||
inline void lazy_mutex_unlock(lazy_mutex_handle &handle) { }
|
||||
inline bool lazy_mutex_try_lock(lazy_mutex_handle &handle) { return true; }
|
||||
|
||||
inline void lazy_mutex_unsafe_lock(lazy_mutex_handle &handle) { }
|
||||
inline void lazy_mutex_unsafe_unlock(lazy_mutex_handle &handle) { }
|
||||
|
||||
// .. Once ...................................................................
|
||||
|
||||
typedef bool once_t;
|
||||
|
||||
inline void once(once_t &predicate, void (*fn)(void *), void *ctx) {
|
||||
if (!predicate) {
|
||||
predicate = true;
|
||||
fn(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
// .. Thread local storage ...................................................
|
||||
|
||||
// If we have no threads, we can use the simple version of TLS
|
||||
#define SWIFT_THREAD_LOCAL
|
||||
|
||||
} // namespace threading_impl
|
||||
|
||||
} // namespace swift
|
||||
|
||||
#endif // SWIFT_THREADING_IMPL_NOTHREADS_H
|
||||
162
include/swift/Threading/Impl/Pthreads.h
Normal file
162
include/swift/Threading/Impl/Pthreads.h
Normal file
@@ -0,0 +1,162 @@
|
||||
//==--- Pthreads.h - Threading abstraction implementation ------ -*-C++ -*-===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2022 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Implements threading support for plain pthreads
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SWIFT_THREADING_IMPL_PTHREADS_H
|
||||
#define SWIFT_THREADING_IMPL_PTHREADS_H
|
||||
|
||||
#include <pthread.h>
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include "swift/Threading/Errors.h"
|
||||
|
||||
namespace swift {
|
||||
namespace threading_impl {
|
||||
|
||||
#define SWIFT_PTHREADS_CHECK(expr) \
|
||||
do { \
|
||||
int res_ = (expr); \
|
||||
if (res_ != 0) \
|
||||
swift::threading::fatal(#expr " failed with error %d\n", res_); \
|
||||
} while (0)
|
||||
|
||||
#define SWIFT_PTHREADS_RETURN_TRUE_OR_FALSE(expr) \
|
||||
do { \
|
||||
int res_ = (expr); \
|
||||
switch (res_) { \
|
||||
case 0: \
|
||||
return true; \
|
||||
case EBUSY: \
|
||||
return false; \
|
||||
default: \
|
||||
swift::threading::fatal(#expr " failed with error (%d)\n", res_); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// .. Thread related things ..................................................
|
||||
|
||||
using thread_id = ::pthread_t;
|
||||
|
||||
inline thread_id thread_get_current() { return ::pthread_self(); }
|
||||
|
||||
thread_id thread_get_main();
|
||||
bool thread_is_main();
|
||||
|
||||
inline bool threads_same(thread_id a, thread_id b) {
|
||||
return ::pthread_equal(a, b);
|
||||
}
|
||||
|
||||
// .. Mutex support ..........................................................
|
||||
|
||||
using mutex_handle = ::pthread_mutex_t;
|
||||
|
||||
inline void mutex_init(mutex_handle &handle, bool checked=false) {
|
||||
if (!checked) {
|
||||
handle = PTHREAD_MUTEX_INITIALIZER;
|
||||
} else {
|
||||
::pthread_mutexattr_t attr;
|
||||
SWIFT_PTHREADS_CHECK(::pthread_mutexattr_init(&attr));
|
||||
SWIFT_PTHREADS_CHECK(::pthread_mutexattr_settype(&attr,
|
||||
PTHREAD_MUTEX_ERRORCHECK));
|
||||
SWIFT_PTHREADS_CHECK(::pthread_mutexattr_destroy(&attr));
|
||||
}
|
||||
}
|
||||
inline void mutex_destroy(mutex_handle &handle) {
|
||||
SWIFT_PTHREADS_CHECK(::pthread_mutex_destroy(&handle));
|
||||
}
|
||||
|
||||
inline void mutex_lock(mutex_handle &handle) {
|
||||
SWIFT_PTHREADS_CHECK(::pthread_mutex_lock(&handle));
|
||||
}
|
||||
inline void mutex_unlock(mutex_handle &handle) {
|
||||
SWIFT_PTHREADS_CHECK(::pthread_mutex_unlock(&handle));
|
||||
}
|
||||
inline bool mutex_try_lock(mutex_handle &handle) {
|
||||
SWIFT_PTHREADS_RETURN_TRUE_OR_FALSE(::pthread_mutex_trylock(&handle));
|
||||
}
|
||||
|
||||
inline void mutex_unsafe_lock(mutex_handle &handle) {
|
||||
(void)::pthread_mutex_lock(&handle);
|
||||
}
|
||||
inline void mutex_unsafe_unlock(mutex_handle &handle) {
|
||||
(void)::pthread_mutex_unlock(&handle);
|
||||
}
|
||||
|
||||
using lazy_mutex_handle = ::pthread_mutex_t;
|
||||
|
||||
// We don't actually need to be lazy here because pthreads has
|
||||
// PTHREAD_MUTEX_INITIALIZER.
|
||||
inline constexpr lazy_mutex_handle lazy_mutex_initializer() {
|
||||
return PTHREAD_MUTEX_INITIALIZER;
|
||||
}
|
||||
inline void lazy_mutex_destroy(lazy_mutex_handle &handle) {
|
||||
SWIFT_PTHREADS_CHECK(::pthread_mutex_destroy(&handle));
|
||||
}
|
||||
|
||||
inline void lazy_mutex_lock(lazy_mutex_handle &handle) {
|
||||
SWIFT_PTHREADS_CHECK(::pthread_mutex_lock(&handle));
|
||||
}
|
||||
inline void lazy_mutex_unlock(lazy_mutex_handle &handle) {
|
||||
SWIFT_PTHREADS_CHECK(::pthread_mutex_unlock(&handle));
|
||||
}
|
||||
inline bool lazy_mutex_try_lock(lazy_mutex_handle &handle) {
|
||||
SWIFT_PTHREADS_RETURN_TRUE_OR_FALSE(::pthread_mutex_trylock(&handle));
|
||||
}
|
||||
|
||||
inline void lazy_mutex_unsafe_lock(lazy_mutex_handle &handle) {
|
||||
(void)::pthread_mutex_lock(&handle);
|
||||
}
|
||||
inline void lazy_mutex_unsafe_unlock(lazy_mutex_handle &handle) {
|
||||
(void)::pthread_mutex_unlock(&handle);
|
||||
}
|
||||
|
||||
// .. Once ...................................................................
|
||||
|
||||
using once_t = std::atomic<std::int64_t>;
|
||||
|
||||
inline void once(once_t &predicate, void (*fn)(void *), void *context) {
|
||||
// Sadly we can't use ::pthread_once() for this (no context)
|
||||
if (predicate.load(std::memory_order_acquire) < 0)
|
||||
return;
|
||||
|
||||
once_slow(predicate, fn, context);
|
||||
}
|
||||
|
||||
// .. Thread local storage ...................................................
|
||||
|
||||
#if __cplusplus >= 201103L || __has_feature(cxx_thread_local)
|
||||
#define SWIFT_THREAD_LOCAL thread_local
|
||||
#endif
|
||||
|
||||
using tls_key = pthread_key_t;
|
||||
using tls_dtor = void (*)(void *);
|
||||
|
||||
inline bool tls_alloc(tls_key &key, tls_dtor dtor) {
|
||||
return pthread_key_create(&key, dtor) == 0;
|
||||
}
|
||||
|
||||
inline void *tls_get(tls_key key) {
|
||||
return pthread_getspecific(key);
|
||||
}
|
||||
|
||||
inline void tls_set(tls_key key, void *value) {
|
||||
pthread_setspecific(key, value);
|
||||
}
|
||||
|
||||
} // namespace threading_impl
|
||||
|
||||
} // namespace swift
|
||||
|
||||
#endif // SWIFT_THREADING_IMPL_PTHREADS_H
|
||||
127
include/swift/Threading/Impl/Win32.h
Normal file
127
include/swift/Threading/Impl/Win32.h
Normal file
@@ -0,0 +1,127 @@
|
||||
//==--- Win32.h - Threading abstraction implementation --------- -*-C++ -*-===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2022 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Implements threading support for Windows threads
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SWIFT_THREADING_IMPL_WIN32_H
|
||||
#define SWIFT_THREADING_IMPL_WIN32_H
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOMINMAX
|
||||
#include <windows.h>
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace swift {
|
||||
namespace threading_impl {
|
||||
|
||||
// .. Thread related things ..................................................
|
||||
|
||||
using thread_id = DWORD;
|
||||
|
||||
inline thread_id thread_get_current() { return ::GetCurrentThreadId(); }
|
||||
thread_id thread_get_main();
|
||||
bool thread_is_main();
|
||||
inline bool threads_same(thread_id a, thread_id b) { return a == b; }
|
||||
|
||||
// .. Mutex support ..........................................................
|
||||
|
||||
using mutex_handle = SRWLOCK;
|
||||
|
||||
inline void mutex_init(mutex_handle &handle, bool checked=false) {
|
||||
handle = SRWLOCK_INIT;
|
||||
}
|
||||
inline void mutex_destroy(mutex_handle &handle) { }
|
||||
|
||||
inline void mutex_lock(mutex_handle &handle) {
|
||||
AcquireSRWLockExclusive(&handle);
|
||||
}
|
||||
inline void mutex_unlock(mutex_handle &handle) {
|
||||
ReleaseSRWLockExclusive(&handle);
|
||||
}
|
||||
inline bool mutex_try_lock(mutex_handle &handle) {
|
||||
return !!TryAcquireSRWLockExclusive(&handle);
|
||||
}
|
||||
|
||||
inline void mutex_unsafe_lock(mutex_handle &handle) {
|
||||
AcquireSRWLockExclusive(&handle);
|
||||
}
|
||||
inline void mutex_unsafe_unlock(mutex_handle &handle) {
|
||||
ReleaseSRWLockExclusive(&handle);
|
||||
}
|
||||
|
||||
using lazy_mutex_handle = SRWLOCK;
|
||||
|
||||
// We don't need to be lazy here because Win32 has SRWLOCK_INIT.
|
||||
inline void lazy_mutex_init(lazy_mutex_handle &handle) {
|
||||
handle = SRWLOCK_INIT;
|
||||
}
|
||||
inline void lazy_mutex_destroy(lazy_mutex_handle &handle) { }
|
||||
|
||||
inline void lazy_mutex_lock(lazy_mutex_handle &handle) {
|
||||
AcquireSRWLockExclusive(&handle);
|
||||
}
|
||||
inline void lazy_mutex_unlock(lazy_mutex_handle &handle) {
|
||||
ReleaseSRWLockExclusive(&handle);
|
||||
}
|
||||
inline bool lazy_mutex_try_lock(lazy_mutex_handle &handle) {
|
||||
return !!TryAcquireSRWLockExclusive(&handle);
|
||||
}
|
||||
|
||||
inline void lazy_mutex_unsafe_lock(lazy_mutex_handle &handle) {
|
||||
AcquireSRWLockExclusive(&handle);
|
||||
}
|
||||
inline void lazy_mutex_unsafe_unlock(lazy_mutex_handle &handle) {
|
||||
ReleaseSRWLockExclusive(&handle);
|
||||
}
|
||||
|
||||
// .. Once ...................................................................
|
||||
|
||||
typedef std::atomic<int64_t> once_t;
|
||||
|
||||
inline void once(once_t &predicate, void (*fn)(void *), void *context) {
|
||||
// Using INIT_ONCE is slower than doing this.
|
||||
if (predicate.load(std::memory_order_acquire) < 0)
|
||||
return;
|
||||
|
||||
once_slow(predicate, fn, context);
|
||||
}
|
||||
|
||||
// .. Thread local storage ...................................................
|
||||
|
||||
#if __cplusplus >= 201103L || __has_feature(cxx_thread_local)
|
||||
#define SWIFT_THREAD_LOCAL thread_local
|
||||
#endif
|
||||
|
||||
#define SWIFT_TLS_DECLARE_DTOR(name) void NTAPI name(void *)
|
||||
|
||||
using tls_key = DWORD;
|
||||
using tls_dtor = void NTAPI (*)(void *);
|
||||
|
||||
inline bool tls_alloc(tls_key &key, tls_dtor dtor) {
|
||||
key = FlsAlloc(dtor);
|
||||
return key != FLS_OUT_OF_INDEXES;
|
||||
}
|
||||
|
||||
inline void *tls_get(tls_key key) {
|
||||
return FlsGetValue(key);
|
||||
}
|
||||
|
||||
inline void tls_set(tls_key key, void *value) {
|
||||
FlsSetValue(key, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // SWIFT_THREADING_IMPL_WIN32_H
|
||||
279
include/swift/Threading/Mutex.h
Normal file
279
include/swift/Threading/Mutex.h
Normal file
@@ -0,0 +1,279 @@
|
||||
//===--- Mutex.h - Mutex and ScopedLock ----------------------- -*- C++ -*-===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2022 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Provides a system-independent Mutex abstraction, as well as some
|
||||
// related utilities like ScopedLock.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SWIFT_THREADING_MUTEX_H
|
||||
#define SWIFT_THREADING_MUTEX_H
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "Impl.h"
|
||||
|
||||
namespace swift {
|
||||
|
||||
// -- ScopedLock ---------------------------------------------------------------
|
||||
|
||||
/// Compile time adjusted stack based object that locks/unlocks the supplied
|
||||
/// Mutex type. Use the provided typedefs instead of this directly.
|
||||
template <typename T, bool Inverted> class ScopedLockT {
|
||||
ScopedLockT() = delete;
|
||||
ScopedLockT(const ScopedLockT &) = delete;
|
||||
ScopedLockT &operator=(const ScopedLockT &) = delete;
|
||||
ScopedLockT(ScopedLockT &&) = delete;
|
||||
ScopedLockT &operator=(ScopedLockT &&) = delete;
|
||||
|
||||
public:
|
||||
explicit ScopedLockT(T &l) : Lock(l) {
|
||||
if (Inverted) {
|
||||
Lock.unlock();
|
||||
} else {
|
||||
Lock.lock();
|
||||
}
|
||||
}
|
||||
|
||||
~ScopedLockT() {
|
||||
if (Inverted) {
|
||||
Lock.lock();
|
||||
} else {
|
||||
Lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
T &Lock;
|
||||
};
|
||||
|
||||
// -- Mutex --------------------------------------------------------------------
|
||||
|
||||
/// A Mutex object that supports `BasicLockable` and `Lockable` C++ concepts.
|
||||
/// See http://en.cppreference.com/w/cpp/concept/BasicLockable
|
||||
/// See http://en.cppreference.com/w/cpp/concept/Lockable
|
||||
///
|
||||
/// This is NOT a recursive mutex.
|
||||
class Mutex {
|
||||
|
||||
Mutex(const Mutex &) = delete;
|
||||
Mutex &operator=(const Mutex &) = delete;
|
||||
Mutex(Mutex &&) = delete;
|
||||
Mutex &operator=(Mutex &&) = delete;
|
||||
|
||||
public:
|
||||
/// Constructs a non-recursive mutex.
|
||||
///
|
||||
/// If `checked` is true the mutex will attempt to check for misuse and
|
||||
/// fatalError when detected. If `checked` is false (the default) the
|
||||
/// mutex will make little to no effort to check for misuse (more efficient).
|
||||
explicit Mutex(bool checked = false) {
|
||||
threading_impl::mutex_init(Handle, checked);
|
||||
}
|
||||
~Mutex() { threading_impl::mutex_destroy(Handle); }
|
||||
|
||||
/// The lock() method has the following properties:
|
||||
/// - Behaves as an atomic operation.
|
||||
/// - Blocks the calling thread until exclusive ownership of the mutex
|
||||
/// can be obtained.
|
||||
/// - Prior m.unlock() operations on the same mutex synchronize-with
|
||||
/// this lock operation.
|
||||
/// - The behavior is undefined if the calling thread already owns
|
||||
/// the mutex (likely a deadlock).
|
||||
/// - Does not throw exceptions but will halt on error (fatalError).
|
||||
void lock() { threading_impl::mutex_lock(Handle); }
|
||||
|
||||
/// The unlock() method has the following properties:
|
||||
/// - Behaves as an atomic operation.
|
||||
/// - Releases the calling thread's ownership of the mutex and
|
||||
/// synchronizes-with the subsequent successful lock operations on
|
||||
/// the same object.
|
||||
/// - The behavior is undefined if the calling thread does not own
|
||||
/// the mutex.
|
||||
/// - Does not throw exceptions but will halt on error (fatalError).
|
||||
void unlock() { threading_impl::mutex_unlock(Handle); }
|
||||
|
||||
/// The try_lock() method has the following properties:
|
||||
/// - Behaves as an atomic operation.
|
||||
/// - Attempts to obtain exclusive ownership of the mutex for the calling
|
||||
/// thread without blocking. If ownership is not obtained, returns
|
||||
/// immediately. The function is allowed to spuriously fail and return
|
||||
/// even if the mutex is not currently owned by another thread.
|
||||
/// - If try_lock() succeeds, prior unlock() operations on the same object
|
||||
/// synchronize-with this operation. lock() does not synchronize with a
|
||||
/// failed try_lock()
|
||||
/// - The behavior is undefined if the calling thread already owns
|
||||
/// the mutex (likely a deadlock)?
|
||||
/// - Does not throw exceptions but will halt on error (fatalError).
|
||||
bool try_lock() { return threading_impl::mutex_try_lock(Handle); }
|
||||
|
||||
/// Acquires lock before calling the supplied critical section and releases
|
||||
/// lock on return from critical section.
|
||||
///
|
||||
/// This call can block while waiting for the lock to become available.
|
||||
///
|
||||
/// For example the following mutates value while holding the mutex lock.
|
||||
///
|
||||
/// ```
|
||||
/// mutex.lock([&value] { value++; });
|
||||
/// ```
|
||||
///
|
||||
/// Precondition: Mutex not held by this thread, undefined otherwise.
|
||||
template <typename CriticalSection>
|
||||
auto withLock(CriticalSection &&criticalSection)
|
||||
-> decltype(std::forward<CriticalSection>(criticalSection)()) {
|
||||
ScopedLock guard(*this);
|
||||
return std::forward<CriticalSection>(criticalSection)();
|
||||
}
|
||||
|
||||
/// A stack based object that locks the supplied mutex on construction
|
||||
/// and unlocks it on destruction.
|
||||
///
|
||||
/// Precondition: Mutex unlocked by this thread, undefined otherwise.
|
||||
typedef ScopedLockT<Mutex, false> ScopedLock;
|
||||
|
||||
/// A stack based object that unlocks the supplied mutex on construction
|
||||
/// and relocks it on destruction.
|
||||
///
|
||||
/// Precondition: Mutex locked by this thread, undefined otherwise.
|
||||
typedef ScopedLockT<Mutex, true> ScopedUnlock;
|
||||
|
||||
protected:
|
||||
threading_impl::mutex_handle Handle;
|
||||
};
|
||||
|
||||
/// An unsafe variant of the above (for use in the error handling path)
|
||||
///
|
||||
/// This is used to ensure that we can't infinitely recurse if the mutex
|
||||
/// itself generates errors.
|
||||
class UnsafeMutex : public Mutex {
|
||||
public:
|
||||
UnsafeMutex() : Mutex() {}
|
||||
|
||||
void lock() { threading_impl::mutex_unsafe_unlock(Handle); }
|
||||
void unlock() { threading_impl::mutex_unsafe_unlock(Handle); }
|
||||
};
|
||||
|
||||
/// A lazily initialized variant of Mutex.
|
||||
///
|
||||
/// Use Mutex instead unless you need static allocation. LazyMutex *may*
|
||||
/// be entirely statically initialized, on some platforms, but on others
|
||||
/// it might be a little larger than and slightly slower than Mutex.
|
||||
class LazyMutex {
|
||||
|
||||
LazyMutex(const LazyMutex &) = delete;
|
||||
LazyMutex &operator=(const LazyMutex &) = delete;
|
||||
LazyMutex(LazyMutex &&) = delete;
|
||||
LazyMutex &operator=(LazyMutex &&) = delete;
|
||||
|
||||
public:
|
||||
constexpr LazyMutex() : Handle(threading_impl::lazy_mutex_initializer()) {}
|
||||
|
||||
// No destructor; this is intentional; this class is for STATIC allocation
|
||||
// and you don't need to delete mutexes on termination.
|
||||
|
||||
/// See Mutex::lock
|
||||
void lock() { threading_impl::lazy_mutex_lock(Handle); }
|
||||
|
||||
/// See Mutex::unlock
|
||||
void unlock() { threading_impl::lazy_mutex_unlock(Handle); }
|
||||
|
||||
/// See Mutex::try_lock
|
||||
bool try_lock() { return threading_impl::lazy_mutex_try_lock(Handle); }
|
||||
|
||||
/// See Mutex::withLock
|
||||
template <typename CriticalSection>
|
||||
auto withLock(CriticalSection &&criticalSection)
|
||||
-> decltype(std::forward<CriticalSection>(criticalSection)()) {
|
||||
ScopedLock guard(*this);
|
||||
return std::forward<CriticalSection>(criticalSection)();
|
||||
}
|
||||
|
||||
/// A stack based object that locks the supplied mutex on construction
|
||||
/// and unlocks it on destruction.
|
||||
///
|
||||
/// Precondition: Mutex unlocked by this thread, undefined otherwise.
|
||||
typedef ScopedLockT<LazyMutex, false> ScopedLock;
|
||||
|
||||
/// A stack based object that unlocks the supplied mutex on construction
|
||||
/// and relocks it on destruction.
|
||||
///
|
||||
/// Precondition: Mutex locked by this thread, undefined otherwise.
|
||||
typedef ScopedLockT<LazyMutex, true> ScopedUnlock;
|
||||
|
||||
protected:
|
||||
threading_impl::lazy_mutex_handle Handle;
|
||||
};
|
||||
|
||||
/// An unsafe variant of the above (for use in the error handling path)
|
||||
///
|
||||
/// This is used to ensure that we can't infinitely recurse if the mutex
|
||||
/// itself generates errors.
|
||||
class LazyUnsafeMutex : public LazyMutex {
|
||||
public:
|
||||
constexpr LazyUnsafeMutex() : LazyMutex() {}
|
||||
|
||||
void lock() { threading_impl::lazy_mutex_unsafe_lock(Handle); }
|
||||
void unlock() { threading_impl::lazy_mutex_unsafe_unlock(Handle); }
|
||||
};
|
||||
|
||||
/// An indirect variant of a Mutex. This allocates the mutex on the heap, for
|
||||
/// places where having the mutex inline takes up too much space. Used for
|
||||
/// SmallMutex on platforms where Mutex is large.
|
||||
class IndirectMutex {
|
||||
IndirectMutex(const IndirectMutex &) = delete;
|
||||
IndirectMutex &operator=(const IndirectMutex &) = delete;
|
||||
IndirectMutex(IndirectMutex &&) = delete;
|
||||
IndirectMutex &operator=(IndirectMutex &&) = delete;
|
||||
|
||||
public:
|
||||
explicit IndirectMutex(bool checked = false) { Ptr = new Mutex(checked); }
|
||||
~IndirectMutex() { delete Ptr; }
|
||||
|
||||
void lock() { Ptr->lock(); }
|
||||
|
||||
void unlock() { Ptr->unlock(); }
|
||||
|
||||
bool try_lock() { return Ptr->try_lock(); }
|
||||
|
||||
template <typename CriticalSection>
|
||||
auto withLock(CriticalSection &&criticalSection)
|
||||
-> decltype(criticalSection()) {
|
||||
return Ptr->withLock(std::forward<CriticalSection>(criticalSection));
|
||||
}
|
||||
|
||||
/// A stack based object that locks the supplied mutex on construction
|
||||
/// and unlocks it on destruction.
|
||||
///
|
||||
/// Precondition: Mutex unlocked by this thread, undefined otherwise.
|
||||
typedef ScopedLockT<IndirectMutex, false> ScopedLock;
|
||||
|
||||
/// A stack based object that unlocks the supplied mutex on construction
|
||||
/// and relocks it on destruction.
|
||||
///
|
||||
/// Precondition: Mutex locked by this thread, undefined otherwise.
|
||||
typedef ScopedLockT<IndirectMutex, true> ScopedUnlock;
|
||||
|
||||
private:
|
||||
Mutex *Ptr;
|
||||
};
|
||||
|
||||
/// A "small" mutex, which is pointer sized or smaller, for places where the
|
||||
/// mutex is stored inline with limited storage space. This uses a normal Mutex
|
||||
/// when that is small, and otherwise uses IndirectMutex.
|
||||
using SmallMutex =
|
||||
std::conditional_t<sizeof(Mutex) <= sizeof(void *), Mutex, IndirectMutex>;
|
||||
|
||||
} // namespace swift
|
||||
|
||||
#endif // SWIFT_THREADING_MUTEX_H
|
||||
35
include/swift/Threading/Once.h
Normal file
35
include/swift/Threading/Once.h
Normal file
@@ -0,0 +1,35 @@
|
||||
//===--- Once.h - Runtime support for lazy initialization -------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Swift runtime functions in support of lazy initialization.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SWIFT_THREADING_ONCE_H
|
||||
#define SWIFT_THREADING_ONCE_H
|
||||
|
||||
#include "Impl.h"
|
||||
|
||||
namespace swift {
|
||||
|
||||
using once_t = threading_impl::once_t;
|
||||
|
||||
/// Runs the given function with the given context argument exactly once.
|
||||
/// The predicate argument must refer to a global or static variable of static
|
||||
/// extent of type swift::once_t.
|
||||
inline void once(once_t &predicate, void (*fn)(void *), void *context=nullptr) {
|
||||
threading_impl::once(predicate, fn, context);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // SWIFT_THREADING_ONCE_H
|
||||
72
include/swift/Threading/Thread.h
Normal file
72
include/swift/Threading/Thread.h
Normal file
@@ -0,0 +1,72 @@
|
||||
//===--- Thread.h - Thread abstraction ------------------------ -*- C++ -*-===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2022 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Provides an abstract Thread class that identifies a system thread,
|
||||
// and can fetch the current and main threads as well as being comparable
|
||||
// with other Thread instances.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SWIFT_THREADING_THREAD_H
|
||||
#define SWIFT_THREADING_THREAD_H
|
||||
|
||||
#include "Impl.h"
|
||||
|
||||
namespace swift {
|
||||
|
||||
/// Identifies a thread
|
||||
class Thread {
|
||||
private:
|
||||
threading_impl::thread_id id_;
|
||||
|
||||
public:
|
||||
Thread() {}
|
||||
Thread(const Thread& other) : id_(other.id_) {}
|
||||
Thread(Thread&& other) : id_(std::move(other.id_)) {}
|
||||
|
||||
Thread& operator=(const Thread& other) {
|
||||
id_ = other.id_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Thread& operator=(Thread&& other) {
|
||||
id_ = other.id_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Returns the currently executing thread
|
||||
static Thread current() {
|
||||
return Thread(threading_impl::thread_get_current());
|
||||
}
|
||||
|
||||
/// Returns the main thread in this program
|
||||
static Thread main() {
|
||||
return Thread(threading_impl::thread_get_main());
|
||||
}
|
||||
|
||||
/// Returns true iff executed on the main thread
|
||||
static bool onMainThread() {
|
||||
return threading_impl::thread_is_main();
|
||||
}
|
||||
|
||||
/// Returns true if the two Thread values are equal
|
||||
bool operator==(const Thread& other) const {
|
||||
return threading_impl::threads_same(id_, other.id_);
|
||||
}
|
||||
bool operator!=(const Thread& other) const {
|
||||
return !threading_impl::threads_same(id_, other.id_);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace swift
|
||||
|
||||
#endif // SWIFT_THREADING_THREAD_H
|
||||
176
include/swift/Threading/ThreadLocalStorage.h
Normal file
176
include/swift/Threading/ThreadLocalStorage.h
Normal file
@@ -0,0 +1,176 @@
|
||||
//===--- ThreadLocalStorage.h - Thread-local storage interface. --*- C++ -*-===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2022 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SWIFT_THREADING_THREADLOCALSTORAGE_H
|
||||
#define SWIFT_THREADING_THREADLOCALSTORAGE_H
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "Impl.h"
|
||||
#include "Once.h"
|
||||
#include "Errors.h"
|
||||
|
||||
namespace swift {
|
||||
|
||||
// -- Low-level TLS functions -------------------------------------------------
|
||||
|
||||
#if !SWIFT_THREADING_NONE
|
||||
using tls_key = threading_impl::tls_key;
|
||||
using tls_dtor = threading_impl::tls_dtor;
|
||||
|
||||
#if SWIFT_THREADING_USE_RESERVED_TLS_KEYS
|
||||
using threading_impl::tls_init;
|
||||
|
||||
/// tls_init_once() - Initialize TLS, once only
|
||||
inline void tls_init_once(once_t &token, tls_key key, tls_dtor dtor) {
|
||||
const struct tls_init_info { tls_key &k; tls_dtor d; } info = { key, dtor };
|
||||
once(token, [](void *ctx) {
|
||||
const struct tls_init_info *pinfo = static_cast<const struct tls_init_info *>(ctx);
|
||||
if (!tls_init(pinfo->k, pinfo->d))
|
||||
swift::threading::fatal("tls_init_once() failed to set destructor");
|
||||
}, (void *)&info);
|
||||
}
|
||||
#endif // SWIFT_THREADING_USE_RESERVED_TLS_KEYS
|
||||
|
||||
using threading_impl::tls_alloc;
|
||||
using threading_impl::tls_get;
|
||||
using threading_impl::tls_set;
|
||||
|
||||
/// tls_alloc_once() - Allocate TLS key, once only
|
||||
inline void tls_alloc_once(once_t &token, tls_key &key, tls_dtor dtor) {
|
||||
const struct tls_init_info { tls_key &k; tls_dtor d; } info = { key, dtor };
|
||||
once(token, [](void *ctx) {
|
||||
const struct tls_init_info *pinfo = static_cast<const struct tls_init_info *>(ctx);
|
||||
if (!tls_alloc(pinfo->k, pinfo->d))
|
||||
swift::threading::fatal("tls_alloc_once() failed to allocate key");
|
||||
}, (void *)&info);
|
||||
}
|
||||
#endif // !SWIFT_THREADING_NONE
|
||||
|
||||
// -- High-level TLS classes --------------------------------------------------
|
||||
|
||||
// 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.
|
||||
#ifdef SWIFT_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 TLS key that is lazily initialized using swift::once.
|
||||
class ThreadLocalKey {
|
||||
// We rely on the zero-initialization of objects with static storage
|
||||
// duration.
|
||||
once_t onceFlag;
|
||||
tls_key key;
|
||||
|
||||
public:
|
||||
threading_impl::tls_key getKey() {
|
||||
once(onceFlag, [](void *ctx) {
|
||||
tls_key *pkey = reinterpret_cast<tls_key *>(ctx);
|
||||
tls_alloc(*pkey, nullptr);
|
||||
}, &key);
|
||||
return key;
|
||||
}
|
||||
};
|
||||
|
||||
// A type representing a constant TLS key, for use on platforms
|
||||
// that provide reserved keys.
|
||||
template <tls_key constantKey>
|
||||
class ConstantThreadLocalKey {
|
||||
public:
|
||||
tls_key getKey() { return constantKey; }
|
||||
};
|
||||
|
||||
template <class T, class Key>
|
||||
class ThreadLocal {
|
||||
VALIDATE_THREAD_LOCAL_TYPE(T)
|
||||
|
||||
Key key;
|
||||
|
||||
public:
|
||||
constexpr ThreadLocal() {}
|
||||
|
||||
T get() {
|
||||
void *storedValue = tls_get(key.getKey());
|
||||
T value;
|
||||
memcpy(&value, &storedValue, sizeof(T));
|
||||
return value;
|
||||
}
|
||||
|
||||
void set(T newValue) {
|
||||
void *storedValue;
|
||||
memcpy(&storedValue, &newValue, sizeof(T));
|
||||
tls_set(key.getKey(), storedValue);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
} // end namespace swift
|
||||
|
||||
/// SWIFT_THREAD_LOCAL_TYPE(TYPE, KEY) - Declare a variable
|
||||
/// to be a thread-local variable. The declaration must have static
|
||||
/// storage duration; it may be prefixed with "static".
|
||||
///
|
||||
/// For example
|
||||
///
|
||||
/// static SWIFT_THREAD_LOCAL_TYPE(int, SWIFT_RESERVED_TLS_KEY_9) frobble;
|
||||
///
|
||||
/// 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_THREAD_LOCAL
|
||||
#define SWIFT_THREAD_LOCAL_TYPE(TYPE, KEY) \
|
||||
SWIFT_THREAD_LOCAL swift::ThreadLocal<TYPE>
|
||||
#elif SWIFT_THREADING_USE_RESERVED_TLS_KEYS
|
||||
#define SWIFT_THREAD_LOCAL_TYPE(TYPE, KEY) \
|
||||
swift::ThreadLocal<TYPE, swift::ConstantThreadLocalKey<KEY>>
|
||||
#else
|
||||
#define SWIFT_THREAD_LOCAL_TYPE(TYPE, KEY) \
|
||||
swift::ThreadLocal<TYPE, swift::ThreadLocalKey>
|
||||
#endif
|
||||
|
||||
|
||||
#endif // SWIFT_THREADING_THREADLOCALSTORAGE_H
|
||||
Reference in New Issue
Block a user