[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:
Alastair Houghton
2022-04-15 13:50:33 +01:00
parent 66b9d21000
commit f5bdb858e0
98 changed files with 2286 additions and 1410 deletions

View 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

View 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

View 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

View 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

View 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

View 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

View 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