From 0cf687aa2b79bd6875601aeb690689401a39db2d Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Fri, 25 Mar 2022 16:10:39 +0000 Subject: [PATCH 01/40] [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 --- CMakeLists.txt | 60 ++++--- cmake/caches/Runtime-WASI-wasm32.cmake | 2 +- cmake/modules/AddSwiftUnittests.cmake | 11 +- cmake/modules/Threading.cmake | 27 +++ include/swift/Basic/Lazy.h | 38 +--- include/swift/Runtime/Concurrency.h | 2 +- include/swift/Runtime/Mutex.h | 10 +- include/swift/Runtime/MutexC11.h | 162 ++++++++++++++++++ include/swift/Runtime/Once.h | 13 +- include/swift/Runtime/ThreadLocal.h | 38 ++-- include/swift/Runtime/ThreadLocalStorage.h | 62 +++---- include/swift/Runtime/VoucherShims.h | 2 +- stdlib/CMakeLists.txt | 4 +- stdlib/cmake/modules/AddSwiftStdlib.cmake | 8 +- stdlib/cmake/modules/StdlibOptions.cmake | 6 +- stdlib/cmake/modules/SwiftSource.cmake | 10 +- stdlib/private/StdlibUnittest/RaceTest.swift | 6 - .../BackDeployConcurrency/CMakeLists.txt | 2 +- stdlib/public/Concurrency/Actor.cpp | 4 +- stdlib/public/Concurrency/Executor.swift | 2 +- stdlib/public/Concurrency/Mutex.cpp | 3 +- stdlib/public/Concurrency/TaskGroup.cpp | 7 +- stdlib/public/Concurrency/TaskPrivate.h | 2 +- stdlib/public/runtime/CMakeLists.txt | 1 + stdlib/public/runtime/HeapObject.cpp | 22 +-- stdlib/public/runtime/MetadataImpl.h | 2 +- stdlib/public/runtime/MutexC11.cpp | 110 ++++++++++++ stdlib/public/runtime/MutexPThread.cpp | 7 +- stdlib/public/runtime/Once.cpp | 10 +- stdlib/public/runtime/SwiftTLSContext.cpp | 4 +- stdlib/public/stubs/Stubs.cpp | 48 ++++-- stdlib/public/stubs/ThreadLocalStorage.cpp | 4 +- test/CMakeLists.txt | 2 +- .../async_task_locals_copy_to_sync.swift | 2 +- .../Runtime/cancellation_handler.swift | 2 +- .../Runtime/data_race_detection.swift | 2 +- test/Concurrency/Runtime/mainactor.swift | 2 +- .../enforce_exclusive_access.swift | 2 +- test/lit.site.cfg.in | 9 +- unittests/runtime/CMakeLists.txt | 2 +- unittests/runtime/Concurrent.cpp | 4 +- utils/build-presets.ini | 6 +- utils/build-script-impl | 20 ++- validation-test/lit.site.cfg.in | 9 +- 44 files changed, 547 insertions(+), 204 deletions(-) create mode 100644 cmake/modules/Threading.cmake create mode 100644 include/swift/Runtime/MutexC11.h create mode 100644 stdlib/public/runtime/MutexC11.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a1c499e8e4279..518e1e529ad76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,6 +66,27 @@ else() any compiler host sources written in Swift") endif() +# A convenience pattern to match Darwin platforms. Example: +# if(SWIFT_HOST_VARIANT MATCHES "${SWIFT_DARWIN_VARIANTS}") +# ... +# endif() +set(SWIFT_DARWIN_VARIANTS "^(macosx|iphoneos|iphonesimulator|appletvos|appletvsimulator|watchos|watchsimulator)") +set(SWIFT_DARWIN_EMBEDDED_VARIANTS "^(iphoneos|iphonesimulator|appletvos|appletvsimulator|watchos|watchsimulator)") + +# A convenient list to match Darwin SDKs. Example: +# if("${SWIFT_HOST_VARIANT_SDK}" IN_LIST SWIFT_DARWIN_PLATFORMS) +# ... +# endif() +set(SWIFT_DARWIN_PLATFORMS "IOS" "IOS_SIMULATOR" "TVOS" "TVOS_SIMULATOR" "WATCHOS" "WATCHOS_SIMULATOR" "OSX") + +set(SWIFT_APPLE_PLATFORMS ${SWIFT_DARWIN_PLATFORMS}) +if(SWIFT_FREESTANDING_FLAVOR STREQUAL "apple") + list(APPEND SWIFT_APPLE_PLATFORMS "FREESTANDING") + if(SWIFT_FREESTANDING_IS_DARWIN) + list(APPEND SWIFT_DARWIN_PLATFORMS "FREESTANDING") + endif() +endif() + # # User-configurable options that control the inclusion and default build # behavior for components which may not strictly be necessary (tools, examples, @@ -103,6 +124,15 @@ option(SWIFT_STDLIB_ENABLE_UNICODE_DATA NOTE: Disabling this will cause many String methods to crash." TRUE) +include(Threading) + +threading_package_default(SWIFT_STDLIB_THREADING_PACKAGE_default) + +set(SWIFT_STDLIB_THREADING_PACKAGE "${SWIFT_STDLIB_THREADING_PACKAGE_default}" + CACHE STRING + "The threading package to use. Must be one of 'none', 'pthreads', + 'darwin', 'win32', 'c11'.") + option(SWIFT_BUILD_DYNAMIC_SDK_OVERLAY "Build dynamic variants of the Swift SDK overlay" TRUE) @@ -671,27 +701,6 @@ include_directories(BEFORE ${SWIFT_INCLUDE_DIR} ) -# A convenience pattern to match Darwin platforms. Example: -# if(SWIFT_HOST_VARIANT MATCHES "${SWIFT_DARWIN_VARIANTS}") -# ... -# endif() -set(SWIFT_DARWIN_VARIANTS "^(macosx|iphoneos|iphonesimulator|appletvos|appletvsimulator|watchos|watchsimulator)") -set(SWIFT_DARWIN_EMBEDDED_VARIANTS "^(iphoneos|iphonesimulator|appletvos|appletvsimulator|watchos|watchsimulator)") - -# A convenient list to match Darwin SDKs. Example: -# if("${SWIFT_HOST_VARIANT_SDK}" IN_LIST SWIFT_DARWIN_PLATFORMS) -# ... -# endif() -set(SWIFT_DARWIN_PLATFORMS "IOS" "IOS_SIMULATOR" "TVOS" "TVOS_SIMULATOR" "WATCHOS" "WATCHOS_SIMULATOR" "OSX") - -set(SWIFT_APPLE_PLATFORMS ${SWIFT_DARWIN_PLATFORMS}) -if(SWIFT_FREESTANDING_FLAVOR STREQUAL "apple") - list(APPEND SWIFT_APPLE_PLATFORMS "FREESTANDING") - if(SWIFT_FREESTANDING_IS_DARWIN) - list(APPEND SWIFT_DARWIN_PLATFORMS "FREESTANDING") - endif() -endif() - # Configuration flags passed to all of our invocations of gyb. Try to # avoid making up new variable names here if you can find a CMake # variable that will do the job. @@ -1037,11 +1046,12 @@ if(SWIFT_BUILD_STDLIB OR SWIFT_BUILD_SDK_OVERLAY) message(STATUS " Leak Detection Checker Entrypoints: ${SWIFT_RUNTIME_ENABLE_LEAK_CHECKER}") message(STATUS "") + message(STATUS "Threading Package: ${SWIFT_STDLIB_THREADING_PACKAGE}") message(STATUS "Differentiable Programming Support: ${SWIFT_ENABLE_EXPERIMENTAL_DIFFERENTIABLE_PROGRAMMING}") - message(STATUS "Concurrency Support: ${SWIFT_ENABLE_EXPERIMENTAL_CONCURRENCY}") - message(STATUS "Distributed Support: ${SWIFT_ENABLE_EXPERIMENTAL_DISTRIBUTED}") - message(STATUS "String Processing Support: ${SWIFT_ENABLE_EXPERIMENTAL_STRING_PROCESSING}") - message(STATUS "Unicode Support: ${SWIFT_STDLIB_ENABLE_UNICODE_DATA}") + message(STATUS "Concurrency Support: ${SWIFT_ENABLE_EXPERIMENTAL_CONCURRENCY}") + message(STATUS "Distributed Support: ${SWIFT_ENABLE_EXPERIMENTAL_DISTRIBUTED}") + message(STATUS "String Processing Support: ${SWIFT_ENABLE_EXPERIMENTAL_STRING_PROCESSING}") + message(STATUS "Unicode Support: ${SWIFT_STDLIB_ENABLE_UNICODE_DATA}") message(STATUS "") else() message(STATUS "Not building Swift standard library, SDK overlays, and runtime") diff --git a/cmake/caches/Runtime-WASI-wasm32.cmake b/cmake/caches/Runtime-WASI-wasm32.cmake index f41634a44fc3c..213682f7b3b8f 100644 --- a/cmake/caches/Runtime-WASI-wasm32.cmake +++ b/cmake/caches/Runtime-WASI-wasm32.cmake @@ -23,4 +23,4 @@ set(SWIFT_ENABLE_EXPERIMENTAL_CONCURRENCY YES CACHE BOOL "") # build with the host compiler set(SWIFT_BUILD_RUNTIME_WITH_HOST_COMPILER YES CACHE BOOL "") -set(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME TRUE CACHE BOOL "") +set(SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY TRUE CACHE BOOL "") diff --git a/cmake/modules/AddSwiftUnittests.cmake b/cmake/modules/AddSwiftUnittests.cmake index 4b9dcf11197b3..256fd0960bd21 100644 --- a/cmake/modules/AddSwiftUnittests.cmake +++ b/cmake/modules/AddSwiftUnittests.cmake @@ -1,5 +1,6 @@ include(AddSwift) +include(Threading) add_custom_target(SwiftUnitTests) @@ -47,11 +48,15 @@ function(add_swift_unittest test_dirname) endif() # some headers switch their inline implementations based on - # SWIFT_STDLIB_SINGLE_THREADED_RUNTIME definition - if(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) + # SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY and + # SWIFT_STDLIB_THREADING_PACKAGE definitions + if(SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY) target_compile_definitions("${test_dirname}" PRIVATE - SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) + SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY) endif() + threading_package_name(_threading_package) + target_compile_definitions("${test_dirname}" PRIVATE + "SWIFT_STDLIB_THREADING_${_threading_package}") if(NOT SWIFT_COMPILER_IS_MSVC_LIKE) if(SWIFT_USE_LINKER) diff --git a/cmake/modules/Threading.cmake b/cmake/modules/Threading.cmake new file mode 100644 index 0000000000000..6d78768b7a64a --- /dev/null +++ b/cmake/modules/Threading.cmake @@ -0,0 +1,27 @@ +# Get the default threading package for the platform +function(threading_package_default out_var) + if("${SWIFT_HOST_VARIANT_SDK}" IN_LIST SWIFT_DARWIN_PLATFORMS) + set("${out_var}" "darwin" PARENT_SCOPE) + elseif("${SWIFT_HOST_VARIANT_SDK}" STREQUAL "WINDOWS") + set("${out_var}" "win32" PARENT_SCOPE) + elseif("${SWIFT_HOST_VARIANT_SDK}" STREQUAL "WASI") + set("${out_var}" "none" PARENT_SCOPE) + else() + set("${out_var}" "pthreads" PARENT_SCOPE) + endif() +endfunction() + +# Given the threading package, find the name for the preprocessor +# define that we need to make. Also deals with the default platform +# setting. +function(threading_package_name out_var) + precondition(SWIFT_HOST_VARIANT_SDK) + precondition(SWIFT_DARWIN_PLATFORMS) + + string(TOUPPER "${SWIFT_STDLIB_THREADING_PACKAGE}" package) + if(package STREQUAL "") + threading_package_default(package) + string(TOUPPER "${package}" package) + endif() + set("${out_var}" "${package}" PARENT_SCOPE) +endfunction() diff --git a/include/swift/Basic/Lazy.h b/include/swift/Basic/Lazy.h index 87eecbe295c3c..692341ae3745c 100644 --- a/include/swift/Basic/Lazy.h +++ b/include/swift/Basic/Lazy.h @@ -14,44 +14,26 @@ #define SWIFT_BASIC_LAZY_H #include -#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME + +#if SWIFT_STDLIB_THREADING_NONE // No dependencies on single-threaded environments. -#elif defined(__APPLE__) +#elif SWIFT_STDLIB_THREADING_DARWIN #include -#elif defined(__wasi__) -// No pthread on wasi, see https://bugs.swift.org/browse/SR-12097 for more details. #else #include #endif + #include "swift/Basic/Malloc.h" #include "swift/Basic/type_traits.h" -#if defined(__wasi__) -// Temporary single-threaded stub. Should be replaced with a thread-safe version -// as soon as the WASI SDK allows it. See https://bugs.swift.org/browse/SR-12766. -inline void wasi_call_once(int *flag, void *context, void (*func)(void *)) { - switch (*flag) { - case 0: - *flag = 1; - func(context); - return; - case 1: - return; - default: - assert(false && "wasi_call_once got invalid flag"); - abort(); - } -} -#endif - namespace swift { -#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#if SWIFT_STDLIB_THREADING_NONE using OnceToken_t = bool; # define SWIFT_ONCE_F(TOKEN, FUNC, CONTEXT) \ - if (!TOKEN) { TOKEN = true; (FUNC)(CONTEXT); } -#elif defined(__APPLE__) - using OnceToken_t = dispatch_once_t; + do { if (!TOKEN) { TOKEN = true; (FUNC)(CONTEXT); } } while (0) +#elif SWIFT_STDLIB_THREADING_DARWIN + using OnceToken_t = ::dispatch_once_t; # define SWIFT_ONCE_F(TOKEN, FUNC, CONTEXT) \ ::dispatch_once_f(&TOKEN, CONTEXT, FUNC) #elif defined(__CYGWIN__) @@ -62,10 +44,6 @@ namespace swift { using OnceToken_t = unsigned long; # define SWIFT_ONCE_F(TOKEN, FUNC, CONTEXT) \ _swift_once_f(&TOKEN, CONTEXT, FUNC) -#elif defined(__wasi__) - using OnceToken_t = int; -# define SWIFT_ONCE_F(TOKEN, FUNC, CONTEXT) \ - ::wasi_call_once(&TOKEN, CONTEXT, FUNC) #else using OnceToken_t = std::once_flag; # define SWIFT_ONCE_F(TOKEN, FUNC, CONTEXT) \ diff --git a/include/swift/Runtime/Concurrency.h b/include/swift/Runtime/Concurrency.h index 176ce73890044..f6a78d8bc3541 100644 --- a/include/swift/Runtime/Concurrency.h +++ b/include/swift/Runtime/Concurrency.h @@ -26,7 +26,7 @@ #pragma clang diagnostic ignored "-Wreturn-type-c-linkage" // Does the runtime use a cooperative global executor? -#if defined(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) +#if defined(SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY) #define SWIFT_CONCURRENCY_COOPERATIVE_GLOBAL_EXECUTOR 1 #else #define SWIFT_CONCURRENCY_COOPERATIVE_GLOBAL_EXECUTOR 0 diff --git a/include/swift/Runtime/Mutex.h b/include/swift/Runtime/Mutex.h index 16682fbe7af43..4271644208271 100644 --- a/include/swift/Runtime/Mutex.h +++ b/include/swift/Runtime/Mutex.h @@ -30,14 +30,14 @@ #include #endif -#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#if SWIFT_STDLIB_THREADING_NONE #include "swift/Runtime/MutexSingleThreaded.h" -#elif defined(_POSIX_THREADS) +#elif SWIFT_STDLIB_THREADING_PTHREADS || SWIFT_STDLIB_THREADING_DARWIN #include "swift/Runtime/MutexPThread.h" -#elif defined(_WIN32) +#elif SWIFT_STDLIB_THREADING_WIN32 #include "swift/Runtime/MutexWin32.h" -#elif defined(__wasi__) -#include "swift/Runtime/MutexSingleThreaded.h" +#elif SWIFT_STDLIB_THREADING_C11 +#include "swift/Runtime/MutexC11.h" #else #error "Implement equivalent of MutexPThread.h/cpp for your platform." #endif diff --git a/include/swift/Runtime/MutexC11.h b/include/swift/Runtime/MutexC11.h new file mode 100644 index 0000000000000..48e2595aaab38 --- /dev/null +++ b/include/swift/Runtime/MutexC11.h @@ -0,0 +1,162 @@ +//===--- MutexC11.h - Supports Mutex.h using C11 threading ------*- 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 +// +//===----------------------------------------------------------------------===// +// +// Mutex, Read/Write lock, and Scoped lock implementations +// using C11 threading primtives. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_RUNTIME_MUTEX_C11_H +#define SWIFT_RUNTIME_MUTEX_C11_H + +#include + +namespace swift { + +namespace c11threads { + class rwlock; + + static void fatalError(int errcode); + static inline void handleError(int errcode) { + if (SWIFT_LIKELY(errcode == thrd_success)) + return; + + fatalError(errcode); + } +} + +typedef c11threads::rwlock *ReadWriteLockHandle; +typedef ::mtx_t MutexHandle; + +#define SWIFT_MUTEX_SUPPORTS_CONSTEXPR 0 +#define SWIFT_READWRITELOCK_SUPPORTS_CONSTEXPR 0 + +/// C11 low-level implementation that supports Mutex +/// found in Mutex.h +/// +/// See Mutex +class MutexPlatformHelper { +public: + static MutexHandle staticInit() { + ::mtx_t mutex; + ::mtx_init(&mutex, ::mtx_plain); + return mutex; + } + + static void init(MutexHandle &mutex, bool checked = false) { + // C11 mutexes can't be checked + c11threads::handleError(::mtx_init(&mutex, ::mtx_plain)); + } + static void destroy(MutexHandle &mutex) { + ::mtx_destroy(&mutex); + } + static void lock(MutexHandle &mutex) { + c11threads::handleError(::mtx_lock(&mutex)); + } + static void unlock(MutexHandle &mutex) { + c11threads::handleError(::mtx_unlock(&mutex)); + } + static bool try_lock(MutexHandle &mutex) { + int err = ::mtx_trylock(&mutex); + switch (err) { + case thrd_success: + return true; + case thrd_busy: + return false; + default: + c11threads::handleError(err); + } + } + + // Skip error checking for the unsafe versions. + static void unsafeLock(MutexHandle &mutex) { + (void)::mtx_lock(&mutex); + } + static void unsafeUnlock(MutexHandle &mutex) { + (void)::mtx_unlock(&mutex); + } +}; + +/// C11 low-level implementation that supports ReadWriteLock +/// found in Mutex.h +/// +/// See ReadWriteLock +namespace c11threads { + +class rwlock { +private: + unsigned activeReaders_; + unsigned waitingWriters_; + bool writerActive_; + ::cnd_t cond_; + ::mtx_t mutex_; + +public: + rwlock(); + ~rwlock(); + + rwlock(const rwlock &other) = delete; + rwlock &operator=(const rwlock &other) = delete; + + void readLock(); + bool try_readLock(); + void readUnlock(); + void writeLock(); + bool try_writeLock(); + void writeUnlock(); +}; + +} + +class ReadWriteLockPlatformHelper { +public: + static ReadWriteLockHandle staticInit() { + return new c11threads::rwlock(); + }; + + static void init(ReadWriteLockHandle &rwlock) { + rwlock = new c11threads::rwlock(); + } + + static void destroy(ReadWriteLockHandle &rwlock) { + delete rwlock; + } + + static void readLock(ReadWriteLockHandle &rwlock) { + rwlock->readLock(); + } + + static bool try_readLock(ReadWriteLockHandle &rwlock) { + rwlock->try_readLock(); + } + + static void readUnlock(ReadWriteLockHandle &rwlock) { + rwlock->readUnlock(); + } + + static void writeLock(ReadWriteLockHandle &rwlock) { + rwlock->writeLock(); + } + + static bool try_writeLock(ReadWriteLockHandle &rwlock) { + rwlock->try_writeLock(); + } + + static void writeUnlock(ReadWriteLockHandle &rwlock) { + rwlock->writeUnlock(); + } +}; + + +} + +#endif diff --git a/include/swift/Runtime/Once.h b/include/swift/Runtime/Once.h index f9931edf5b9bf..c51c585de10a6 100644 --- a/include/swift/Runtime/Once.h +++ b/include/swift/Runtime/Once.h @@ -18,18 +18,23 @@ #define SWIFT_RUNTIME_ONCE_H #include "swift/Runtime/HeapObject.h" + +#if SWIFT_STDLIB_THREADING_DARWIN +#include +#else #include +#endif namespace swift { -#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#ifdef SWIFT_STDLIB_THREADING_NONE typedef bool swift_once_t; -#elif defined(__APPLE__) +#elif SWIFT_STDLIB_THREADING_DARWIN -// On OS X and iOS, swift_once_t matches dispatch_once_t. -typedef long swift_once_t; +// On OS X and iOS, swift_once_t is really a dispatch_once_t. +typedef dispatch_once_t swift_once_t; #elif defined(__CYGWIN__) diff --git a/include/swift/Runtime/ThreadLocal.h b/include/swift/Runtime/ThreadLocal.h index f952b2d5a4b2b..7e56e62b3c087 100644 --- a/include/swift/Runtime/ThreadLocal.h +++ b/include/swift/Runtime/ThreadLocal.h @@ -20,14 +20,15 @@ #include #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_SINGLE_THREADED_RUNTIME +#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 defined(__APPLE__) +#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) @@ -43,7 +44,7 @@ /// SWIFT_RUNTIME_THREAD_LOCAL - Declare that something is a /// thread-local variable in the runtime. -#if SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#if SWIFT_STDLIB_THREADING_NONE // In a single-threaded runtime, thread-locals are global. #define SWIFT_RUNTIME_ATTRIBUTE_THREAD_LOCAL #elif defined(__GNUC__) @@ -81,14 +82,14 @@ namespace swift { // SWIFT_RUNTIME_ATTRIBUTE_THREAD_LOCAL. This makes the object // itself thread-local, and no internal support is required. // -// Note that this includes platforms that set -// SWIFT_STDLIB_SINGLE_THREADED_RUNTIME, for which -// SWIFT_RUNTIME_ATTRIBUTE_THREAD_LOCAL is empty; +// 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. +// these platforms (at least for now) support pthread_getspecific +// or similar. #if SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL template class ThreadLocal { @@ -104,29 +105,30 @@ class ThreadLocal { void set(T newValue) { value = newValue; } }; #else -// A wrapper around a pthread_key_t that is lazily initialized using +// 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. - dispatch_once_t once; - pthread_key_t key; + swift_once_t once; + __swift_thread_key_t key; public: - pthread_key_t getKey() { - dispatch_once_f(&once, &key, [](void *ctx) { - pthread_key_create(reinterpret_cast(ctx), nullptr); - }); + __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 pthread_key_t, for use on platforms that -// provide reserved keys. -template +// 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: - pthread_key_t getKey() { return constantKey; } + __swift_thread_key_t getKey() { return constantKey; } }; template diff --git a/include/swift/Runtime/ThreadLocalStorage.h b/include/swift/Runtime/ThreadLocalStorage.h index 5cfab5ad65ae2..c9f06317597e5 100644 --- a/include/swift/Runtime/ThreadLocalStorage.h +++ b/include/swift/Runtime/ThreadLocalStorage.h @@ -15,23 +15,30 @@ #include "swift/Runtime/Config.h" +#if SWIFT_STDLIB_THREADING_DARWIN || SWIFT_STDLIB_THREADING_PTHREADS +#include +#elif SWIFT_STDLIB_THREADING_C11 +#include +#elif SWIFT_STDLIB_THREADING_WIN32 +# define WIN32_LEAN_AND_MEAN +# include +#endif + // Depending on the target, we may be able to use dedicated TSD keys or // thread_local variables. When dedicated TSD keys aren't available, // wrap the target's API for thread-local data for things that don't want // to use thread_local. // On Apple platforms, we have dedicated TSD keys. -#if defined(__APPLE__) +#if SWIFT_STDLIB_THREADING_DARWIN # define SWIFT_TLS_HAS_RESERVED_PTHREAD_SPECIFIC 1 -#endif - -#if SWIFT_TLS_HAS_RESERVED_PTHREAD_SPECIFIC // Use reserved TSD keys. # if __has_include() # include # else // We still need to use the SPI for setting the destructor, so declare it here. extern "C" int pthread_key_init_np(int key, void (*destructor)(void *)); +#define SWIFT_THREAD_KEY_INIT pthread_key_init_np # endif // If the keys are not available from the header, define them ourselves. The values match @@ -83,46 +90,25 @@ extern "C" int pthread_key_init_np(int key, void (*destructor)(void *)); #ifndef SWIFT_THREAD_GETSPECIFIC // Pick the right typedef for the key. -# if defined(__linux__) -# if defined(__ANDROID__) -typedef int __swift_thread_key_t; -# else -typedef unsigned int __swift_thread_key_t; -# endif -# elif defined(__FreeBSD__) -typedef int __swift_thread_key_t; -# elif defined(__OpenBSD__) -typedef int __swift_thread_key_t; -# elif defined(_WIN32) -typedef unsigned long __swift_thread_key_t; -# elif defined(__HAIKU__) -typedef int __swift_thread_key_t; -# else -typedef unsigned long __swift_thread_key_t; -# endif - -# if defined(_WIN32) && !defined(__CYGWIN__) -// Windows has its own flavor of API. -# include -# define WIN32_LEAN_AND_MEAN -# include - -#include - -static_assert(std::is_same<__swift_thread_key_t, DWORD>::value, - "__swift_thread_key_t is not a DWORD"); - +#if SWIFT_STDLIB_THREADING_WIN32 +typedef DWORD __swift_thread_key_t; # define SWIFT_THREAD_KEY_CREATE _stdlib_thread_key_create # define SWIFT_THREAD_GETSPECIFIC FlsGetValue # define SWIFT_THREAD_SETSPECIFIC(key, value) (FlsSetValue(key, value) == FALSE) - -# elif !defined(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) -// Otherwise use the pthread API. -# include +#elif SWIFT_STDLIB_THREADING_PTHREADS || SWIFT_STDLIB_THREADING_DARWIN +typedef pthread_key_t __swift_thread_key_t; # define SWIFT_THREAD_KEY_CREATE pthread_key_create # define SWIFT_THREAD_GETSPECIFIC pthread_getspecific # define SWIFT_THREAD_SETSPECIFIC pthread_setspecific -# endif +#elif SWIFT_STDLIB_THREADING_C11 +typedef tss_t __swift_thread_key_t; +# define SWIFT_THREAD_KEY_CREATE tss_create +# define SWIFT_THREAD_GETSPECIFIC tss_get +# define SWIFT_THREAD_SETSPECIFIC tss_set +#else +typedef unsigned long __swift_thread_key_t; +#endif + #endif #endif // SWIFT_RUNTIME_THREADLOCALSTORAGE_H diff --git a/include/swift/Runtime/VoucherShims.h b/include/swift/Runtime/VoucherShims.h index 64662cea7c275..b0287a5150ab2 100644 --- a/include/swift/Runtime/VoucherShims.h +++ b/include/swift/Runtime/VoucherShims.h @@ -22,7 +22,7 @@ // swift-corelibs-libdispatch has os/voucher_private.h but it doesn't work for // us yet, so only look for it on Apple platforms. We also don't need vouchers // in the single threaded concurrency runtime. -#if __APPLE__ && !SWIFT_STDLIB_SINGLE_THREADED_RUNTIME \ +#if __APPLE__ && !SWIFT_STDLIB_THREADING_NONE \ && __has_include() #define SWIFT_HAS_VOUCHER_HEADER 1 #include diff --git a/stdlib/CMakeLists.txt b/stdlib/CMakeLists.txt index e8e3e22826a2b..7e0d2d27666a6 100644 --- a/stdlib/CMakeLists.txt +++ b/stdlib/CMakeLists.txt @@ -174,8 +174,8 @@ function(swift_create_stdlib_targets name variant define_all_alias) endfunction() if("${SWIFT_CONCURRENCY_GLOBAL_EXECUTOR}" STREQUAL "singlethreaded" - AND NOT SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) - message(SEND_ERROR "Cannot enable the single-threaded global executor without enabling SWIFT_STDLIB_SINGLE_THREADED_RUNTIME") + AND NOT SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY) + message(SEND_ERROR "Cannot enable the single-threaded global executor without enabling SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY") endif() swift_create_stdlib_targets("swift-stdlib" "" TRUE) diff --git a/stdlib/cmake/modules/AddSwiftStdlib.cmake b/stdlib/cmake/modules/AddSwiftStdlib.cmake index 5e6cad7a2e9a8..945950f8f2b2b 100644 --- a/stdlib/cmake/modules/AddSwiftStdlib.cmake +++ b/stdlib/cmake/modules/AddSwiftStdlib.cmake @@ -1,6 +1,7 @@ include(AddSwift) include(SwiftSource) +include(Threading) function(add_dependencies_multiple_targets) cmake_parse_arguments( @@ -350,10 +351,13 @@ function(_add_target_variant_c_compile_flags) list(APPEND result "-DSWIFT_STDLIB_HAS_LOCALE") endif() - if(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) - list(APPEND result "-DSWIFT_STDLIB_SINGLE_THREADED_RUNTIME") + if(SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY) + list(APPEND result "-DSWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY") endif() + threading_package_name(_threading_package) + list(APPEND result "-DSWIFT_STDLIB_THREADING_${_threading_package}") + if(SWIFT_STDLIB_OS_VERSIONING) list(APPEND result "-DSWIFT_RUNTIME_OS_VERSIONING") endif() diff --git a/stdlib/cmake/modules/StdlibOptions.cmake b/stdlib/cmake/modules/StdlibOptions.cmake index 2d0f2fa63a3f1..69be588bbcbd3 100644 --- a/stdlib/cmake/modules/StdlibOptions.cmake +++ b/stdlib/cmake/modules/StdlibOptions.cmake @@ -1,6 +1,8 @@ include_guard(GLOBAL) include(${CMAKE_CURRENT_LIST_DIR}/../../../cmake/modules/SwiftUtils.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/../../../cmake/modules/Threading.cmake) + precondition(SWIFT_HOST_VARIANT_SDK) precondition(SWIFT_DARWIN_PLATFORMS) @@ -166,11 +168,11 @@ option(SWIFT_STDLIB_HAS_ENVIRON "Build stdlib assuming the platform supports environment variables." TRUE) -option(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +option(SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY "Build the standard libraries assuming that they will be used in an environment with only a single thread." FALSE) -if(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) +if(SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY) set(SWIFT_CONCURRENCY_GLOBAL_EXECUTOR_default "singlethreaded") else() set(SWIFT_CONCURRENCY_GLOBAL_EXECUTOR_default "dispatch") diff --git a/stdlib/cmake/modules/SwiftSource.cmake b/stdlib/cmake/modules/SwiftSource.cmake index 6286db16ddafb..18eecad5624d0 100644 --- a/stdlib/cmake/modules/SwiftSource.cmake +++ b/stdlib/cmake/modules/SwiftSource.cmake @@ -1,5 +1,6 @@ include(macCatalystUtils) include(SwiftUtils) +include(Threading) function(_compute_lto_swift_flag option out_var) string(TOLOWER "${option}" lowercase_option) @@ -322,10 +323,13 @@ function(_add_target_variant_swift_compile_flags list(APPEND result "-Xcc" "-DSWIFT_STDLIB_HAS_ENVIRON") endif() - if(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) - list(APPEND result "-D" "SWIFT_STDLIB_SINGLE_THREADED_RUNTIME") + if(SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY) + list(APPEND result "-D" "SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY") endif() + threading_package_name(_threading_package) + list(APPEND result "-D" "SWIFT_STDLIB_THREADING_${_threading_package}") + set("${result_var_name}" "${result}" PARENT_SCOPE) endfunction() @@ -479,7 +483,7 @@ function(_compile_swift_files list(APPEND swift_flags "-Xfrontend" "-library-level" "-Xfrontend" "api") endif() - if(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) + if(SWIFT_STDLIB_THREADING_PACKAGE STREQUAL "none") list(APPEND swift_flags "-Xfrontend" "-assume-single-threaded") endif() diff --git a/stdlib/private/StdlibUnittest/RaceTest.swift b/stdlib/private/StdlibUnittest/RaceTest.swift index 0380579c644c4..008f17a52000a 100644 --- a/stdlib/private/StdlibUnittest/RaceTest.swift +++ b/stdlib/private/StdlibUnittest/RaceTest.swift @@ -619,12 +619,6 @@ class _InterruptibleSleep { } #endif -#if os(Windows) -typealias ThreadHandle = HANDLE -#else -typealias ThreadHandle = pthread_t -#endif - public func runRaceTest( _: RT.Type, trials: Int, diff --git a/stdlib/public/BackDeployConcurrency/CMakeLists.txt b/stdlib/public/BackDeployConcurrency/CMakeLists.txt index 5da354361110d..a6f24ae406c92 100644 --- a/stdlib/public/BackDeployConcurrency/CMakeLists.txt +++ b/stdlib/public/BackDeployConcurrency/CMakeLists.txt @@ -16,7 +16,7 @@ cmake_minimum_required(VERSION 3.19.6) include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/modules/StandaloneOverlay.cmake") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules") set(SWIFT_STDLIB_STABLE_ABI TRUE) -set(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME FALSE) +set(SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY FALSE) set(SWIFT_CONCURRENCY_GLOBAL_EXECUTOR "dispatch") include(AddSwiftStdlib) diff --git a/stdlib/public/Concurrency/Actor.cpp b/stdlib/public/Concurrency/Actor.cpp index 535f02cb371fe..cf594ba10f855 100644 --- a/stdlib/public/Concurrency/Actor.cpp +++ b/stdlib/public/Concurrency/Actor.cpp @@ -287,7 +287,7 @@ static HANDLE __initialPthread = INVALID_HANDLE_VALUE; /// Determine whether we are currently executing on the main thread /// independently of whether we know that we are on the main actor. static bool isExecutingOnMainThread() { -#if SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#if SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY return true; #elif defined(__linux__) return syscall(SYS_gettid) == getpid(); @@ -307,7 +307,7 @@ static bool isExecutingOnMainThread() { } JobPriority swift::swift_task_getCurrentThreadPriority() { -#if SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#if SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY return JobPriority::UserInitiated; #elif defined(__APPLE__) return static_cast(qos_class_self()); diff --git a/stdlib/public/Concurrency/Executor.swift b/stdlib/public/Concurrency/Executor.swift index 35862d5bf223f..13e2811b83ef5 100644 --- a/stdlib/public/Concurrency/Executor.swift +++ b/stdlib/public/Concurrency/Executor.swift @@ -93,7 +93,7 @@ func _checkExpectedExecutor(_filenameStart: Builtin.RawPointer, _filenameStart, _filenameLength, _filenameIsASCII, _line, _executor) } -#if !SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#if !SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY // This must take a DispatchQueueShim, not something like AnyObject, // or else SILGen will emit a retain/release in unoptimized builds, // which won't work because DispatchQueues aren't actually diff --git a/stdlib/public/Concurrency/Mutex.cpp b/stdlib/public/Concurrency/Mutex.cpp index ccf4ec939d882..46a311d85529c 100644 --- a/stdlib/public/Concurrency/Mutex.cpp +++ b/stdlib/public/Concurrency/Mutex.cpp @@ -19,6 +19,7 @@ #include "../runtime/MutexPThread.cpp" #include "../runtime/MutexWin32.cpp" -#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#include "../runtime/MutexC11.cpp" +#ifdef SWIFT_STDLIB_THREADING_NONE #include "swift/Runtime/MutexSingleThreaded.h" #endif diff --git a/stdlib/public/Concurrency/TaskGroup.cpp b/stdlib/public/Concurrency/TaskGroup.cpp index 60ff5d8670c21..e8f1cb6f80369 100644 --- a/stdlib/public/Concurrency/TaskGroup.cpp +++ b/stdlib/public/Concurrency/TaskGroup.cpp @@ -34,6 +34,11 @@ #include "queue" // TODO: remove and replace with usage of our mpsc queue #include #include + +#if !SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY +#include +#endif + #include #if SWIFT_CONCURRENCY_ENABLE_DISPATCH #include @@ -280,7 +285,7 @@ class TaskGroupImpl: public TaskGroupTaskStatusRecord { private: -#if !SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#if !SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY // TODO: move to lockless via the status atomic (make readyQueue an mpsc_queue_t) mutable std::mutex mutex_; diff --git a/stdlib/public/Concurrency/TaskPrivate.h b/stdlib/public/Concurrency/TaskPrivate.h index cdda19c5d3056..36ee085fcc983 100644 --- a/stdlib/public/Concurrency/TaskPrivate.h +++ b/stdlib/public/Concurrency/TaskPrivate.h @@ -114,7 +114,7 @@ void _swift_tsan_release(void *addr); /// executors. #define DISPATCH_QUEUE_GLOBAL_EXECUTOR (void *)1 -#if !defined(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) +#if !SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY inline SerialExecutorWitnessTable * _swift_task_getDispatchQueueSerialExecutorWitnessTable() { extern SerialExecutorWitnessTable wtable diff --git a/stdlib/public/runtime/CMakeLists.txt b/stdlib/public/runtime/CMakeLists.txt index e87bda0ed6057..2f4b7caa855d6 100644 --- a/stdlib/public/runtime/CMakeLists.txt +++ b/stdlib/public/runtime/CMakeLists.txt @@ -59,6 +59,7 @@ set(swift_runtime_sources KnownMetadata.cpp Metadata.cpp MetadataLookup.cpp + MutexC11.cpp MutexPThread.cpp MutexWin32.cpp Numeric.cpp diff --git a/stdlib/public/runtime/HeapObject.cpp b/stdlib/public/runtime/HeapObject.cpp index 510ec6e6256f8..1a820040ebef9 100644 --- a/stdlib/public/runtime/HeapObject.cpp +++ b/stdlib/public/runtime/HeapObject.cpp @@ -350,7 +350,7 @@ static HeapObject *_swift_retain_(HeapObject *object) { } HeapObject *swift::swift_retain(HeapObject *object) { -#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#ifdef SWIFT_STDLIB_THREADING_NONE return swift_nonatomic_retain(object); #else CALL_IMPL(swift_retain, (object)); @@ -377,7 +377,7 @@ static HeapObject *_swift_retain_n_(HeapObject *object, uint32_t n) { } HeapObject *swift::swift_retain_n(HeapObject *object, uint32_t n) { -#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#ifdef SWIFT_STDLIB_THREADING_NONE return swift_nonatomic_retain_n(object, n); #else CALL_IMPL(swift_retain_n, (object, n)); @@ -403,7 +403,7 @@ static void _swift_release_(HeapObject *object) { } void swift::swift_release(HeapObject *object) { -#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#ifdef SWIFT_STDLIB_THREADING_NONE swift_nonatomic_release(object); #else CALL_IMPL(swift_release, (object)); @@ -428,7 +428,7 @@ static void _swift_release_n_(HeapObject *object, uint32_t n) { } void swift::swift_release_n(HeapObject *object, uint32_t n) { -#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#ifdef SWIFT_STDLIB_THREADING_NONE swift_nonatomic_release_n(object, n); #else CALL_IMPL(swift_release_n, (object, n)); @@ -460,7 +460,7 @@ size_t swift::swift_weakRetainCount(HeapObject *object) { } HeapObject *swift::swift_unownedRetain(HeapObject *object) { -#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#ifdef SWIFT_STDLIB_THREADING_NONE return static_cast(swift_nonatomic_unownedRetain(object)); #else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRetain); @@ -473,7 +473,7 @@ HeapObject *swift::swift_unownedRetain(HeapObject *object) { } void swift::swift_unownedRelease(HeapObject *object) { -#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#ifdef SWIFT_STDLIB_THREADING_NONE swift_nonatomic_unownedRelease(object); #else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRelease); @@ -520,7 +520,7 @@ void swift::swift_nonatomic_unownedRelease(HeapObject *object) { } HeapObject *swift::swift_unownedRetain_n(HeapObject *object, int n) { -#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#ifdef SWIFT_STDLIB_THREADING_NONE return swift_nonatomic_unownedRetain_n(object, n); #else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRetain_n); @@ -533,7 +533,7 @@ HeapObject *swift::swift_unownedRetain_n(HeapObject *object, int n) { } void swift::swift_unownedRelease_n(HeapObject *object, int n) { -#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#ifdef SWIFT_STDLIB_THREADING_NONE swift_nonatomic_unownedRelease_n(object, n); #else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRelease_n); @@ -583,7 +583,7 @@ static HeapObject *_swift_tryRetain_(HeapObject *object) { if (!isValidPointerForNativeRetain(object)) return nullptr; -#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#ifdef SWIFT_STDLIB_THREADING_NONE if (object->refCounts.tryIncrementNonAtomic()) return object; else return nullptr; #else @@ -612,7 +612,7 @@ void swift::swift_setDeallocating(HeapObject *object) { } HeapObject *swift::swift_unownedRetainStrong(HeapObject *object) { -#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#ifdef SWIFT_STDLIB_THREADING_NONE return swift_nonatomic_unownedRetainStrong(object); #else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRetainStrong); @@ -640,7 +640,7 @@ HeapObject *swift::swift_nonatomic_unownedRetainStrong(HeapObject *object) { } void swift::swift_unownedRetainStrongAndRelease(HeapObject *object) { -#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#ifdef SWIFT_STDLIB_THREADING_NONE swift_nonatomic_unownedRetainStrongAndRelease(object); #else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRetainStrongAndRelease); diff --git a/stdlib/public/runtime/MetadataImpl.h b/stdlib/public/runtime/MetadataImpl.h index 211d2b93512e8..c3aaf4eb6098c 100644 --- a/stdlib/public/runtime/MetadataImpl.h +++ b/stdlib/public/runtime/MetadataImpl.h @@ -137,7 +137,7 @@ template struct RetainableBoxBase { static constexpr size_t stride = sizeof(T); static constexpr bool isPOD = false; static constexpr bool isBitwiseTakable = true; -#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#ifdef SWIFT_STDLIB_THREADING_NONE static constexpr bool isAtomic = false; #else static constexpr bool isAtomic = true; diff --git a/stdlib/public/runtime/MutexC11.cpp b/stdlib/public/runtime/MutexC11.cpp new file mode 100644 index 0000000000000..7e2892134b2de --- /dev/null +++ b/stdlib/public/runtime/MutexC11.cpp @@ -0,0 +1,110 @@ +//===--- MutexC11.cpp - Supports Mutex.h using C11 threads ----------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Mutex and Read/Write lock implementations using C11 threads. +// +//===----------------------------------------------------------------------===// + +#include "swift/Runtime/Mutex.h" +#include "swift/Runtime/Debug.h" + +#if SWIFT_STDLIB_THREADING_C11 + +using namespace swift; + +namespace { + +// A simple scoped locker class for a C11 mutex +class locker { +private: + mtx_t &mutex_; + +public: + explicit locker(mtx_t &mutex) : mutex_(mutex) { + c11threads::handleError(mtx_lock(&mutex_)); + } + ~locker() { + c11threads::handleError(mtx_unlock(&mutex_)); + } +}; + +} + +namespace c11threads { + +#ifndef SWIFT_FATAL_ERROR +#define SWIFT_FATAL_ERROR swift::fatalError +#endif + +// Triggered if a C11 threads call fails +void fatalError(int errcode) { + SWIFT_FATAL_ERROR(0, "C11 threads call failed with %d\n", errcode); +} + +// A simple reader/writer lock implementation, with writer priority +rwlock::rwlock() : activeReaders_(0), waitingWriters_(0), writerActive_(false) { + handleError(::cnd_init(&cond_)); + handleError(::mtx_init(&mutex_, ::mtx_plain)); +} + +rwlock::~rwlock() { + ::cnd_destroy(&cond_); + ::mtx_destroy(&mutex_); +} + +void rwlock::readLock() { + locker l(mutex_); + while (waitingWriters_ || writerActive_) + handleError(::cnd_wait(&cond_, &mutex_)); + ++activeReaders_; +} + +bool rwlock::try_readLock() { + locker l(mutex_); + if (waitingWriters_ || writerActive_) + return false; + ++activeReaders_; + return true; +} + +void rwlock::readUnlock() { + locker l(mutex_); + if (!--activeReaders_) + handleError(::cnd_broadcast(&cond_)); +} + +void rwlock::writeLock() { + locker l(mutex_); + ++waitingWriters_; + while (activeReaders_ || writerActive_) + handleError(::cnd_wait(&cond_, mutex_)); + --waitingWriters_; + writerActive_ = true; +} + +bool rwlock::try_writeLock() { + locker l(mutex_); + if (activeReaders_ || writerActive_) + return false; + writerActive_ = true; + return true; +} + +void rwlock::writeUnlock() { + locker l(mutex_); + writerActive_ = false; + handleError(::cnd_broadcast(&cond_)); +} + +} + +#endif // SWIFT_STDLIB_THREADING_C11 diff --git a/stdlib/public/runtime/MutexPThread.cpp b/stdlib/public/runtime/MutexPThread.cpp index 6c27207092224..99250d0ee4702 100644 --- a/stdlib/public/runtime/MutexPThread.cpp +++ b/stdlib/public/runtime/MutexPThread.cpp @@ -17,12 +17,12 @@ // //===----------------------------------------------------------------------===// +#if SWIFT_STDLIB_THREADING_PTHREADS || SWIFT_STDLIB_THREADING_DARWIN + #if __has_include() #include #endif -#if defined(_POSIX_THREADS) && !defined(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) - // Notes: swift::fatalError is not shared between libswiftCore and libswift_Concurrency // and libswift_Concurrency uses swift_Concurrency_fatalError instead. #ifndef SWIFT_FATAL_ERROR @@ -139,4 +139,5 @@ void ReadWriteLockPlatformHelper::readUnlock(pthread_rwlock_t &rwlock) { void ReadWriteLockPlatformHelper::writeUnlock(pthread_rwlock_t &rwlock) { reportError(pthread_rwlock_unlock(&rwlock)); } -#endif + +#endif // SWIFT_STDLIB_THREADING_PTHREADS diff --git a/stdlib/public/runtime/Once.cpp b/stdlib/public/runtime/Once.cpp index 1460b0603ef17..2878fcbe0621a 100644 --- a/stdlib/public/runtime/Once.cpp +++ b/stdlib/public/runtime/Once.cpp @@ -21,11 +21,11 @@ using namespace swift; -#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#if SWIFT_STDLIB_THREADING_NONE // No dependencies on single-threaded environments. -#elif defined(__APPLE__) +#elif SWIFT_STDLIB_THREADING_DARWIN // On macOS and iOS, swift_once is implemented using GCD. // The compiler emits an inline check matching the barrier-free inline fast @@ -52,16 +52,16 @@ static_assert(sizeof(swift_once_t) <= sizeof(void*), /// extent of type swift_once_t. void swift::swift_once(swift_once_t *predicate, void (*fn)(void *), void *context) { -#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#ifdef SWIFT_STDLIB_THREADING_NONE if (! *predicate) { *predicate = true; fn(context); } -#elif defined(__APPLE__) +#elif SWIFT_STDLIB_THREADING_DARWIN dispatch_once_f(predicate, context, fn); #elif defined(__CYGWIN__) _swift_once_f(predicate, context, fn); #else - std::call_once(*predicate, [fn, context]() { fn(context); }); + std::call_once(*predicate, fn, context); #endif } diff --git a/stdlib/public/runtime/SwiftTLSContext.cpp b/stdlib/public/runtime/SwiftTLSContext.cpp index 59657e89df1a5..a0e52253caba3 100644 --- a/stdlib/public/runtime/SwiftTLSContext.cpp +++ b/stdlib/public/runtime/SwiftTLSContext.cpp @@ -18,7 +18,7 @@ using namespace swift; using namespace swift::runtime; -#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#ifdef SWIFT_STDLIB_THREADING_NONE SwiftTLSContext &SwiftTLSContext::get() { static SwiftTLSContext TLSContext; @@ -38,7 +38,7 @@ SwiftTLSContext &SwiftTLSContext::get() { SWIFT_ONCE_F( setupToken, [](void *) { - pthread_key_init_np(SWIFT_RUNTIME_TLS_KEY, [](void *pointer) { + SWIFT_THREAD_KEY_INIT(SWIFT_RUNTIME_TLS_KEY, [](void *pointer) { delete static_cast(pointer); }); }, diff --git a/stdlib/public/stubs/Stubs.cpp b/stdlib/public/stubs/Stubs.cpp index 0cc0efa2576dd..286ffd753f61f 100644 --- a/stdlib/public/stubs/Stubs.cpp +++ b/stdlib/public/stubs/Stubs.cpp @@ -484,7 +484,7 @@ int _swift_stdlib_putc_stderr(int C) { } size_t _swift_stdlib_getHardwareConcurrency() { -#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#ifdef SWIFT_STDLIB_THREADING_NONE return 1; #else return std::thread::hardware_concurrency(); @@ -537,16 +537,17 @@ __swift_bool swift_stdlib_isStackAllocationSafe(__swift_size_t byteCount, __swift_bool _swift_stdlib_getCurrentStackBounds(__swift_uintptr_t *outBegin, __swift_uintptr_t *outEnd) { -#if defined(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) +#if SWIFT_STDLIB_THREADING_NONE // This platform does not support threads, so the API we'd call to get stack // bounds (i.e. libpthread) is not going to be usable. return false; - -#elif defined(__APPLE__) + +#elif SWIFT_STDLIB_THREADING_DARWIN pthread_t thread = pthread_self(); - // On Apple platforms, the stack grows down, so that the end of the stack - // comes before the beginning on the number line, and an address on the stack - // will be LESS than the start of the stack and GREATER than the end. + + // On Apple platforms, pthread_get_stackaddr_np() gets the address of the + // *end* of the stack (i.e. the highest address in stack space), *NOT* the + // address of the *base* of the stack (the lowest address). void *end = pthread_get_stackaddr_np(thread); if (!end) { return false; @@ -555,15 +556,29 @@ __swift_bool _swift_stdlib_getCurrentStackBounds(__swift_uintptr_t *outBegin, *outBegin = *outEnd - pthread_get_stacksize_np(thread); return true; -#elif defined(_WIN32) && (_WIN32_WINNT >= 0x0602) +#elif SWIFT_STDLIB_THREADING_C11 + // We don't know any way to do this for C11 threads + return false + +#elif SWIFT_STDLIB_THREADING_WIN32 + +# if _WIN32_WINNT >= 0x0602 ULONG_PTR lowLimit = 0; ULONG_PTR highLimit = 0; GetCurrentThreadStackLimits(&lowLimit, &highLimit); *outBegin = lowLimit; *outEnd = highLimit; return true; +# else + // Need _WIN32_WINNT to be 0x0602 or higher to use + // GetCurrentThreadStackLimits(). We could use VirtualQuery() instead, + // and give it the address of a page we know is on the stack? + return false; +# endif + +#elif SWIFT_STDLIB_THREADING_PTHREADS -#elif defined(__OpenBSD__) +# if defined(__OpenBSD__) stack_t sinfo; if (pthread_stackseg_np(pthread_self(), &sinfo) != 0) { return false; @@ -572,18 +587,18 @@ __swift_bool _swift_stdlib_getCurrentStackBounds(__swift_uintptr_t *outBegin, *outBegin = (uintptr_t)sinfo.ss_sp - sinfo.ss_size; *outEnd = (uintptr_t)sinfo.ss_sp; return true; -#elif defined(__FreeBSD__) || defined(__ANDROID__) || defined(__linux__) +# elif defined(__FreeBSD__) || defined(__ANDROID__) || defined(__linux__) pthread_attr_t attr; -#if defined(__FreeBSD__) +# if defined(__FreeBSD__) if (0 != pthread_attr_init(&attr) || 0 != pthread_attr_get_np(pthread_self(), &attr)) { return false; } -#else +# else if (0 != pthread_getattr_np(pthread_self(), &attr)) { return false; } -#endif +# endif void *begin = nullptr; size_t size = 0; @@ -594,9 +609,12 @@ __swift_bool _swift_stdlib_getCurrentStackBounds(__swift_uintptr_t *outBegin, pthread_attr_destroy(&attr); return success; +# else +# warning Please teach _swift_stdlib_getCurrentStackBounds() about your platform + return false; +# endif #else - // FIXME: implement on this platform - return false; +# error Unknown threading package selected; please teach _swift_stdlib_getCurrentStackBounds() what to do. #endif } diff --git a/stdlib/public/stubs/ThreadLocalStorage.cpp b/stdlib/public/stubs/ThreadLocalStorage.cpp index 20c70fc922559..77a5c63fc2f67 100644 --- a/stdlib/public/stubs/ThreadLocalStorage.cpp +++ b/stdlib/public/stubs/ThreadLocalStorage.cpp @@ -54,7 +54,7 @@ _stdlib_thread_key_create(__swift_thread_key_t * _Nonnull key, #endif -#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#ifdef SWIFT_STDLIB_THREADING_NONE SWIFT_RUNTIME_STDLIB_INTERNAL void * @@ -77,7 +77,7 @@ _swift_stdlib_threadLocalStorageGet(void) { static swift::OnceToken_t token; SWIFT_ONCE_F(token, [](void *) { - int result = pthread_key_init_np(SWIFT_STDLIB_TLS_KEY, [](void *pointer) { + int result = SWIFT_THREAD_KEY_INIT(SWIFT_STDLIB_TLS_KEY, [](void *pointer) { _stdlib_destroyTLS(pointer); }); if (result != 0) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index eaf28db082459..2098f93114638 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -199,7 +199,7 @@ normalize_boolean_spelling(SWIFT_ENABLE_MACCATALYST) normalize_boolean_spelling(SWIFT_RUN_TESTS_WITH_HOST_COMPILER) normalize_boolean_spelling(SWIFT_RUNTIME_ENABLE_LEAK_CHECKER) normalize_boolean_spelling(SWIFT_OPTIMIZED) -normalize_boolean_spelling(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) +normalize_boolean_spelling(SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY) normalize_boolean_spelling(SWIFT_ENABLE_REFLECTION) normalize_boolean_spelling(SWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS) normalize_boolean_spelling(SWIFT_STDLIB_ENABLE_DEBUG_PRECONDITIONS_IN_RELEASE) diff --git a/test/Concurrency/Runtime/async_task_locals_copy_to_sync.swift b/test/Concurrency/Runtime/async_task_locals_copy_to_sync.swift index 839dc833e2bc6..99f81b654839d 100644 --- a/test/Concurrency/Runtime/async_task_locals_copy_to_sync.swift +++ b/test/Concurrency/Runtime/async_task_locals_copy_to_sync.swift @@ -8,7 +8,7 @@ // REQUIRES: concurrency_runtime // UNSUPPORTED: back_deployment_runtime // Disable on cooperative executor because it can't dispatch jobs before the end of main function -// UNSUPPORTED: single_threaded_runtime +// UNSUPPORTED: single_threaded_concurrency // REQUIRES: rdar80824152 import Dispatch diff --git a/test/Concurrency/Runtime/cancellation_handler.swift b/test/Concurrency/Runtime/cancellation_handler.swift index 4c99261e2ded6..6a096c54a743e 100644 --- a/test/Concurrency/Runtime/cancellation_handler.swift +++ b/test/Concurrency/Runtime/cancellation_handler.swift @@ -5,7 +5,7 @@ // rdar://76038845 // REQUIRES: concurrency_runtime // UNSUPPORTED: back_deployment_runtime -// UNSUPPORTED: single_threaded_runtime +// UNSUPPORTED: single_threaded_concurrency // for sleep #if canImport(Darwin) diff --git a/test/Concurrency/Runtime/data_race_detection.swift b/test/Concurrency/Runtime/data_race_detection.swift index 81153db0a178e..8eb43a94e3d8e 100644 --- a/test/Concurrency/Runtime/data_race_detection.swift +++ b/test/Concurrency/Runtime/data_race_detection.swift @@ -8,7 +8,7 @@ // rdar://76038845 // REQUIRES: concurrency_runtime // UNSUPPORTED: back_deployment_runtime -// UNSUPPORTED: single_threaded_runtime +// UNSUPPORTED: single_threaded_concurrency import _Concurrency import Dispatch diff --git a/test/Concurrency/Runtime/mainactor.swift b/test/Concurrency/Runtime/mainactor.swift index 5fcfb1d5b61c5..08c96067adbb6 100644 --- a/test/Concurrency/Runtime/mainactor.swift +++ b/test/Concurrency/Runtime/mainactor.swift @@ -7,7 +7,7 @@ // rdar://76038845 // REQUIRES: concurrency_runtime // UNSUPPORTED: back_deployment_runtime -// UNSUPPORTED: single_threaded_runtime +// UNSUPPORTED: single_threaded_concurrency import Dispatch diff --git a/test/Interpreter/enforce_exclusive_access.swift b/test/Interpreter/enforce_exclusive_access.swift index 066052419262c..4fa3022bb9a0f 100644 --- a/test/Interpreter/enforce_exclusive_access.swift +++ b/test/Interpreter/enforce_exclusive_access.swift @@ -4,7 +4,7 @@ // RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out // REQUIRES: executable_test -// UNSUPPORTED: single_threaded_runtime +// REQUIRES: thread_safe_runtime // UNSUPPORTED: use_os_stdlib diff --git a/test/lit.site.cfg.in b/test/lit.site.cfg.in index 31402817a8913..dc5cb938be465 100644 --- a/test/lit.site.cfg.in +++ b/test/lit.site.cfg.in @@ -96,8 +96,13 @@ else: if "@SWIFT_OPTIMIZED@" == "TRUE": config.available_features.add("optimized_stdlib") -if "@SWIFT_STDLIB_SINGLE_THREADED_RUNTIME@" == "TRUE": - config.available_features.add("single_threaded_runtime") +if "@SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY@" == "TRUE": + config.available_features.add("single_threaded_concurrency") + +if "@SWIFT_STDLIB_THREADING_PACKAGE@" != "none": + # This is not called "threading" because we might want that later + config.available_features.add("thread_safe_runtime") + config.available_features.add("threading_@SWIFT_STDLIB_THREADING_PACKAGE@") if "@SWIFT_ENABLE_REFLECTION@" == "TRUE": config.available_features.add("reflection") diff --git a/unittests/runtime/CMakeLists.txt b/unittests/runtime/CMakeLists.txt index 323a3ec49ce8c..bc086d84b421f 100644 --- a/unittests/runtime/CMakeLists.txt +++ b/unittests/runtime/CMakeLists.txt @@ -84,7 +84,7 @@ if(("${SWIFT_HOST_VARIANT_SDK}" STREQUAL "${SWIFT_PRIMARY_VARIANT_SDK}") AND endif() endif() - if(NOT SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) + if(NOT "${SWIFT_STDLIB_THREADING_PACKAGE}" STREQUAL "none") list(APPEND PLATFORM_SOURCES Mutex.cpp) endif() diff --git a/unittests/runtime/Concurrent.cpp b/unittests/runtime/Concurrent.cpp index f3b3ea9308b1e..a72d2d16b2eb1 100644 --- a/unittests/runtime/Concurrent.cpp +++ b/unittests/runtime/Concurrent.cpp @@ -45,7 +45,7 @@ TEST(ConcurrentReadableArrayTest, SingleThreaded) { check(); } -#ifndef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#ifndef SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY TEST(ConcurrentReadableArrayTest, MultiThreaded) { const int insertCount = 100000; @@ -544,4 +544,4 @@ TEST(ConcurrentReadableHashMapTest, MultiThreaded4) { runTest(16, 1); runTest(16, 8); } -#endif // !SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#endif // !SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY diff --git a/utils/build-presets.ini b/utils/build-presets.ini index ea44792dbd615..4814fc3a0052f 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -1205,7 +1205,8 @@ mixin-preset=buildbot_incremental_linux_base llvm-targets-to-build=X86;ARM;AArch64;WebAssembly # Ensure single-thread-mode is not broken because it's used # by stdlib for wasm32 in SwiftWasm fork. -swift-stdlib-single-threaded-runtime=1 +swift-stdlib-threading-package=none +swift-stdlib-single-threaded-concurrency=1 #===------------------------------------------------------------------------===# # OS X Package Builders @@ -2508,7 +2509,8 @@ swift-stdlib-has-stdin=0 swift-stdlib-has-environ=0 swift-stdlib-has-locale=0 swift-runtime-static-image-inspection=1 -swift-stdlib-single-threaded-runtime=1 +swift-stdlib-threading-package=none +swift-stdlib-single-threaded-concurrency=1 swift-stdlib-concurrency-tracing=0 swift-stdlib-os-versioning=0 swift-stdlib-has-commandline=0 diff --git a/utils/build-script-impl b/utils/build-script-impl index b2b91d551e20f..981f1f9a10e4e 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -206,7 +206,8 @@ KNOWN_SETTINGS=( swift-stdlib-has-dladdr "1" "whether to build stdlib assuming the runtime environment provides dladdr API" swift-stdlib-supports-backtrace-reporting "" "whether to build stdlib assuming the runtime environment provides the backtrace(3) API, if not set defaults to true on all platforms except for Cygwin, Haiku and wasm" swift-runtime-static-image-inspection "0" "whether to build stdlib assuming the runtime environment only supports a single runtime image with Swift code" - swift-stdlib-single-threaded-runtime "0" "whether to build stdlib as a single-threaded runtime only" + swift-stdlib-threading-package "" "which threading package to use for Swift; valid values are empty string (default based on platform), 'pthreads', 'darwin', 'win32', 'c11', 'none'" + swift-stdlib-single-threaded-concurrency "0" "build Swift concurrency in single-threaded mode" swift-stdlib-concurrency-tracing "" "whether to enable tracing signposts for concurrency; default is 1 on Darwin platforms, 0 otherwise" swift-stdlib-os-versioning "1" "whether to build stdlib with availability based on OS versions (Darwin only)" swift-stdlib-has-commandline "1" "whether to build stdlib with the CommandLine enum and support for argv/argc" @@ -2004,7 +2005,7 @@ for host in "${ALL_HOSTS[@]}"; do -DSWIFT_ENABLE_DISPATCH:BOOL=$(true_false "${SWIFT_ENABLE_DISPATCH}") -DSWIFT_IMPLICIT_CONCURRENCY_IMPORT:BOOL=$(true_false "${SWIFT_IMPLICIT_CONCURRENCY_IMPORT}") -DSWIFT_STDLIB_SUPPORT_BACK_DEPLOYMENT:BOOL=$(true_false "${SWIFT_STDLIB_SUPPORT_BACK_DEPLOYMENT}") - -DSWIFT_STDLIB_SINGLE_THREADED_RUNTIME:BOOL=$(true_false "${SWIFT_STDLIB_SINGLE_THREADED_RUNTIME}") + -DSWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY:BOOL=$(true_false "${SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY}") -DSWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS:BOOL=$(true_false "${SWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS}") -DSWIFT_STDLIB_HAS_DLADDR:BOOL=$(true_false "${SWIFT_STDLIB_HAS_DLADDR}") -DSWIFT_RUNTIME_STATIC_IMAGE_INSPECTION:BOOL=$(true_false "${SWIFT_RUNTIME_STATIC_IMAGE_INSPECTION}") @@ -2226,6 +2227,21 @@ for host in "${ALL_HOSTS[@]}"; do ) fi + if [[ "${SWIFT_STDLIB_THREADING_PACKAGE}" ]] ; then + case "${SWIFT_STDLIB_THREADING_PACKAGE}" in + "" | pthreads | darwin | win32 | c11 | none) ;; + *) + echo "build-script: unknown threading package ${SWIFT_STDLIB_THREADING_PACKAGE}; must be one of 'pthreads', 'darwin', 'win32', 'c11', 'none', or empty for platform default" >&2 + exit 1 + ;; + esac + + cmake_options=( + "${cmake_options[@]}" + -DSWIFT_STDLIB_THREADING_PACKAGE:STRING="${SWIFT_STDLIB_THREADING_PACKAGE}" + ) + fi + build_targets=(all "${SWIFT_STDLIB_TARGETS[@]}") if [[ $(true_false "${build_perf_testsuite_this_time}") == "TRUE" ]]; then native_swift_tools_path="$(build_directory_bin ${LOCAL_HOST} swift)" diff --git a/validation-test/lit.site.cfg.in b/validation-test/lit.site.cfg.in index 6e4718d9bff30..cd49fe8f293fe 100644 --- a/validation-test/lit.site.cfg.in +++ b/validation-test/lit.site.cfg.in @@ -94,8 +94,13 @@ if "@SWIFT_OPTIMIZED@" == "TRUE": if "@SWIFT_ENABLE_SOURCEKIT_TESTS@" == "TRUE": config.available_features.add('sourcekit') -if "@SWIFT_STDLIB_SINGLE_THREADED_RUNTIME@" == "TRUE": - config.available_features.add("single_threaded_runtime") +if "@SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY@" == "TRUE": + config.available_features.add("single_threaded_concurrency") + +if "@SWIFT_STDLIB_THREADING_PACKAGE@" != "none": + # This is not called "threading" because we might want that later + config.available_features.add("thread_safe_runtime") + config.available_features.add("threading_@SWIFT_STDLIB_THREADING_PACKAGE@") if "@SWIFT_ENABLE_REFLECTION@" == "TRUE": config.available_features.add("reflection") From 66b9d2100082e21b79959df232e7c0ba49d89ef3 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Tue, 29 Mar 2022 16:03:07 +0100 Subject: [PATCH 02/40] [Runtime] Remove all use of read/write locks. Read/write locks are not as good as you'd think; a simple mutex is better in almost all cases. rdar://90776105 --- include/swift/Runtime/Mutex.h | 309 +---------- include/swift/Runtime/MutexC11.h | 73 --- include/swift/Runtime/MutexPThread.h | 28 - include/swift/Runtime/MutexSingleThreaded.h | 13 - include/swift/Runtime/MutexWin32.h | 27 - stdlib/public/runtime/Casting.cpp | 16 +- stdlib/public/runtime/MutexC11.cpp | 73 --- stdlib/public/runtime/MutexPThread.cpp | 34 -- .../runtime/RuntimeInvocationsTracking.cpp | 18 +- stdlib/public/stubs/OptionalBridgingHelper.mm | 6 +- unittests/runtime/Mutex.cpp | 503 +----------------- 11 files changed, 28 insertions(+), 1072 deletions(-) diff --git a/include/swift/Runtime/Mutex.h b/include/swift/Runtime/Mutex.h index 4271644208271..1a539798a4010 100644 --- a/include/swift/Runtime/Mutex.h +++ b/include/swift/Runtime/Mutex.h @@ -1,4 +1,4 @@ -//===--- Mutex.h - Mutex and ReadWriteLock ----------------------*- C++ -*-===// +//===--- Mutex.h - Mutex ----------------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // @@ -10,14 +10,18 @@ // //===----------------------------------------------------------------------===// // -// Mutex, ReadWriteLock, and Scoped lock abstractions for use in -// Swift runtime. +// Mutex and Scoped lock abstractions for use in Swift runtime. // // We intentionally do not provide a condition-variable abstraction. // Traditional condition-variable interfaces are subject to unavoidable // priority inversions, as well as making poor use of threads. // Prefer AtomicWaitQueue. // +// We also intentionally avoid read/write locks. It's difficult to implement a +// performant and fair read/write lock, and indeed many common implementations +// rely on condition variables, which, again, are subject to unavoidable +// priority inversions. +// //===----------------------------------------------------------------------===// #ifndef SWIFT_RUNTIME_MUTEX_H @@ -167,238 +171,6 @@ class Mutex { MutexHandle Handle; }; -/// Compile time adjusted stack based object that locks/unlocks the supplied -/// ReadWriteLock type. Use the provided typedefs instead of this directly. -template class ScopedRWLockT { - - ScopedRWLockT() = delete; - ScopedRWLockT(const ScopedRWLockT &) = delete; - ScopedRWLockT &operator=(const ScopedRWLockT &) = delete; - ScopedRWLockT(ScopedRWLockT &&) = delete; - ScopedRWLockT &operator=(ScopedRWLockT &&) = delete; - -public: - explicit ScopedRWLockT(T &l) : Lock(l) { - if (Inverted) { - if (Read) { - Lock.readUnlock(); - } else { - Lock.writeUnlock(); - } - } else { - if (Read) { - Lock.readLock(); - } else { - Lock.writeLock(); - } - } - } - - ~ScopedRWLockT() { - if (Inverted) { - if (Read) { - Lock.readLock(); - } else { - Lock.writeLock(); - } - } else { - if (Read) { - Lock.readUnlock(); - } else { - Lock.writeUnlock(); - } - } - } - -private: - T &Lock; -}; - -class ReadWriteLock; -class StaticReadWriteLock; - -/// A stack based object that unlocks the supplied ReadWriteLock on -/// construction and locks it for reading on destruction. -/// -/// Precondition: ReadWriteLock unlocked by this thread, undefined otherwise. -typedef ScopedRWLockT ScopedReadLock; -typedef ScopedRWLockT StaticScopedReadLock; - -/// A stack based object that unlocks the supplied ReadWriteLock on -/// construction and locks it for reading on destruction. -/// -/// Precondition: ReadWriteLock unlocked by this thread, undefined -/// otherwise. -typedef ScopedRWLockT ScopedReadUnlock; -typedef ScopedRWLockT StaticScopedReadUnlock; - -/// A stack based object that unlocks the supplied ReadWriteLock on -/// construction and locks it for reading on destruction. -/// -/// Precondition: ReadWriteLock unlocked by this thread, undefined otherwise. -typedef ScopedRWLockT ScopedWriteLock; -typedef ScopedRWLockT StaticScopedWriteLock; - -/// A stack based object that unlocks the supplied ReadWriteLock on -/// construction and locks it for writing on destruction. -/// -/// Precondition: ReadWriteLock unlocked by this thread, undefined otherwise. -typedef ScopedRWLockT ScopedWriteUnlock; -typedef ScopedRWLockT StaticScopedWriteUnlock; - -/// A Read / Write lock object that has semantics similar to `BasicLockable` -/// and `Lockable` C++ concepts however it supports multiple concurrent -/// threads holding the reader lock as long as the write lock isn't held and -/// only one thread can hold the write local at the same time. -/// -/// If you need static allocated ReadWriteLock use StaticReadWriteLock. -/// -/// 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 ReadWriteLock { - - ReadWriteLock(const ReadWriteLock &) = delete; - ReadWriteLock &operator=(const ReadWriteLock &) = delete; - ReadWriteLock(ReadWriteLock &&) = delete; - ReadWriteLock &operator=(ReadWriteLock &&) = delete; - -public: - ReadWriteLock() { ReadWriteLockPlatformHelper::init(Handle); } - ~ReadWriteLock() { ReadWriteLockPlatformHelper::destroy(Handle); } - - /// The readLock() method has the following properties: - /// - Behaves as an atomic operation. - /// - Blocks the calling thread while the write lock is held by another - /// thread and once the read lock is acquired by the calling thread - /// other threads are prevented from acquiring the write lock. - /// - Multiple threads can hold the read lock at the same time. - /// - Prior unlock() operations on the same lock synchronize-with - /// this lock operation. - /// - The behavior is undefined if the calling thread already owns - /// the read or write lock (likely a deadlock). - /// - Does not throw exceptions but will halt on error (fatalError). - /// - /// Callers must not mutate the data protected by the ReadWriteLock while - /// holding the read lock, the write lock must be used. - void readLock() { ReadWriteLockPlatformHelper::readLock(Handle); } - - /// The try_readLock() method has the following properties: - /// - Behaves as an atomic operation. - /// - Attempts to obtain the read lock without blocking the calling thread. - /// If ownership is not obtained, returns immediately. The function is - /// allowed to spuriously fail and return even if the lock is not - /// currently owned by another thread. - /// - If try_readLock() succeeds, prior unlock() operations on the same - /// object synchronize-with this operation. unlock() does not synchronize - /// with a failed try_readLock(). - /// - The behavior is undefined if the calling thread already owns - /// the read or write lock (likely a deadlock)? - /// - Does not throw exceptions but will halt on error (fatalError). - /// - /// Callers must not mutate the data protected by the ReadWriteLock while - /// holding the read lock, the write lock must be used. - bool try_readLock() { - return ReadWriteLockPlatformHelper::try_readLock(Handle); - } - - /// The readUnlock() method has the following properties: - /// - Behaves as an atomic operation. - /// - Releases the calling thread's ownership of the read lock - /// and synchronizes-with the subsequent successful lock operations on - /// the same object. - /// - The behavior is undefined if the calling thread does not own - /// the read lock. - /// - Does not throw exceptions but will halt on error (fatalError). - void readUnlock() { ReadWriteLockPlatformHelper::readUnlock(Handle); } - - /// The writeLock() method has the following properties: - /// - Behaves as an atomic operation. - /// - Blocks the calling thread while the write lock or a read lock is held - /// by another thread and once the write lock is acquired by the calling - /// thread other threads are prevented from acquiring the write lock or a - /// read lock. - /// - Only one thread can hold the write lock at the same time. - /// - Prior unlock() operations on the same lock synchronize-with - /// this lock operation. - /// - The behavior is undefined if the calling thread already owns - /// the read or write lock (likely a deadlock). - /// - Does not throw exceptions but will halt on error (fatalError). - void writeLock() { ReadWriteLockPlatformHelper::writeLock(Handle); } - - /// The try_writeLock() method has the following properties: - /// - Behaves as an atomic operation. - /// - Attempts to obtain the write lock without blocking the calling thread. - /// If ownership is not obtained, returns immediately. The function is - /// allowed to spuriously fail and return even if the lock is not - /// currently owned by another thread. - /// - If try_writeLock() succeeds, prior unlock() operations on the same - /// object synchronize-with this operation. unlock() does not synchronize - /// with a failed try_writeLock(). - /// - The behavior is undefined if the calling thread already owns - /// the read or write lock (likely a deadlock)? - /// - Does not throw exceptions but will halt on error (fatalError). - bool try_writeLock() { - return ReadWriteLockPlatformHelper::try_writeLock(Handle); - } - - /// The writeUnlock() method has the following properties: - /// - Behaves as an atomic operation. - /// - Releases the calling thread's ownership of the write lock - /// and synchronizes-with the subsequent successful lock operations on - /// the same object. - /// - The behavior is undefined if the calling thread does not own - /// the write lock. - /// - Does not throw exceptions but will halt on error (fatalError). - void writeUnlock() { ReadWriteLockPlatformHelper::writeUnlock(Handle); } - - /// Acquires read lock before calling the supplied critical section and - /// releases lock on return from critical section. Callers must not mutate - /// the data protected by the ReadWriteLock while holding the read lock, the - /// write lock must be used. - /// - /// This call can block while waiting for the lock to become available. - /// - /// For example the following reads the cached value while holding - /// the read lock. - /// - /// ``` - /// rw.withReadLock([&value] { value = cachedValue; }); - /// ``` - /// - /// Precondition: ReadWriteLock not held by this thread, undefined otherwise. - template - auto withReadLock(CriticalSection &&criticalSection) - -> decltype(std::forward(criticalSection)()) { - ScopedReadLock guard(*this); - return std::forward(criticalSection)(); - } - - /// Acquires write 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 updates the cached value while holding - /// the write lock. - /// - /// ``` - /// rw.withWriteLock([&newValue] { cachedValue = newValue }); - /// ``` - /// - /// Precondition: ReadWriteLock not held by this thread, undefined otherwise. - template - auto withWriteLock(CriticalSection &&criticalSection) - -> decltype(std::forward(criticalSection)()) { - ScopedWriteLock guard(*this); - return std::forward(criticalSection)(); - } - -private: - ReadWriteLockHandle Handle; -}; - /// A static allocation variant of Mutex. /// /// Use Mutex instead unless you need static allocation. @@ -450,66 +222,6 @@ class StaticMutex { MutexHandle Handle; }; -/// A static allocation variant of ReadWriteLock. -/// -/// Use ReadWriteLock instead unless you need static allocation. -class StaticReadWriteLock { - - StaticReadWriteLock(const StaticReadWriteLock &) = delete; - StaticReadWriteLock &operator=(const StaticReadWriteLock &) = delete; - StaticReadWriteLock(StaticReadWriteLock &&) = delete; - StaticReadWriteLock &operator=(StaticReadWriteLock &&) = delete; - -public: -#if SWIFT_READWRITELOCK_SUPPORTS_CONSTEXPR - constexpr -#endif - StaticReadWriteLock() - : Handle(ReadWriteLockPlatformHelper::staticInit()) { - } - - /// See ReadWriteLock::readLock - void readLock() { ReadWriteLockPlatformHelper::readLock(Handle); } - - /// See ReadWriteLock::try_readLock - bool try_readLock() { - return ReadWriteLockPlatformHelper::try_readLock(Handle); - } - - /// See ReadWriteLock::readUnlock - void readUnlock() { ReadWriteLockPlatformHelper::readUnlock(Handle); } - - /// See ReadWriteLock::writeLock - void writeLock() { ReadWriteLockPlatformHelper::writeLock(Handle); } - - /// See ReadWriteLock::try_writeLock - bool try_writeLock() { - return ReadWriteLockPlatformHelper::try_writeLock(Handle); - } - - /// See ReadWriteLock::writeUnlock - void writeUnlock() { ReadWriteLockPlatformHelper::writeUnlock(Handle); } - - /// See ReadWriteLock::withReadLock - template - auto withReadLock(CriticalSection &&criticalSection) - -> decltype(std::forward(criticalSection)()) { - StaticScopedReadLock guard(*this); - return std::forward(criticalSection)(); - } - - /// See ReadWriteLock::withWriteLock - template - auto withWriteLock(CriticalSection &&criticalSection) - -> decltype(std::forward(criticalSection)()) { - StaticScopedWriteLock guard(*this); - return std::forward(criticalSection)(); - } - -private: - ReadWriteLockHandle Handle; -}; - /// A Mutex object that supports `BasicLockable` C++ concepts. It is /// considered /// unsafe to use because it doesn't do any error checking. It is only for @@ -634,13 +346,6 @@ static_assert(std::is_literal_type::value, // you will possibly see global-constructors warnings #endif -#if SWIFT_READWRITELOCK_SUPPORTS_CONSTEXPR -static_assert(std::is_literal_type::value, - "StaticReadWriteLock must be literal type"); -#else -// Your platform doesn't currently support statically allocated ReadWriteLocks -// you will possibly see global-constructors warnings -#endif } #endif diff --git a/include/swift/Runtime/MutexC11.h b/include/swift/Runtime/MutexC11.h index 48e2595aaab38..b0c4003f48efd 100644 --- a/include/swift/Runtime/MutexC11.h +++ b/include/swift/Runtime/MutexC11.h @@ -34,11 +34,9 @@ namespace c11threads { } } -typedef c11threads::rwlock *ReadWriteLockHandle; typedef ::mtx_t MutexHandle; #define SWIFT_MUTEX_SUPPORTS_CONSTEXPR 0 -#define SWIFT_READWRITELOCK_SUPPORTS_CONSTEXPR 0 /// C11 low-level implementation that supports Mutex /// found in Mutex.h @@ -86,77 +84,6 @@ class MutexPlatformHelper { } }; -/// C11 low-level implementation that supports ReadWriteLock -/// found in Mutex.h -/// -/// See ReadWriteLock -namespace c11threads { - -class rwlock { -private: - unsigned activeReaders_; - unsigned waitingWriters_; - bool writerActive_; - ::cnd_t cond_; - ::mtx_t mutex_; - -public: - rwlock(); - ~rwlock(); - - rwlock(const rwlock &other) = delete; - rwlock &operator=(const rwlock &other) = delete; - - void readLock(); - bool try_readLock(); - void readUnlock(); - void writeLock(); - bool try_writeLock(); - void writeUnlock(); -}; - -} - -class ReadWriteLockPlatformHelper { -public: - static ReadWriteLockHandle staticInit() { - return new c11threads::rwlock(); - }; - - static void init(ReadWriteLockHandle &rwlock) { - rwlock = new c11threads::rwlock(); - } - - static void destroy(ReadWriteLockHandle &rwlock) { - delete rwlock; - } - - static void readLock(ReadWriteLockHandle &rwlock) { - rwlock->readLock(); - } - - static bool try_readLock(ReadWriteLockHandle &rwlock) { - rwlock->try_readLock(); - } - - static void readUnlock(ReadWriteLockHandle &rwlock) { - rwlock->readUnlock(); - } - - static void writeLock(ReadWriteLockHandle &rwlock) { - rwlock->writeLock(); - } - - static bool try_writeLock(ReadWriteLockHandle &rwlock) { - rwlock->try_writeLock(); - } - - static void writeUnlock(ReadWriteLockHandle &rwlock) { - rwlock->writeUnlock(); - } -}; - - } #endif diff --git a/include/swift/Runtime/MutexPThread.h b/include/swift/Runtime/MutexPThread.h index 5d467d05a20d3..bcf409ddd0eb1 100644 --- a/include/swift/Runtime/MutexPThread.h +++ b/include/swift/Runtime/MutexPThread.h @@ -27,8 +27,6 @@ namespace swift { -typedef pthread_rwlock_t ReadWriteLockHandle; - #if HAS_OS_UNFAIR_LOCK typedef os_unfair_lock MutexHandle; #else @@ -41,10 +39,8 @@ typedef pthread_mutex_t MutexHandle; // results in a reinterpret_cast which violates constexpr. // WASI currently doesn't support threading/locking at all. #define SWIFT_MUTEX_SUPPORTS_CONSTEXPR 0 -#define SWIFT_READWRITELOCK_SUPPORTS_CONSTEXPR 0 #else #define SWIFT_MUTEX_SUPPORTS_CONSTEXPR 1 -#define SWIFT_READWRITELOCK_SUPPORTS_CONSTEXPR 1 #endif /// PThread low-level implementation that supports Mutex @@ -114,30 +110,6 @@ inline bool MutexPlatformHelper::try_lock(os_unfair_lock &lock) { #endif -/// PThread low-level implementation that supports ReadWriteLock -/// found in Mutex.h -/// -/// See ReadWriteLock -struct ReadWriteLockPlatformHelper { -#if SWIFT_READWRITELOCK_SUPPORTS_CONSTEXPR - static constexpr -#else - static -#endif - ReadWriteLockHandle - staticInit() { - return PTHREAD_RWLOCK_INITIALIZER; - }; - - static void init(ReadWriteLockHandle &rwlock); - static void destroy(ReadWriteLockHandle &rwlock); - static void readLock(ReadWriteLockHandle &rwlock); - static bool try_readLock(ReadWriteLockHandle &rwlock); - static void readUnlock(ReadWriteLockHandle &rwlock); - static void writeLock(ReadWriteLockHandle &rwlock); - static bool try_writeLock(ReadWriteLockHandle &rwlock); - static void writeUnlock(ReadWriteLockHandle &rwlock); -}; } #endif diff --git a/include/swift/Runtime/MutexSingleThreaded.h b/include/swift/Runtime/MutexSingleThreaded.h index 3eee91f414ce9..35e18f45d3bde 100644 --- a/include/swift/Runtime/MutexSingleThreaded.h +++ b/include/swift/Runtime/MutexSingleThreaded.h @@ -22,10 +22,8 @@ namespace swift { typedef void* MutexHandle; -typedef void* ReadWriteLockHandle; #define SWIFT_MUTEX_SUPPORTS_CONSTEXPR 1 -#define SWIFT_READWRITELOCK_SUPPORTS_CONSTEXPR 1 struct MutexPlatformHelper { static constexpr MutexHandle staticInit() { return nullptr; } @@ -38,17 +36,6 @@ struct MutexPlatformHelper { static void unsafeUnlock(MutexHandle &mutex) {} }; -struct ReadWriteLockPlatformHelper { - static constexpr ReadWriteLockHandle staticInit() { return nullptr; } - static void init(ReadWriteLockHandle &rwlock) {} - static void destroy(ReadWriteLockHandle &rwlock) {} - static void readLock(ReadWriteLockHandle &rwlock) {} - static bool try_readLock(ReadWriteLockHandle &rwlock) { return true; } - static void readUnlock(ReadWriteLockHandle &rwlock) {} - static void writeLock(ReadWriteLockHandle &rwlock) {} - static bool try_writeLock(ReadWriteLockHandle &rwlock) { return true; } - static void writeUnlock(ReadWriteLockHandle &rwlock) {} -}; } #endif diff --git a/include/swift/Runtime/MutexWin32.h b/include/swift/Runtime/MutexWin32.h index 4e1f0b680d832..6ed68bf03c507 100644 --- a/include/swift/Runtime/MutexWin32.h +++ b/include/swift/Runtime/MutexWin32.h @@ -25,10 +25,8 @@ namespace swift { typedef SRWLOCK MutexHandle; -typedef SRWLOCK ReadWriteLockHandle; #define SWIFT_MUTEX_SUPPORTS_CONSTEXPR 1 -#define SWIFT_READWRITELOCK_SUPPORTS_CONSTEXPR 1 struct MutexPlatformHelper { static constexpr MutexHandle staticInit() { return SRWLOCK_INIT; } @@ -50,29 +48,4 @@ struct MutexPlatformHelper { } }; -struct ReadWriteLockPlatformHelper { - static constexpr ReadWriteLockHandle staticInit() { return SRWLOCK_INIT; } - static void init(ReadWriteLockHandle &rwlock) { InitializeSRWLock(&rwlock); } - static void destroy(ReadWriteLockHandle &rwlock) {} - static void readLock(ReadWriteLockHandle &rwlock) { - AcquireSRWLockShared(&rwlock); - } - static bool try_readLock(ReadWriteLockHandle &rwlock) { - return TryAcquireSRWLockShared(&rwlock) != 0; - } - static void readUnlock(ReadWriteLockHandle &rwlock) { - ReleaseSRWLockShared(&rwlock); - } - static void writeLock(ReadWriteLockHandle &rwlock) { - AcquireSRWLockExclusive(&rwlock); - } - static bool try_writeLock(ReadWriteLockHandle &rwlock) { - return TryAcquireSRWLockExclusive(&rwlock) != 0; - } - static void writeUnlock(ReadWriteLockHandle &rwlock) { - ReleaseSRWLockExclusive(&rwlock); - } -}; -} - #endif diff --git a/stdlib/public/runtime/Casting.cpp b/stdlib/public/runtime/Casting.cpp index 864f662655086..cf3c4ff82a1c7 100644 --- a/stdlib/public/runtime/Casting.cpp +++ b/stdlib/public/runtime/Casting.cpp @@ -145,8 +145,8 @@ enum class TypeNameKind { using TypeNameCacheKey = llvm::PointerIntPair; #if SWIFT_CASTING_SUPPORTS_MUTEX -static StaticReadWriteLock TypeNameCacheLock; -static StaticReadWriteLock MangledToPrettyFunctionNameCacheLock; +static StaticMutex TypeNameCacheLock; +static StaticMutex MangledToPrettyFunctionNameCacheLock; #endif /// Cache containing rendered names for Metadata. @@ -167,7 +167,7 @@ swift::swift_getTypeName(const Metadata *type, bool qualified) { // Attempt read-only lookup of cache entry. { #if SWIFT_CASTING_SUPPORTS_MUTEX - StaticScopedReadLock guard(TypeNameCacheLock); + StaticMutex::ScopedLock guard(TypeNameCacheLock); #endif auto found = cache.find(key); @@ -180,7 +180,7 @@ swift::swift_getTypeName(const Metadata *type, bool qualified) { // Read-only lookup failed to find item, we may need to create it. { #if SWIFT_CASTING_SUPPORTS_MUTEX - StaticScopedWriteLock guard(TypeNameCacheLock); + StaticMutex::ScopedLock guard(TypeNameCacheLock); #endif // Do lookup again just to make sure it wasn't created by another @@ -213,7 +213,7 @@ swift::swift_getMangledTypeName(const Metadata *type) { // Attempt read-only lookup of cache entry. { #if SWIFT_CASTING_SUPPORTS_MUTEX - StaticScopedReadLock guard(TypeNameCacheLock); + StaticMutex::ScopedLock guard(TypeNameCacheLock); #endif auto found = cache.find(key); @@ -226,7 +226,7 @@ swift::swift_getMangledTypeName(const Metadata *type) { // Read-only cache lookup failed, we may need to create it. { #if SWIFT_CASTING_SUPPORTS_MUTEX - StaticScopedWriteLock guard(TypeNameCacheLock); + StaticMutex::ScopedLock guard(TypeNameCacheLock); #endif // Do lookup again just to make sure it wasn't created by another @@ -271,7 +271,7 @@ swift::swift_getFunctionFullNameFromMangledName( // Attempt read-only lookup of cache entry. { #if SWIFT_CASTING_SUPPORTS_MUTEX - StaticScopedReadLock guard(MangledToPrettyFunctionNameCacheLock); + StaticMutex::ScopedLock guard(MangledToPrettyFunctionNameCacheLock); #endif auto found = cache.find(mangledName); @@ -388,7 +388,7 @@ swift::swift_getFunctionFullNameFromMangledName( { #if SWIFT_CASTING_SUPPORTS_MUTEX - StaticScopedWriteLock guard(MangledToPrettyFunctionNameCacheLock); + StaticMutex::ScopedLock guard(MangledToPrettyFunctionNameCacheLock); #endif cache.insert({mangledName, {result, size}}); diff --git a/stdlib/public/runtime/MutexC11.cpp b/stdlib/public/runtime/MutexC11.cpp index 7e2892134b2de..1c31e2de6c39d 100644 --- a/stdlib/public/runtime/MutexC11.cpp +++ b/stdlib/public/runtime/MutexC11.cpp @@ -21,24 +21,6 @@ using namespace swift; -namespace { - -// A simple scoped locker class for a C11 mutex -class locker { -private: - mtx_t &mutex_; - -public: - explicit locker(mtx_t &mutex) : mutex_(mutex) { - c11threads::handleError(mtx_lock(&mutex_)); - } - ~locker() { - c11threads::handleError(mtx_unlock(&mutex_)); - } -}; - -} - namespace c11threads { #ifndef SWIFT_FATAL_ERROR @@ -50,61 +32,6 @@ void fatalError(int errcode) { SWIFT_FATAL_ERROR(0, "C11 threads call failed with %d\n", errcode); } -// A simple reader/writer lock implementation, with writer priority -rwlock::rwlock() : activeReaders_(0), waitingWriters_(0), writerActive_(false) { - handleError(::cnd_init(&cond_)); - handleError(::mtx_init(&mutex_, ::mtx_plain)); -} - -rwlock::~rwlock() { - ::cnd_destroy(&cond_); - ::mtx_destroy(&mutex_); -} - -void rwlock::readLock() { - locker l(mutex_); - while (waitingWriters_ || writerActive_) - handleError(::cnd_wait(&cond_, &mutex_)); - ++activeReaders_; -} - -bool rwlock::try_readLock() { - locker l(mutex_); - if (waitingWriters_ || writerActive_) - return false; - ++activeReaders_; - return true; -} - -void rwlock::readUnlock() { - locker l(mutex_); - if (!--activeReaders_) - handleError(::cnd_broadcast(&cond_)); -} - -void rwlock::writeLock() { - locker l(mutex_); - ++waitingWriters_; - while (activeReaders_ || writerActive_) - handleError(::cnd_wait(&cond_, mutex_)); - --waitingWriters_; - writerActive_ = true; -} - -bool rwlock::try_writeLock() { - locker l(mutex_); - if (activeReaders_ || writerActive_) - return false; - writerActive_ = true; - return true; -} - -void rwlock::writeUnlock() { - locker l(mutex_); - writerActive_ = false; - handleError(::cnd_broadcast(&cond_)); -} - } #endif // SWIFT_STDLIB_THREADING_C11 diff --git a/stdlib/public/runtime/MutexPThread.cpp b/stdlib/public/runtime/MutexPThread.cpp index 99250d0ee4702..54626f9489393 100644 --- a/stdlib/public/runtime/MutexPThread.cpp +++ b/stdlib/public/runtime/MutexPThread.cpp @@ -106,38 +106,4 @@ bool MutexPlatformHelper::try_lock(pthread_mutex_t &mutex) { #endif -void ReadWriteLockPlatformHelper::init(pthread_rwlock_t &rwlock) { - reportError(pthread_rwlock_init(&rwlock, nullptr)); -} - -void ReadWriteLockPlatformHelper::destroy(pthread_rwlock_t &rwlock) { - reportError(pthread_rwlock_destroy(&rwlock)); -} - -void ReadWriteLockPlatformHelper::readLock(pthread_rwlock_t &rwlock) { - reportError(pthread_rwlock_rdlock(&rwlock)); -} - -bool ReadWriteLockPlatformHelper::try_readLock(pthread_rwlock_t &rwlock) { - returnTrueOrReportError(pthread_rwlock_tryrdlock(&rwlock), - /* returnFalseOnEBUSY = */ true); -} - -void ReadWriteLockPlatformHelper::writeLock(pthread_rwlock_t &rwlock) { - reportError(pthread_rwlock_wrlock(&rwlock)); -} - -bool ReadWriteLockPlatformHelper::try_writeLock(pthread_rwlock_t &rwlock) { - returnTrueOrReportError(pthread_rwlock_trywrlock(&rwlock), - /* returnFalseOnEBUSY = */ true); -} - -void ReadWriteLockPlatformHelper::readUnlock(pthread_rwlock_t &rwlock) { - reportError(pthread_rwlock_unlock(&rwlock)); -} - -void ReadWriteLockPlatformHelper::writeUnlock(pthread_rwlock_t &rwlock) { - reportError(pthread_rwlock_unlock(&rwlock)); -} - #endif // SWIFT_STDLIB_THREADING_PTHREADS diff --git a/stdlib/public/runtime/RuntimeInvocationsTracking.cpp b/stdlib/public/runtime/RuntimeInvocationsTracking.cpp index 8971902e6146d..e678faa7962a7 100644 --- a/stdlib/public/runtime/RuntimeInvocationsTracking.cpp +++ b/stdlib/public/runtime/RuntimeInvocationsTracking.cpp @@ -49,7 +49,7 @@ static bool UpdateGlobalRuntimeFunctionCounters = false; /// Global set of counters tracking the total number of runtime invocations. struct RuntimeFunctionCountersStateSentinel { RuntimeFunctionCountersState State; - StaticReadWriteLock Lock; + StaticMutex Lock; }; static RuntimeFunctionCountersStateSentinel RuntimeGlobalFunctionCountersState; @@ -57,7 +57,7 @@ static RuntimeFunctionCountersStateSentinel RuntimeGlobalFunctionCountersState; /// them. struct RuntimeObjectCacheSentinel { llvm::DenseMap Cache; - StaticReadWriteLock Lock; + StaticMutex Lock; }; static Lazy RuntimeObjectStateCache; @@ -101,7 +101,7 @@ static uint16_t RuntimeFunctionCountersOffsets[] = { void SWIFT_RT_TRACK_INVOCATION_NAME(RT_FUNCTION)(HeapObject * object) { \ /* Update global counters. */ \ if (UpdateGlobalRuntimeFunctionCounters) { \ - StaticScopedWriteLock lock(RuntimeGlobalFunctionCountersState.Lock); \ + StaticMutex::ScopedLock lock(RuntimeGlobalFunctionCountersState.Lock); \ RuntimeGlobalFunctionCountersState.State \ .SWIFT_RT_FUNCTION_INVOCATION_COUNTER_NAME(RT_FUNCTION)++; \ if (GlobalRuntimeFunctionCountersUpdateHandler) { \ @@ -117,7 +117,7 @@ static uint16_t RuntimeFunctionCountersOffsets[] = { /* Update per object counters. */ \ if (UpdatePerObjectRuntimeFunctionCounters && object) { \ auto &theSentinel = RuntimeObjectStateCache.get(); \ - StaticScopedWriteLock lock(theSentinel.Lock); \ + StaticMutex::ScopedLock lock(theSentinel.Lock); \ theSentinel.Cache[object].SWIFT_RT_FUNCTION_INVOCATION_COUNTER_NAME( \ RT_FUNCTION)++; \ /* TODO: Remember the order/history of operations? */ \ @@ -131,7 +131,7 @@ static uint16_t RuntimeFunctionCountersOffsets[] = { void _swift_getObjectRuntimeFunctionCounters( HeapObject *object, RuntimeFunctionCountersState *result) { auto &theSentinel = RuntimeObjectStateCache.get(); - StaticScopedReadLock lock(theSentinel.Lock); + StaticMutex::ScopedLock lock(theSentinel.Lock); *result = theSentinel.Cache[object]; } @@ -140,7 +140,7 @@ void _swift_getObjectRuntimeFunctionCounters( void _swift_setObjectRuntimeFunctionCounters( HeapObject *object, RuntimeFunctionCountersState *state) { auto &theSentinel = RuntimeObjectStateCache.get(); - StaticScopedWriteLock lock(theSentinel.Lock); + StaticMutex::ScopedLock lock(theSentinel.Lock); theSentinel.Cache[object] = *state; } @@ -148,14 +148,14 @@ void _swift_setObjectRuntimeFunctionCounters( /// each runtime function of interest. void _swift_getGlobalRuntimeFunctionCounters( RuntimeFunctionCountersState *result) { - StaticScopedReadLock lock(RuntimeGlobalFunctionCountersState.Lock); + StaticMutex::ScopedLock lock(RuntimeGlobalFunctionCountersState.Lock); *result = RuntimeGlobalFunctionCountersState.State; } /// Set the global runtime state of function pointers from a provided state. void _swift_setGlobalRuntimeFunctionCounters( RuntimeFunctionCountersState *state) { - StaticScopedWriteLock lock(RuntimeGlobalFunctionCountersState.Lock); + StaticMutex::ScopedLock lock(RuntimeGlobalFunctionCountersState.Lock); RuntimeGlobalFunctionCountersState.State = *state; } @@ -192,7 +192,7 @@ static void _swift_dumpRuntimeCounters(RuntimeFunctionCountersState *State) { /// Dump all per-object runtime function pointers. void _swift_dumpObjectsRuntimeFunctionPointers() { auto &theSentinel = RuntimeObjectStateCache.get(); - StaticScopedReadLock lock(theSentinel.Lock); + StaticMutex::ScopedLock lock(theSentinel.Lock); for (auto &Pair : theSentinel.Cache) { printf("\n\nRuntime counters for object at address %p:\n", Pair.getFirst()); _swift_dumpRuntimeCounters(&Pair.getSecond()); diff --git a/stdlib/public/stubs/OptionalBridgingHelper.mm b/stdlib/public/stubs/OptionalBridgingHelper.mm index 4d44fad1e8cf7..76361258f5f2e 100644 --- a/stdlib/public/stubs/OptionalBridgingHelper.mm +++ b/stdlib/public/stubs/OptionalBridgingHelper.mm @@ -59,7 +59,7 @@ - (id)description { struct SwiftNullSentinelCache { std::vector Cache; - StaticReadWriteLock Lock; + StaticMutex Lock; }; static Lazy Sentinels; @@ -73,7 +73,7 @@ static id getSentinelForDepth(unsigned depth) { auto &theSentinels = Sentinels.get(); unsigned depthIndex = depth - 2; { - StaticScopedReadLock lock(theSentinels.Lock); + StaticMutex::ScopedLock lock(theSentinels.Lock); const auto &cache = theSentinels.Cache; if (depthIndex < cache.size()) { id cached = cache[depthIndex]; @@ -83,7 +83,7 @@ static id getSentinelForDepth(unsigned depth) { } // Make one if we need to. { - StaticScopedWriteLock lock(theSentinels.Lock); + StaticMutex::ScopedLock lock(theSentinels.Lock); if (depthIndex >= theSentinels.Cache.size()) theSentinels.Cache.resize(depthIndex + 1); auto &cached = theSentinels.Cache[depthIndex]; diff --git a/unittests/runtime/Mutex.cpp b/unittests/runtime/Mutex.cpp index f3344184be0a8..b09e45888a999 100644 --- a/unittests/runtime/Mutex.cpp +++ b/unittests/runtime/Mutex.cpp @@ -1,4 +1,4 @@ -//===--- Mutex.cpp - Mutex and ReadWriteLock Tests ------------------------===// +//===--- Mutex.cpp - Mutex Tests ------------------------------------------===// // // This source file is part of the Swift.org open source project // @@ -254,504 +254,3 @@ void scopedReadThreaded(RW &lock) { } } } - -TEST(ReadWriteLockTest, ScopedReadLockThreaded) { - ReadWriteLock lock; - scopedReadThreaded(lock); -} - -TEST(StaticReadWriteLockTest, ScopedReadLockThreaded) { - static StaticReadWriteLock lock; - scopedReadThreaded(lock); -} - -TEST(ReadWriteLockTest, ScopedReadUnlockThreaded) { - ReadWriteLock lock; - scopedReadThreaded(lock); -} - -TEST(StaticReadWriteLockTest, ScopedReadUnlockThreaded) { - static StaticReadWriteLock lock; - scopedReadThreaded(lock); -} - -template -void scopedWriteLockThreaded(RW &lock) { - const int threadCount = 10; - - std::set readerHistory; - std::vector> writerHistory; - writerHistory.assign(threadCount, std::set()); - - int protectedValue = 0; - readerHistory.insert(protectedValue); - - threadedExecute(threadCount, - [&](int index) { - if (Locking) { - for (int i = 0; i < 20; ++i) { - { - SWL guard(lock); - protectedValue += index * i; - writerHistory[index].insert(protectedValue); - } - std::this_thread::yield(); - } - } else { - lock.writeLock(); - for (int i = 0; i < 20; ++i) { - protectedValue += index * i; - writerHistory[index].insert(protectedValue); - { - SWL unguard(lock); - std::this_thread::yield(); - } - } - lock.writeUnlock(); - } - }, - [&] { - for (int i = 0; i < 100; ++i) { - lock.readLock(); - readerHistory.insert(protectedValue); - lock.readUnlock(); - } - }); - - std::set mergedHistory; - for (auto &history : writerHistory) { - mergedHistory.insert(history.begin(), history.end()); - } - - for (auto value : readerHistory) { - ASSERT_EQ(mergedHistory.count(value), 1U); - } -} - -TEST(ReadWriteLockTest, ScopedWriteLockThreaded) { - ReadWriteLock lock; - scopedWriteLockThreaded(lock); -} - -TEST(StaticReadWriteLockTest, ScopedWriteLockThreaded) { - static StaticReadWriteLock lock; - scopedWriteLockThreaded(lock); -} - -TEST(ReadWriteLockTest, ScopedWriteUnlockThreaded) { - ReadWriteLock lock; - scopedWriteLockThreaded(lock); -} - -TEST(StaticReadWriteLockTest, ScopedWriteUnlockThreaded) { - static StaticReadWriteLock lock; - scopedWriteLockThreaded(lock); -} - -template void readLockWhileReadLockedThreaded(RW &lock) { - lock.readLock(); - - const int threadCount = 10; - - std::atomic results[threadCount] = {}; - - std::atomic done(false); - threadedExecute(threadCount, - [&](int index) { - // Always perform at least one iteration of this loop to - // avoid spurious failures if this thread is slow to run. - do { - lock.withReadLock([&] { - results[index] = true; - std::this_thread::sleep_for( - std::chrono::milliseconds(5)); - }); - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } while (!done); - }, - [&] { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - done = true; - }); - - lock.readUnlock(); - - for (auto &result : results) { - ASSERT_TRUE(result); - } -} - -TEST(ReadWriteLockTest, ReadLockWhileReadLockedThreaded) { - ReadWriteLock lock; - readLockWhileReadLockedThreaded(lock); -} - -TEST(StaticReadWriteLockTest, ReadLockWhileReadLockedThreaded) { - static StaticReadWriteLock lock; - readLockWhileReadLockedThreaded(lock); -} - -template void readLockWhileWriteLockedThreaded(RW &lock) { - lock.writeLock(); - - const int threadCount = 10; - - std::atomic results[threadCount] = {}; - - std::atomic done(false); - threadedExecute(threadCount, - [&](int index) { - // Always perform at least one iteration of this loop to - // avoid spurious failures if this thread is slow to run. - do { - lock.withReadLock([&] { - results[index] += 1; - std::this_thread::sleep_for( - std::chrono::milliseconds(5)); - }); - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } while (!done); - }, - [&] { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - done = true; - lock.writeUnlock(); - }); - - for (auto &result : results) { - ASSERT_EQ(result, 1); - } -} - -TEST(ReadWriteLockTest, ReadLockWhileWriteLockedThreaded) { - ReadWriteLock lock; - readLockWhileWriteLockedThreaded(lock); -} - -TEST(StaticReadWriteLockTest, ReadLockWhileWriteLockedThreaded) { - static StaticReadWriteLock lock; - readLockWhileWriteLockedThreaded(lock); -} - -template void writeLockWhileReadLockedThreaded(RW &lock) { - lock.readLock(); - - const int threadCount = 10; - - std::atomic results[threadCount] = {}; - - std::atomic done(false); - threadedExecute(threadCount, - [&](int index) { - // Always perform at least one iteration of this loop to - // avoid spurious failures if this thread is slow to run. - do { - lock.withWriteLock([&] { - results[index] += 1; - std::this_thread::sleep_for( - std::chrono::milliseconds(5)); - }); - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } while (!done); - }, - [&] { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - done = true; - lock.readUnlock(); - }); - - for (auto &result : results) { - ASSERT_EQ(result, 1); - } -} - -TEST(ReadWriteLockTest, WriteLockWhileReadLockedThreaded) { - ReadWriteLock lock; - writeLockWhileReadLockedThreaded(lock); -} - -TEST(StaticReadWriteLockTest, WriteLockWhileReadLockedThreaded) { - static StaticReadWriteLock lock; - writeLockWhileReadLockedThreaded(lock); -} - -template void writeLockWhileWriteLockedThreaded(RW &lock) { - lock.writeLock(); - - const int threadCount = 10; - - std::atomic results[threadCount] = {}; - - std::atomic done(false); - threadedExecute(threadCount, - [&](int index) { - // Always perform at least one iteration of this loop to - // avoid spurious failures if this thread is slow to run. - do { - lock.withWriteLock([&] { - results[index] += 1; - std::this_thread::sleep_for( - std::chrono::milliseconds(5)); - }); - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } while (!done); - }, - [&] { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - done = true; - lock.writeUnlock(); - }); - - for (auto &result : results) { - ASSERT_EQ(result, 1); - } -} - -TEST(ReadWriteLockTest, WriteLockWhileWriteLockedThreaded) { - ReadWriteLock lock; - writeLockWhileWriteLockedThreaded(lock); -} - -TEST(StaticReadWriteLockTest, WriteLockWhileWriteLockedThreaded) { - static StaticReadWriteLock lock; - writeLockWhileWriteLockedThreaded(lock); -} - -template void tryReadLockWhileWriteLockedThreaded(RW &lock) { - lock.writeLock(); - - std::atomic done(false); - threadedExecute(10, - [&](int) { - // Always perform at least one iteration of this loop to - // avoid spurious failures if this thread is slow to run. - do { - ASSERT_FALSE(lock.try_readLock()); - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } while (!done); - }, - [&] { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - done = true; - }); - - lock.writeUnlock(); -} - -TEST(ReadWriteLockTest, TryReadLockWhileWriteLockedThreaded) { - ReadWriteLock lock; - tryReadLockWhileWriteLockedThreaded(lock); -} - -TEST(StaticReadWriteLockTest, TryReadLockWhileWriteLockedThreaded) { - static StaticReadWriteLock lock; - tryReadLockWhileWriteLockedThreaded(lock); -} - -template void tryReadLockWhileReadLockedThreaded(RW &lock) { - lock.readLock(); - - const int threadCount = 10; - - std::atomic results[threadCount] = {}; - - std::atomic done(false); - threadedExecute(threadCount, - [&](int index) { - // Always perform at least one iteration of this loop to - // avoid spurious failures if this thread is slow to run. - do { - ASSERT_TRUE(lock.try_readLock()); - results[index] = true; - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - lock.readUnlock(); - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } while (!done); - }, - [&] { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - done = true; - }); - - lock.readUnlock(); - - for (auto &result : results) { - ASSERT_TRUE(result); - } -} - -TEST(ReadWriteLockTest, TryReadLockWhileReadLockedThreaded) { - ReadWriteLock lock; - tryReadLockWhileReadLockedThreaded(lock); -} - -TEST(StaticReadWriteLockTest, TryReadLockWhileReadLockedThreaded) { - static StaticReadWriteLock lock; - tryReadLockWhileReadLockedThreaded(lock); -} - -template void tryWriteLockWhileWriteLockedThreaded(RW &lock) { - lock.writeLock(); - - std::atomic done(false); - threadedExecute(10, - [&](int) { - // Always perform at least one iteration of this loop to - // avoid spurious failures if this thread is slow to run. - do { - ASSERT_FALSE(lock.try_writeLock()); - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } while (!done); - }, - [&] { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - done = true; - }); - - lock.writeUnlock(); -} - -TEST(ReadWriteLockTest, TryWriteLockWhileWriteLockedThreaded) { - ReadWriteLock lock; - tryWriteLockWhileWriteLockedThreaded(lock); -} - -TEST(StaticReadWriteLockTest, TryWriteLockWhileWriteLockedThreaded) { - static StaticReadWriteLock lock; - tryWriteLockWhileWriteLockedThreaded(lock); -} - -template void tryWriteLockWhileReadLockedThreaded(RW &lock) { - lock.readLock(); - - std::atomic done(false); - threadedExecute(10, - [&](int) { - // Always perform at least one iteration of this loop to - // avoid spurious failures if this thread is slow to run. - do { - ASSERT_FALSE(lock.try_writeLock()); - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } while (!done); - }, - [&] { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - done = true; - }); - - lock.readUnlock(); -} - -TEST(ReadWriteLockTest, TryWriteLockWhileReadLockedThreaded) { - ReadWriteLock lock; - tryWriteLockWhileReadLockedThreaded(lock); -} - -TEST(StaticReadWriteLockTest, TryWriteLockWhileReadLockedThreaded) { - static StaticReadWriteLock lock; - tryWriteLockWhileReadLockedThreaded(lock); -} - -template void readWriteLockCacheExampleThreaded(RW &lock) { - std::map cache; - std::vector workers; - std::vector> workerHistory; - - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_int_distribution<> dis(0, UINT8_MAX); - - workerHistory.push_back(std::set()); - for (int i = 0; i < 16; i++) { - uint8_t key = dis(gen); - cache[key] = 0; - workerHistory[0].insert(key); - - if (trace) - printf("WarmUp create for key = %d, value = %d.\n", key, 0); - } - - // Block the threads we are about to create. - const int threadCount = 20; - std::atomic spinWait(true); - std::atomic readyCount(0); - - for (int i = 1; i <= threadCount; ++i) { - workerHistory.push_back(std::set()); - workers.push_back(std::thread([&, i] { - readyCount++; - - // Block ourself until we are released to start working. - while (spinWait) { - std::this_thread::sleep_for(std::chrono::microseconds(10)); - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - - for (int j = 0; j < 50; j++) { - uint8_t key = dis(gen); - bool found = false; - - auto cacheLookupSection = [&] { - auto value = cache.find(key); - if (value == cache.end()) { - if (trace) - printf("Worker[%d] miss for key = %d.\n", i, key); - found = false; // cache miss, need to grab write lock - } - if (trace) - printf("Worker[%d] HIT for key = %d, value = %d.\n", i, key, - value->second); - found = true; // cache hit, no need to grab write lock - }; - - lock.withReadLock(cacheLookupSection); - if (found) { - continue; - } - - lock.withWriteLock([&] { - cacheLookupSection(); - if (!found) { - if (trace) - printf("Worker[%d] create for key = %d, value = %d.\n", i, key, - i); - cache[key] = i; - workerHistory[i].insert(key); - } - }); - } - - if (trace) - printf("### Worker[%d] thread exiting.\n", i); - })); - } - - while (readyCount < threadCount) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - - // Allow our threads to fight for the lock. - spinWait = false; - - // Wait until all of our workers threads have finished. - for (auto &thread : workers) { - thread.join(); - } - - for (auto &entry : cache) { - if (trace) - printf("### Cache dump key = %d, value = %d.\n", entry.first, - entry.second); - ASSERT_EQ(workerHistory[entry.second].count(entry.first), 1U); - } -} - -TEST(ReadWriteLockTest, ReadWriteLockCacheExampleThreaded) { - ReadWriteLock lock; - readWriteLockCacheExampleThreaded(lock); -} - -TEST(StaticReadWriteLockTest, ReadWriteLockCacheExampleThreaded) { - static StaticReadWriteLock lock; - readWriteLockCacheExampleThreaded(lock); -} From f5bdb858e0e5a6476a00ff20db05cf74a0ded49c Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Fri, 15 Apr 2022 13:50:33 +0100 Subject: [PATCH 03/40] [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 --- CMakeLists.txt | 9 +- cmake/modules/AddSwift.cmake | 5 + cmake/modules/AddSwiftUnittests.cmake | 6 +- cmake/modules/Threading.cmake | 14 +- include/swift/Basic/Compiler.h | 16 ++ include/swift/Basic/Lazy.h | 41 +--- include/swift/Runtime/AtomicWaitQueue.h | 2 +- include/swift/Runtime/Concurrent.h | 6 +- include/swift/Runtime/Config.h | 16 -- include/swift/Runtime/EnvironmentVariables.h | 6 +- include/swift/Runtime/MutexC11.h | 89 -------- include/swift/Runtime/MutexPThread.h | 115 ----------- include/swift/Runtime/MutexSingleThreaded.h | 41 ---- include/swift/Runtime/MutexWin32.h | 51 ----- include/swift/Runtime/Once.h | 32 +-- include/swift/Runtime/ThreadLocal.h | 178 ---------------- include/swift/Runtime/ThreadLocalStorage.h | 114 ---------- include/swift/Runtime/VoucherShims.h | 2 +- include/swift/Threading/Errors.h | 35 ++++ include/swift/Threading/Impl.h | 37 ++++ include/swift/Threading/Impl/C11.h | 180 ++++++++++++++++ include/swift/Threading/Impl/Darwin.h | 177 ++++++++++++++++ include/swift/Threading/Impl/Linux.h | 168 +++++++++++++++ include/swift/Threading/Impl/Linux/ulock.h | 99 +++++++++ include/swift/Threading/Impl/Nothreads.h | 76 +++++++ include/swift/Threading/Impl/Pthreads.h | 162 +++++++++++++++ include/swift/Threading/Impl/Win32.h | 127 ++++++++++++ include/swift/{Runtime => Threading}/Mutex.h | 194 ++++++------------ include/swift/Threading/Once.h | 35 ++++ include/swift/Threading/Thread.h | 72 +++++++ include/swift/Threading/ThreadLocalStorage.h | 176 ++++++++++++++++ lib/CMakeLists.txt | 2 + lib/Threading/C11.cpp | 103 ++++++++++ lib/Threading/CMakeLists.txt | 5 + lib/Threading/Linux.cpp | 67 ++++++ lib/Threading/Nothreads.cpp | 21 ++ lib/Threading/Pthreads.cpp | 82 ++++++++ lib/Threading/Win32.cpp | 103 ++++++++++ stdlib/cmake/modules/AddSwiftStdlib.cmake | 4 +- stdlib/cmake/modules/StdlibOptions.cmake | 23 +++ stdlib/cmake/modules/SwiftSource.cmake | 6 +- stdlib/public/CMakeLists.txt | 1 + stdlib/public/Concurrency/Actor.cpp | 32 ++- stdlib/public/Concurrency/AsyncLet.cpp | 3 +- stdlib/public/Concurrency/AsyncStream.cpp | 18 +- stdlib/public/Concurrency/CMakeLists.txt | 3 +- .../Concurrency/DispatchGlobalExecutor.inc | 2 +- stdlib/public/Concurrency/Error.cpp | 27 ++- stdlib/public/Concurrency/Error.h | 8 +- stdlib/public/Concurrency/Mutex.cpp | 25 --- stdlib/public/Concurrency/Task.cpp | 2 +- stdlib/public/Concurrency/TaskGroup.cpp | 2 +- stdlib/public/Concurrency/TaskLocal.cpp | 18 +- stdlib/public/Concurrency/TaskStatus.cpp | 6 +- stdlib/public/Concurrency/TracingSignpost.cpp | 2 +- stdlib/public/Concurrency/TracingSignpost.h | 4 +- stdlib/public/Threading/CMakeLists.txt | 6 + stdlib/public/core/CMakeLists.txt | 2 +- stdlib/public/runtime/CMakeLists.txt | 4 - stdlib/public/runtime/Casting.cpp | 37 +--- stdlib/public/runtime/CygwinPort.cpp | 49 ----- .../public/runtime/EnvironmentVariables.cpp | 2 +- stdlib/public/runtime/Errors.cpp | 13 +- stdlib/public/runtime/Exclusivity.cpp | 2 +- stdlib/public/runtime/HeapObject.cpp | 36 ++-- stdlib/public/runtime/ImageInspectionCOFF.cpp | 4 +- stdlib/public/runtime/Metadata.cpp | 14 +- stdlib/public/runtime/MetadataCache.h | 4 +- stdlib/public/runtime/MetadataImpl.h | 2 +- stdlib/public/runtime/MetadataLookup.cpp | 2 +- stdlib/public/runtime/MutexC11.cpp | 37 ---- stdlib/public/runtime/MutexPThread.cpp | 109 ---------- stdlib/public/runtime/MutexWin32.cpp | 31 --- stdlib/public/runtime/Once.cpp | 27 +-- .../runtime/RuntimeInvocationsTracking.cpp | 20 +- stdlib/public/runtime/SwiftTLSContext.cpp | 83 +++----- stdlib/public/stubs/OptionalBridgingHelper.mm | 8 +- stdlib/public/stubs/Random.cpp | 3 +- stdlib/public/stubs/Stubs.cpp | 12 +- stdlib/public/stubs/ThreadLocalStorage.cpp | 103 +++------- .../Compatibility50/ProtocolConformance.cpp | 6 +- .../DynamicReplaceable.cpp | 11 +- test/CMakeLists.txt | 9 + .../class-class-flags-run.swift | 2 +- .../enum-extradata-run.swift | 2 +- .../enum-trailing-flags-run.swift | 2 +- .../struct-extradata-run.swift | 2 +- .../struct-multi-conformance.swift | 2 +- .../struct-outmodule-run.swift | 2 +- .../struct-trailing-flags-run.swift | 2 +- test/TypeRoundTrip/round-trip.swift | 2 +- test/lit.cfg | 8 + test/lit.site.cfg.in | 4 +- unittests/{runtime => Threading}/Mutex.cpp | 32 +-- unittests/Threading/ThreadingHelpers.h | 134 ++++++++++++ unittests/runtime/CMakeLists.txt | 2 +- utils/build-script-impl | 12 +- validation-test/lit.site.cfg.in | 4 +- 98 files changed, 2287 insertions(+), 1411 deletions(-) delete mode 100644 include/swift/Runtime/MutexC11.h delete mode 100644 include/swift/Runtime/MutexPThread.h delete mode 100644 include/swift/Runtime/MutexSingleThreaded.h delete mode 100644 include/swift/Runtime/MutexWin32.h delete mode 100644 include/swift/Runtime/ThreadLocal.h delete mode 100644 include/swift/Runtime/ThreadLocalStorage.h create mode 100644 include/swift/Threading/Errors.h create mode 100644 include/swift/Threading/Impl.h create mode 100644 include/swift/Threading/Impl/C11.h create mode 100644 include/swift/Threading/Impl/Darwin.h create mode 100644 include/swift/Threading/Impl/Linux.h create mode 100644 include/swift/Threading/Impl/Linux/ulock.h create mode 100644 include/swift/Threading/Impl/Nothreads.h create mode 100644 include/swift/Threading/Impl/Pthreads.h create mode 100644 include/swift/Threading/Impl/Win32.h rename include/swift/{Runtime => Threading}/Mutex.h (57%) create mode 100644 include/swift/Threading/Once.h create mode 100644 include/swift/Threading/Thread.h create mode 100644 include/swift/Threading/ThreadLocalStorage.h create mode 100644 lib/Threading/C11.cpp create mode 100644 lib/Threading/CMakeLists.txt create mode 100644 lib/Threading/Linux.cpp create mode 100644 lib/Threading/Nothreads.cpp create mode 100644 lib/Threading/Pthreads.cpp create mode 100644 lib/Threading/Win32.cpp delete mode 100644 stdlib/public/Concurrency/Mutex.cpp create mode 100644 stdlib/public/Threading/CMakeLists.txt delete mode 100644 stdlib/public/runtime/CygwinPort.cpp delete mode 100644 stdlib/public/runtime/MutexC11.cpp delete mode 100644 stdlib/public/runtime/MutexPThread.cpp delete mode 100644 stdlib/public/runtime/MutexWin32.cpp rename unittests/{runtime => Threading}/Mutex.cpp (89%) create mode 100644 unittests/Threading/ThreadingHelpers.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 518e1e529ad76..6779f1fc0264e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -126,12 +126,13 @@ option(SWIFT_STDLIB_ENABLE_UNICODE_DATA include(Threading) -threading_package_default(SWIFT_STDLIB_THREADING_PACKAGE_default) +threading_package_default("${SWIFT_HOST_VARIANT_SDK}" + SWIFT_THREADING_PACKAGE_default) -set(SWIFT_STDLIB_THREADING_PACKAGE "${SWIFT_STDLIB_THREADING_PACKAGE_default}" +set(SWIFT_THREADING_PACKAGE "${SWIFT_THREADING_PACKAGE_default}" CACHE STRING "The threading package to use. Must be one of 'none', 'pthreads', - 'darwin', 'win32', 'c11'.") + 'darwin', 'linux', 'win32', 'c11'.") option(SWIFT_BUILD_DYNAMIC_SDK_OVERLAY "Build dynamic variants of the Swift SDK overlay" @@ -1046,7 +1047,7 @@ if(SWIFT_BUILD_STDLIB OR SWIFT_BUILD_SDK_OVERLAY) message(STATUS " Leak Detection Checker Entrypoints: ${SWIFT_RUNTIME_ENABLE_LEAK_CHECKER}") message(STATUS "") - message(STATUS "Threading Package: ${SWIFT_STDLIB_THREADING_PACKAGE}") + message(STATUS "Threading Package: ${SWIFT_THREADING_PACKAGE}") message(STATUS "Differentiable Programming Support: ${SWIFT_ENABLE_EXPERIMENTAL_DIFFERENTIABLE_PROGRAMMING}") message(STATUS "Concurrency Support: ${SWIFT_ENABLE_EXPERIMENTAL_CONCURRENCY}") message(STATUS "Distributed Support: ${SWIFT_ENABLE_EXPERIMENTAL_DISTRIBUTED}") diff --git a/cmake/modules/AddSwift.cmake b/cmake/modules/AddSwift.cmake index 5cf79d8e3c1ca..949010484bd84 100644 --- a/cmake/modules/AddSwift.cmake +++ b/cmake/modules/AddSwift.cmake @@ -4,6 +4,7 @@ include(SwiftXcodeSupport) include(SwiftWindowsSupport) include(SwiftAndroidSupport) include(SwiftCXXUtils) +include(Threading) function(_swift_gyb_target_sources target scope) file(GLOB GYB_UNICODE_DATA ${SWIFT_SOURCE_DIR}/utils/UnicodeData/*) @@ -308,6 +309,10 @@ function(_add_host_variant_c_compile_flags target) $<$:SWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS>) endif() + threading_package_name("${SWIFT_HOST_VARIANT_SDK}" _threading_package) + target_compile_definitions(${target} PRIVATE + "SWIFT_THREADING_${_threading_package}") + if(SWIFT_ANALYZE_CODE_COVERAGE) target_compile_options(${target} PRIVATE $<$:-fprofile-instr-generate -fcoverage-mapping>) diff --git a/cmake/modules/AddSwiftUnittests.cmake b/cmake/modules/AddSwiftUnittests.cmake index 256fd0960bd21..e19a1b6a8cff6 100644 --- a/cmake/modules/AddSwiftUnittests.cmake +++ b/cmake/modules/AddSwiftUnittests.cmake @@ -49,14 +49,14 @@ function(add_swift_unittest test_dirname) # some headers switch their inline implementations based on # SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY and - # SWIFT_STDLIB_THREADING_PACKAGE definitions + # SWIFT_THREADING_PACKAGE definitions if(SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY) target_compile_definitions("${test_dirname}" PRIVATE SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY) endif() - threading_package_name(_threading_package) + threading_package_name("${SWIFT_HOST_VARIANT_SDK}" _threading_package) target_compile_definitions("${test_dirname}" PRIVATE - "SWIFT_STDLIB_THREADING_${_threading_package}") + "SWIFT_THREADING_${_threading_package}") if(NOT SWIFT_COMPILER_IS_MSVC_LIKE) if(SWIFT_USE_LINKER) diff --git a/cmake/modules/Threading.cmake b/cmake/modules/Threading.cmake index 6d78768b7a64a..f439ed0ba90b0 100644 --- a/cmake/modules/Threading.cmake +++ b/cmake/modules/Threading.cmake @@ -1,10 +1,12 @@ # Get the default threading package for the platform -function(threading_package_default out_var) - if("${SWIFT_HOST_VARIANT_SDK}" IN_LIST SWIFT_DARWIN_PLATFORMS) +function(threading_package_default sdk out_var) + if(sdk IN_LIST SWIFT_DARWIN_PLATFORMS) set("${out_var}" "darwin" PARENT_SCOPE) - elseif("${SWIFT_HOST_VARIANT_SDK}" STREQUAL "WINDOWS") + elseif(sdk STREQUAL "LINUX") + set("${out_var}" "linux" PARENT_SCOPE) + elseif(sdk STREQUAL "WINDOWS") set("${out_var}" "win32" PARENT_SCOPE) - elseif("${SWIFT_HOST_VARIANT_SDK}" STREQUAL "WASI") + elseif(sdk STREQUAL "WASI") set("${out_var}" "none" PARENT_SCOPE) else() set("${out_var}" "pthreads" PARENT_SCOPE) @@ -14,11 +16,11 @@ endfunction() # Given the threading package, find the name for the preprocessor # define that we need to make. Also deals with the default platform # setting. -function(threading_package_name out_var) +function(threading_package_name sdk out_var) precondition(SWIFT_HOST_VARIANT_SDK) precondition(SWIFT_DARWIN_PLATFORMS) - string(TOUPPER "${SWIFT_STDLIB_THREADING_PACKAGE}" package) + string(TOUPPER "${SWIFT_THREADING_PACKAGE}" package) if(package STREQUAL "") threading_package_default(package) string(TOUPPER "${package}" package) diff --git a/include/swift/Basic/Compiler.h b/include/swift/Basic/Compiler.h index e181a24139d82..eec7da704c3e7 100644 --- a/include/swift/Basic/Compiler.h +++ b/include/swift/Basic/Compiler.h @@ -162,4 +162,20 @@ #define SWIFT_ASM_LABEL_WITH_PREFIX(STRING) \ SWIFT_ASM_LABEL_RAW(SWIFT_SYMBOL_PREFIX_STRING STRING) +// SWIFT_FORMAT(fmt,first) marks a function as taking a format string argument +// at argument `fmt`, with the first argument for the format string as `first`. +#if __has_attribute(format) +#define SWIFT_FORMAT(fmt,first) __attribute__((format(printf, fmt, first))) +#else +#define SWIFT_FORMAT(fmt,first) +#endif + +// SWIFT_VFORMAT(fmt) marks a function as taking a format string argument at +// argument `fmt`, with the arguments in a `va_list`. +#if __has_attribute(format) +#define SWIFT_VFORMAT(fmt) __attribute__((format(printf, fmt, 0))) +#else +#define SWIFT_VFORMAT(fmt) +#endif + #endif // SWIFT_BASIC_COMPILER_H diff --git a/include/swift/Basic/Lazy.h b/include/swift/Basic/Lazy.h index 692341ae3745c..4a99b78fc802f 100644 --- a/include/swift/Basic/Lazy.h +++ b/include/swift/Basic/Lazy.h @@ -15,55 +15,26 @@ #include -#if SWIFT_STDLIB_THREADING_NONE -// No dependencies on single-threaded environments. -#elif SWIFT_STDLIB_THREADING_DARWIN -#include -#else -#include -#endif - #include "swift/Basic/Malloc.h" #include "swift/Basic/type_traits.h" +#include "swift/Threading/Once.h" namespace swift { -#if SWIFT_STDLIB_THREADING_NONE - using OnceToken_t = bool; -# define SWIFT_ONCE_F(TOKEN, FUNC, CONTEXT) \ - do { if (!TOKEN) { TOKEN = true; (FUNC)(CONTEXT); } } while (0) -#elif SWIFT_STDLIB_THREADING_DARWIN - using OnceToken_t = ::dispatch_once_t; -# define SWIFT_ONCE_F(TOKEN, FUNC, CONTEXT) \ - ::dispatch_once_f(&TOKEN, CONTEXT, FUNC) -#elif defined(__CYGWIN__) - // _swift_once_f() is declared in Private.h. - // This prototype is copied instead including the header file. - void _swift_once_f(uintptr_t *predicate, void *context, - void (*function)(void *)); - using OnceToken_t = unsigned long; -# define SWIFT_ONCE_F(TOKEN, FUNC, CONTEXT) \ - _swift_once_f(&TOKEN, CONTEXT, FUNC) -#else - using OnceToken_t = std::once_flag; -# define SWIFT_ONCE_F(TOKEN, FUNC, CONTEXT) \ - ::std::call_once(TOKEN, FUNC, CONTEXT) -#endif - /// A template for lazily-constructed, zero-initialized, leaked-on-exit /// global objects. template class Lazy { alignas(T) char Value[sizeof(T)] = { 0 }; - OnceToken_t OnceToken = {}; + swift::once_t OnceToken = {}; static void defaultInitCallback(void *ValueAddr) { ::new (ValueAddr) T(); } - + public: using Type = T; - + T &get(void (*initCallback)(void *) = defaultInitCallback); template @@ -87,7 +58,7 @@ template inline T &Lazy::get(void (*initCallback)(void*)) { static_assert(std::is_literal_type>::value, "Lazy must be a literal type"); - SWIFT_ONCE_F(OnceToken, initCallback, &Value); + swift::once(OnceToken, initCallback, &Value); return unsafeGetAlreadyInitialized(); } @@ -103,7 +74,7 @@ template inline T &Lazy::getWithInit(Arg1 &&arg1) { } } data{&Value, static_cast(arg1)}; - SWIFT_ONCE_F(OnceToken, &Data::init, &data); + swift::once(OnceToken, &Data::init, &data); return unsafeGetAlreadyInitialized(); } diff --git a/include/swift/Runtime/AtomicWaitQueue.h b/include/swift/Runtime/AtomicWaitQueue.h index bfad6c71ccb5b..88a566d7d971a 100644 --- a/include/swift/Runtime/AtomicWaitQueue.h +++ b/include/swift/Runtime/AtomicWaitQueue.h @@ -21,7 +21,7 @@ #include "swift/Runtime/Heap.h" #include "swift/Runtime/HeapObject.h" -#include "swift/Runtime/Mutex.h" +#include "swift/Threading/Mutex.h" #include namespace swift { diff --git a/include/swift/Runtime/Concurrent.h b/include/swift/Runtime/Concurrent.h index 4121e88f2c603..3221eb558214a 100644 --- a/include/swift/Runtime/Concurrent.h +++ b/include/swift/Runtime/Concurrent.h @@ -21,7 +21,7 @@ #include "llvm/Support/Allocator.h" #include "Atomic.h" #include "Debug.h" -#include "Mutex.h" +#include "swift/Threading/Mutex.h" #if defined(__FreeBSD__) || defined(__CYGWIN__) || defined(__HAIKU__) #include @@ -624,7 +624,7 @@ using llvm::hash_value; /// process. It has no destructor, to avoid generating useless global destructor /// calls. The memory it allocates can be freed by calling clear() with no /// outstanding readers, but this won't destroy the static mutex it uses. -template +template struct ConcurrentReadableHashMap { // We don't call destructors. Make sure the elements will put up with this. static_assert(std::is_trivially_destructible::value, @@ -1171,7 +1171,7 @@ template struct HashMapElementWrapper { /// by allocating them separately and storing pointers to them. The elements of /// the hash table are instances of HashMapElementWrapper. A new getOrInsert /// method is provided that directly returns the stable element pointer. -template +template struct StableAddressConcurrentReadableHashMap : public ConcurrentReadableHashMap, MutexTy> { // Implicitly trivial destructor. diff --git a/include/swift/Runtime/Config.h b/include/swift/Runtime/Config.h index 3baae757440a1..41a02738161e8 100644 --- a/include/swift/Runtime/Config.h +++ b/include/swift/Runtime/Config.h @@ -232,22 +232,6 @@ extern uintptr_t __COMPATIBILITY_LIBRARIES_CANNOT_CHECK_THE_IS_SWIFT_BIT_DIRECTL // so changing this value is not sufficient. #define SWIFT_DEFAULT_LLVM_CC llvm::CallingConv::C -// SWIFT_FORMAT(fmt,first) marks a function as taking a format string argument -// at argument `fmt`, with the first argument for the format string as `first`. -#if __has_attribute(format) -#define SWIFT_FORMAT(fmt,first) __attribute__((format(printf, fmt, first))) -#else -#define SWIFT_FORMAT(fmt,first) -#endif - -// SWIFT_VFORMAT(fmt) marks a function as taking a format string argument at -// argument `fmt`, with the arguments in a `va_list`. -#if __has_attribute(format) -#define SWIFT_VFORMAT(fmt) __attribute__((format(printf, fmt, 0))) -#else -#define SWIFT_VFORMAT(fmt) -#endif - /// Should we use absolute function pointers instead of relative ones? /// WebAssembly target uses it by default. #ifndef SWIFT_COMPACT_ABSOLUTE_FUNCTION_POINTER diff --git a/include/swift/Runtime/EnvironmentVariables.h b/include/swift/Runtime/EnvironmentVariables.h index 51d78e31d3110..5cf45b1f41220 100644 --- a/include/swift/Runtime/EnvironmentVariables.h +++ b/include/swift/Runtime/EnvironmentVariables.h @@ -14,7 +14,7 @@ // //===----------------------------------------------------------------------===// -#include "../Basic/Lazy.h" +#include "swift/Threading/Once.h" namespace swift { namespace runtime { @@ -22,7 +22,7 @@ namespace environment { void initialize(void *); -extern OnceToken_t initializeToken; +extern swift::once_t initializeToken; // Declare backing variables. #define VARIABLE(name, type, defaultValue, help) extern type name ## _variable; @@ -31,7 +31,7 @@ extern OnceToken_t initializeToken; // Define getter functions. #define VARIABLE(name, type, defaultValue, help) \ inline type name() { \ - SWIFT_ONCE_F(initializeToken, initialize, nullptr); \ + swift::once(initializeToken, initialize, nullptr); \ return name ## _variable; \ } #include "../../../stdlib/public/runtime/EnvironmentVariables.def" diff --git a/include/swift/Runtime/MutexC11.h b/include/swift/Runtime/MutexC11.h deleted file mode 100644 index b0c4003f48efd..0000000000000 --- a/include/swift/Runtime/MutexC11.h +++ /dev/null @@ -1,89 +0,0 @@ -//===--- MutexC11.h - Supports Mutex.h using C11 threading ------*- 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 -// -//===----------------------------------------------------------------------===// -// -// Mutex, Read/Write lock, and Scoped lock implementations -// using C11 threading primtives. -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_RUNTIME_MUTEX_C11_H -#define SWIFT_RUNTIME_MUTEX_C11_H - -#include - -namespace swift { - -namespace c11threads { - class rwlock; - - static void fatalError(int errcode); - static inline void handleError(int errcode) { - if (SWIFT_LIKELY(errcode == thrd_success)) - return; - - fatalError(errcode); - } -} - -typedef ::mtx_t MutexHandle; - -#define SWIFT_MUTEX_SUPPORTS_CONSTEXPR 0 - -/// C11 low-level implementation that supports Mutex -/// found in Mutex.h -/// -/// See Mutex -class MutexPlatformHelper { -public: - static MutexHandle staticInit() { - ::mtx_t mutex; - ::mtx_init(&mutex, ::mtx_plain); - return mutex; - } - - static void init(MutexHandle &mutex, bool checked = false) { - // C11 mutexes can't be checked - c11threads::handleError(::mtx_init(&mutex, ::mtx_plain)); - } - static void destroy(MutexHandle &mutex) { - ::mtx_destroy(&mutex); - } - static void lock(MutexHandle &mutex) { - c11threads::handleError(::mtx_lock(&mutex)); - } - static void unlock(MutexHandle &mutex) { - c11threads::handleError(::mtx_unlock(&mutex)); - } - static bool try_lock(MutexHandle &mutex) { - int err = ::mtx_trylock(&mutex); - switch (err) { - case thrd_success: - return true; - case thrd_busy: - return false; - default: - c11threads::handleError(err); - } - } - - // Skip error checking for the unsafe versions. - static void unsafeLock(MutexHandle &mutex) { - (void)::mtx_lock(&mutex); - } - static void unsafeUnlock(MutexHandle &mutex) { - (void)::mtx_unlock(&mutex); - } -}; - -} - -#endif diff --git a/include/swift/Runtime/MutexPThread.h b/include/swift/Runtime/MutexPThread.h deleted file mode 100644 index bcf409ddd0eb1..0000000000000 --- a/include/swift/Runtime/MutexPThread.h +++ /dev/null @@ -1,115 +0,0 @@ -//===--- MutexPThread.h - Supports Mutex.h using PThreads -------*- 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 -// -//===----------------------------------------------------------------------===// -// -// Mutex, Read/Write lock, and Scoped lock implementations -// using PThreads. -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_RUNTIME_MUTEX_PHTREAD_H -#define SWIFT_RUNTIME_MUTEX_PHTREAD_H - -#include - -#if defined(__APPLE__) && defined(__MACH__) -#include -#define HAS_OS_UNFAIR_LOCK 1 -#endif - -namespace swift { - -#if HAS_OS_UNFAIR_LOCK -typedef os_unfair_lock MutexHandle; -#else -typedef pthread_mutex_t MutexHandle; -#endif - -#if defined(__CYGWIN__) || defined(__HAIKU__) || defined(__wasi__) -// At the moment CYGWIN pthreads implementation doesn't support the use of -// constexpr for static allocation versions. The way they define things -// results in a reinterpret_cast which violates constexpr. -// WASI currently doesn't support threading/locking at all. -#define SWIFT_MUTEX_SUPPORTS_CONSTEXPR 0 -#else -#define SWIFT_MUTEX_SUPPORTS_CONSTEXPR 1 -#endif - -/// PThread low-level implementation that supports Mutex -/// found in Mutex.h -/// -/// See Mutex -struct MutexPlatformHelper { -#if SWIFT_MUTEX_SUPPORTS_CONSTEXPR - static constexpr -#else - static -#endif - MutexHandle - staticInit() { -#if HAS_OS_UNFAIR_LOCK - return OS_UNFAIR_LOCK_INIT; -#else - return PTHREAD_MUTEX_INITIALIZER; -#endif - } - - static void init(MutexHandle &mutex, bool checked = false); - static void destroy(MutexHandle &mutex); - static void lock(MutexHandle &mutex); - static void unlock(MutexHandle &mutex); - static bool try_lock(MutexHandle &mutex); - -#if HAS_OS_UNFAIR_LOCK - // os_unfair_lock always checks for errors, so just call through. - static void unsafeLock(MutexHandle &mutex) { - lock(mutex); - } - static void unsafeUnlock(MutexHandle &mutex) { - unlock(mutex); - } -#else - // Skip error checking for the unsafe versions. - static void unsafeLock(MutexHandle &mutex) { - (void)pthread_mutex_lock(&mutex); - } - static void unsafeUnlock(MutexHandle &mutex) { - (void)pthread_mutex_unlock(&mutex); - } -#endif -}; - -#if HAS_OS_UNFAIR_LOCK - -inline void MutexPlatformHelper::init(os_unfair_lock &lock, bool checked) { - (void)checked; // Unfair locks are always checked. - lock = OS_UNFAIR_LOCK_INIT; -} - -inline void MutexPlatformHelper::destroy(os_unfair_lock &lock) {} - -inline void MutexPlatformHelper::lock(os_unfair_lock &lock) { - os_unfair_lock_lock(&lock); -} - -inline void MutexPlatformHelper::unlock(os_unfair_lock &lock) { - os_unfair_lock_unlock(&lock); -} - -inline bool MutexPlatformHelper::try_lock(os_unfair_lock &lock) { - return os_unfair_lock_trylock(&lock); -} - -#endif - -} - -#endif diff --git a/include/swift/Runtime/MutexSingleThreaded.h b/include/swift/Runtime/MutexSingleThreaded.h deleted file mode 100644 index 35e18f45d3bde..0000000000000 --- a/include/swift/Runtime/MutexSingleThreaded.h +++ /dev/null @@ -1,41 +0,0 @@ -//===--- MutexSingleThreaded.h - --------------------------------*- C++ -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2020 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 -// -//===----------------------------------------------------------------------===// -// -// No-op implementation of locks for single-threaded environments. -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_RUNTIME_MUTEX_SINGLE_THREADED_H -#define SWIFT_RUNTIME_MUTEX_SINGLE_THREADED_H - -#include "swift/Runtime/Debug.h" - -namespace swift { - -typedef void* MutexHandle; - -#define SWIFT_MUTEX_SUPPORTS_CONSTEXPR 1 - -struct MutexPlatformHelper { - static constexpr MutexHandle staticInit() { return nullptr; } - static void init(MutexHandle &mutex, bool checked = false) {} - static void destroy(MutexHandle &mutex) {} - static void lock(MutexHandle &mutex) {} - static void unlock(MutexHandle &mutex) {} - static bool try_lock(MutexHandle &mutex) { return true; } - static void unsafeLock(MutexHandle &mutex) {} - static void unsafeUnlock(MutexHandle &mutex) {} -}; - -} - -#endif diff --git a/include/swift/Runtime/MutexWin32.h b/include/swift/Runtime/MutexWin32.h deleted file mode 100644 index 6ed68bf03c507..0000000000000 --- a/include/swift/Runtime/MutexWin32.h +++ /dev/null @@ -1,51 +0,0 @@ -//===--- MutexWin32.h - -----------------------------------------*- 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 -// -//===----------------------------------------------------------------------===// -// -// Mutex and Read/Write lock implementations using Windows Slim -// Reader/Writer Locks and Conditional Variables. -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_RUNTIME_MUTEX_WIN32_H -#define SWIFT_RUNTIME_MUTEX_WIN32_H - -#define WIN32_LEAN_AND_MEAN -#define NOMINMAX -#include - -namespace swift { - -typedef SRWLOCK MutexHandle; - -#define SWIFT_MUTEX_SUPPORTS_CONSTEXPR 1 - -struct MutexPlatformHelper { - static constexpr MutexHandle staticInit() { return SRWLOCK_INIT; } - static void init(MutexHandle &mutex, bool checked = false) { - InitializeSRWLock(&mutex); - } - static void destroy(MutexHandle &mutex) {} - static void lock(MutexHandle &mutex) { AcquireSRWLockExclusive(&mutex); } - static void unlock(MutexHandle &mutex) { ReleaseSRWLockExclusive(&mutex); } - static bool try_lock(MutexHandle &mutex) { - return TryAcquireSRWLockExclusive(&mutex) != 0; - } - // The unsafe versions don't do error checking. - static void unsafeLock(MutexHandle &mutex) { - AcquireSRWLockExclusive(&mutex); - } - static void unsafeUnlock(MutexHandle &mutex) { - ReleaseSRWLockExclusive(&mutex); - } -}; - -#endif diff --git a/include/swift/Runtime/Once.h b/include/swift/Runtime/Once.h index c51c585de10a6..55921d76dac41 100644 --- a/include/swift/Runtime/Once.h +++ b/include/swift/Runtime/Once.h @@ -17,40 +17,18 @@ #ifndef SWIFT_RUNTIME_ONCE_H #define SWIFT_RUNTIME_ONCE_H -#include "swift/Runtime/HeapObject.h" - -#if SWIFT_STDLIB_THREADING_DARWIN -#include -#else -#include -#endif +#include "swift/Threading/Once.h" namespace swift { -#ifdef SWIFT_STDLIB_THREADING_NONE - -typedef bool swift_once_t; - -#elif SWIFT_STDLIB_THREADING_DARWIN - -// On OS X and iOS, swift_once_t is really a dispatch_once_t. -typedef dispatch_once_t swift_once_t; - -#elif defined(__CYGWIN__) - -// On Cygwin, std::once_flag can not be used because it is larger than the -// platform word. -typedef uintptr_t swift_once_t; -#else - -// On other platforms swift_once_t is std::once_flag -typedef std::once_flag swift_once_t; - -#endif +typedef swift::once_t swift_once_t; /// Runs the given function with the given context argument exactly once. /// The predicate argument must point to a global or static variable of static /// extent of type swift_once_t. +/// +/// Within the runtime, you should be using swift::once, which will be faster; +/// this is exposed so that the compiler can generate calls to it. SWIFT_RUNTIME_EXPORT void swift_once(swift_once_t *predicate, void (*fn)(void *), void *context); diff --git a/include/swift/Runtime/ThreadLocal.h b/include/swift/Runtime/ThreadLocal.h deleted file mode 100644 index 7e56e62b3c087..0000000000000 --- a/include/swift/Runtime/ThreadLocal.h +++ /dev/null @@ -1,178 +0,0 @@ -//===--- 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 -#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 -#include -#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::value, \ - "ThreadLocal values must be trivially copyable"); \ - static_assert(std::is_trivially_destructible::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 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 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 NAME -#elif SWIFT_TLS_HAS_RESERVED_PTHREAD_SPECIFIC -#define SWIFT_RUNTIME_DECLARE_THREAD_LOCAL(TYPE, NAME, KEY) \ - swift::ThreadLocal> NAME -#else -#define SWIFT_RUNTIME_DECLARE_THREAD_LOCAL(TYPE, NAME, KEY) \ - swift::ThreadLocal NAME -#endif - -#endif diff --git a/include/swift/Runtime/ThreadLocalStorage.h b/include/swift/Runtime/ThreadLocalStorage.h deleted file mode 100644 index c9f06317597e5..0000000000000 --- a/include/swift/Runtime/ThreadLocalStorage.h +++ /dev/null @@ -1,114 +0,0 @@ -//===--- ThreadLocalStorage.h - Thread-local storage interface. --*- C++ -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2018 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_RUNTIME_THREADLOCALSTORAGE_H -#define SWIFT_RUNTIME_THREADLOCALSTORAGE_H - -#include "swift/Runtime/Config.h" - -#if SWIFT_STDLIB_THREADING_DARWIN || SWIFT_STDLIB_THREADING_PTHREADS -#include -#elif SWIFT_STDLIB_THREADING_C11 -#include -#elif SWIFT_STDLIB_THREADING_WIN32 -# define WIN32_LEAN_AND_MEAN -# include -#endif - -// Depending on the target, we may be able to use dedicated TSD keys or -// thread_local variables. When dedicated TSD keys aren't available, -// wrap the target's API for thread-local data for things that don't want -// to use thread_local. - -// On Apple platforms, we have dedicated TSD keys. -#if SWIFT_STDLIB_THREADING_DARWIN -# define SWIFT_TLS_HAS_RESERVED_PTHREAD_SPECIFIC 1 -// Use reserved TSD keys. -# if __has_include() -# include -# else -// We still need to use the SPI for setting the destructor, so declare it here. -extern "C" int pthread_key_init_np(int key, void (*destructor)(void *)); -#define SWIFT_THREAD_KEY_INIT pthread_key_init_np -# endif - -// If the keys are not available from the header, define them ourselves. The values match -// what tsd_private.h provides. -# ifndef __PTK_FRAMEWORK_SWIFT_KEY0 -# define __PTK_FRAMEWORK_SWIFT_KEY0 100 -# endif -# ifndef __PTK_FRAMEWORK_SWIFT_KEY1 -# define __PTK_FRAMEWORK_SWIFT_KEY1 101 -# endif -# ifndef __PTK_FRAMEWORK_SWIFT_KEY2 -# define __PTK_FRAMEWORK_SWIFT_KEY2 102 -# endif -# ifndef __PTK_FRAMEWORK_SWIFT_KEY3 -# define __PTK_FRAMEWORK_SWIFT_KEY3 103 -# endif -# ifndef __PTK_FRAMEWORK_SWIFT_KEY4 -# define __PTK_FRAMEWORK_SWIFT_KEY4 104 -# endif -# ifndef __PTK_FRAMEWORK_SWIFT_KEY5 -# define __PTK_FRAMEWORK_SWIFT_KEY5 105 -# endif -# ifndef __PTK_FRAMEWORK_SWIFT_KEY6 -# define __PTK_FRAMEWORK_SWIFT_KEY6 106 -# endif -# ifndef __PTK_FRAMEWORK_SWIFT_KEY7 -# define __PTK_FRAMEWORK_SWIFT_KEY7 107 -# endif -# ifndef __PTK_FRAMEWORK_SWIFT_KEY8 -# define __PTK_FRAMEWORK_SWIFT_KEY8 108 -# endif -# ifndef __PTK_FRAMEWORK_SWIFT_KEY9 -# define __PTK_FRAMEWORK_SWIFT_KEY9 109 -# endif - - -# define SWIFT_RUNTIME_TLS_KEY __PTK_FRAMEWORK_SWIFT_KEY0 -# define SWIFT_STDLIB_TLS_KEY __PTK_FRAMEWORK_SWIFT_KEY1 -# define SWIFT_COMPATIBILITY_50_TLS_KEY __PTK_FRAMEWORK_SWIFT_KEY2 -# define SWIFT_CONCURRENCY_TASK_KEY __PTK_FRAMEWORK_SWIFT_KEY3 -# define SWIFT_CONCURRENCY_EXECUTOR_TRACKING_INFO_KEY __PTK_FRAMEWORK_SWIFT_KEY4 -# define SWIFT_CONCURRENCY_FALLBACK_TASK_LOCAL_STORAGE_KEY \ - __PTK_FRAMEWORK_SWIFT_KEY5 - -#endif - -// If the reserved key path didn't already provide get/setspecific macros, -// wrap the platform's APIs. -#ifndef SWIFT_THREAD_GETSPECIFIC - -// Pick the right typedef for the key. -#if SWIFT_STDLIB_THREADING_WIN32 -typedef DWORD __swift_thread_key_t; -# define SWIFT_THREAD_KEY_CREATE _stdlib_thread_key_create -# define SWIFT_THREAD_GETSPECIFIC FlsGetValue -# define SWIFT_THREAD_SETSPECIFIC(key, value) (FlsSetValue(key, value) == FALSE) -#elif SWIFT_STDLIB_THREADING_PTHREADS || SWIFT_STDLIB_THREADING_DARWIN -typedef pthread_key_t __swift_thread_key_t; -# define SWIFT_THREAD_KEY_CREATE pthread_key_create -# define SWIFT_THREAD_GETSPECIFIC pthread_getspecific -# define SWIFT_THREAD_SETSPECIFIC pthread_setspecific -#elif SWIFT_STDLIB_THREADING_C11 -typedef tss_t __swift_thread_key_t; -# define SWIFT_THREAD_KEY_CREATE tss_create -# define SWIFT_THREAD_GETSPECIFIC tss_get -# define SWIFT_THREAD_SETSPECIFIC tss_set -#else -typedef unsigned long __swift_thread_key_t; -#endif - -#endif - -#endif // SWIFT_RUNTIME_THREADLOCALSTORAGE_H diff --git a/include/swift/Runtime/VoucherShims.h b/include/swift/Runtime/VoucherShims.h index b0287a5150ab2..e0fdadbf23295 100644 --- a/include/swift/Runtime/VoucherShims.h +++ b/include/swift/Runtime/VoucherShims.h @@ -22,7 +22,7 @@ // swift-corelibs-libdispatch has os/voucher_private.h but it doesn't work for // us yet, so only look for it on Apple platforms. We also don't need vouchers // in the single threaded concurrency runtime. -#if __APPLE__ && !SWIFT_STDLIB_THREADING_NONE \ +#if __APPLE__ && !SWIFT_THREADING_NONE \ && __has_include() #define SWIFT_HAS_VOUCHER_HEADER 1 #include diff --git a/include/swift/Threading/Errors.h b/include/swift/Threading/Errors.h new file mode 100644 index 0000000000000..f656b003bec28 --- /dev/null +++ b/include/swift/Threading/Errors.h @@ -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 + +#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 diff --git a/include/swift/Threading/Impl.h b/include/swift/Threading/Impl.h new file mode 100644 index 0000000000000..9151e2e1b801b --- /dev/null +++ b/include/swift/Threading/Impl.h @@ -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 diff --git a/include/swift/Threading/Impl/C11.h b/include/swift/Threading/Impl/C11.h new file mode 100644 index 0000000000000..a1f601b011590 --- /dev/null +++ b/include/swift/Threading/Impl/C11.h @@ -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 +#include + +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 diff --git a/include/swift/Threading/Impl/Darwin.h b/include/swift/Threading/Impl/Darwin.h new file mode 100644 index 0000000000000..b22a644afee42 --- /dev/null +++ b/include/swift/Threading/Impl/Darwin.h @@ -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 +#include +#include + +#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() +#include +#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 diff --git a/include/swift/Threading/Impl/Linux.h b/include/swift/Threading/Impl/Linux.h new file mode 100644 index 0000000000000..3f51914583ce9 --- /dev/null +++ b/include/swift/Threading/Impl/Linux.h @@ -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 +#include +#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 flag; + linux::ulock_t lock; +}; + +using once_t = std::atomic; + +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 diff --git a/include/swift/Threading/Impl/Linux/ulock.h b/include/swift/Threading/Impl/Linux/ulock.h new file mode 100644 index 0000000000000..04cfba9205877 --- /dev/null +++ b/include/swift/Threading/Impl/Linux/ulock.h @@ -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 +#include +#include +#include +#include + +#include +#include + +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 diff --git a/include/swift/Threading/Impl/Nothreads.h b/include/swift/Threading/Impl/Nothreads.h new file mode 100644 index 0000000000000..a29bace201e9d --- /dev/null +++ b/include/swift/Threading/Impl/Nothreads.h @@ -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 diff --git a/include/swift/Threading/Impl/Pthreads.h b/include/swift/Threading/Impl/Pthreads.h new file mode 100644 index 0000000000000..85c95296ad584 --- /dev/null +++ b/include/swift/Threading/Impl/Pthreads.h @@ -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 +#include +#include +#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; + +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 diff --git a/include/swift/Threading/Impl/Win32.h b/include/swift/Threading/Impl/Win32.h new file mode 100644 index 0000000000000..f395327c7e2b0 --- /dev/null +++ b/include/swift/Threading/Impl/Win32.h @@ -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 + +#include + +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 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 diff --git a/include/swift/Runtime/Mutex.h b/include/swift/Threading/Mutex.h similarity index 57% rename from include/swift/Runtime/Mutex.h rename to include/swift/Threading/Mutex.h index 1a539798a4010..13cd8e9cd6961 100644 --- a/include/swift/Runtime/Mutex.h +++ b/include/swift/Threading/Mutex.h @@ -1,8 +1,8 @@ -//===--- Mutex.h - Mutex ----------------------------------------*- C++ -*-===// +//===--- Mutex.h - Mutex and ScopedLock ----------------------- -*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// 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 @@ -10,44 +10,23 @@ // //===----------------------------------------------------------------------===// // -// Mutex and Scoped lock abstractions for use in Swift runtime. -// -// We intentionally do not provide a condition-variable abstraction. -// Traditional condition-variable interfaces are subject to unavoidable -// priority inversions, as well as making poor use of threads. -// Prefer AtomicWaitQueue. -// -// We also intentionally avoid read/write locks. It's difficult to implement a -// performant and fair read/write lock, and indeed many common implementations -// rely on condition variables, which, again, are subject to unavoidable -// priority inversions. +// Provides a system-independent Mutex abstraction, as well as some +// related utilities like ScopedLock. // //===----------------------------------------------------------------------===// -#ifndef SWIFT_RUNTIME_MUTEX_H -#define SWIFT_RUNTIME_MUTEX_H +#ifndef SWIFT_THREADING_MUTEX_H +#define SWIFT_THREADING_MUTEX_H #include #include -#if __has_include() -#include -#endif - -#if SWIFT_STDLIB_THREADING_NONE -#include "swift/Runtime/MutexSingleThreaded.h" -#elif SWIFT_STDLIB_THREADING_PTHREADS || SWIFT_STDLIB_THREADING_DARWIN -#include "swift/Runtime/MutexPThread.h" -#elif SWIFT_STDLIB_THREADING_WIN32 -#include "swift/Runtime/MutexWin32.h" -#elif SWIFT_STDLIB_THREADING_C11 -#include "swift/Runtime/MutexC11.h" -#else -#error "Implement equivalent of MutexPThread.h/cpp for your platform." -#endif +#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 class ScopedLockT { @@ -78,6 +57,8 @@ template class ScopedLockT { 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 @@ -97,9 +78,9 @@ class Mutex { /// 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) { - MutexPlatformHelper::init(Handle, checked); + threading_impl::mutex_init(Handle, checked); } - ~Mutex() { MutexPlatformHelper::destroy(Handle); } + ~Mutex() { threading_impl::mutex_destroy(Handle); } /// The lock() method has the following properties: /// - Behaves as an atomic operation. @@ -110,7 +91,7 @@ class Mutex { /// - 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() { MutexPlatformHelper::lock(Handle); } + void lock() { threading_impl::mutex_lock(Handle); } /// The unlock() method has the following properties: /// - Behaves as an atomic operation. @@ -120,7 +101,7 @@ class Mutex { /// - 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() { MutexPlatformHelper::unlock(Handle); } + void unlock() { threading_impl::mutex_unlock(Handle); } /// The try_lock() method has the following properties: /// - Behaves as an atomic operation. @@ -134,7 +115,7 @@ class Mutex { /// - 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 MutexPlatformHelper::try_lock(Handle); } + 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. @@ -167,38 +148,50 @@ class Mutex { /// Precondition: Mutex locked by this thread, undefined otherwise. typedef ScopedLockT ScopedUnlock; -private: - MutexHandle Handle; +protected: + threading_impl::mutex_handle Handle; }; -/// A static allocation variant of Mutex. +/// An unsafe variant of the above (for use in the error handling path) /// -/// Use Mutex instead unless you need static allocation. -class StaticMutex { +/// This is used to ensure that we can't infinitely recurse if the mutex +/// itself generates errors. +class UnsafeMutex : public Mutex { +public: + UnsafeMutex() : Mutex() {} - StaticMutex(const StaticMutex &) = delete; - StaticMutex &operator=(const StaticMutex &) = delete; - StaticMutex(StaticMutex &&) = delete; - StaticMutex &operator=(StaticMutex &&) = delete; + 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: -#if SWIFT_MUTEX_SUPPORTS_CONSTEXPR - constexpr -#endif - StaticMutex() - : Handle(MutexPlatformHelper::staticInit()) { - } + 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() { MutexPlatformHelper::lock(Handle); } + void lock() { threading_impl::lazy_mutex_lock(Handle); } /// See Mutex::unlock - void unlock() { MutexPlatformHelper::unlock(Handle); } + void unlock() { threading_impl::lazy_mutex_unlock(Handle); } /// See Mutex::try_lock - bool try_lock() { return MutexPlatformHelper::try_lock(Handle); } + bool try_lock() { return threading_impl::lazy_mutex_try_lock(Handle); } - /// See Mutex::lock + /// See Mutex::withLock template auto withLock(CriticalSection &&criticalSection) -> decltype(std::forward(criticalSection)()) { @@ -210,74 +203,28 @@ class StaticMutex { /// and unlocks it on destruction. /// /// Precondition: Mutex unlocked by this thread, undefined otherwise. - typedef ScopedLockT ScopedLock; + typedef ScopedLockT 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 ScopedUnlock; + typedef ScopedLockT ScopedUnlock; -private: - MutexHandle Handle; +protected: + threading_impl::lazy_mutex_handle Handle; }; -/// A Mutex object that supports `BasicLockable` C++ concepts. It is -/// considered -/// unsafe to use because it doesn't do any error checking. It is only for -/// use in pathways that deal with reporting fatalErrors to avoid the -/// potential -/// for recursive fatalErrors that could happen if you used Mutex. +/// An unsafe variant of the above (for use in the error handling path) /// -/// Always use Mutex, unless in the above mentioned error pathway situation. -class StaticUnsafeMutex { - - StaticUnsafeMutex(const StaticUnsafeMutex &) = delete; - StaticUnsafeMutex &operator=(const StaticUnsafeMutex &) = delete; - StaticUnsafeMutex(StaticUnsafeMutex &&) = delete; - StaticUnsafeMutex &operator=(StaticUnsafeMutex &&) = delete; - +/// This is used to ensure that we can't infinitely recurse if the mutex +/// itself generates errors. +class LazyUnsafeMutex : public LazyMutex { public: -#if SWIFT_MUTEX_SUPPORTS_CONSTEXPR - constexpr -#endif - StaticUnsafeMutex() - : Handle(MutexPlatformHelper::staticInit()) { - } - - /// 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). - /// - Ignores errors that may happen, undefined when an error happens. - void lock() { MutexPlatformHelper::unsafeLock(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. - /// - Ignores errors that may happen, undefined when an error happens. - void unlock() { MutexPlatformHelper::unsafeUnlock(Handle); } + constexpr LazyUnsafeMutex() : LazyMutex() {} - template - auto withLock(CriticalSection &&criticalSection) - -> decltype(std::forward(criticalSection)()) { - ScopedLock guard(*this); - return std::forward(criticalSection)(); - } - - typedef ScopedLockT ScopedLock; - typedef ScopedLockT ScopedUnlock; - -private: - MutexHandle Handle; + 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 @@ -327,25 +274,6 @@ class IndirectMutex { using SmallMutex = std::conditional_t; -// Enforce literal requirements for static variants. -#if SWIFT_MUTEX_SUPPORTS_CONSTEXPR -static_assert(std::is_literal_type::value, - "StaticMutex must be literal type"); -static_assert(std::is_literal_type::value, - "StaticUnsafeMutex must be literal type"); -#else -// Your platform doesn't currently support statically allocated Mutex -// you will possibly see global-constructors warnings -#endif - -#if SWIFT_CONDITION_SUPPORTS_CONSTEXPR -static_assert(std::is_literal_type::value, - "StaticConditionVariable must be literal type"); -#else -// Your platform doesn't currently support statically allocated ConditionVar -// you will possibly see global-constructors warnings -#endif - -} - -#endif +} // namespace swift + +#endif // SWIFT_THREADING_MUTEX_H diff --git a/include/swift/Threading/Once.h b/include/swift/Threading/Once.h new file mode 100644 index 0000000000000..056dce7c2f348 --- /dev/null +++ b/include/swift/Threading/Once.h @@ -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 diff --git a/include/swift/Threading/Thread.h b/include/swift/Threading/Thread.h new file mode 100644 index 0000000000000..063cf77b0b63d --- /dev/null +++ b/include/swift/Threading/Thread.h @@ -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 diff --git a/include/swift/Threading/ThreadLocalStorage.h b/include/swift/Threading/ThreadLocalStorage.h new file mode 100644 index 0000000000000..adf8f4a4ea506 --- /dev/null +++ b/include/swift/Threading/ThreadLocalStorage.h @@ -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 + +#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(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(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::value, \ + "ThreadLocal values must be trivially copyable"); \ + static_assert(std::is_trivially_destructible::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 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(ctx); + tls_alloc(*pkey, nullptr); + }, &key); + return key; + } +}; + +// A type representing a constant TLS key, for use on platforms +// that provide reserved keys. +template +class ConstantThreadLocalKey { +public: + tls_key getKey() { return constantKey; } +}; + +template +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 +#elif SWIFT_THREADING_USE_RESERVED_TLS_KEYS +#define SWIFT_THREAD_LOCAL_TYPE(TYPE, KEY) \ + swift::ThreadLocal> +#else +#define SWIFT_THREAD_LOCAL_TYPE(TYPE, KEY) \ + swift::ThreadLocal +#endif + + +#endif // SWIFT_THREADING_THREADLOCALSTORAGE_H diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 71f673185e08d..a5edfe8773a17 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -50,3 +50,5 @@ add_subdirectory(SymbolGraphGen) add_subdirectory(Syntax) add_subdirectory(SyntaxParse) add_subdirectory(TBDGen) +add_subdirectory(Threading) + diff --git a/lib/Threading/C11.cpp b/lib/Threading/C11.cpp new file mode 100644 index 0000000000000..2a54d42e7ac78 --- /dev/null +++ b/lib/Threading/C11.cpp @@ -0,0 +1,103 @@ +//==--- C11.cpp - 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 +// +//===----------------------------------------------------------------------===// + +#if SWIFT_THREADING_C11 + +#include "swift/Threading/Errors.h" +#include "swift/Threading/Impl/C11.h" + +namespace { + +#pragma clang diagnostic push +#pragma GCC diagnostic ignored "-Wglobal-constructors" + +class C11ThreadingHelper { +private: + thrd_t mainThread_; + mut_t onceMutex_; + cnd_t onceCond_; + +public: + C11ThreadingHelper() { + mainThread_ = thrd_current(); + SWIFT_C11THREADS_CHECK(::mtx_init(&onceMutex_, ::mtx_plain)); + SWIFT_C11THREADS_CHECK(::cnd_init(&onceCond_)); + } + + thrd_t main_thread() const { return mainThread_; } + + void once_lock() { + SWIFT_C11THREADS_CHECK(mtx_lock(&onceMutex_)); + } + void once_unlock() { + SWIFT_C11THREADS_CHECK(mtx_unlock(&onceMutex_)); + } + void once_broadcast() { + SWIFT_C11THREADS_CHECK(cnd_broadcast(&onceCond_)); + } + void once_wait() { + SWIFT_C11THREADS_CHECK(mtx_lock(&onceMutex_)); + SWIFT_C11THREADS_CHECK(cnd_wait(&onceCond_, &onceMutex_)); + SWIFT_C11THREADS_CHECK(mtx_unlock(&onceMutex_)); + } +}; + +C11ThreadingHelper helper; + +#pragma clang diagnostic pop + +} + +using namespace swift; +using namespace threading_impl; + +thread_id +swift::threading_impl::thread_get_main() { + return helper.main_thread(); +} + +bool +swift::threading_impl::thread_is_main() { + return thrd_equal(thrd_current(), thread_get_main()); +} + +void +swift::threading_impl::once_slow(once_t &predicate, + void (*fn)(void *), + void *context) { + if (::atomic_compare_exchange_strong_explicit(&predicate, + &(int){ 0 }, + 1, + ::memory_order_relaxed, + ::memory_order_relaxed)) { + fn(context); + + ::atomic_store_explicit(&predicate, -1, ::memory_order_release); + + helper.once_lock(); + helper.once_unlock(); + helper.once_broadcast(); + return; + } + + helper.once_lock(); + while (::atomic_load_explicit(&predicate, memory_order_acquire) >= 0) { + helper.once_wait(); + } + helper.once_unlock(); +} + +#endif // SWIFT_THREADING_C11 diff --git a/lib/Threading/CMakeLists.txt b/lib/Threading/CMakeLists.txt new file mode 100644 index 0000000000000..b0b574e634720 --- /dev/null +++ b/lib/Threading/CMakeLists.txt @@ -0,0 +1,5 @@ +add_swift_host_library(swiftThreading STATIC + C11.cpp + Nothreads.cpp + Pthreads.cpp + Win32.cpp) diff --git a/lib/Threading/Linux.cpp b/lib/Threading/Linux.cpp new file mode 100644 index 0000000000000..0536ddc743bec --- /dev/null +++ b/lib/Threading/Linux.cpp @@ -0,0 +1,67 @@ +//==--- Linux.cpp - 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 +// +//===----------------------------------------------------------------------===// + +#if SWIFT_THREADING_LINUX + +#include "swift/Threading/Errors.h" +#include "swift/Threading/Impl/Linux.h" + +namespace { + +#pragma clang diagnostic push +#pragma GCC diagnostic ignored "-Wglobal-constructors" + +class MainThreadRememberer { +private: + pthread_t mainThread_; +public: + MainThreadRememberer() { mainThread_ = pthread_self(); } + + pthread_t main_thread() const { return mainThread_; } +}; + +MainThreadRememberer rememberer; + +#pragma clang diagnostic pop + +} + +using namespace swift; +using namespace threading_impl; + +thread_id +swift::threading_impl::thread_get_main() { + return rememberer.main_thread(); +} + +bool +swift::threading_impl::thread_is_main() { + return pthread_equal(pthread_self(), thread_get_main()); +} + +void +swift::threading_impl::once_slow(once_t &predicate, + void (*fn)(void *), + void *context) { + linux::ulock_lock(&predicate.lock); + if (predicate.flag.load(std::memory_order_acquire) == 0) { + fn(context); + predicate.flag.store(-1, std::memory_order_release); + } + linux::ulock_unlock(&predicate.lock); +} + +#endif // SWIFT_THREADING_PTHREADS diff --git a/lib/Threading/Nothreads.cpp b/lib/Threading/Nothreads.cpp new file mode 100644 index 0000000000000..60cfe3071e601 --- /dev/null +++ b/lib/Threading/Nothreads.cpp @@ -0,0 +1,21 @@ +//==--- Nothreads.cpp - 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 +// +//===----------------------------------------------------------------------===// + +#if SWIFT_THREADING_NONE + +#include "swift/Threading/Impl/Nothreads.h" + +#endif // SWIFT_THREADING_NONE diff --git a/lib/Threading/Pthreads.cpp b/lib/Threading/Pthreads.cpp new file mode 100644 index 0000000000000..a77b4819d0bb1 --- /dev/null +++ b/lib/Threading/Pthreads.cpp @@ -0,0 +1,82 @@ +//==--- Pthreads.cpp - 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 +// +//===----------------------------------------------------------------------===// + +#if SWIFT_THREADING_PTHREADS + +#include "swift/Threading/Errors.h" +#include "swift/Threading/Impl/Pthreads.h" + +namespace { + +#pragma clang diagnostic push +#pragma GCC diagnostic ignored "-Wglobal-constructors" + +class MainThreadRememberer { +private: + pthread_t mainThread_; +public: + MainThreadRememberer() { mainThread_ = pthread_self(); } + + pthread_t main_thread() const { return mainThread_; } +}; + +MainThreadRememberer rememberer; +pthread_mutex_t onceMutex = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t onceCond = PTHREAD_COND_INITIALIZER; + +#pragma clang diagnostic pop + +} + +using namespace swift; +using namespace threading_impl; + +thread_id +swift::threading_impl::thread_get_main() { + return rememberer.main_thread(); +} + +bool +swift::threading_impl::thread_is_main() { + return pthread_equal(pthread_self(), thread_get_main()); +} + +void +swift::threading_impl::once_slow(once_t &predicate, + void (*fn)(void *), + void *context) { + std::int64_t zero = 0; + if (predicate.compare_exchange_strong(zero, (std::int64_t)1, + std::memory_order_relaxed, + std::memory_order_relaxed)) { + fn(context); + + predicate.store((std::int64_t)-1, std::memory_order_release); + + pthread_mutex_lock(&onceMutex); + pthread_mutex_unlock(&onceMutex); + pthread_cond_broadcast(&onceCond); + return; + } + + pthread_mutex_lock(&onceMutex); + while (predicate.load(std::memory_order_acquire) >= (std::int64_t)0) { + pthread_cond_wait(&onceCond); + } + pthread_mutex_unlock(&onceMutex); +} + +#endif // SWIFT_THREADING_PTHREADS diff --git a/lib/Threading/Win32.cpp b/lib/Threading/Win32.cpp new file mode 100644 index 0000000000000..6e7f4a9d8dbee --- /dev/null +++ b/lib/Threading/Win32.cpp @@ -0,0 +1,103 @@ +//==--- Win32.cpp - 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 +// +//===----------------------------------------------------------------------===// + +#if SWIFT_THREADING_WIN32 + +#include "swift/Threading/Errors.h" +#include "swift/Threading/Impl/Win32.h" + +namespace { + +#pragma clang diagnostic push +#pragma GCC diagnostic ignored "-Wglobal-constructors" + +class MainThreadRememberer { +private: + DWORD dwMainThread_; +public: + MainThreadRememberer() { dwMainThread_ = ::GetCurrentThreadId(); } + + DWORD main_thread() const { return dwMainThread_; } +}; + +MainThreadRememberer rememberer; + +// Prior to Windows 8, we have to use a global lock +#if _WIN32_WINNT < 0x0602 +SRWLOCK onceMutex = SRWLOCK_INIT; +CONDITION_VARIABLE onceCond = CONDITION_VARIABLE_INIT; +#endif + +#pragma clang diagnostic pop + +} + +using namespace swift; +using namespace threading_impl; + +thread_id +swift::threading_impl::thread_get_main() { + return rememberer.main_thread(); +} + +bool +swift::threading_impl::thread_is_main() { + return ::GetCurrentThreadId() == thread_get_main(); +} + +void +swift::threading_impl::once_slow(once_t &predicate, + void (*fn)(void *), + void *context) { + std::int64_t expected = 0; + if (predicate.compare_exchange_strong(expected, (std::int64_t)1, + std::memory_order_relaxed, + std::memory_order_relaxed)) { + fn(context); + + predicate.store((std::int64_t)-1, std::memory_order_release); + +#if _WIN32_WINNT >= 0x0602 + // On Windows 8, use WakeByAddressAll() to wake waiters + WakeByAddressAll(&predicate); +#else + // On Windows 7 and earlier, we use a global lock and condition variable; + // this will wake *all* waiters on *all* onces, which might result in a + // thundering herd problem, but it's the best we can do. + AcquireSRWLockExclusive(&onceMutex); + WakeAllConditionVariable(&onceCond); + ReleaseSRWLockExclusive(&onceMutex); +#endif + return; + } + +#if _WIN32_WINNT >= 0x0602 + // On Windows 8, loop waiting on the address until it changes to -1 + while (expected >= 0) { + WaitOnAddress(&predicate, &expected, 8, INFINITE); + expected = predicate.load(std::memory_order_acquire); + } +#else + // On Windows 7 and earlier, wait on the global condition variable + AcquireSRWLockExclusive(&onceMutex); + while (predicate.load(std::memory_order_acquire) >= 0) { + SleepConditionVariableSRW(&onceCond, &onceMutex, INFINITE, 0); + } + ReleaseSRWLockExclusive(&onceMutex); +#endif +} + +#endif // SWIFT_THREADING_WIN32 diff --git a/stdlib/cmake/modules/AddSwiftStdlib.cmake b/stdlib/cmake/modules/AddSwiftStdlib.cmake index 945950f8f2b2b..36463c7c77aa1 100644 --- a/stdlib/cmake/modules/AddSwiftStdlib.cmake +++ b/stdlib/cmake/modules/AddSwiftStdlib.cmake @@ -355,8 +355,8 @@ function(_add_target_variant_c_compile_flags) list(APPEND result "-DSWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY") endif() - threading_package_name(_threading_package) - list(APPEND result "-DSWIFT_STDLIB_THREADING_${_threading_package}") + threading_package_name("${CFLAGS_SDK}" _threading_package) + list(APPEND result "-DSWIFT_THREADING_${_threading_package}") if(SWIFT_STDLIB_OS_VERSIONING) list(APPEND result "-DSWIFT_RUNTIME_OS_VERSIONING") diff --git a/stdlib/cmake/modules/StdlibOptions.cmake b/stdlib/cmake/modules/StdlibOptions.cmake index 69be588bbcbd3..04e5e6c842e84 100644 --- a/stdlib/cmake/modules/StdlibOptions.cmake +++ b/stdlib/cmake/modules/StdlibOptions.cmake @@ -6,6 +6,19 @@ include(${CMAKE_CURRENT_LIST_DIR}/../../../cmake/modules/Threading.cmake) precondition(SWIFT_HOST_VARIANT_SDK) precondition(SWIFT_DARWIN_PLATFORMS) +# +----------------------------------------------------------------------+ +# | | +# | NOTE: It makes no sense setting defaults here on the basis of | +# | SWIFT_HOST_VARIANT_SDK, because the stdlib is a *TARGET* | +# | library, not a host library. | +# | | +# | Rather, if you have a default to set, you need to do that | +# | in AddSwiftStdlib.cmake, in an appropriate place, | +# | likely on the basis of CFLAGS_SDK, SWIFTLIB_SINGLE_SDK or | +# | similar. | +# | | +# +----------------------------------------------------------------------+ + if("${SWIFT_HOST_VARIANT_SDK}" MATCHES "CYGWIN") set(SWIFT_STDLIB_SUPPORTS_BACKTRACE_REPORTING_default FALSE) elseif("${SWIFT_HOST_VARIANT_SDK}" MATCHES "HAIKU") @@ -178,6 +191,16 @@ else() set(SWIFT_CONCURRENCY_GLOBAL_EXECUTOR_default "dispatch") endif() +include(Threading) + +threading_package_default("${SWIFT_HOST_VARIANT_SDK}" + SWIFT_THREADING_PACKAGE_default) + +set(SWIFT_THREADING_PACKAGE "${SWIFT_THREADING_PACKAGE_default}" + CACHE STRING + "The threading package to use. Must be one of 'none', 'pthreads', + 'darwin', 'linux', 'win32', 'c11'.") + set(SWIFT_CONCURRENCY_GLOBAL_EXECUTOR "${SWIFT_CONCURRENCY_GLOBAL_EXECUTOR_default}" CACHE STRING "Build the concurrency library to use the given global executor (options: dispatch, singlethreaded, hooked)") diff --git a/stdlib/cmake/modules/SwiftSource.cmake b/stdlib/cmake/modules/SwiftSource.cmake index 18eecad5624d0..c5c6366bcb5ec 100644 --- a/stdlib/cmake/modules/SwiftSource.cmake +++ b/stdlib/cmake/modules/SwiftSource.cmake @@ -327,8 +327,8 @@ function(_add_target_variant_swift_compile_flags list(APPEND result "-D" "SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY") endif() - threading_package_name(_threading_package) - list(APPEND result "-D" "SWIFT_STDLIB_THREADING_${_threading_package}") + threading_package_name("${sdk}" _threading_package) + list(APPEND result "-D" "SWIFT_THREADING_${_threading_package}") set("${result_var_name}" "${result}" PARENT_SCOPE) endfunction() @@ -483,7 +483,7 @@ function(_compile_swift_files list(APPEND swift_flags "-Xfrontend" "-library-level" "-Xfrontend" "api") endif() - if(SWIFT_STDLIB_THREADING_PACKAGE STREQUAL "none") + if(SWIFT_THREADING_PACKAGE STREQUAL "none") list(APPEND swift_flags "-Xfrontend" "-assume-single-threaded") endif() diff --git a/stdlib/public/CMakeLists.txt b/stdlib/public/CMakeLists.txt index 73e8183d4a78e..c122134e92baa 100644 --- a/stdlib/public/CMakeLists.txt +++ b/stdlib/public/CMakeLists.txt @@ -64,6 +64,7 @@ endif() add_subdirectory(SwiftShims) add_subdirectory(CommandLineSupport) +add_subdirectory(Threading) # This static library is shared across swiftCore and swiftReflection if(SWIFT_BUILD_STDLIB OR SWIFT_BUILD_REMOTE_MIRROR) diff --git a/stdlib/public/Concurrency/Actor.cpp b/stdlib/public/Concurrency/Actor.cpp index cf594ba10f855..0820a853fef1d 100644 --- a/stdlib/public/Concurrency/Actor.cpp +++ b/stdlib/public/Concurrency/Actor.cpp @@ -31,11 +31,10 @@ #include "swift/Runtime/Atomic.h" #include "swift/Runtime/AccessibleFunction.h" #include "swift/Runtime/Casting.h" -#include "swift/Runtime/Once.h" -#include "swift/Runtime/Mutex.h" -#include "swift/Runtime/ThreadLocal.h" -#include "swift/Runtime/ThreadLocalStorage.h" #include "swift/Runtime/DispatchShims.h" +#include "swift/Threading/Once.h" +#include "swift/Threading/Mutex.h" +#include "swift/Threading/ThreadLocalStorage.h" #include "swift/ABI/Task.h" #include "swift/ABI/Actor.h" #include "swift/Basic/ListMerger.h" @@ -126,9 +125,9 @@ class ExecutorTrackingInfo { /// the right executor. It would make sense for that to be a /// separate thread-local variable (or whatever is most efficient /// on the target platform). - static SWIFT_RUNTIME_DECLARE_THREAD_LOCAL( - Pointer, ActiveInfoInThread, - SWIFT_CONCURRENCY_EXECUTOR_TRACKING_INFO_KEY); + static SWIFT_THREAD_LOCAL_TYPE( + Pointer, + SWIFT_CONCURRENCY_EXECUTOR_TRACKING_INFO_KEY) ActiveInfoInThread; /// The active executor. ExecutorRef ActiveExecutor = ExecutorRef::generic(); @@ -194,8 +193,8 @@ class ExecutorTrackingInfo { class ActiveTask { /// A thread-local variable pointing to the active tracking /// information about the current thread, if any. - static SWIFT_RUNTIME_DECLARE_THREAD_LOCAL(Pointer, Value, - SWIFT_CONCURRENCY_TASK_KEY); + static SWIFT_THREAD_LOCAL_TYPE(Pointer, + SWIFT_CONCURRENCY_TASK_KEY) Value; public: static void set(AsyncTask *task) { Value.set(task); } @@ -203,15 +202,14 @@ class ActiveTask { }; /// Define the thread-locals. -SWIFT_RUNTIME_DECLARE_THREAD_LOCAL( +SWIFT_THREAD_LOCAL_TYPE( Pointer, - ActiveTask::Value, - SWIFT_CONCURRENCY_TASK_KEY); + SWIFT_CONCURRENCY_TASK_KEY) ActiveTask::Value; -SWIFT_RUNTIME_DECLARE_THREAD_LOCAL( +SWIFT_THREAD_LOCAL_TYPE( Pointer, - ExecutorTrackingInfo::ActiveInfoInThread, - SWIFT_CONCURRENCY_EXECUTOR_TRACKING_INFO_KEY); + SWIFT_CONCURRENCY_EXECUTOR_TRACKING_INFO_KEY) +ExecutorTrackingInfo::ActiveInfoInThread; } // end anonymous namespace @@ -351,8 +349,8 @@ void swift::swift_task_reportUnexpectedExecutor( const unsigned char *file, uintptr_t fileLength, bool fileIsASCII, uintptr_t line, ExecutorRef executor) { // Make sure we have an appropriate log level. - static swift_once_t logLevelToken; - swift_once(&logLevelToken, checkUnexpectedExecutorLogLevel, nullptr); + static swift::once_t logLevelToken; + swift::once(logLevelToken, checkUnexpectedExecutorLogLevel, nullptr); bool isFatalError = false; switch (unexpectedExecutorLogLevel) { diff --git a/stdlib/public/Concurrency/AsyncLet.cpp b/stdlib/public/Concurrency/AsyncLet.cpp index eb2d91fbcfadf..4d24a6e8aa835 100644 --- a/stdlib/public/Concurrency/AsyncLet.cpp +++ b/stdlib/public/Concurrency/AsyncLet.cpp @@ -20,8 +20,9 @@ #include "swift/ABI/Metadata.h" #include "swift/ABI/Task.h" #include "swift/ABI/TaskOptions.h" -#include "swift/Runtime/Mutex.h" +#include "swift/Runtime/Heap.h" #include "swift/Runtime/HeapObject.h" +#include "swift/Threading/Mutex.h" #include "llvm/ADT/PointerIntPair.h" #include "TaskPrivate.h" #include "Debug.h" diff --git a/stdlib/public/Concurrency/AsyncStream.cpp b/stdlib/public/Concurrency/AsyncStream.cpp index 14b7caf0ad463..d6ada4cabcbec 100644 --- a/stdlib/public/Concurrency/AsyncStream.cpp +++ b/stdlib/public/Concurrency/AsyncStream.cpp @@ -10,30 +10,32 @@ // //===----------------------------------------------------------------------===// -#include "swift/Runtime/Mutex.h" +#include + +#include "swift/Threading/Mutex.h" namespace swift { // return the size in words for the given mutex primitive extern "C" size_t _swift_async_stream_lock_size() { - size_t words = sizeof(MutexHandle) / sizeof(void *); + size_t words = sizeof(Mutex) / sizeof(void *); if (words < 1) { return 1; } return words; } extern "C" -void _swift_async_stream_lock_init(MutexHandle &lock) { - MutexPlatformHelper::init(lock); +void _swift_async_stream_lock_init(Mutex &lock) { + new (&lock) Mutex(); } extern "C" -void _swift_async_stream_lock_lock(MutexHandle &lock) { - MutexPlatformHelper::lock(lock); +void _swift_async_stream_lock_lock(Mutex &lock) { + lock.lock(); } extern "C" -void _swift_async_stream_lock_unlock(MutexHandle &lock) { - MutexPlatformHelper::unlock(lock); +void _swift_async_stream_lock_unlock(Mutex &lock) { + lock.unlock(); } } diff --git a/stdlib/public/Concurrency/CMakeLists.txt b/stdlib/public/Concurrency/CMakeLists.txt index 06752c398d077..4251e1ccf07cc 100644 --- a/stdlib/public/Concurrency/CMakeLists.txt +++ b/stdlib/public/Concurrency/CMakeLists.txt @@ -112,7 +112,6 @@ add_swift_target_library(swift_Concurrency ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} I TaskSleep.swift ThreadSanitizer.cpp TracingSignpost.cpp - Mutex.cpp AsyncStreamBuffer.swift AsyncStream.swift AsyncThrowingStream.swift @@ -128,6 +127,8 @@ add_swift_target_library(swift_Concurrency ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} I SWIFT_MODULE_DEPENDS_HAIKU Glibc SWIFT_MODULE_DEPENDS_WINDOWS CRT + PRIVATE_LINK_LIBRARIES swiftThreading + LINK_LIBRARIES ${swift_concurrency_link_libraries} C_COMPILE_FLAGS diff --git a/stdlib/public/Concurrency/DispatchGlobalExecutor.inc b/stdlib/public/Concurrency/DispatchGlobalExecutor.inc index d5613f804cd48..511e4b96ba958 100644 --- a/stdlib/public/Concurrency/DispatchGlobalExecutor.inc +++ b/stdlib/public/Concurrency/DispatchGlobalExecutor.inc @@ -116,7 +116,7 @@ extern "C" void dispatch_queue_set_width(dispatch_queue_t dq, long width); static dispatch_queue_t getGlobalQueue(JobPriority priority) { size_t numericPriority = static_cast(priority); if (numericPriority >= globalQueueCacheCount) - swift_Concurrency_fatalError(0, "invalid job priority %#zx"); + swift_Concurrency_fatalError(0, "invalid job priority %#zx", numericPriority); #ifdef SWIFT_CONCURRENCY_BACK_DEPLOYMENT std::memory_order loadOrder = std::memory_order_acquire; diff --git a/stdlib/public/Concurrency/Error.cpp b/stdlib/public/Concurrency/Error.cpp index 2fbe4b0865c0b..0afb619e2cee5 100644 --- a/stdlib/public/Concurrency/Error.cpp +++ b/stdlib/public/Concurrency/Error.cpp @@ -10,10 +10,35 @@ // //===----------------------------------------------------------------------===// +#include "swift/Threading/Errors.h" +#include + #include "Error.h" // swift::fatalError is not exported from libswiftCore and not shared, so define another // internal function instead. -SWIFT_NORETURN void swift::swift_Concurrency_fatalError(uint32_t flags, const char *format, ...) { +SWIFT_NORETURN +SWIFT_VFORMAT(2) +void swift::swift_Concurrency_fatalErrorv(uint32_t flags, const char *format, va_list val) { + vfprintf(stderr, format, val); abort(); } + +SWIFT_NORETURN +SWIFT_FORMAT(2, 3) +void swift::swift_Concurrency_fatalError(uint32_t flags, const char *format, ...) { + va_list val; + + va_start(val, format); + swift_Concurrency_fatalErrorv(flags, format, val); +} + +// Handle fatal errors from the threading library +SWIFT_ATTRIBUTE_NORETURN +SWIFT_FORMAT(1, 2) +void swift::threading::fatal(const char *format, ...) { + va_list val; + + va_start(val, format); + swift_Concurrency_fatalErrorv(0, format, val); +} diff --git a/stdlib/public/Concurrency/Error.h b/stdlib/public/Concurrency/Error.h index 1e0fd3ffd339c..20b96467fc896 100644 --- a/stdlib/public/Concurrency/Error.h +++ b/stdlib/public/Concurrency/Error.h @@ -17,13 +17,17 @@ #ifndef SWIFT_CONCURRENCY_ERRORS_H #define SWIFT_CONCURRENCY_ERRORS_H +#include "swift/Basic/Compiler.h" + #include "../SwiftShims/Visibility.h" #include -#include +#include +#include namespace swift { -SWIFT_NORETURN void swift_Concurrency_fatalError(uint32_t flags, const char *format, ...); +SWIFT_NORETURN SWIFT_FORMAT(2, 3) void swift_Concurrency_fatalError(uint32_t flags, const char *format, ...); +SWIFT_NORETURN SWIFT_VFORMAT(2) void swift_Concurrency_fatalErrorv(uint32_t flags, const char *format, va_list val); } // namespace swift diff --git a/stdlib/public/Concurrency/Mutex.cpp b/stdlib/public/Concurrency/Mutex.cpp deleted file mode 100644 index 46a311d85529c..0000000000000 --- a/stdlib/public/Concurrency/Mutex.cpp +++ /dev/null @@ -1,25 +0,0 @@ -//===--- Mutex.cpp - Mutex support code -----------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -#include "Error.h" - -#define SWIFT_FATAL_ERROR swift_Concurrency_fatalError - -// Include the runtime's mutex support code. -// FIXME: figure out some reasonable way to share this stuff - -#include "../runtime/MutexPThread.cpp" -#include "../runtime/MutexWin32.cpp" -#include "../runtime/MutexC11.cpp" -#ifdef SWIFT_STDLIB_THREADING_NONE - #include "swift/Runtime/MutexSingleThreaded.h" -#endif diff --git a/stdlib/public/Concurrency/Task.cpp b/stdlib/public/Concurrency/Task.cpp index 6baeaaff94bfa..74282940d253a 100644 --- a/stdlib/public/Concurrency/Task.cpp +++ b/stdlib/public/Concurrency/Task.cpp @@ -20,8 +20,8 @@ #include "swift/ABI/TaskLocal.h" #include "swift/ABI/TaskOptions.h" #include "swift/ABI/Metadata.h" -#include "swift/Runtime/Mutex.h" #include "swift/Runtime/HeapObject.h" +#include "swift/Threading/Mutex.h" #include "TaskGroupPrivate.h" #include "TaskPrivate.h" #include "Tracing.h" diff --git a/stdlib/public/Concurrency/TaskGroup.cpp b/stdlib/public/Concurrency/TaskGroup.cpp index e8f1cb6f80369..6bbb6454bad5f 100644 --- a/stdlib/public/Concurrency/TaskGroup.cpp +++ b/stdlib/public/Concurrency/TaskGroup.cpp @@ -26,8 +26,8 @@ #include "swift/Basic/STLExtras.h" #include "swift/Runtime/Concurrency.h" #include "swift/Runtime/Config.h" -#include "swift/Runtime/Mutex.h" #include "swift/Runtime/HeapObject.h" +#include "swift/Threading/Mutex.h" #include "Debug.h" #include "bitset" #include "string" diff --git a/stdlib/public/Concurrency/TaskLocal.cpp b/stdlib/public/Concurrency/TaskLocal.cpp index dec28b157a012..05b2d9b10f713 100644 --- a/stdlib/public/Concurrency/TaskLocal.cpp +++ b/stdlib/public/Concurrency/TaskLocal.cpp @@ -13,11 +13,8 @@ #include "../CompatibilityOverride/CompatibilityOverride.h" #include "swift/Runtime/Atomic.h" #include "swift/Runtime/Casting.h" -#include "swift/Runtime/Once.h" -#include "swift/Runtime/Mutex.h" #include "swift/Runtime/Concurrency.h" -#include "swift/Runtime/ThreadLocal.h" -#include "swift/Runtime/ThreadLocalStorage.h" +#include "swift/Threading/ThreadLocalStorage.h" #include "swift/ABI/TaskLocal.h" #include "swift/ABI/Task.h" #include "swift/ABI/Actor.h" @@ -59,9 +56,9 @@ template struct Pointer { /// THIS IS RUNTIME INTERNAL AND NOT ABI. class FallbackTaskLocalStorage { - static SWIFT_RUNTIME_DECLARE_THREAD_LOCAL( - Pointer, Value, - SWIFT_CONCURRENCY_FALLBACK_TASK_LOCAL_STORAGE_KEY); + static SWIFT_THREAD_LOCAL_TYPE( + Pointer, + SWIFT_CONCURRENCY_FALLBACK_TASK_LOCAL_STORAGE_KEY) Value; public: static void set(TaskLocal::Storage *task) { Value.set(task); } @@ -69,9 +66,10 @@ class FallbackTaskLocalStorage { }; /// Define the thread-locals. -SWIFT_RUNTIME_DECLARE_THREAD_LOCAL( - Pointer, FallbackTaskLocalStorage::Value, - SWIFT_CONCURRENCY_FALLBACK_TASK_LOCAL_STORAGE_KEY); +SWIFT_THREAD_LOCAL_TYPE( + Pointer, + SWIFT_CONCURRENCY_FALLBACK_TASK_LOCAL_STORAGE_KEY) +FallbackTaskLocalStorage::Value; // ==== ABI -------------------------------------------------------------------- diff --git a/stdlib/public/Concurrency/TaskStatus.cpp b/stdlib/public/Concurrency/TaskStatus.cpp index 7c85aba19a000..efbdd14f61467 100644 --- a/stdlib/public/Concurrency/TaskStatus.cpp +++ b/stdlib/public/Concurrency/TaskStatus.cpp @@ -17,8 +17,8 @@ #include "../CompatibilityOverride/CompatibilityOverride.h" #include "swift/Runtime/Concurrency.h" -#include "swift/Runtime/Mutex.h" #include "swift/Runtime/AtomicWaitQueue.h" +#include "swift/Threading/Mutex.h" #include "swift/ABI/TaskStatus.h" #include "TaskPrivate.h" #include @@ -36,7 +36,7 @@ ActiveTaskStatus::getStatusRecordParent(TaskStatusRecord *ptr) { /// A lock used to protect management of task-specific status /// record locks. -static StaticMutex StatusRecordLockLock; +static LazyMutex StatusRecordLockLock; namespace { @@ -62,7 +62,7 @@ namespace { /// must acquire the global status-record lock, find this record /// (which should be the innermost record), and wait for an unlock. class StatusRecordLockRecord : - public AtomicWaitQueue, + public AtomicWaitQueue, public TaskStatusRecord { public: StatusRecordLockRecord(TaskStatusRecord *parent) diff --git a/stdlib/public/Concurrency/TracingSignpost.cpp b/stdlib/public/Concurrency/TracingSignpost.cpp index 3efaf4d0f7b80..798e9c52eac21 100644 --- a/stdlib/public/Concurrency/TracingSignpost.cpp +++ b/stdlib/public/Concurrency/TracingSignpost.cpp @@ -35,7 +35,7 @@ namespace trace { os_log_t ActorLog; os_log_t TaskLog; -OnceToken_t LogsToken; +swift::once_t LogsToken; void setupLogs(void *unused) { ActorLog = os_log_create(SWIFT_LOG_CONCURRENCY_ACTOR_SUBSYSTEM, diff --git a/stdlib/public/Concurrency/TracingSignpost.h b/stdlib/public/Concurrency/TracingSignpost.h index a4ac6ae86c2f7..ab9d98e52d0db 100644 --- a/stdlib/public/Concurrency/TracingSignpost.h +++ b/stdlib/public/Concurrency/TracingSignpost.h @@ -69,7 +69,7 @@ namespace trace { extern os_log_t ActorLog; extern os_log_t TaskLog; -extern OnceToken_t LogsToken; +extern swift::once_t LogsToken; void setupLogs(void *unused); @@ -80,7 +80,7 @@ void setupLogs(void *unused); do { \ if (!SWIFT_RUNTIME_WEAK_CHECK(os_signpost_enabled)) \ return __VA_ARGS__; \ - SWIFT_ONCE_F(LogsToken, setupLogs, nullptr); \ + swift::once(LogsToken, setupLogs, nullptr); \ } while (0) // Every function does ENSURE_LOGS() before making any os_signpost calls, so diff --git a/stdlib/public/Threading/CMakeLists.txt b/stdlib/public/Threading/CMakeLists.txt new file mode 100644 index 0000000000000..84f23bce811ab --- /dev/null +++ b/stdlib/public/Threading/CMakeLists.txt @@ -0,0 +1,6 @@ +add_swift_target_library(swiftThreading STATIC + "${SWIFT_SOURCE_DIR}/lib/Threading/C11.cpp" + "${SWIFT_SOURCE_DIR}/lib/Threading/NoThreads.cpp" + "${SWIFT_SOURCE_DIR}/lib/Threading/Pthreads.cpp" + "${SWIFT_SOURCE_DIR}/lib/Threading/Win32.cpp" + INSTALL_IN_COMPONENT never_install) diff --git a/stdlib/public/core/CMakeLists.txt b/stdlib/public/core/CMakeLists.txt index f33f2da1362e9..3d6a88aba9bea 100644 --- a/stdlib/public/core/CMakeLists.txt +++ b/stdlib/public/core/CMakeLists.txt @@ -245,7 +245,7 @@ endif() set(GROUP_INFO_JSON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/GroupInfo.json) set(swift_core_link_flags "${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}") set(swift_core_framework_depends) -set(swift_core_private_link_libraries) +set(swift_core_private_link_libraries swiftThreading) set(swift_stdlib_compile_flags "${SWIFT_RUNTIME_SWIFT_COMPILE_FLAGS}") if(SWIFT_PRIMARY_VARIANT_SDK STREQUAL CYGWIN) diff --git a/stdlib/public/runtime/CMakeLists.txt b/stdlib/public/runtime/CMakeLists.txt index 2f4b7caa855d6..1664fb14d1cab 100644 --- a/stdlib/public/runtime/CMakeLists.txt +++ b/stdlib/public/runtime/CMakeLists.txt @@ -33,7 +33,6 @@ set(swift_runtime_sources Bincompat.cpp Casting.cpp CrashReporter.cpp - CygwinPort.cpp Demangle.cpp DynamicCast.cpp Enum.cpp @@ -59,9 +58,6 @@ set(swift_runtime_sources KnownMetadata.cpp Metadata.cpp MetadataLookup.cpp - MutexC11.cpp - MutexPThread.cpp - MutexWin32.cpp Numeric.cpp Once.cpp Portability.cpp diff --git a/stdlib/public/runtime/Casting.cpp b/stdlib/public/runtime/Casting.cpp index cf3c4ff82a1c7..4943af0282110 100644 --- a/stdlib/public/runtime/Casting.cpp +++ b/stdlib/public/runtime/Casting.cpp @@ -31,12 +31,7 @@ #include "swift/Runtime/ExistentialContainer.h" #include "swift/Runtime/HeapObject.h" #include "swift/Runtime/Metadata.h" -#if defined(__wasi__) -# define SWIFT_CASTING_SUPPORTS_MUTEX 0 -#else -# define SWIFT_CASTING_SUPPORTS_MUTEX 1 -# include "swift/Runtime/Mutex.h" -#endif +#include "swift/Threading/Mutex.h" #include "swift/Basic/Unreachable.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PointerIntPair.h" @@ -144,10 +139,8 @@ enum class TypeNameKind { using TypeNameCacheKey = llvm::PointerIntPair; -#if SWIFT_CASTING_SUPPORTS_MUTEX -static StaticMutex TypeNameCacheLock; -static StaticMutex MangledToPrettyFunctionNameCacheLock; -#endif +static LazyMutex TypeNameCacheLock; +static LazyMutex MangledToPrettyFunctionNameCacheLock; /// Cache containing rendered names for Metadata. /// Access MUST be protected using `TypeNameCacheLock`. @@ -166,9 +159,7 @@ swift::swift_getTypeName(const Metadata *type, bool qualified) { // Attempt read-only lookup of cache entry. { - #if SWIFT_CASTING_SUPPORTS_MUTEX - StaticMutex::ScopedLock guard(TypeNameCacheLock); - #endif + LazyMutex::ScopedLock guard(TypeNameCacheLock); auto found = cache.find(key); if (found != cache.end()) { @@ -179,9 +170,7 @@ swift::swift_getTypeName(const Metadata *type, bool qualified) { // Read-only lookup failed to find item, we may need to create it. { - #if SWIFT_CASTING_SUPPORTS_MUTEX - StaticMutex::ScopedLock guard(TypeNameCacheLock); - #endif + LazyMutex::ScopedLock guard(TypeNameCacheLock); // Do lookup again just to make sure it wasn't created by another // thread before we acquired the write lock. @@ -212,9 +201,7 @@ swift::swift_getMangledTypeName(const Metadata *type) { // Attempt read-only lookup of cache entry. { - #if SWIFT_CASTING_SUPPORTS_MUTEX - StaticMutex::ScopedLock guard(TypeNameCacheLock); - #endif + LazyMutex::ScopedLock guard(TypeNameCacheLock); auto found = cache.find(key); if (found != cache.end()) { @@ -225,9 +212,7 @@ swift::swift_getMangledTypeName(const Metadata *type) { // Read-only cache lookup failed, we may need to create it. { - #if SWIFT_CASTING_SUPPORTS_MUTEX - StaticMutex::ScopedLock guard(TypeNameCacheLock); - #endif + LazyMutex::ScopedLock guard(TypeNameCacheLock); // Do lookup again just to make sure it wasn't created by another // thread before we acquired the write lock. @@ -270,9 +255,7 @@ swift::swift_getFunctionFullNameFromMangledName( auto &cache = MangledToPrettyFunctionNameCache.get(); // Attempt read-only lookup of cache entry. { - #if SWIFT_CASTING_SUPPORTS_MUTEX - StaticMutex::ScopedLock guard(MangledToPrettyFunctionNameCacheLock); - #endif + LazyMutex::ScopedLock guard(MangledToPrettyFunctionNameCacheLock); auto found = cache.find(mangledName); if (found != cache.end()) { @@ -387,9 +370,7 @@ swift::swift_getFunctionFullNameFromMangledName( result[size] = 0; // 0-terminated string { - #if SWIFT_CASTING_SUPPORTS_MUTEX - StaticMutex::ScopedLock guard(MangledToPrettyFunctionNameCacheLock); - #endif + LazyMutex::ScopedLock guard(MangledToPrettyFunctionNameCacheLock); cache.insert({mangledName, {result, size}}); return TypeNamePair{result, size}; diff --git a/stdlib/public/runtime/CygwinPort.cpp b/stdlib/public/runtime/CygwinPort.cpp deleted file mode 100644 index e3f7ba9c065fa..0000000000000 --- a/stdlib/public/runtime/CygwinPort.cpp +++ /dev/null @@ -1,49 +0,0 @@ -//===--- CygwinPort.cpp - Functions for Cygwin port -----------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// Implementations Cygwin specific functions needed for running Swift. -// -//===----------------------------------------------------------------------===// - -#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(_MSC_VER) -#include "Private.h" -#include "swift/Runtime/Debug.h" -#include -#include -#include -#include -#include - -#define WIN32_LEAN_AND_MEAN -#define NOMINMAX -#include -#include - -using namespace swift; - -static std::mutex swiftOnceMutex; - -void swift::_swift_once_f(uintptr_t *predicate, void *context, - void (*function)(void *)) { - // FIXME: This implementation does a global lock, which is much worse than - // what we have on other platforms. Each swift_once should synchronize on the - // token. - swiftOnceMutex.lock(); - if (*predicate == 0) { - *predicate = 1ul; - swiftOnceMutex.unlock(); - - function(context); - } else - swiftOnceMutex.unlock(); -} -#endif // (defined(_WIN32) || defined(__CYGWIN__)) && !defined(_MSC_VER) diff --git a/stdlib/public/runtime/EnvironmentVariables.cpp b/stdlib/public/runtime/EnvironmentVariables.cpp index 9094a7f1a6629..7f1d09025a2f9 100644 --- a/stdlib/public/runtime/EnvironmentVariables.cpp +++ b/stdlib/public/runtime/EnvironmentVariables.cpp @@ -150,7 +150,7 @@ void printHelp(const char *extra) { #include "EnvironmentVariables.def" // Initialization code. -OnceToken_t swift::runtime::environment::initializeToken; +swift::once_t swift::runtime::environment::initializeToken; #if SWIFT_STDLIB_HAS_ENVIRON && (defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__linux__)) extern "C" char **environ; diff --git a/stdlib/public/runtime/Errors.cpp b/stdlib/public/runtime/Errors.cpp index 1129f20cfeba3..cb665d46ada56 100644 --- a/stdlib/public/runtime/Errors.cpp +++ b/stdlib/public/runtime/Errors.cpp @@ -30,8 +30,9 @@ #include "ImageInspection.h" #include "swift/Runtime/Debug.h" -#include "swift/Runtime/Mutex.h" #include "swift/Runtime/Portability.h" +#include "swift/Threading/Errors.h" +#include "swift/Threading/Mutex.h" #include "swift/Demangling/Demangle.h" #include "llvm/ADT/StringRef.h" @@ -460,3 +461,13 @@ void swift::swift_abortDisabledUnicodeSupport() { "Unicode normalization data is disabled on this platform"); } + +/// Halt because of a problem in the threading library +SWIFT_ATTRIBUTE_NORETURN +SWIFT_FORMAT(1, 2) +void swift::threading::fatal(const char *msg, ...) { + va_list val; + va_start(val, msg); + + swift::fatalErrorv(0, msg, val); +} diff --git a/stdlib/public/runtime/Exclusivity.cpp b/stdlib/public/runtime/Exclusivity.cpp index 5e0cf63fd114f..44cc94f490bf3 100644 --- a/stdlib/public/runtime/Exclusivity.cpp +++ b/stdlib/public/runtime/Exclusivity.cpp @@ -31,7 +31,7 @@ #include "swift/Runtime/Debug.h" #include "swift/Runtime/EnvironmentVariables.h" #include "swift/Runtime/Metadata.h" -#include "swift/Runtime/ThreadLocalStorage.h" +#include "swift/Threading/ThreadLocalStorage.h" #include #include #include diff --git a/stdlib/public/runtime/HeapObject.cpp b/stdlib/public/runtime/HeapObject.cpp index 1a820040ebef9..d0aeb466f32fd 100644 --- a/stdlib/public/runtime/HeapObject.cpp +++ b/stdlib/public/runtime/HeapObject.cpp @@ -41,7 +41,6 @@ # include # include # include "swift/Runtime/ObjCBridge.h" -# include "swift/Runtime/Once.h" # include #endif #include "Leaks.h" @@ -162,13 +161,6 @@ struct InitStaticObjectContext { HeapMetadata const *metadata; }; -// Callback for swift_once. -static void initStaticObjectWithContext(void *OpaqueCtx) { - InitStaticObjectContext *Ctx = (InitStaticObjectContext *)OpaqueCtx; - Ctx->object->metadata = Ctx->metadata; - Ctx->object->refCounts.initImmortal(); -} - // TODO: We could generate inline code for the fast-path, i.e. the metadata // pointer is already set. That would be a performance/codesize tradeoff. HeapObject * @@ -182,7 +174,11 @@ swift::swift_initStaticObject(HeapMetadata const *metadata, // refcount to 1 while another thread already incremented it - and would // decrement it to 0 afterwards. InitStaticObjectContext Ctx = { object, metadata }; - swift_once(token, initStaticObjectWithContext, &Ctx); + swift::once(*token, [](void *OpaqueCtx) { + InitStaticObjectContext *Ctx = (InitStaticObjectContext *)OpaqueCtx; + Ctx->object->metadata = Ctx->metadata; + Ctx->object->refCounts.initImmortal(); + }, &Ctx); return object; } @@ -350,7 +346,7 @@ static HeapObject *_swift_retain_(HeapObject *object) { } HeapObject *swift::swift_retain(HeapObject *object) { -#ifdef SWIFT_STDLIB_THREADING_NONE +#ifdef SWIFT_THREADING_NONE return swift_nonatomic_retain(object); #else CALL_IMPL(swift_retain, (object)); @@ -377,7 +373,7 @@ static HeapObject *_swift_retain_n_(HeapObject *object, uint32_t n) { } HeapObject *swift::swift_retain_n(HeapObject *object, uint32_t n) { -#ifdef SWIFT_STDLIB_THREADING_NONE +#ifdef SWIFT_THREADING_NONE return swift_nonatomic_retain_n(object, n); #else CALL_IMPL(swift_retain_n, (object, n)); @@ -403,7 +399,7 @@ static void _swift_release_(HeapObject *object) { } void swift::swift_release(HeapObject *object) { -#ifdef SWIFT_STDLIB_THREADING_NONE +#ifdef SWIFT_THREADING_NONE swift_nonatomic_release(object); #else CALL_IMPL(swift_release, (object)); @@ -428,7 +424,7 @@ static void _swift_release_n_(HeapObject *object, uint32_t n) { } void swift::swift_release_n(HeapObject *object, uint32_t n) { -#ifdef SWIFT_STDLIB_THREADING_NONE +#ifdef SWIFT_THREADING_NONE swift_nonatomic_release_n(object, n); #else CALL_IMPL(swift_release_n, (object, n)); @@ -460,7 +456,7 @@ size_t swift::swift_weakRetainCount(HeapObject *object) { } HeapObject *swift::swift_unownedRetain(HeapObject *object) { -#ifdef SWIFT_STDLIB_THREADING_NONE +#ifdef SWIFT_THREADING_NONE return static_cast(swift_nonatomic_unownedRetain(object)); #else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRetain); @@ -473,7 +469,7 @@ HeapObject *swift::swift_unownedRetain(HeapObject *object) { } void swift::swift_unownedRelease(HeapObject *object) { -#ifdef SWIFT_STDLIB_THREADING_NONE +#ifdef SWIFT_THREADING_NONE swift_nonatomic_unownedRelease(object); #else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRelease); @@ -520,7 +516,7 @@ void swift::swift_nonatomic_unownedRelease(HeapObject *object) { } HeapObject *swift::swift_unownedRetain_n(HeapObject *object, int n) { -#ifdef SWIFT_STDLIB_THREADING_NONE +#ifdef SWIFT_THREADING_NONE return swift_nonatomic_unownedRetain_n(object, n); #else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRetain_n); @@ -533,7 +529,7 @@ HeapObject *swift::swift_unownedRetain_n(HeapObject *object, int n) { } void swift::swift_unownedRelease_n(HeapObject *object, int n) { -#ifdef SWIFT_STDLIB_THREADING_NONE +#ifdef SWIFT_THREADING_NONE swift_nonatomic_unownedRelease_n(object, n); #else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRelease_n); @@ -583,7 +579,7 @@ static HeapObject *_swift_tryRetain_(HeapObject *object) { if (!isValidPointerForNativeRetain(object)) return nullptr; -#ifdef SWIFT_STDLIB_THREADING_NONE +#ifdef SWIFT_THREADING_NONE if (object->refCounts.tryIncrementNonAtomic()) return object; else return nullptr; #else @@ -612,7 +608,7 @@ void swift::swift_setDeallocating(HeapObject *object) { } HeapObject *swift::swift_unownedRetainStrong(HeapObject *object) { -#ifdef SWIFT_STDLIB_THREADING_NONE +#ifdef SWIFT_THREADING_NONE return swift_nonatomic_unownedRetainStrong(object); #else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRetainStrong); @@ -640,7 +636,7 @@ HeapObject *swift::swift_nonatomic_unownedRetainStrong(HeapObject *object) { } void swift::swift_unownedRetainStrongAndRelease(HeapObject *object) { -#ifdef SWIFT_STDLIB_THREADING_NONE +#ifdef SWIFT_THREADING_NONE swift_nonatomic_unownedRetainStrongAndRelease(object); #else SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRetainStrongAndRelease); diff --git a/stdlib/public/runtime/ImageInspectionCOFF.cpp b/stdlib/public/runtime/ImageInspectionCOFF.cpp index f952dc8b3dd22..53bf6c70e8e4a 100644 --- a/stdlib/public/runtime/ImageInspectionCOFF.cpp +++ b/stdlib/public/runtime/ImageInspectionCOFF.cpp @@ -23,7 +23,7 @@ #include #endif -#include "swift/Runtime/Mutex.h" +#include "swift/Threading/Mutex.h" using namespace swift; @@ -73,7 +73,7 @@ int swift::lookupSymbol(const void *address, SymbolInfo *info) { } #if defined(_WIN32) -static StaticMutex mutex; +static LazyMutex mutex; static bool isDbgHelpInitialized = false; void swift::_swift_withWin32DbgHelpLibrary( diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp index c1a7a04350b4e..0f02a2f103a92 100644 --- a/stdlib/public/runtime/Metadata.cpp +++ b/stdlib/public/runtime/Metadata.cpp @@ -25,10 +25,10 @@ #include "swift/Runtime/EnvironmentVariables.h" #include "swift/Runtime/ExistentialContainer.h" #include "swift/Runtime/HeapObject.h" -#include "swift/Runtime/Mutex.h" #include "swift/Runtime/Once.h" #include "swift/Runtime/Portability.h" #include "swift/Strings.h" +#include "swift/Threading/Mutex.h" #include "llvm/ADT/StringExtras.h" #include #include @@ -786,8 +786,8 @@ _cacheCanonicalSpecializedMetadata(const TypeContextDescriptor *description) { static void cacheCanonicalSpecializedMetadata(const TypeContextDescriptor *description, swift_once_t *token) { - swift_once( - token, + swift::once( + *token, [](void *uncastDescription) { auto *description = (const TypeContextDescriptor *)uncastDescription; _cacheCanonicalSpecializedMetadata(description); @@ -3148,8 +3148,8 @@ _swift_initClassMetadataImpl(ClassMetadata *self, self->Superclass = getRootSuperclass(); // Register our custom implementation of class_getImageName. - static swift_once_t onceToken; - swift_once(&onceToken, [](void *unused) { + static swift::once_t onceToken; + swift::once(onceToken, [](void *unused) { (void)unused; setUpObjCRuntimeGetImageNameFromClass(); }, nullptr); @@ -6282,8 +6282,8 @@ void *MetadataAllocator::Allocate(size_t size, size_t alignment) { assert(alignment <= alignof(void*)); assert(size % alignof(void*) == 0); - static OnceToken_t getenvToken; - SWIFT_ONCE_F(getenvToken, checkAllocatorDebugEnvironmentVariables, nullptr); + static swift::once_t getenvToken; + swift::once(getenvToken, checkAllocatorDebugEnvironmentVariables); // If the size is larger than the maximum, just do a normal heap allocation. if (size > PoolRange::MaxPoolAllocationSize) { diff --git a/stdlib/public/runtime/MetadataCache.h b/stdlib/public/runtime/MetadataCache.h index e854ba3f669ef..2c1af5ed74862 100644 --- a/stdlib/public/runtime/MetadataCache.h +++ b/stdlib/public/runtime/MetadataCache.h @@ -16,8 +16,8 @@ #include "llvm/ADT/STLExtras.h" #include "swift/Runtime/Concurrent.h" #include "swift/Runtime/Metadata.h" -#include "swift/Runtime/Mutex.h" #include "swift/Runtime/AtomicWaitQueue.h" +#include "swift/Threading/Mutex.h" #include "../SwiftShims/Visibility.h" #include #include @@ -170,7 +170,7 @@ class LockingConcurrentMapStorage { // space is not large enough to accommodate a Mutex along with everything // else. There, use a SmallMutex to squeeze into the available space. using MutexTy = - std::conditional_t; + std::conditional_t; StableAddressConcurrentReadableHashMap, MutexTy> Map; diff --git a/stdlib/public/runtime/MetadataImpl.h b/stdlib/public/runtime/MetadataImpl.h index c3aaf4eb6098c..1365e24d6f783 100644 --- a/stdlib/public/runtime/MetadataImpl.h +++ b/stdlib/public/runtime/MetadataImpl.h @@ -137,7 +137,7 @@ template struct RetainableBoxBase { static constexpr size_t stride = sizeof(T); static constexpr bool isPOD = false; static constexpr bool isBitwiseTakable = true; -#ifdef SWIFT_STDLIB_THREADING_NONE +#ifdef SWIFT_THREADING_NONE static constexpr bool isAtomic = false; #else static constexpr bool isAtomic = true; diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp index aab427dc0bc58..57c44bf1630b8 100644 --- a/stdlib/public/runtime/MetadataLookup.cpp +++ b/stdlib/public/runtime/MetadataLookup.cpp @@ -24,8 +24,8 @@ #include "swift/Runtime/Debug.h" #include "swift/Runtime/HeapObject.h" #include "swift/Runtime/Metadata.h" -#include "swift/Runtime/Mutex.h" #include "swift/Strings.h" +#include "swift/Threading/Mutex.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/Optional.h" diff --git a/stdlib/public/runtime/MutexC11.cpp b/stdlib/public/runtime/MutexC11.cpp deleted file mode 100644 index 1c31e2de6c39d..0000000000000 --- a/stdlib/public/runtime/MutexC11.cpp +++ /dev/null @@ -1,37 +0,0 @@ -//===--- MutexC11.cpp - Supports Mutex.h using C11 threads ----------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// Mutex and Read/Write lock implementations using C11 threads. -// -//===----------------------------------------------------------------------===// - -#include "swift/Runtime/Mutex.h" -#include "swift/Runtime/Debug.h" - -#if SWIFT_STDLIB_THREADING_C11 - -using namespace swift; - -namespace c11threads { - -#ifndef SWIFT_FATAL_ERROR -#define SWIFT_FATAL_ERROR swift::fatalError -#endif - -// Triggered if a C11 threads call fails -void fatalError(int errcode) { - SWIFT_FATAL_ERROR(0, "C11 threads call failed with %d\n", errcode); -} - -} - -#endif // SWIFT_STDLIB_THREADING_C11 diff --git a/stdlib/public/runtime/MutexPThread.cpp b/stdlib/public/runtime/MutexPThread.cpp deleted file mode 100644 index 54626f9489393..0000000000000 --- a/stdlib/public/runtime/MutexPThread.cpp +++ /dev/null @@ -1,109 +0,0 @@ -//===--- MutexPThread.cpp - Supports Mutex.h using PThreads ---------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// Mutex and Read/Write lock implementations using pthreads. -// -// Darwin shares the pthreads implementation for read/write locks, but -// uses inline implementations for os_unfair_lock. -// -//===----------------------------------------------------------------------===// - -#if SWIFT_STDLIB_THREADING_PTHREADS || SWIFT_STDLIB_THREADING_DARWIN - -#if __has_include() -#include -#endif - -// Notes: swift::fatalError is not shared between libswiftCore and libswift_Concurrency -// and libswift_Concurrency uses swift_Concurrency_fatalError instead. -#ifndef SWIFT_FATAL_ERROR -#define SWIFT_FATAL_ERROR swift::fatalError -#endif - -#include "swift/Runtime/Mutex.h" - -#include "swift/Runtime/Debug.h" -#include -#include - -using namespace swift; - -#define reportError(PThreadFunction) \ - do { \ - int errorcode = PThreadFunction; \ - if (errorcode != 0) { \ - SWIFT_FATAL_ERROR(/* flags = */ 0, "'%s' failed with error '%s'(%d)\n", \ - #PThreadFunction, errorName(errorcode), errorcode); \ - } \ - } while (false) - -#define returnTrueOrReportError(PThreadFunction, returnFalseOnEBUSY) \ - do { \ - int errorcode = PThreadFunction; \ - if (errorcode == 0) \ - return true; \ - if (returnFalseOnEBUSY && errorcode == EBUSY) \ - return false; \ - SWIFT_FATAL_ERROR(/* flags = */ 0, "'%s' failed with error '%s'(%d)\n", \ - #PThreadFunction, errorName(errorcode), errorcode); \ - } while (false) - -static const char *errorName(int errorcode) { - switch (errorcode) { - case EINVAL: - return "EINVAL"; - case EPERM: - return "EPERM"; - case EDEADLK: - return "EDEADLK"; - case ENOMEM: - return "ENOMEM"; - case EAGAIN: - return "EAGAIN"; - case EBUSY: - return "EBUSY"; - default: - return ""; - } -} - -#if !HAS_OS_UNFAIR_LOCK - -void MutexPlatformHelper::init(pthread_mutex_t &mutex, bool checked) { - pthread_mutexattr_t attr; - int kind = (checked ? PTHREAD_MUTEX_ERRORCHECK : PTHREAD_MUTEX_NORMAL); - reportError(pthread_mutexattr_init(&attr)); - reportError(pthread_mutexattr_settype(&attr, kind)); - reportError(pthread_mutex_init(&mutex, &attr)); - reportError(pthread_mutexattr_destroy(&attr)); -} - -void MutexPlatformHelper::destroy(pthread_mutex_t &mutex) { - reportError(pthread_mutex_destroy(&mutex)); -} - -void MutexPlatformHelper::lock(pthread_mutex_t &mutex) { - reportError(pthread_mutex_lock(&mutex)); -} - -void MutexPlatformHelper::unlock(pthread_mutex_t &mutex) { - reportError(pthread_mutex_unlock(&mutex)); -} - -bool MutexPlatformHelper::try_lock(pthread_mutex_t &mutex) { - returnTrueOrReportError(pthread_mutex_trylock(&mutex), - /* returnFalseOnEBUSY = */ true); -} - -#endif - -#endif // SWIFT_STDLIB_THREADING_PTHREADS diff --git a/stdlib/public/runtime/MutexWin32.cpp b/stdlib/public/runtime/MutexWin32.cpp deleted file mode 100644 index 1ce30fd9d6f08..0000000000000 --- a/stdlib/public/runtime/MutexWin32.cpp +++ /dev/null @@ -1,31 +0,0 @@ -//===--- MutexWin32.cpp - -------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// Mutex, Read/Write lock, and Scoped lock implementations -// using Windows Slim Reader/Writer Locks. -// -//===----------------------------------------------------------------------===// - -#if defined(_WIN32) - -// Notes: swift::fatalError is not shared between libswiftCore and libswift_Concurrency -// and libswift_Concurrency uses swift_Concurrency_fatalError instead. -#ifndef SWIFT_FATAL_ERROR -#define SWIFT_FATAL_ERROR swift::fatalError -#endif - -#include "swift/Runtime/Mutex.h" -#include "swift/Runtime/Debug.h" - -using namespace swift; - -#endif diff --git a/stdlib/public/runtime/Once.cpp b/stdlib/public/runtime/Once.cpp index 2878fcbe0621a..e450b5547e994 100644 --- a/stdlib/public/runtime/Once.cpp +++ b/stdlib/public/runtime/Once.cpp @@ -15,17 +15,13 @@ //===----------------------------------------------------------------------===// #include "Private.h" -#include "swift/Runtime/Once.h" +#include "swift/Threading/Once.h" #include "swift/Runtime/Debug.h" #include using namespace swift; -#if SWIFT_STDLIB_THREADING_NONE - -// No dependencies on single-threaded environments. - -#elif SWIFT_STDLIB_THREADING_DARWIN +#if SWIFT_THREADING_DARWIN // On macOS and iOS, swift_once is implemented using GCD. // The compiler emits an inline check matching the barrier-free inline fast @@ -34,12 +30,8 @@ using namespace swift; #include static_assert(std::is_same::value, "swift_once_t and dispatch_once_t must stay in sync"); -#else - -// On non-Darwin platforms we do not assume any barrier-free inline path -// and SwiftTargetInfo.OnceDonePredicateValue is unset in the compiler. -#endif +#endif // SWIFT_THREADING_DARWIN // The compiler generates the swift_once_t values as word-sized zero-initialized // variables, so we want to make sure swift_once_t isn't larger than the @@ -52,16 +44,5 @@ static_assert(sizeof(swift_once_t) <= sizeof(void*), /// extent of type swift_once_t. void swift::swift_once(swift_once_t *predicate, void (*fn)(void *), void *context) { -#ifdef SWIFT_STDLIB_THREADING_NONE - if (! *predicate) { - *predicate = true; - fn(context); - } -#elif SWIFT_STDLIB_THREADING_DARWIN - dispatch_once_f(predicate, context, fn); -#elif defined(__CYGWIN__) - _swift_once_f(predicate, context, fn); -#else - std::call_once(*predicate, fn, context); -#endif + swift::once(*predicate, fn, context); } diff --git a/stdlib/public/runtime/RuntimeInvocationsTracking.cpp b/stdlib/public/runtime/RuntimeInvocationsTracking.cpp index e678faa7962a7..1d803ffce1950 100644 --- a/stdlib/public/runtime/RuntimeInvocationsTracking.cpp +++ b/stdlib/public/runtime/RuntimeInvocationsTracking.cpp @@ -19,7 +19,7 @@ #include "RuntimeInvocationsTracking.h" #include "swift/Basic/Lazy.h" #include "swift/Runtime/HeapObject.h" -#include "swift/Runtime/Mutex.h" +#include "swift/Threading/Mutex.h" #if defined(SWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS) @@ -49,7 +49,7 @@ static bool UpdateGlobalRuntimeFunctionCounters = false; /// Global set of counters tracking the total number of runtime invocations. struct RuntimeFunctionCountersStateSentinel { RuntimeFunctionCountersState State; - StaticMutex Lock; + LazyMutex Lock; }; static RuntimeFunctionCountersStateSentinel RuntimeGlobalFunctionCountersState; @@ -57,7 +57,7 @@ static RuntimeFunctionCountersStateSentinel RuntimeGlobalFunctionCountersState; /// them. struct RuntimeObjectCacheSentinel { llvm::DenseMap Cache; - StaticMutex Lock; + Mutex Lock; }; static Lazy RuntimeObjectStateCache; @@ -101,7 +101,7 @@ static uint16_t RuntimeFunctionCountersOffsets[] = { void SWIFT_RT_TRACK_INVOCATION_NAME(RT_FUNCTION)(HeapObject * object) { \ /* Update global counters. */ \ if (UpdateGlobalRuntimeFunctionCounters) { \ - StaticMutex::ScopedLock lock(RuntimeGlobalFunctionCountersState.Lock); \ + LazyMutex::ScopedLock lock(RuntimeGlobalFunctionCountersState.Lock); \ RuntimeGlobalFunctionCountersState.State \ .SWIFT_RT_FUNCTION_INVOCATION_COUNTER_NAME(RT_FUNCTION)++; \ if (GlobalRuntimeFunctionCountersUpdateHandler) { \ @@ -117,7 +117,7 @@ static uint16_t RuntimeFunctionCountersOffsets[] = { /* Update per object counters. */ \ if (UpdatePerObjectRuntimeFunctionCounters && object) { \ auto &theSentinel = RuntimeObjectStateCache.get(); \ - StaticMutex::ScopedLock lock(theSentinel.Lock); \ + Mutex::ScopedLock lock(theSentinel.Lock); \ theSentinel.Cache[object].SWIFT_RT_FUNCTION_INVOCATION_COUNTER_NAME( \ RT_FUNCTION)++; \ /* TODO: Remember the order/history of operations? */ \ @@ -131,7 +131,7 @@ static uint16_t RuntimeFunctionCountersOffsets[] = { void _swift_getObjectRuntimeFunctionCounters( HeapObject *object, RuntimeFunctionCountersState *result) { auto &theSentinel = RuntimeObjectStateCache.get(); - StaticMutex::ScopedLock lock(theSentinel.Lock); + Mutex::ScopedLock lock(theSentinel.Lock); *result = theSentinel.Cache[object]; } @@ -140,7 +140,7 @@ void _swift_getObjectRuntimeFunctionCounters( void _swift_setObjectRuntimeFunctionCounters( HeapObject *object, RuntimeFunctionCountersState *state) { auto &theSentinel = RuntimeObjectStateCache.get(); - StaticMutex::ScopedLock lock(theSentinel.Lock); + Mutex::ScopedLock lock(theSentinel.Lock); theSentinel.Cache[object] = *state; } @@ -148,14 +148,14 @@ void _swift_setObjectRuntimeFunctionCounters( /// each runtime function of interest. void _swift_getGlobalRuntimeFunctionCounters( RuntimeFunctionCountersState *result) { - StaticMutex::ScopedLock lock(RuntimeGlobalFunctionCountersState.Lock); + LazyMutex::ScopedLock lock(RuntimeGlobalFunctionCountersState.Lock); *result = RuntimeGlobalFunctionCountersState.State; } /// Set the global runtime state of function pointers from a provided state. void _swift_setGlobalRuntimeFunctionCounters( RuntimeFunctionCountersState *state) { - StaticMutex::ScopedLock lock(RuntimeGlobalFunctionCountersState.Lock); + LazyMutex::ScopedLock lock(RuntimeGlobalFunctionCountersState.Lock); RuntimeGlobalFunctionCountersState.State = *state; } @@ -192,7 +192,7 @@ static void _swift_dumpRuntimeCounters(RuntimeFunctionCountersState *State) { /// Dump all per-object runtime function pointers. void _swift_dumpObjectsRuntimeFunctionPointers() { auto &theSentinel = RuntimeObjectStateCache.get(); - StaticMutex::ScopedLock lock(theSentinel.Lock); + Mutex::ScopedLock lock(theSentinel.Lock); for (auto &Pair : theSentinel.Cache) { printf("\n\nRuntime counters for object at address %p:\n", Pair.getFirst()); _swift_dumpRuntimeCounters(&Pair.getSecond()); diff --git a/stdlib/public/runtime/SwiftTLSContext.cpp b/stdlib/public/runtime/SwiftTLSContext.cpp index a0e52253caba3..5d18e7e10ab27 100644 --- a/stdlib/public/runtime/SwiftTLSContext.cpp +++ b/stdlib/public/runtime/SwiftTLSContext.cpp @@ -11,81 +11,58 @@ //===----------------------------------------------------------------------===// #include "SwiftTLSContext.h" -#include "swift/Basic/Lazy.h" -#include "swift/Runtime/Once.h" -#include "swift/Runtime/ThreadLocalStorage.h" + +#include "swift/Threading/Once.h" +#include "swift/Threading/ThreadLocalStorage.h" using namespace swift; using namespace swift::runtime; -#ifdef SWIFT_STDLIB_THREADING_NONE - SwiftTLSContext &SwiftTLSContext::get() { - static SwiftTLSContext TLSContext; - return TLSContext; -} -#elif SWIFT_TLS_HAS_RESERVED_PTHREAD_SPECIFIC -// Use the reserved TSD key if possible. +#if SWIFT_THREADING_USE_RESERVED_TLS_KEYS -SwiftTLSContext &SwiftTLSContext::get() { - SwiftTLSContext *ctx = static_cast( - SWIFT_THREAD_GETSPECIFIC(SWIFT_RUNTIME_TLS_KEY)); + // If we have reserved keys, use those + SwiftTLSContext *ctx + = static_cast(swift::tls_get(SWIFT_RUNTIME_TLS_KEY)); if (ctx) return *ctx; - static OnceToken_t setupToken; - SWIFT_ONCE_F( - setupToken, - [](void *) { - SWIFT_THREAD_KEY_INIT(SWIFT_RUNTIME_TLS_KEY, [](void *pointer) { - delete static_cast(pointer); - }); - }, - nullptr); + static swift::once_t token; + swift::tls_init_once(token, SWIFT_RUNTIME_TLS_KEY, [](void *pointer) { + delete static_cast(pointer); + }); ctx = new SwiftTLSContext(); - SWIFT_THREAD_SETSPECIFIC(SWIFT_RUNTIME_TLS_KEY, ctx); + swift::tls_set(SWIFT_RUNTIME_TLS_KEY, ctx); return *ctx; -} - -#elif __has_feature(cxx_thread_local) -// Second choice is direct language support for thread-locals. - -namespace { - -static thread_local SwiftTLSContext TLSContext; -} // anonymous namespace +#elif defined(SWIFT_THREAD_LOCAL) -SwiftTLSContext &SwiftTLSContext::get() { return TLSContext; } + // If we have the thread local attribute, use that + // (note that this happens for the no-threads case too) + static SWIFT_THREAD_LOCAL SwiftTLSContext TLSContext; + return TLSContext; #else -// Use the platform thread-local data API. -static __swift_thread_key_t createSwiftThreadKey() { - __swift_thread_key_t key; - int result = SWIFT_THREAD_KEY_CREATE(&key, [](void *pointer) { + // Otherwise, allocate ourselves a key and use that + static swift::tls_key runtimeKey; + static swift::once_t token; + + swift::tls_alloc_once(token, runtimeKey, [](void *pointer) { delete static_cast(pointer); }); - if (result != 0) { - fatalError(0, "couldn't create thread key for exclusivity: %s\n", - strerror(result)); - } - return key; -} - -static SwiftTLSContext &getTLSContext() { - static __swift_thread_key_t key = createSwiftThreadKey(); + SwiftTLSContext *ctx + = static_cast(swift::tls_get(runtimeKey)); + if (ctx) + return *ctx; - SwiftTLSContext *ctx = - static_cast(SWIFT_THREAD_GETSPECIFIC(key)); - if (!ctx) { - ctx = new SwiftTLSContext(); - SWIFT_THREAD_SETSPECIFIC(key, ctx); - } + ctx = new SwiftTLSContext(); + swift::tls_set(runtimeKey, ctx); return *ctx; -} #endif + +} diff --git a/stdlib/public/stubs/OptionalBridgingHelper.mm b/stdlib/public/stubs/OptionalBridgingHelper.mm index 76361258f5f2e..2182f6b4b6c5a 100644 --- a/stdlib/public/stubs/OptionalBridgingHelper.mm +++ b/stdlib/public/stubs/OptionalBridgingHelper.mm @@ -15,9 +15,9 @@ #if SWIFT_OBJC_INTEROP #include "swift/Basic/Lazy.h" #include "swift/Runtime/Metadata.h" -#include "swift/Runtime/Mutex.h" #include "swift/Runtime/ObjCBridge.h" #include "swift/Runtime/Portability.h" +#include "swift/Threading/Mutex.h" #include #import #import @@ -59,7 +59,7 @@ - (id)description { struct SwiftNullSentinelCache { std::vector Cache; - StaticMutex Lock; + Mutex Lock; }; static Lazy Sentinels; @@ -73,7 +73,7 @@ static id getSentinelForDepth(unsigned depth) { auto &theSentinels = Sentinels.get(); unsigned depthIndex = depth - 2; { - StaticMutex::ScopedLock lock(theSentinels.Lock); + Mutex::ScopedLock lock(theSentinels.Lock); const auto &cache = theSentinels.Cache; if (depthIndex < cache.size()) { id cached = cache[depthIndex]; @@ -83,7 +83,7 @@ static id getSentinelForDepth(unsigned depth) { } // Make one if we need to. { - StaticMutex::ScopedLock lock(theSentinels.Lock); + Mutex::ScopedLock lock(theSentinels.Lock); if (depthIndex >= theSentinels.Cache.size()) theSentinels.Cache.resize(depthIndex + 1); auto &cached = theSentinels.Cache[depthIndex]; diff --git a/stdlib/public/stubs/Random.cpp b/stdlib/public/stubs/Random.cpp index dab27c0d8b430..498b6b253fc01 100644 --- a/stdlib/public/stubs/Random.cpp +++ b/stdlib/public/stubs/Random.cpp @@ -42,7 +42,7 @@ #include #include "swift/Runtime/Debug.h" -#include "swift/Runtime/Mutex.h" +#include "swift/Threading/Mutex.h" #include "SwiftShims/Random.h" #include // required for std::min @@ -108,6 +108,7 @@ void swift_stdlib_random(void *buf, __swift_size_t nbytes) { WHILE_EINTR(open("/dev/urandom", O_RDONLY | O_CLOEXEC, 0)); if (fd != -1) { + // ###FIXME: Why is this locked? None of the others are. static StaticMutex mutex; mutex.withLock([&] { actual_nbytes = WHILE_EINTR(read(fd, buf, nbytes)); diff --git a/stdlib/public/stubs/Stubs.cpp b/stdlib/public/stubs/Stubs.cpp index 286ffd753f61f..7d5ff82d48da7 100644 --- a/stdlib/public/stubs/Stubs.cpp +++ b/stdlib/public/stubs/Stubs.cpp @@ -484,7 +484,7 @@ int _swift_stdlib_putc_stderr(int C) { } size_t _swift_stdlib_getHardwareConcurrency() { -#ifdef SWIFT_STDLIB_THREADING_NONE +#ifdef SWIFT_THREADING_NONE return 1; #else return std::thread::hardware_concurrency(); @@ -537,12 +537,12 @@ __swift_bool swift_stdlib_isStackAllocationSafe(__swift_size_t byteCount, __swift_bool _swift_stdlib_getCurrentStackBounds(__swift_uintptr_t *outBegin, __swift_uintptr_t *outEnd) { -#if SWIFT_STDLIB_THREADING_NONE +#if SWIFT_THREADING_NONE // This platform does not support threads, so the API we'd call to get stack // bounds (i.e. libpthread) is not going to be usable. return false; -#elif SWIFT_STDLIB_THREADING_DARWIN +#elif SWIFT_THREADING_DARWIN pthread_t thread = pthread_self(); // On Apple platforms, pthread_get_stackaddr_np() gets the address of the @@ -556,11 +556,11 @@ __swift_bool _swift_stdlib_getCurrentStackBounds(__swift_uintptr_t *outBegin, *outBegin = *outEnd - pthread_get_stacksize_np(thread); return true; -#elif SWIFT_STDLIB_THREADING_C11 +#elif SWIFT_THREADING_C11 // We don't know any way to do this for C11 threads return false -#elif SWIFT_STDLIB_THREADING_WIN32 +#elif SWIFT_THREADING_WIN32 # if _WIN32_WINNT >= 0x0602 ULONG_PTR lowLimit = 0; @@ -576,7 +576,7 @@ __swift_bool _swift_stdlib_getCurrentStackBounds(__swift_uintptr_t *outBegin, return false; # endif -#elif SWIFT_STDLIB_THREADING_PTHREADS +#elif SWIFT_THREADING_PTHREADS # if defined(__OpenBSD__) stack_t sinfo; diff --git a/stdlib/public/stubs/ThreadLocalStorage.cpp b/stdlib/public/stubs/ThreadLocalStorage.cpp index 77a5c63fc2f67..9d0b9118878c7 100644 --- a/stdlib/public/stubs/ThreadLocalStorage.cpp +++ b/stdlib/public/stubs/ThreadLocalStorage.cpp @@ -13,9 +13,8 @@ #include #include "SwiftShims/ThreadLocalStorage.h" -#include "swift/Basic/Lazy.h" +#include "swift/Threading/ThreadLocalStorage.h" #include "swift/Runtime/Debug.h" -#include "swift/Runtime/ThreadLocalStorage.h" SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API void _stdlib_destroyTLS(void *); @@ -23,97 +22,49 @@ void _stdlib_destroyTLS(void *); SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API void *_stdlib_createTLS(void); -#if !SWIFT_TLS_HAS_RESERVED_PTHREAD_SPECIFIC || (defined(_WIN32) && !defined(__CYGWIN__)) - -static void -#if defined(_M_IX86) -__stdcall -#endif -destroyTLS_CCAdjustmentThunk(void *ptr) { - _stdlib_destroyTLS(ptr); -} - -#endif - -#if defined(_WIN32) && !defined(__CYGWIN__) - -typedef -#if defined(_M_IX86) -__stdcall -#endif -void (*__swift_thread_key_destructor)(void *); - -static inline int -_stdlib_thread_key_create(__swift_thread_key_t * _Nonnull key, - __swift_thread_key_destructor _Nullable destructor) { - *key = FlsAlloc(destroyTLS_CCAdjustmentThunk); - if (*key == FLS_OUT_OF_INDEXES) - return GetLastError(); - return 0; -} - -#endif - -#ifdef SWIFT_STDLIB_THREADING_NONE - SWIFT_RUNTIME_STDLIB_INTERNAL void * _swift_stdlib_threadLocalStorageGet(void) { - static void *value; - if (!value) { - value = _stdlib_createTLS(); - } + +#if SWIFT_THREADING_NONE + + // If there's no threading, we can just keep a static variable. + static void *value = _stdlib_createTLS(); return value; -} -#elif SWIFT_TLS_HAS_RESERVED_PTHREAD_SPECIFIC +#elif SWIFT_THREADING_USE_RESERVED_TLS_KEYS -SWIFT_RUNTIME_STDLIB_INTERNAL -void * -_swift_stdlib_threadLocalStorageGet(void) { - void *value = SWIFT_THREAD_GETSPECIFIC(SWIFT_STDLIB_TLS_KEY); + // If we have reserved keys, use those + void *value = swift::tls_get(SWIFT_STDLIB_TLS_KEY); if (value) return value; - - static swift::OnceToken_t token; - SWIFT_ONCE_F(token, [](void *) { - int result = SWIFT_THREAD_KEY_INIT(SWIFT_STDLIB_TLS_KEY, [](void *pointer) { - _stdlib_destroyTLS(pointer); - }); - if (result != 0) - swift::fatalError(0, "couldn't create pthread key for stdlib TLS: %s\n", - std::strerror(result)); - }, nullptr); - + + static swift::once_t token; + swift::tls_init_once(token, SWIFT_STDLIB_TLS_KEY, [](void *pointer) { + _stdlib_destroyTLS(pointer); + }); + value = _stdlib_createTLS(); - SWIFT_THREAD_SETSPECIFIC(SWIFT_STDLIB_TLS_KEY, value); + swift::tls_set(SWIFT_STDLIB_TLS_KEY, value); return value; -} -#else +#else // Threaded, but not using reserved keys -SWIFT_RUNTIME_STDLIB_INTERNAL -void * -_swift_stdlib_threadLocalStorageGet(void) { - static swift::OnceToken_t token; - static __swift_thread_key_t key; + // Register a key and use it + static swift::tls_key key; + static swift::once_t token; - SWIFT_ONCE_F(token, [](void *) { - int result = SWIFT_THREAD_KEY_CREATE(&key, destroyTLS_CCAdjustmentThunk); - if (result != 0) - swift::fatalError(0, "couldn't create pthread key for stdlib TLS: %s\n", - std::strerror(result)); - }, nullptr); + swift::tls_alloc_once(token, key, [](void *)pointer { + _stdlib_destroyTLS(pointer); + }); - void *value = SWIFT_THREAD_GETSPECIFIC(key); + void *value = swift::tls_get(key); if (!value) { value = _stdlib_createTLS(); - int result = SWIFT_THREAD_SETSPECIFIC(key, value); - if (result != 0) - swift::fatalError(0, "pthread_setspecific failed: %s\n", - std::strerror(result)); + swift::tls_set(key, value); } return value; -} #endif + +} diff --git a/stdlib/toolchain/Compatibility50/ProtocolConformance.cpp b/stdlib/toolchain/Compatibility50/ProtocolConformance.cpp index a48e801a5a43a..51bb7aee766b6 100644 --- a/stdlib/toolchain/Compatibility50/ProtocolConformance.cpp +++ b/stdlib/toolchain/Compatibility50/ProtocolConformance.cpp @@ -19,7 +19,7 @@ #include "Overrides.h" #include "../../public/runtime/Private.h" -#include "swift/Basic/Lazy.h" +#include "swift/Threading/Once.h" #include #include #include @@ -91,8 +91,8 @@ swift::swift50override_conformsToProtocol(const Metadata *type, ConformsToProtocol_t *original_conformsToProtocol) { // Register our add image callback if necessary. - static OnceToken_t token; - SWIFT_ONCE_F(token, registerAddImageCallback, nullptr); + static swift::once_t token; + swift::once(token, registerAddImageCallback, nullptr); // The implementation of swift_conformsToProtocol in Swift 5.0 would return // a false negative answer when asking whether a subclass conforms using diff --git a/stdlib/toolchain/CompatibilityDynamicReplacements/DynamicReplaceable.cpp b/stdlib/toolchain/CompatibilityDynamicReplacements/DynamicReplaceable.cpp index c3467e2bf901e..7067319589e42 100644 --- a/stdlib/toolchain/CompatibilityDynamicReplacements/DynamicReplaceable.cpp +++ b/stdlib/toolchain/CompatibilityDynamicReplacements/DynamicReplaceable.cpp @@ -19,8 +19,7 @@ #include "swift/Runtime/Exclusivity.h" #include "swift/Runtime/FunctionReplacement.h" -#include "swift/Runtime/Once.h" -#include "swift/Runtime/ThreadLocalStorage.h" +#include "swift/Threading/ThreadLocalStorage.h" using namespace swift; @@ -41,11 +40,11 @@ extern "C" char *swift_getFunctionReplacement50(char **ReplFnPtr, char *CurrFn) return nullptr; auto origKey = - (uintptr_t)SWIFT_THREAD_GETSPECIFIC(SWIFT_COMPATIBILITY_50_TLS_KEY); + (uintptr_t)swift::tls_get(SWIFT_COMPATIBILITY_50_TLS_KEY); if ((origKey & 0x1) != 0) { auto mask = ((uintptr_t)-1) < 1; auto resetKey = origKey & mask; - SWIFT_THREAD_SETSPECIFIC(SWIFT_COMPATIBILITY_50_TLS_KEY, (void *)resetKey); + swift::tls_set(SWIFT_COMPATIBILITY_50_TLS_KEY, (void *)resetKey); return nullptr; } return ReplFn; @@ -59,9 +58,9 @@ extern "C" char *swift_getOrigOfReplaceable50(char **OrigFnPtr) { char *OrigFn = *OrigFnPtr; auto origKey = - (uintptr_t)SWIFT_THREAD_GETSPECIFIC(SWIFT_COMPATIBILITY_50_TLS_KEY); + (uintptr_t)swift::tls_get(SWIFT_COMPATIBILITY_50_TLS_KEY); auto newKey = origKey | 0x1; - SWIFT_THREAD_SETSPECIFIC(SWIFT_COMPATIBILITY_50_TLS_KEY, (void *)newKey); + swift::tls_set(SWIFT_COMPATIBILITY_50_TLS_KEY, (void *)newKey); return OrigFn; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2098f93114638..30883669dcc20 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,6 +1,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules") include(SwiftTestUtils) +include(Threading) function(swift_configure_lit_site_cfg source_path destination_path installed_name) if (CMAKE_CFG_INTDIR STREQUAL ".") @@ -394,6 +395,14 @@ foreach(SDK ${SWIFT_SDKS}) list(APPEND LIT_ARGS "--param" "string_processing") endif() + if("${SWIFT_SDK_${SDK}_THREADING_PACKAGE}") + list(APPEND LIT_ARGS "--param" "threading=${SWIFT_SDK_${SDK}_THREADING_PACKAGE}") + else() + threading_package_default("${SDK}" SWIFT_THREADING_PACKAGE) + list(APPEND LIT_ARGS "--param" + "threading=${SWIFT_THREADING_PACKAGE}") + endif() + foreach(test_subset ${TEST_SUBSETS}) set(directories) set(dependencies ${test_dependencies}) diff --git a/test/IRGen/prespecialized-metadata/class-class-flags-run.swift b/test/IRGen/prespecialized-metadata/class-class-flags-run.swift index 265b146b060b0..5d29e157eccc9 100644 --- a/test/IRGen/prespecialized-metadata/class-class-flags-run.swift +++ b/test/IRGen/prespecialized-metadata/class-class-flags-run.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %llvm_src_root/include -I %llvm_obj_root/include -L %clang-include-dir/../lib/swift/macosx +// RUN: %clang -c -v %target-cc-options %target-threading-opt -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %llvm_src_root/include -I %llvm_obj_root/include -L %clang-include-dir/../lib/swift/macosx // RUN: %target-build-swift -v %mcp_opt %s %t/isPrespecialized.o -import-objc-header %S/Inputs/isPrespecialized.h -Xfrontend -prespecialize-generic-metadata -target %module-target-future -lc++ -L %clang-include-dir/../lib/swift/macosx -sdk %sdk -o %t/main // RUN: %target-codesign %t/main diff --git a/test/IRGen/prespecialized-metadata/enum-extradata-run.swift b/test/IRGen/prespecialized-metadata/enum-extradata-run.swift index 14b4cc981df34..8e59bc10ab3b8 100644 --- a/test/IRGen/prespecialized-metadata/enum-extradata-run.swift +++ b/test/IRGen/prespecialized-metadata/enum-extradata-run.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/extraDataFields.cpp -o %t/extraDataFields.o -I %clang-include-dir -I %swift_src_root/include/ -I %llvm_src_root/include -I %llvm_obj_root/include -L %clang-include-dir/../lib/swift/macosx +// RUN: %clang -c -v %target-cc-options %target-threading-opt -g -O0 -isysroot %sdk %S/Inputs/extraDataFields.cpp -o %t/extraDataFields.o -I %clang-include-dir -I %swift_src_root/include/ -I %llvm_src_root/include -I %llvm_obj_root/include -L %clang-include-dir/../lib/swift/macosx // RUN: %target-build-swift -c %S/Inputs/enum-extra-data-fields.swift -emit-library -emit-module -enable-library-evolution -module-name ExtraDataFieldsNoTrailingFlags -target %module-target-future -Xfrontend -disable-generic-metadata-prespecialization -emit-module-path %t/ExtraDataFieldsNoTrailingFlags.swiftmodule -o %t/%target-library-name(ExtraDataFieldsNoTrailingFlags) // RUN: %target-build-swift -c %S/Inputs/enum-extra-data-fields.swift -emit-library -emit-module -enable-library-evolution -module-name ExtraDataFieldsTrailingFlags -target %module-target-future -Xfrontend -prespecialize-generic-metadata -emit-module-path %t/ExtraDataFieldsTrailingFlags.swiftmodule -o %t/%target-library-name(ExtraDataFieldsTrailingFlags) diff --git a/test/IRGen/prespecialized-metadata/enum-trailing-flags-run.swift b/test/IRGen/prespecialized-metadata/enum-trailing-flags-run.swift index 227b8f31f23ec..dfa893285f840 100644 --- a/test/IRGen/prespecialized-metadata/enum-trailing-flags-run.swift +++ b/test/IRGen/prespecialized-metadata/enum-trailing-flags-run.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %llvm_src_root/include -I %llvm_obj_root/include -L %clang-include-dir/../lib/swift/macosx +// RUN: %clang -c -v %target-cc-options %target-threading-opt -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %llvm_src_root/include -I %llvm_obj_root/include -L %clang-include-dir/../lib/swift/macosx // RUN: %target-build-swift -v %mcp_opt %s %t/isPrespecialized.o -import-objc-header %S/Inputs/isPrespecialized.h -Xfrontend -prespecialize-generic-metadata -target %module-target-future -lc++ -L %clang-include-dir/../lib/swift/macosx -sdk %sdk -o %t/main // RUN: %target-codesign %t/main diff --git a/test/IRGen/prespecialized-metadata/struct-extradata-run.swift b/test/IRGen/prespecialized-metadata/struct-extradata-run.swift index 6125ef79efc65..9f9d876172f26 100644 --- a/test/IRGen/prespecialized-metadata/struct-extradata-run.swift +++ b/test/IRGen/prespecialized-metadata/struct-extradata-run.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/extraDataFields.cpp -o %t/extraDataFields.o -I %clang-include-dir -I %swift_src_root/include/ -I %llvm_src_root/include -I %llvm_obj_root/include -L %clang-include-dir/../lib/swift/macosx -I %swift_obj_root/include +// RUN: %clang -c -v %target-cc-options %target-threading-opt -g -O0 -isysroot %sdk %S/Inputs/extraDataFields.cpp -o %t/extraDataFields.o -I %clang-include-dir -I %swift_src_root/include/ -I %llvm_src_root/include -I %llvm_obj_root/include -L %clang-include-dir/../lib/swift/macosx -I %swift_obj_root/include // RUN: %target-build-swift -c %S/Inputs/struct-extra-data-fields.swift -emit-library -emit-module -module-name ExtraDataFieldsNoTrailingFlags -target %module-target-future -Xfrontend -disable-generic-metadata-prespecialization -emit-module-path %t/ExtraDataFieldsNoTrailingFlags.swiftmodule -o %t/%target-library-name(ExtraDataFieldsNoTrailingFlags) // RUN: %target-build-swift -c %S/Inputs/struct-extra-data-fields.swift -emit-library -emit-module -module-name ExtraDataFieldsTrailingFlags -target %module-target-future -Xfrontend -prespecialize-generic-metadata -emit-module-path %t/ExtraDataFieldsTrailingFlags.swiftmodule -o %t/%target-library-name(ExtraDataFieldsTrailingFlags) diff --git a/test/IRGen/prespecialized-metadata/struct-multi-conformance.swift b/test/IRGen/prespecialized-metadata/struct-multi-conformance.swift index 2eadbb46f97ca..97153c7681e19 100644 --- a/test/IRGen/prespecialized-metadata/struct-multi-conformance.swift +++ b/test/IRGen/prespecialized-metadata/struct-multi-conformance.swift @@ -5,7 +5,7 @@ // RUN: %target-build-swift -c %s -DCONFORMANCE_2 -emit-library -emit-module -module-name Conformance2 -target %module-target-future -Xfrontend -prespecialize-generic-metadata -emit-module-path %t/Conformance2.swiftmodule -o %t/%target-library-name(Conformance2) -lBase -I %t -L %t // RUN: %target-build-swift -c %s -DGENERIC -emit-library -emit-module -module-name Generic -target %module-target-future -Xfrontend -prespecialize-generic-metadata -emit-module-path %t/Generic.swiftmodule -o %t/%target-library-name(Generic) -lBase -lConformance1 -I %t -L %t // RUN: %target-build-swift -c %s -DERASE -emit-library -emit-module -module-name Erase -target %module-target-future -Xfrontend -prespecialize-generic-metadata -emit-module-path %t/Erase.swiftmodule -o %t/%target-library-name(Erase) -lBase -lConformance2 -I %t -L %t -// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %llvm_src_root/include -I %llvm_obj_root/include -L %clang-include-dir/../lib/swift/macosx +// RUN: %clang -c -v %target-cc-options %target-threading-opt -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %llvm_src_root/include -I %llvm_obj_root/include -L %clang-include-dir/../lib/swift/macosx // RUN: %target-build-swift %s %S/Inputs/main.swift %S/Inputs/consume-logging-metadata-value.swift %t/isPrespecialized.o -import-objc-header %S/Inputs/isPrespecialized.h -DMAIN -target %module-target-future -Xfrontend -prespecialize-generic-metadata -lBase -lConformance1 -lConformance2 -lGeneric -lErase -lc++ -I %t -L %t -L %clang-include-dir/../lib/swift/macosx -o %t/main // RUN: %target-codesign %t/main diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-run.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-run.swift index d91573301b7ed..d63c93316d8a9 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-run.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-run.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %llvm_src_root/include -I %llvm_obj_root/include -L %clang-include-dir/../lib/swift/macosx +// RUN: %clang -c -v %target-cc-options %target-threading-opt -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %llvm_src_root/include -I %llvm_obj_root/include -L %clang-include-dir/../lib/swift/macosx // RUN: %target-build-swift %S/Inputs/struct-public-nonfrozen-1argument.swift -emit-module -emit-library -module-name Module -Xfrontend -prespecialize-generic-metadata -target %module-target-future -emit-module-path %t/Module.swiftmodule -o %t/%target-library-name(Module) diff --git a/test/IRGen/prespecialized-metadata/struct-trailing-flags-run.swift b/test/IRGen/prespecialized-metadata/struct-trailing-flags-run.swift index a896e21db6e9f..5eaa447ce7763 100644 --- a/test/IRGen/prespecialized-metadata/struct-trailing-flags-run.swift +++ b/test/IRGen/prespecialized-metadata/struct-trailing-flags-run.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %llvm_src_root/include -I %llvm_obj_root/include -L %clang-include-dir/../lib/swift/macosx +// RUN: %clang -c -v %target-cc-options %target-threading-opt -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %llvm_src_root/include -I %llvm_obj_root/include -L %clang-include-dir/../lib/swift/macosx // RUN: %target-build-swift -v %mcp_opt %s %t/isPrespecialized.o -import-objc-header %S/Inputs/isPrespecialized.h -Xfrontend -prespecialize-generic-metadata -target %module-target-future -lc++ -L %clang-include-dir/../lib/swift/macosx -sdk %sdk -o %t/main // RUN: %target-codesign %t/main diff --git a/test/TypeRoundTrip/round-trip.swift b/test/TypeRoundTrip/round-trip.swift index ecac9c6150bc1..b9fd055c7cb39 100644 --- a/test/TypeRoundTrip/round-trip.swift +++ b/test/TypeRoundTrip/round-trip.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %target-clang -std=c++14 %target-rtti-opt %target-pic-opt %target-msvc-runtime-opt -DSWIFT_INLINE_NAMESPACE=__runtime -g -c %S/Inputs/RoundTrip/RoundTrip.cpp -I%swift_obj_root/include -I%swift_src_root/include -I%swift_src_root/stdlib/include -I%swift_src_root/stdlib/public/runtime -I%llvm_src_root/include -I%llvm_obj_root/include -o %t/RoundTrip.o +// RUN: %target-clang -std=c++14 %target-threading-opt %target-rtti-opt %target-pic-opt %target-msvc-runtime-opt -DSWIFT_INLINE_NAMESPACE=__runtime -g -c %S/Inputs/RoundTrip/RoundTrip.cpp -I%swift_obj_root/include -I%swift_src_root/include -I%swift_src_root/stdlib/include -I%swift_src_root/stdlib/public/runtime -I%llvm_src_root/include -I%llvm_obj_root/include -o %t/RoundTrip.o // RUN: %target-build-swift -g -static -emit-module-path %t/RoundTrip.swiftmodule -emit-module -emit-library -module-name RoundTrip -o %t/%target-static-library-name(RoundTrip) %S/Inputs/RoundTrip/RoundTrip.swift %t/RoundTrip.o // RUN: echo "// AUTOGENERATED" > %t/all-tests.swift // RUN: for module in %S/Inputs/testcases/*.swift; do modname=$(basename $module .swift); echo "import $modname" >> %t/all-tests.swift; done diff --git a/test/lit.cfg b/test/lit.cfg index 9ccf987f95eb9..6db7a6af29dc5 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -448,6 +448,14 @@ if string_processing is not None: config.available_features.add('lld_lto') +threading = lit_config.params.get('threading', 'none') +config.available_features.add('threading_{}'.format(threading)) +if threading != "none": + config.available_features.add('thread_safe_runtime') + +config.substitutions.append(('%target-threading-opt', + '-DSWIFT_THREADING_{0}=1'.format(threading.upper()))) + test_options = os.environ.get('SWIFT_TEST_OPTIONS') if test_options: config.swift_test_options += ' ' diff --git a/test/lit.site.cfg.in b/test/lit.site.cfg.in index dc5cb938be465..1299d45c51534 100644 --- a/test/lit.site.cfg.in +++ b/test/lit.site.cfg.in @@ -99,10 +99,10 @@ if "@SWIFT_OPTIMIZED@" == "TRUE": if "@SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY@" == "TRUE": config.available_features.add("single_threaded_concurrency") -if "@SWIFT_STDLIB_THREADING_PACKAGE@" != "none": +if "@SWIFT_THREADING_PACKAGE@" != "none": # This is not called "threading" because we might want that later config.available_features.add("thread_safe_runtime") - config.available_features.add("threading_@SWIFT_STDLIB_THREADING_PACKAGE@") + config.available_features.add("threading_@SWIFT_THREADING_PACKAGE@") if "@SWIFT_ENABLE_REFLECTION@" == "TRUE": config.available_features.add("reflection") diff --git a/unittests/runtime/Mutex.cpp b/unittests/Threading/Mutex.cpp similarity index 89% rename from unittests/runtime/Mutex.cpp rename to unittests/Threading/Mutex.cpp index b09e45888a999..c4e4ae4dbe28d 100644 --- a/unittests/runtime/Mutex.cpp +++ b/unittests/Threading/Mutex.cpp @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -#include "swift/Runtime/Mutex.h" +#include "swift/Threading/Mutex.h" #include "gtest/gtest.h" #include #include @@ -46,13 +46,13 @@ TEST(MutexTest, BasicLockableThreaded) { basicLockableThreaded(mutex); } -TEST(StaticMutexTest, BasicLockableThreaded) { - static StaticMutex mutex; +TEST(LazyMutexTest, BasicLockableThreaded) { + static LazyMutex mutex; basicLockableThreaded(mutex); } -TEST(StaticUnsafeMutexTest, BasicLockableThreaded) { - static StaticUnsafeMutex mutex; +TEST(LazyUnsafeMutexTest, BasicLockableThreaded) { + static LazyUnsafeMutex mutex; basicLockableThreaded(mutex); } @@ -94,8 +94,8 @@ TEST(MutexTest, LockableThreaded) { lockableThreaded(mutex); } -TEST(StaticMutexTest, LockableThreaded) { - static StaticMutex Mutex; +TEST(LazyMutexTest, LockableThreaded) { + static LazyMutex Mutex; lockableThreaded(Mutex); } @@ -126,9 +126,9 @@ TEST(MutexTest, ScopedLockThreaded) { scopedLockThreaded(mutex); } -TEST(StaticMutexTest, ScopedLockThreaded) { - static StaticMutex Mutex; - scopedLockThreaded(Mutex); +TEST(LazyMutexTest, ScopedLockThreaded) { + static LazyMutex Mutex; + scopedLockThreaded(Mutex); } TEST(SmallMutexTest, ScopedLockThreaded) { @@ -165,10 +165,10 @@ TEST(MutexTest, ScopedUnlockUnderScopedLockThreaded) { mutex); } -TEST(StaticMutexTest, ScopedUnlockUnderScopedLockThreaded) { - static StaticMutex Mutex; - scopedUnlockUnderScopedLockThreaded(Mutex); +TEST(LazyMutexTest, ScopedUnlockUnderScopedLockThreaded) { + static LazyMutex Mutex; + scopedUnlockUnderScopedLockThreaded(Mutex); } TEST(SmallMutexTest, ScopedUnlockUnderScopedLockThreaded) { @@ -200,8 +200,8 @@ TEST(MutexTest, CriticalSectionThreaded) { criticalSectionThreaded(mutex); } -TEST(StaticMutexTest, CriticalSectionThreaded) { - static StaticMutex Mutex; +TEST(LazyMutexTest, CriticalSectionThreaded) { + static LazyMutex Mutex; criticalSectionThreaded(Mutex); } diff --git a/unittests/Threading/ThreadingHelpers.h b/unittests/Threading/ThreadingHelpers.h new file mode 100644 index 0000000000000..667c847959744 --- /dev/null +++ b/unittests/Threading/ThreadingHelpers.h @@ -0,0 +1,134 @@ +//===--- Concurrent.cpp - Concurrent data structure tests -----------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 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 THREADING_HELPERS_H +#define THREADING_HELPERS_H + +#include + +// When true many of the threaded tests log activity to help triage issues. +static bool trace = false; + +template +void threadedExecute(int threadCount, ThreadBody threadBody, + AfterSpinRelease afterSpinRelease) { + + std::vector threads; + + // Block the threads we are about to create. + std::atomic spinWait(true); + std::atomic readyCount(0); + std::atomic activeCount(0); + + for (int i = 0; i < threadCount; ++i) { + threads.push_back(std::thread([&, i] { + readyCount++; + + while (spinWait) { + std::this_thread::sleep_for(std::chrono::microseconds(10)); + } + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + + activeCount++; + + threadBody(i); + })); + } + + while (readyCount < threadCount) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + + // Allow our threads to fight for the lock. + spinWait = false; + + while (activeCount < threadCount) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + + afterSpinRelease(); + + // Wait until all of our threads have finished. + for (auto &thread : threads) { + thread.join(); + } +} + +template +void threadedExecute(int threadCount, ThreadBody threadBody) { + threadedExecute(threadCount, threadBody, [] {}); +} + +template +void threadedExecute(M &mutex, C &condition, bool &doneCondition, + ConsumerBody consumerBody, ProducerBody producerBody) { + + std::vector producers; + std::vector consumers; + + // Block the threads we are about to create. + std::atomic spinWait(true); + + for (int i = 1; i <= 8; ++i) { + consumers.push_back(std::thread([&, i] { + while (spinWait) { + std::this_thread::sleep_for(std::chrono::microseconds(10)); + } + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + + consumerBody(i); + + if (trace) + printf("### Consumer[%d] thread exiting.\n", i); + })); + } + + for (int i = 1; i <= 5; ++i) { + producers.push_back(std::thread([&, i] { + while (spinWait) { + std::this_thread::sleep_for(std::chrono::microseconds(10)); + } + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + + producerBody(i); + + if (trace) + printf("### Producer[%d] thread exiting.\n", i); + })); + } + + // Poor mans attempt to get as many threads ready as possible before + // dropping spinWait, it doesn't have to be perfect. + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + // Allow our threads to fight for the lock. + spinWait = false; + + // Wait until all of our producer threads have finished. + for (auto &thread : producers) { + thread.join(); + } + + // Inform consumers that producers are done. + mutex.withLockThenNotifyAll(condition, [&] { + if (trace) + printf("### Informing consumers we are done.\n"); + doneCondition = true; + }); + + // Wait for consumers to finish. + for (auto &thread : consumers) { + thread.join(); + } +} + +#endif diff --git a/unittests/runtime/CMakeLists.txt b/unittests/runtime/CMakeLists.txt index bc086d84b421f..dfd405dbd849c 100644 --- a/unittests/runtime/CMakeLists.txt +++ b/unittests/runtime/CMakeLists.txt @@ -84,7 +84,7 @@ if(("${SWIFT_HOST_VARIANT_SDK}" STREQUAL "${SWIFT_PRIMARY_VARIANT_SDK}") AND endif() endif() - if(NOT "${SWIFT_STDLIB_THREADING_PACKAGE}" STREQUAL "none") + if(NOT "${SWIFT_THREADING_PACKAGE}" STREQUAL "none") list(APPEND PLATFORM_SOURCES Mutex.cpp) endif() diff --git a/utils/build-script-impl b/utils/build-script-impl index 981f1f9a10e4e..3a47fc49eb60c 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -206,7 +206,7 @@ KNOWN_SETTINGS=( swift-stdlib-has-dladdr "1" "whether to build stdlib assuming the runtime environment provides dladdr API" swift-stdlib-supports-backtrace-reporting "" "whether to build stdlib assuming the runtime environment provides the backtrace(3) API, if not set defaults to true on all platforms except for Cygwin, Haiku and wasm" swift-runtime-static-image-inspection "0" "whether to build stdlib assuming the runtime environment only supports a single runtime image with Swift code" - swift-stdlib-threading-package "" "which threading package to use for Swift; valid values are empty string (default based on platform), 'pthreads', 'darwin', 'win32', 'c11', 'none'" + swift-threading-package "" "which threading package to use for Swift; valid values are empty string (default based on platform), 'pthreads', 'darwin', 'linux', 'win32', 'c11', 'none'" swift-stdlib-single-threaded-concurrency "0" "build Swift concurrency in single-threaded mode" swift-stdlib-concurrency-tracing "" "whether to enable tracing signposts for concurrency; default is 1 on Darwin platforms, 0 otherwise" swift-stdlib-os-versioning "1" "whether to build stdlib with availability based on OS versions (Darwin only)" @@ -2227,18 +2227,18 @@ for host in "${ALL_HOSTS[@]}"; do ) fi - if [[ "${SWIFT_STDLIB_THREADING_PACKAGE}" ]] ; then - case "${SWIFT_STDLIB_THREADING_PACKAGE}" in - "" | pthreads | darwin | win32 | c11 | none) ;; + if [[ "${SWIFT_THREADING_PACKAGE}" ]] ; then + case "${SWIFT_THREADING_PACKAGE}" in + "" | pthreads | darwin | linux | win32 | c11 | none) ;; *) - echo "build-script: unknown threading package ${SWIFT_STDLIB_THREADING_PACKAGE}; must be one of 'pthreads', 'darwin', 'win32', 'c11', 'none', or empty for platform default" >&2 + echo "build-script: unknown threading package ${SWIFT_THREADING_PACKAGE}; must be one of 'pthreads', 'darwin', 'linux', 'win32', 'c11', 'none', or empty for platform default" >&2 exit 1 ;; esac cmake_options=( "${cmake_options[@]}" - -DSWIFT_STDLIB_THREADING_PACKAGE:STRING="${SWIFT_STDLIB_THREADING_PACKAGE}" + -DSWIFT_THREADING_PACKAGE:STRING="${SWIFT_THREADING_PACKAGE}" ) fi diff --git a/validation-test/lit.site.cfg.in b/validation-test/lit.site.cfg.in index cd49fe8f293fe..ee541f7f53657 100644 --- a/validation-test/lit.site.cfg.in +++ b/validation-test/lit.site.cfg.in @@ -97,10 +97,10 @@ if "@SWIFT_ENABLE_SOURCEKIT_TESTS@" == "TRUE": if "@SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY@" == "TRUE": config.available_features.add("single_threaded_concurrency") -if "@SWIFT_STDLIB_THREADING_PACKAGE@" != "none": +if "@SWIFT_THREADING_PACKAGE@" != "none": # This is not called "threading" because we might want that later config.available_features.add("thread_safe_runtime") - config.available_features.add("threading_@SWIFT_STDLIB_THREADING_PACKAGE@") + config.available_features.add("threading_@SWIFT_THREADING_PACKAGE@") if "@SWIFT_ENABLE_REFLECTION@" == "TRUE": config.available_features.add("reflection") From 2ba80e1180016f1f80b9bfdfa0d805b2077716cb Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Wed, 20 Apr 2022 12:50:19 +0100 Subject: [PATCH 04/40] [Unittests] Make the Threading unit tests work. The threading unit tests currently just check the operation of Mutex. This used to be part of the runtime tests, but now it's a separate library we can test it separately. rdar://90776105 --- unittests/CMakeLists.txt | 1 + unittests/Threading/CMakeLists.txt | 9 +++++++++ unittests/runtime/CMakeLists.txt | 7 +------ 3 files changed, 11 insertions(+), 6 deletions(-) create mode 100644 unittests/Threading/CMakeLists.txt diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index cd2e6bdac1b55..be3c50083a30f 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -22,6 +22,7 @@ if(SWIFT_INCLUDE_TOOLS) if(SWIFT_BUILD_SYNTAXPARSERLIB) add_subdirectory(SyntaxParser) endif() + add_subdirectory(Threading) if(SWIFT_BUILD_SDK_OVERLAY) # Runtime tests depend on symbols in StdlibUnittest. diff --git a/unittests/Threading/CMakeLists.txt b/unittests/Threading/CMakeLists.txt new file mode 100644 index 0000000000000..35e1a75c37cbf --- /dev/null +++ b/unittests/Threading/CMakeLists.txt @@ -0,0 +1,9 @@ +add_swift_unittest(SwiftThreadingTests + Mutex.cpp + ) + +target_link_libraries(SwiftThreadingTests + PRIVATE + swiftThreading${SWIFT_PRIMARY_VARIANT_SUFFIX} + swiftCore${SWIFT_PRIMARY_VARIANT_SUFFIX} + ) diff --git a/unittests/runtime/CMakeLists.txt b/unittests/runtime/CMakeLists.txt index dfd405dbd849c..cb6bf9bbb57dd 100644 --- a/unittests/runtime/CMakeLists.txt +++ b/unittests/runtime/CMakeLists.txt @@ -84,10 +84,6 @@ if(("${SWIFT_HOST_VARIANT_SDK}" STREQUAL "${SWIFT_PRIMARY_VARIANT_SDK}") AND endif() endif() - if(NOT "${SWIFT_THREADING_PACKAGE}" STREQUAL "none") - list(APPEND PLATFORM_SOURCES Mutex.cpp) - endif() - if(SWIFT_ENABLE_EXPERIMENTAL_DISTRIBUTED) # list(APPEND PLATFORM_SOURCES # DistributedActor.cpp @@ -102,8 +98,7 @@ if(("${SWIFT_HOST_VARIANT_SDK}" STREQUAL "${SWIFT_PRIMARY_VARIANT_SDK}") AND weak.mm Refcounting.mm Actor.cpp - TaskStatus.cpp - Mutex.cpp) + TaskStatus.cpp) add_swift_unittest(SwiftRuntimeTests Array.cpp From 785f4a215c294f08ab0007a7aaeab0b6ff2cccc3 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Wed, 20 Apr 2022 15:22:26 +0100 Subject: [PATCH 05/40] [Unittests] Add more threading library tests. Added explicit tests for `swift::once` and also for the ulock implementation used on Linux. rdar://90776105 --- unittests/Threading/CMakeLists.txt | 2 + unittests/Threading/LinuxUlock.cpp | 58 ++++++++ unittests/Threading/LockingHelpers.h | 151 ++++++++++++++++++++ unittests/Threading/Mutex.cpp | 188 +++++-------------------- unittests/Threading/Once.cpp | 66 +++++++++ unittests/Threading/ThreadingHelpers.h | 2 +- 6 files changed, 315 insertions(+), 152 deletions(-) create mode 100644 unittests/Threading/LinuxUlock.cpp create mode 100644 unittests/Threading/LockingHelpers.h create mode 100644 unittests/Threading/Once.cpp diff --git a/unittests/Threading/CMakeLists.txt b/unittests/Threading/CMakeLists.txt index 35e1a75c37cbf..83bc84b18fa8e 100644 --- a/unittests/Threading/CMakeLists.txt +++ b/unittests/Threading/CMakeLists.txt @@ -1,5 +1,7 @@ add_swift_unittest(SwiftThreadingTests Mutex.cpp + Once.cpp + LinuxUlock.cpp ) target_link_libraries(SwiftThreadingTests diff --git a/unittests/Threading/LinuxUlock.cpp b/unittests/Threading/LinuxUlock.cpp new file mode 100644 index 0000000000000..cf274d8b8f1f8 --- /dev/null +++ b/unittests/Threading/LinuxUlock.cpp @@ -0,0 +1,58 @@ +//===--- LinuxULock.cpp - Tests the Linux ulock implementation ------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#if SWIFT_THREADING_LINUX + +#include "swift/Threading/Impl/Linux/ulock.h" +#include "gtest/gtest.h" + +#include "LockingHelpers.h" + +using namespace swift; +using namespace swift::threading_impl; + +// ----------------------------------------------------------------------------- + +// Use the existing locking tests to check threaded operation +class UlockMutex { +private: + linux::ulock_t lock_; + +public: + UlockMutex() : lock_(0) {} + + void lock() { linux::ulock_lock(&lock); } + void unlock() { linux::ulock_unlock(&lock); } + bool try_lock() { return linux::ulock_trylock(&lock); } +}; + +TEST(LinuxUlockTest, SingleThreaded) { + UlockMutex mutex; + basicLockable(mutex); +} + +TEST(LinuxUlockTest, SingleThreadedTryLock) { + UlockMutex mutex; + tryLockable(mutex); +} + +TEST(LinuxULockTest, BasicLockableThreaded) { + UlockMutex mutex; + basicLockableThreaded(mutex); +} + +TEST(LinuxULockTest, LockableThreaded) { + UlockMutex mutex; + lockableThreaded(mutex); +} + +#endif // SWIFT_THREADING_LINUX diff --git a/unittests/Threading/LockingHelpers.h b/unittests/Threading/LockingHelpers.h new file mode 100644 index 0000000000000..0929a1eeaa0bb --- /dev/null +++ b/unittests/Threading/LockingHelpers.h @@ -0,0 +1,151 @@ +//===--- LockingHelpers.h - Utilities to help test locks ------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 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 LOCKING_HELPERS_H +#define LOCKING_HELPERS_H + +#include "ThreadingHelpers.h" + +// Test that a Mutex object can be locked and unlocked from a single thread +template void basicLockable(M &mutex) { + // We can lock, unlock, lock and unlock an unlocked lock + mutex.lock(); + mutex.unlock(); + mutex.lock(); + mutex.unlock(); +} + +// Test that a Mutex object's try_lock() method works. +template void tryLockable(M &mutex) { + bool ret; + + // We can lock an unlocked lock + ret = mutex.try_lock(); + ASSERT_TRUE(ret); + + // We cannot lock a locked lock + ret = mutex.try_lock(); + ASSERT_FALSE(ret); + + mutex.unlock(); +} + +// Test that a Mutex object can be locked and unlocked +template void basicLockableThreaded(M &mutex) { + int count1 = 0; + int count2 = 0; + + threadedExecute(10, [&](int) { + for (int j = 0; j < 50; ++j) { + mutex.lock(); + auto count = count2; + count1++; + count2 = count + 1; + mutex.unlock(); + } + }); + + ASSERT_EQ(count1, 500); + ASSERT_EQ(count2, 500); +} + +// More extensive tests +template void lockableThreaded(M &mutex) { + mutex.lock(); + threadedExecute(5, [&](int) { ASSERT_FALSE(mutex.try_lock()); }); + mutex.unlock(); + threadedExecute(1, [&](int) { + ASSERT_TRUE(mutex.try_lock()); + mutex.unlock(); + }); + + int count1 = 0; + int count2 = 0; + threadedExecute(10, [&](int) { + for (int j = 0; j < 50; ++j) { + if (mutex.try_lock()) { + auto count = count2; + count1++; + count2 = count + 1; + mutex.unlock(); + } else { + j--; + } + } + }); + + ASSERT_EQ(count1, 500); + ASSERT_EQ(count2, 500); +} + +// Test a scoped lock implementation +template void scopedLockThreaded(M &mutex) { + int count1 = 0; + int count2 = 0; + + threadedExecute(10, [&](int) { + for (int j = 0; j < 50; ++j) { + SL guard(mutex); + auto count = count2; + count1++; + count2 = count + 1; + } + }); + + ASSERT_EQ(count1, 500); + ASSERT_EQ(count2, 500); +} + +// Test a scoped unlock nested in a scoped lock +template +void scopedUnlockUnderScopedLockThreaded(M &mutex) { + int count1 = 0; + int count2 = 0; + int badCount = 0; + + threadedExecute(10, [&](int) { + for (int j = 0; j < 50; ++j) { + SL guard(mutex); + { + SU unguard(mutex); + badCount++; + } + auto count = count2; + count1++; + count2 = count + 1; + } + }); + + ASSERT_EQ(count1, 500); + ASSERT_EQ(count2, 500); +} + +// Test a critical section +template void criticalSectionThreaded(M &mutex) { + int count1 = 0; + int count2 = 0; + + threadedExecute(10, [&](int) { + for (int j = 0; j < 50; ++j) { + mutex.withLock([&] { + auto count = count2; + count1++; + count2 = count + 1; + }); + } + }); + + ASSERT_EQ(count1, 500); + ASSERT_EQ(count2, 500); +} + +#endif diff --git a/unittests/Threading/Mutex.cpp b/unittests/Threading/Mutex.cpp index c4e4ae4dbe28d..d5e5dbd45d2f4 100644 --- a/unittests/Threading/Mutex.cpp +++ b/unittests/Threading/Mutex.cpp @@ -17,28 +17,50 @@ #include #include -#include "ThreadingHelpers.h" +#include "LockingHelpers.h" using namespace swift; // ----------------------------------------------------------------------------- -template void basicLockableThreaded(M &mutex) { - int count1 = 0; - int count2 = 0; +TEST(MutexTest, BasicLockable) { + Mutex mutex(/* checked = */ true); + basicLockable(mutex); +} + +TEST(LazyMutexTest, BasicLockable) { + static LazyMutex mutex; + basicLockable(mutex); +} + +TEST(LazyUnsafeMutexTest, BasicLockable) { + static LazyUnsafeMutex mutex; + basicLockable(mutex); +} + +TEST(SmallMutex, BasicLockable) { + SmallMutex mutex; + basicLockable(mutex); +} - threadedExecute(10, [&](int) { - for (int j = 0; j < 50; ++j) { - mutex.lock(); - auto count = count2; - count1++; - count2 = count + 1; - mutex.unlock(); - } - }); +TEST(MutexTest, TryLockable) { + Mutex mutex(/* checked = */ true); + tryLockable(mutex); +} + +TEST(LazyMutexTest, TryLockable) { + static LazyMutex mutex; + tryLockable(mutex); +} - ASSERT_EQ(count1, 500); - ASSERT_EQ(count2, 500); +TEST(LazyUnsafeMutexTest, TryLockable) { + static LazyUnsafeMutex mutex; + tryLockable(mutex); +} + +TEST(SmallMutex, TryLockable) { + SmallMutex mutex; + tryLockable(mutex); } TEST(MutexTest, BasicLockableThreaded) { @@ -61,34 +83,6 @@ TEST(SmallMutex, BasicLockableThreaded) { basicLockableThreaded(mutex); } -template void lockableThreaded(M &mutex) { - mutex.lock(); - threadedExecute(5, [&](int) { ASSERT_FALSE(mutex.try_lock()); }); - mutex.unlock(); - threadedExecute(1, [&](int) { - ASSERT_TRUE(mutex.try_lock()); - mutex.unlock(); - }); - - int count1 = 0; - int count2 = 0; - threadedExecute(10, [&](int) { - for (int j = 0; j < 50; ++j) { - if (mutex.try_lock()) { - auto count = count2; - count1++; - count2 = count + 1; - mutex.unlock(); - } else { - j--; - } - } - }); - - ASSERT_EQ(count1, 500); - ASSERT_EQ(count2, 500); -} - TEST(MutexTest, LockableThreaded) { Mutex mutex(/* checked = */ true); lockableThreaded(mutex); @@ -104,23 +98,6 @@ TEST(SmallMutexTest, LockableThreaded) { lockableThreaded(Mutex); } -template void scopedLockThreaded(M &mutex) { - int count1 = 0; - int count2 = 0; - - threadedExecute(10, [&](int) { - for (int j = 0; j < 50; ++j) { - SL guard(mutex); - auto count = count2; - count1++; - count2 = count + 1; - } - }); - - ASSERT_EQ(count1, 500); - ASSERT_EQ(count2, 500); -} - TEST(MutexTest, ScopedLockThreaded) { Mutex mutex(/* checked = */ true); scopedLockThreaded(mutex); @@ -136,29 +113,6 @@ TEST(SmallMutexTest, ScopedLockThreaded) { scopedLockThreaded>(mutex); } -template -void scopedUnlockUnderScopedLockThreaded(M &mutex) { - int count1 = 0; - int count2 = 0; - int badCount = 0; - - threadedExecute(10, [&](int) { - for (int j = 0; j < 50; ++j) { - SL guard(mutex); - { - SU unguard(mutex); - badCount++; - } - auto count = count2; - count1++; - count2 = count + 1; - } - }); - - ASSERT_EQ(count1, 500); - ASSERT_EQ(count2, 500); -} - TEST(MutexTest, ScopedUnlockUnderScopedLockThreaded) { Mutex mutex(/* checked = */ true); scopedUnlockUnderScopedLockThreaded( @@ -177,24 +131,6 @@ TEST(SmallMutexTest, ScopedUnlockUnderScopedLockThreaded) { SmallMutex::ScopedUnlock>(mutex); } -template void criticalSectionThreaded(M &mutex) { - int count1 = 0; - int count2 = 0; - - threadedExecute(10, [&](int) { - for (int j = 0; j < 50; ++j) { - mutex.withLock([&] { - auto count = count2; - count1++; - count2 = count + 1; - }); - } - }); - - ASSERT_EQ(count1, 500); - ASSERT_EQ(count2, 500); -} - TEST(MutexTest, CriticalSectionThreaded) { Mutex mutex(/* checked = */ true); criticalSectionThreaded(mutex); @@ -204,53 +140,3 @@ TEST(LazyMutexTest, CriticalSectionThreaded) { static LazyMutex Mutex; criticalSectionThreaded(Mutex); } - -template -void scopedReadThreaded(RW &lock) { - const int threadCount = 10; - - std::set writerHistory; - std::vector> readerHistory; - readerHistory.assign(threadCount, std::set()); - - int protectedValue = 0; - writerHistory.insert(protectedValue); - - threadedExecute(threadCount, - [&](int index) { - if (Locking) { - for (int i = 0; i < 50; ++i) { - { - SRL guard(lock); - readerHistory[index].insert(protectedValue); - } - std::this_thread::yield(); - } - } else { - lock.readLock(); - for (int i = 0; i < 50; ++i) { - readerHistory[index].insert(protectedValue); - - { - SRL unguard(lock); - std::this_thread::yield(); - } - } - lock.readUnlock(); - } - }, - [&] { - for (int i = 0; i < 25; ++i) { - lock.writeLock(); - protectedValue += i; - writerHistory.insert(protectedValue); - lock.writeUnlock(); - } - }); - - for (auto &history : readerHistory) { - for (auto value : history) { - ASSERT_EQ(writerHistory.count(value), 1U); - } - } -} diff --git a/unittests/Threading/Once.cpp b/unittests/Threading/Once.cpp new file mode 100644 index 0000000000000..52686637d68f8 --- /dev/null +++ b/unittests/Threading/Once.cpp @@ -0,0 +1,66 @@ +//===--- Once.cpp - Tests the swift::once() implementation ----------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "swift/Threading/Once.h" +#include "gtest/gtest.h" + +#include "ThreadingHelpers.h" + +using namespace swift; + +// Check that swift::once calls the function, with the correct argument +TEST(OnceTest, once_calls_function) { + static swift::once_t predicate; + bool wasCalled = false; + + swift::once(predicate, [](void *ctx) { + bool *pWasCalled = static_cast(ctx); + *pWasCalled = true; + }, &wasCalled); + + ASSERT_TRUE(wasCalled); +} + +// Check that calling swift::once twice only calls the function once +TEST(OnceTest, once_calls_only_once) { + static swift::once_t predicate; + unsigned callCount = 0; + + void (*fn)(void *) = [](void *ctx) { + unsigned *pCallCount = static_cast(ctx); + ++*pCallCount; + }; + + swift::once(predicate, fn, &callCount); + swift::once(predicate, fn, &callCount); + + ASSERT_EQ(1u, callCount); +} + +// Check that swift::once works when threaded +TEST(OnceTest, once_threaded) { + void (*fn)(void *) = [](void *ctx) { + unsigned *pCallCount = static_cast(ctx); + ++*pCallCount; + }; + + for (unsigned tries = 0; tries < 1000; ++tries) { + swift::once_t predicate = {0}; + unsigned callCount = 0; + + threadedExecute(16, [&](int) { + swift::once(predicate, fn, &callCount); + }); + + ASSERT_EQ(1u, callCount); + } +} diff --git a/unittests/Threading/ThreadingHelpers.h b/unittests/Threading/ThreadingHelpers.h index 667c847959744..08e0e2d9a227f 100644 --- a/unittests/Threading/ThreadingHelpers.h +++ b/unittests/Threading/ThreadingHelpers.h @@ -1,4 +1,4 @@ -//===--- Concurrent.cpp - Concurrent data structure tests -----------------===// +//===--- ThreadingHelpers.h - Utilities to help test threading ------------===// // // This source file is part of the Swift.org open source project // From e934cbcf233024581bd9c0f547c06a480235fcde Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Wed, 20 Apr 2022 16:29:19 +0100 Subject: [PATCH 06/40] [Threading] Fix case sensitivity bug. The file is called Nothreads.cpp, not NoThreads.cpp. rdar://90776105 --- stdlib/public/Threading/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/public/Threading/CMakeLists.txt b/stdlib/public/Threading/CMakeLists.txt index 84f23bce811ab..115fc20ca6be0 100644 --- a/stdlib/public/Threading/CMakeLists.txt +++ b/stdlib/public/Threading/CMakeLists.txt @@ -1,6 +1,6 @@ add_swift_target_library(swiftThreading STATIC "${SWIFT_SOURCE_DIR}/lib/Threading/C11.cpp" - "${SWIFT_SOURCE_DIR}/lib/Threading/NoThreads.cpp" + "${SWIFT_SOURCE_DIR}/lib/Threading/Nothreads.cpp" "${SWIFT_SOURCE_DIR}/lib/Threading/Pthreads.cpp" "${SWIFT_SOURCE_DIR}/lib/Threading/Win32.cpp" INSTALL_IN_COMPONENT never_install) From a6996333e83a234d7c53c15ea2c4b1acb63ef58e Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Wed, 20 Apr 2022 17:13:10 +0100 Subject: [PATCH 07/40] [Threading] Auto-detect threading in the preprocessor. Some things (LLDB's language plugin, for instance), include Swift headers from outside of our build system, and may not know to define one of the threading package defines. rdar://90776105 --- include/swift/Threading/Impl.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/include/swift/Threading/Impl.h b/include/swift/Threading/Impl.h index 9151e2e1b801b..e40ee97f8138c 100644 --- a/include/swift/Threading/Impl.h +++ b/include/swift/Threading/Impl.h @@ -18,6 +18,30 @@ #ifndef SWIFT_THREADING_IMPL_H #define SWIFT_THREADING_IMPL_H +// Try to autodetect if we aren't told what to do +#if !SWIFT_THREADING_NONE && \ + !SWIFT_THREADING_DARWIN && \ + !SWIFT_THREADING_LINUX && \ + !SWIFT_THREADING_PTHREADS && \ + !SWIFT_THREADING_C11 && \ + !SWIFT_THREADING_WIN32 + #ifdef __APPLE__ + #define SWIFT_THREADING_DARWIN 1 + #elif defined(__linux__) + #define SWIFT_THREADING_LINUX 1 + #elif defined(_WIN32) + #define SWIFT_THREADING_WIN32 1 + #elif defined(__wasi__) + #define SWIFT_THREADING_NONE 1 + #elif __has_include() + #define SWIFT_THREADING_C11 1 + #elif __has_include() + #define SWIFT_THREADING_PTHREADS 1 + #else + #error Unable to autodetect threading package. Please define SWIFT_THREADING_x as appropriate for your platform. + #endif +#endif + #if SWIFT_THREADING_NONE #include "Impl/Nothreads.h" #elif SWIFT_THREADING_DARWIN From e0d23ed6a832ef1f49b4e8bece0452507e517bfb Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Wed, 20 Apr 2022 17:51:19 +0100 Subject: [PATCH 08/40] [Threading] A couple of header file fixes. Some declarations were missing from non-Darwin sources, and the Linux header was slightly broken. rdar://90776105 --- include/swift/Threading/Impl/Linux.h | 4 ++-- include/swift/Threading/Impl/Pthreads.h | 2 ++ include/swift/Threading/Impl/Win32.h | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/swift/Threading/Impl/Linux.h b/include/swift/Threading/Impl/Linux.h index 3f51914583ce9..20925c10bb78f 100644 --- a/include/swift/Threading/Impl/Linux.h +++ b/include/swift/Threading/Impl/Linux.h @@ -130,11 +130,11 @@ struct once_t { linux::ulock_t lock; }; -using once_t = std::atomic; +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 ::pthread_once() for this (no context) - if (predicate.load(std::memory_order_acquire) < 0) + if (predicate.flag.load(std::memory_order_acquire) < 0) return; once_slow(predicate, fn, context); diff --git a/include/swift/Threading/Impl/Pthreads.h b/include/swift/Threading/Impl/Pthreads.h index 85c95296ad584..8eb08aec64580 100644 --- a/include/swift/Threading/Impl/Pthreads.h +++ b/include/swift/Threading/Impl/Pthreads.h @@ -126,6 +126,8 @@ inline void lazy_mutex_unsafe_unlock(lazy_mutex_handle &handle) { using once_t = std::atomic; +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 ::pthread_once() for this (no context) if (predicate.load(std::memory_order_acquire) < 0) diff --git a/include/swift/Threading/Impl/Win32.h b/include/swift/Threading/Impl/Win32.h index f395327c7e2b0..f7a71587cae7c 100644 --- a/include/swift/Threading/Impl/Win32.h +++ b/include/swift/Threading/Impl/Win32.h @@ -90,6 +90,8 @@ inline void lazy_mutex_unsafe_unlock(lazy_mutex_handle &handle) { typedef std::atomic once_t; +void once_slow(once_t &predicate, void (*fn)(void *), void *context); + 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) From 6d1b6dbd1c2332d72449b06a4c61c2639794cf7d Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Thu, 21 Apr 2022 15:03:58 +0100 Subject: [PATCH 09/40] [Threading] Fix the Linux build. A few fixes specifically for the Linux build. rdar://90776105 --- include/swift/Threading/Impl/C11.h | 2 +- include/swift/Threading/Impl/Darwin.h | 2 +- include/swift/Threading/Impl/Linux.h | 14 ++++++---- include/swift/Threading/Impl/Nothreads.h | 2 +- include/swift/Threading/Impl/Pthreads.h | 6 +++- include/swift/Threading/Impl/Win32.h | 2 +- include/swift/Threading/Once.h | 2 +- include/swift/Threading/ThreadLocalStorage.h | 2 +- lib/Threading/CMakeLists.txt | 1 + lib/Threading/Linux.cpp | 2 +- stdlib/public/Threading/CMakeLists.txt | 1 + stdlib/public/stubs/Random.cpp | 2 +- stdlib/public/stubs/Stubs.cpp | 2 +- stdlib/public/stubs/ThreadLocalStorage.cpp | 2 +- unittests/Basic/CMakeLists.txt | 1 + unittests/Threading/CMakeLists.txt | 1 + unittests/Threading/Fatal.cpp | 29 ++++++++++++++++++++ unittests/Threading/LinuxUlock.cpp | 6 ++-- unittests/Threading/Once.cpp | 8 +++++- unittests/runtime/CMakeLists.txt | 1 + unittests/runtime/LongTests/CMakeLists.txt | 1 + 21 files changed, 69 insertions(+), 20 deletions(-) create mode 100644 unittests/Threading/Fatal.cpp diff --git a/include/swift/Threading/Impl/C11.h b/include/swift/Threading/Impl/C11.h index a1f601b011590..53d46060be016 100644 --- a/include/swift/Threading/Impl/C11.h +++ b/include/swift/Threading/Impl/C11.h @@ -144,7 +144,7 @@ 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) { +inline void once_impl(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; diff --git a/include/swift/Threading/Impl/Darwin.h b/include/swift/Threading/Impl/Darwin.h index b22a644afee42..6aeed2d0d1867 100644 --- a/include/swift/Threading/Impl/Darwin.h +++ b/include/swift/Threading/Impl/Darwin.h @@ -94,7 +94,7 @@ inline void lazy_mutex_unsafe_unlock(lazy_mutex_handle &handle) { using once_t = ::dispatch_once_t; -inline void once(once_t &predicate, void (*fn)(void *), void *context) { +inline void once_impl(once_t &predicate, void (*fn)(void *), void *context) { dispatch_once_f(&predicate, context, fn); } diff --git a/include/swift/Threading/Impl/Linux.h b/include/swift/Threading/Impl/Linux.h index 20925c10bb78f..e651b53d9d0ae 100644 --- a/include/swift/Threading/Impl/Linux.h +++ b/include/swift/Threading/Impl/Linux.h @@ -18,7 +18,10 @@ #define SWIFT_THREADING_IMPL_LINUX_H #include +#include + #include + #include "swift/Threading/Errors.h" #include "Linux/ulock.h" @@ -26,14 +29,14 @@ namespace swift { namespace threading_impl { -#define SWIFT_LINUXTHREADS_CHECK(expr) \ +#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) \ +#define SWIFT_LINUXTHREADS_RETURN_TRUE_OR_FALSE(expr) \ do { \ int res_ = (expr); \ switch (res_) { \ @@ -71,6 +74,7 @@ inline void mutex_init(mutex_handle &handle, bool checked=false) { SWIFT_LINUXTHREADS_CHECK(::pthread_mutexattr_init(&attr)); SWIFT_LINUXTHREADS_CHECK(::pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK)); + SWIFT_LINUXTHREADS_CHECK(::pthread_mutex_init(&handle, &attr)); SWIFT_LINUXTHREADS_CHECK(::pthread_mutexattr_destroy(&attr)); } } @@ -85,7 +89,7 @@ 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)); + SWIFT_LINUXTHREADS_RETURN_TRUE_OR_FALSE(::pthread_mutex_trylock(&handle)); } inline void mutex_unsafe_lock(mutex_handle &handle) { @@ -113,7 +117,7 @@ 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)); + SWIFT_LINUXTHREADS_RETURN_TRUE_OR_FALSE(::pthread_mutex_trylock(&handle)); } inline void lazy_mutex_unsafe_lock(lazy_mutex_handle &handle) { @@ -132,7 +136,7 @@ struct once_t { void once_slow(once_t &predicate, void (*fn)(void *), void *context); -inline void once(once_t &predicate, void (*fn)(void *), void *context) { +inline void once_impl(once_t &predicate, void (*fn)(void *), void *context) { // Sadly we can't use ::pthread_once() for this (no context) if (predicate.flag.load(std::memory_order_acquire) < 0) return; diff --git a/include/swift/Threading/Impl/Nothreads.h b/include/swift/Threading/Impl/Nothreads.h index a29bace201e9d..ce4ee05cb670b 100644 --- a/include/swift/Threading/Impl/Nothreads.h +++ b/include/swift/Threading/Impl/Nothreads.h @@ -57,7 +57,7 @@ inline void lazy_mutex_unsafe_unlock(lazy_mutex_handle &handle) { } typedef bool once_t; -inline void once(once_t &predicate, void (*fn)(void *), void *ctx) { +inline void once_impl(once_t &predicate, void (*fn)(void *), void *ctx) { if (!predicate) { predicate = true; fn(ctx); diff --git a/include/swift/Threading/Impl/Pthreads.h b/include/swift/Threading/Impl/Pthreads.h index 8eb08aec64580..24ab686d0be81 100644 --- a/include/swift/Threading/Impl/Pthreads.h +++ b/include/swift/Threading/Impl/Pthreads.h @@ -18,8 +18,11 @@ #define SWIFT_THREADING_IMPL_PTHREADS_H #include +#include + #include #include + #include "swift/Threading/Errors.h" namespace swift { @@ -70,6 +73,7 @@ inline void mutex_init(mutex_handle &handle, bool checked=false) { SWIFT_PTHREADS_CHECK(::pthread_mutexattr_init(&attr)); SWIFT_PTHREADS_CHECK(::pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK)); + SWIFT_PTHREADS_CHECK(::pthread_mutex_init(&handle, &attr)); SWIFT_PTHREADS_CHECK(::pthread_mutexattr_destroy(&attr)); } } @@ -128,7 +132,7 @@ using once_t = std::atomic; void once_slow(once_t &predicate, void (*fn)(void *), void *context); -inline void once(once_t &predicate, void (*fn)(void *), void *context) { +inline void once_impl(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; diff --git a/include/swift/Threading/Impl/Win32.h b/include/swift/Threading/Impl/Win32.h index f7a71587cae7c..f03f7adb5bc32 100644 --- a/include/swift/Threading/Impl/Win32.h +++ b/include/swift/Threading/Impl/Win32.h @@ -92,7 +92,7 @@ typedef std::atomic once_t; void once_slow(once_t &predicate, void (*fn)(void *), void *context); -inline void once(once_t &predicate, void (*fn)(void *), void *context) { +inline void once_impl(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; diff --git a/include/swift/Threading/Once.h b/include/swift/Threading/Once.h index 056dce7c2f348..253995ac2104a 100644 --- a/include/swift/Threading/Once.h +++ b/include/swift/Threading/Once.h @@ -27,7 +27,7 @@ using once_t = threading_impl::once_t; /// 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); + threading_impl::once_impl(predicate, fn, context); } } diff --git a/include/swift/Threading/ThreadLocalStorage.h b/include/swift/Threading/ThreadLocalStorage.h index adf8f4a4ea506..cd56ac15e8a56 100644 --- a/include/swift/Threading/ThreadLocalStorage.h +++ b/include/swift/Threading/ThreadLocalStorage.h @@ -84,7 +84,7 @@ inline void tls_alloc_once(once_t &token, tls_key &key, tls_dtor dtor) { // 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 +#if SWIFT_THREAD_LOCAL template class ThreadLocal { VALIDATE_THREAD_LOCAL_TYPE(T) diff --git a/lib/Threading/CMakeLists.txt b/lib/Threading/CMakeLists.txt index b0b574e634720..4ded5235438c5 100644 --- a/lib/Threading/CMakeLists.txt +++ b/lib/Threading/CMakeLists.txt @@ -1,5 +1,6 @@ add_swift_host_library(swiftThreading STATIC C11.cpp + Linux.cpp Nothreads.cpp Pthreads.cpp Win32.cpp) diff --git a/lib/Threading/Linux.cpp b/lib/Threading/Linux.cpp index 0536ddc743bec..9d51a61328173 100644 --- a/lib/Threading/Linux.cpp +++ b/lib/Threading/Linux.cpp @@ -64,4 +64,4 @@ swift::threading_impl::once_slow(once_t &predicate, linux::ulock_unlock(&predicate.lock); } -#endif // SWIFT_THREADING_PTHREADS +#endif // SWIFT_THREADING_LINUX diff --git a/stdlib/public/Threading/CMakeLists.txt b/stdlib/public/Threading/CMakeLists.txt index 115fc20ca6be0..57e988bbaac14 100644 --- a/stdlib/public/Threading/CMakeLists.txt +++ b/stdlib/public/Threading/CMakeLists.txt @@ -1,5 +1,6 @@ add_swift_target_library(swiftThreading STATIC "${SWIFT_SOURCE_DIR}/lib/Threading/C11.cpp" + "${SWIFT_SOURCE_DIR}/lib/Threading/Linux.cpp" "${SWIFT_SOURCE_DIR}/lib/Threading/Nothreads.cpp" "${SWIFT_SOURCE_DIR}/lib/Threading/Pthreads.cpp" "${SWIFT_SOURCE_DIR}/lib/Threading/Win32.cpp" diff --git a/stdlib/public/stubs/Random.cpp b/stdlib/public/stubs/Random.cpp index 498b6b253fc01..c6a247ccd1328 100644 --- a/stdlib/public/stubs/Random.cpp +++ b/stdlib/public/stubs/Random.cpp @@ -109,7 +109,7 @@ void swift_stdlib_random(void *buf, __swift_size_t nbytes) { if (fd != -1) { // ###FIXME: Why is this locked? None of the others are. - static StaticMutex mutex; + static LazyMutex mutex; mutex.withLock([&] { actual_nbytes = WHILE_EINTR(read(fd, buf, nbytes)); }); diff --git a/stdlib/public/stubs/Stubs.cpp b/stdlib/public/stubs/Stubs.cpp index 7d5ff82d48da7..bb593781b94a4 100644 --- a/stdlib/public/stubs/Stubs.cpp +++ b/stdlib/public/stubs/Stubs.cpp @@ -576,7 +576,7 @@ __swift_bool _swift_stdlib_getCurrentStackBounds(__swift_uintptr_t *outBegin, return false; # endif -#elif SWIFT_THREADING_PTHREADS +#elif SWIFT_THREADING_PTHREADS || SWIFT_THREADING_LINUX # if defined(__OpenBSD__) stack_t sinfo; diff --git a/stdlib/public/stubs/ThreadLocalStorage.cpp b/stdlib/public/stubs/ThreadLocalStorage.cpp index 9d0b9118878c7..958e89c349633 100644 --- a/stdlib/public/stubs/ThreadLocalStorage.cpp +++ b/stdlib/public/stubs/ThreadLocalStorage.cpp @@ -54,7 +54,7 @@ _swift_stdlib_threadLocalStorageGet(void) { static swift::tls_key key; static swift::once_t token; - swift::tls_alloc_once(token, key, [](void *)pointer { + swift::tls_alloc_once(token, key, [](void *pointer) { _stdlib_destroyTLS(pointer); }); diff --git a/unittests/Basic/CMakeLists.txt b/unittests/Basic/CMakeLists.txt index bb25992c61c60..72c954e1d3b40 100644 --- a/unittests/Basic/CMakeLists.txt +++ b/unittests/Basic/CMakeLists.txt @@ -44,6 +44,7 @@ add_dependencies(SwiftBasicTests "${gyb_dependency_targets}") target_link_libraries(SwiftBasicTests PRIVATE swiftBasic + swiftThreading clangBasic LLVMTestingSupport ) diff --git a/unittests/Threading/CMakeLists.txt b/unittests/Threading/CMakeLists.txt index 83bc84b18fa8e..2de1814a6e16f 100644 --- a/unittests/Threading/CMakeLists.txt +++ b/unittests/Threading/CMakeLists.txt @@ -2,6 +2,7 @@ add_swift_unittest(SwiftThreadingTests Mutex.cpp Once.cpp LinuxUlock.cpp + Fatal.cpp ) target_link_libraries(SwiftThreadingTests diff --git a/unittests/Threading/Fatal.cpp b/unittests/Threading/Fatal.cpp new file mode 100644 index 0000000000000..d4944b10211bd --- /dev/null +++ b/unittests/Threading/Fatal.cpp @@ -0,0 +1,29 @@ +//===---Fatal.cpp - Stub for the threading tests --------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "swift/Threading/Errors.h" + +#include +#include +#include + +SWIFT_ATTRIBUTE_NORETURN +SWIFT_FORMAT(1, 2) +void swift::threading::fatal(const char *msg, ...) { + va_list val; + + va_start(val, msg); + std::vfprintf(stderr, msg, val); + va_end(val); + + std::abort(); +} diff --git a/unittests/Threading/LinuxUlock.cpp b/unittests/Threading/LinuxUlock.cpp index cf274d8b8f1f8..d8fabe3a520cd 100644 --- a/unittests/Threading/LinuxUlock.cpp +++ b/unittests/Threading/LinuxUlock.cpp @@ -30,9 +30,9 @@ class UlockMutex { public: UlockMutex() : lock_(0) {} - void lock() { linux::ulock_lock(&lock); } - void unlock() { linux::ulock_unlock(&lock); } - bool try_lock() { return linux::ulock_trylock(&lock); } + void lock() { linux::ulock_lock(&lock_); } + void unlock() { linux::ulock_unlock(&lock_); } + bool try_lock() { return linux::ulock_trylock(&lock_); } }; TEST(LinuxUlockTest, SingleThreaded) { diff --git a/unittests/Threading/Once.cpp b/unittests/Threading/Once.cpp index 52686637d68f8..3bca18f93bf77 100644 --- a/unittests/Threading/Once.cpp +++ b/unittests/Threading/Once.cpp @@ -13,6 +13,8 @@ #include "swift/Threading/Once.h" #include "gtest/gtest.h" +#include + #include "ThreadingHelpers.h" using namespace swift; @@ -54,9 +56,13 @@ TEST(OnceTest, once_threaded) { }; for (unsigned tries = 0; tries < 1000; ++tries) { - swift::once_t predicate = {0}; + swift::once_t predicate; unsigned callCount = 0; + // We're being naughty here; swift::once_t is supposed to be global/static, + // but since we know what we're doing, this should be OK. + std::memset(&predicate, 0, sizeof(predicate)); + threadedExecute(16, [&](int) { swift::once(predicate, fn, &callCount); }); diff --git a/unittests/runtime/CMakeLists.txt b/unittests/runtime/CMakeLists.txt index cb6bf9bbb57dd..e45b0bdbaa6c7 100644 --- a/unittests/runtime/CMakeLists.txt +++ b/unittests/runtime/CMakeLists.txt @@ -143,6 +143,7 @@ if(("${SWIFT_HOST_VARIANT_SDK}" STREQUAL "${SWIFT_PRIMARY_VARIANT_SDK}") AND target_link_libraries(SwiftRuntimeTests PRIVATE swiftCore${SWIFT_PRIMARY_VARIANT_SUFFIX} + swiftThreading${SWIFT_PRIMARY_VARIANT_SUFFIX} ${PLATFORM_TARGET_LINK_LIBRARIES} ) endif() diff --git a/unittests/runtime/LongTests/CMakeLists.txt b/unittests/runtime/LongTests/CMakeLists.txt index 0f8268ea6941e..35f7ef727ff52 100644 --- a/unittests/runtime/LongTests/CMakeLists.txt +++ b/unittests/runtime/LongTests/CMakeLists.txt @@ -60,6 +60,7 @@ if(("${SWIFT_HOST_VARIANT_SDK}" STREQUAL "${SWIFT_PRIMARY_VARIANT_SDK}") AND target_link_libraries(SwiftRuntimeLongTests PRIVATE swiftCore${SWIFT_PRIMARY_VARIANT_SUFFIX} + swiftThreading${SWIFT_PRIMARY_VARIANT_SUFFIX} ${PLATFORM_TARGET_LINK_LIBRARIES} ${swift_runtime_test_extra_libraries} ) From 84083afef1de5931904d5c815d53856cdb3fb232 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Thu, 21 Apr 2022 16:26:28 +0100 Subject: [PATCH 10/40] [Build] Move initialization of SWIFT_HOST_VARIANT_SDK further up. We want this initialized when we decide which threading package to use. This isn't a problem on Darwin or Linux where we're using the build script, but on Windows it relies on the defaulting mechanism, which didn't happen until further down the `CMakeLists.txt`. rdar://90776105 --- CMakeLists.txt | 136 ++++++++++++++++++++++++------------------------- 1 file changed, 68 insertions(+), 68 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6779f1fc0264e..ec702f0b7e39b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,6 +87,74 @@ if(SWIFT_FREESTANDING_FLAVOR STREQUAL "apple") endif() endif() +# If SWIFT_HOST_VARIANT_SDK not given, try to detect from the CMAKE_SYSTEM_NAME. +if(SWIFT_HOST_VARIANT_SDK) + set(SWIFT_HOST_VARIANT_SDK_default "${SWIFT_HOST_VARIANT_SDK}") +else() + if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") + set(SWIFT_HOST_VARIANT_SDK_default "LINUX") + elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "FreeBSD") + set(SWIFT_HOST_VARIANT_SDK_default "FREEBSD") + elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "OpenBSD") + set(SWIFT_HOST_VARIANT_SDK_default "OPENBSD") + elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "CYGWIN") + set(SWIFT_HOST_VARIANT_SDK_default "CYGWIN") + elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows") + set(SWIFT_HOST_VARIANT_SDK_default "WINDOWS") + elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Haiku") + set(SWIFT_HOST_VARIANT_SDK_default "HAIKU") + elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Android") + set(SWIFT_HOST_VARIANT_SDK_default "ANDROID") + elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin") + set(SWIFT_HOST_VARIANT_SDK_default "OSX") + else() + message(FATAL_ERROR "Unable to detect SDK for host system: ${CMAKE_SYSTEM_NAME}") + endif() +endif() + +# If SWIFT_HOST_VARIANT_ARCH not given, try to detect from the CMAKE_SYSTEM_PROCESSOR. +if(SWIFT_HOST_VARIANT_ARCH) + set(SWIFT_HOST_VARIANT_ARCH_default "${SWIFT_HOST_VARIANT_ARCH}") +else() + if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64") + set(SWIFT_HOST_VARIANT_ARCH_default "x86_64") + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|ARM64|arm64") + if(SWIFT_HOST_VARIANT_SDK_default STREQUAL OSX) + set(SWIFT_HOST_VARIANT_ARCH_default "arm64") + else() + set(SWIFT_HOST_VARIANT_ARCH_default "aarch64") + endif() + elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64") + set(SWIFT_HOST_VARIANT_ARCH_default "powerpc64") + elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc") + set(SWIFT_HOST_VARIANT_ARCH_default "powerpc") + elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64le") + set(SWIFT_HOST_VARIANT_ARCH_default "powerpc64le") + elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "s390x") + set(SWIFT_HOST_VARIANT_ARCH_default "s390x") + elseif("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "armv5|armv5te") + set(SWIFT_HOST_VARIANT_ARCH_default "armv5") + # FIXME: Only matches v6l/v7l - by far the most common variants + elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv6l") + set(SWIFT_HOST_VARIANT_ARCH_default "armv6") + elseif("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "armv7l|armv7-a") + set(SWIFT_HOST_VARIANT_ARCH_default "armv7") + elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "IA64") + set(SWIFT_HOST_VARIANT_ARCH_default "itanium") + elseif("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "(x86|i686)") + set(SWIFT_HOST_VARIANT_ARCH_default "i686") + elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "wasm32") + set(SWIFT_HOST_VARIANT_ARCH_default "wasm32") + else() + message(FATAL_ERROR "Unrecognized architecture on host system: ${CMAKE_SYSTEM_PROCESSOR}") + endif() +endif() + +set(SWIFT_HOST_VARIANT_SDK "${SWIFT_HOST_VARIANT_SDK_default}" CACHE STRING + "Deployment sdk for Swift host tools (the compiler).") +set(SWIFT_HOST_VARIANT_ARCH "${SWIFT_HOST_VARIANT_ARCH_default}" CACHE STRING + "Deployment arch for Swift host tools (the compiler).") + # # User-configurable options that control the inclusion and default build # behavior for components which may not strictly be necessary (tools, examples, @@ -718,74 +786,6 @@ if(XCODE) swift_common_xcode_cxx_config() endif() -# If SWIFT_HOST_VARIANT_SDK not given, try to detect from the CMAKE_SYSTEM_NAME. -if(SWIFT_HOST_VARIANT_SDK) - set(SWIFT_HOST_VARIANT_SDK_default "${SWIFT_HOST_VARIANT_SDK}") -else() - if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") - set(SWIFT_HOST_VARIANT_SDK_default "LINUX") - elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "FreeBSD") - set(SWIFT_HOST_VARIANT_SDK_default "FREEBSD") - elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "OpenBSD") - set(SWIFT_HOST_VARIANT_SDK_default "OPENBSD") - elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "CYGWIN") - set(SWIFT_HOST_VARIANT_SDK_default "CYGWIN") - elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows") - set(SWIFT_HOST_VARIANT_SDK_default "WINDOWS") - elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Haiku") - set(SWIFT_HOST_VARIANT_SDK_default "HAIKU") - elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Android") - set(SWIFT_HOST_VARIANT_SDK_default "ANDROID") - elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin") - set(SWIFT_HOST_VARIANT_SDK_default "OSX") - else() - message(FATAL_ERROR "Unable to detect SDK for host system: ${CMAKE_SYSTEM_NAME}") - endif() -endif() - -# If SWIFT_HOST_VARIANT_ARCH not given, try to detect from the CMAKE_SYSTEM_PROCESSOR. -if(SWIFT_HOST_VARIANT_ARCH) - set(SWIFT_HOST_VARIANT_ARCH_default "${SWIFT_HOST_VARIANT_ARCH}") -else() - if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64") - set(SWIFT_HOST_VARIANT_ARCH_default "x86_64") - elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|ARM64|arm64") - if(SWIFT_HOST_VARIANT_SDK_default STREQUAL OSX) - set(SWIFT_HOST_VARIANT_ARCH_default "arm64") - else() - set(SWIFT_HOST_VARIANT_ARCH_default "aarch64") - endif() - elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64") - set(SWIFT_HOST_VARIANT_ARCH_default "powerpc64") - elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc") - set(SWIFT_HOST_VARIANT_ARCH_default "powerpc") - elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64le") - set(SWIFT_HOST_VARIANT_ARCH_default "powerpc64le") - elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "s390x") - set(SWIFT_HOST_VARIANT_ARCH_default "s390x") - elseif("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "armv5|armv5te") - set(SWIFT_HOST_VARIANT_ARCH_default "armv5") - # FIXME: Only matches v6l/v7l - by far the most common variants - elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv6l") - set(SWIFT_HOST_VARIANT_ARCH_default "armv6") - elseif("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "armv7l|armv7-a") - set(SWIFT_HOST_VARIANT_ARCH_default "armv7") - elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "IA64") - set(SWIFT_HOST_VARIANT_ARCH_default "itanium") - elseif("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "(x86|i686)") - set(SWIFT_HOST_VARIANT_ARCH_default "i686") - elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "wasm32") - set(SWIFT_HOST_VARIANT_ARCH_default "wasm32") - else() - message(FATAL_ERROR "Unrecognized architecture on host system: ${CMAKE_SYSTEM_PROCESSOR}") - endif() -endif() - -set(SWIFT_HOST_VARIANT_SDK "${SWIFT_HOST_VARIANT_SDK_default}" CACHE STRING - "Deployment sdk for Swift host tools (the compiler).") -set(SWIFT_HOST_VARIANT_ARCH "${SWIFT_HOST_VARIANT_ARCH_default}" CACHE STRING - "Deployment arch for Swift host tools (the compiler).") - # Which default linker to use. Prefer LLVM_USE_LINKER if it set, otherwise use # our own defaults. This should only be possible in a unified (not stand alone) # build environment. From 8615983174f4c2a275701c198549ef0e3982daab Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Fri, 22 Apr 2022 10:01:45 +0100 Subject: [PATCH 11/40] [Build] Fix static linking. When we static link against libswiftCore, we need it to contain the actual object modules from the threading library (when it's dynamically linked, the shared object will already contain those modules because it's been linked against libswiftThreading), which means that the threading library in the stdlib needs to be an OBJECT_LIBRARY rather than a STATIC library (otherwise people will have to statically link against the threading library as well, and that'll need to be installed, and we don't want that). rdar://90776105 --- stdlib/public/Threading/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/public/Threading/CMakeLists.txt b/stdlib/public/Threading/CMakeLists.txt index 57e988bbaac14..a4f14655233fe 100644 --- a/stdlib/public/Threading/CMakeLists.txt +++ b/stdlib/public/Threading/CMakeLists.txt @@ -1,4 +1,4 @@ -add_swift_target_library(swiftThreading STATIC +add_swift_target_library(swiftThreading OBJECT_LIBRARY "${SWIFT_SOURCE_DIR}/lib/Threading/C11.cpp" "${SWIFT_SOURCE_DIR}/lib/Threading/Linux.cpp" "${SWIFT_SOURCE_DIR}/lib/Threading/Nothreads.cpp" From 02b343100e27beb438a675dc7c3f33e316608b5b Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Fri, 22 Apr 2022 10:04:02 +0100 Subject: [PATCH 12/40] [Build] Fix the name of the threading package setting. I'd renamed the setting, but failed to update build-presets.ini. rdar://90776105 --- utils/build-presets.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/build-presets.ini b/utils/build-presets.ini index 4814fc3a0052f..07b9365b10323 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -1205,8 +1205,8 @@ mixin-preset=buildbot_incremental_linux_base llvm-targets-to-build=X86;ARM;AArch64;WebAssembly # Ensure single-thread-mode is not broken because it's used # by stdlib for wasm32 in SwiftWasm fork. -swift-stdlib-threading-package=none swift-stdlib-single-threaded-concurrency=1 +swift-threading-package=none #===------------------------------------------------------------------------===# # OS X Package Builders @@ -2509,7 +2509,6 @@ swift-stdlib-has-stdin=0 swift-stdlib-has-environ=0 swift-stdlib-has-locale=0 swift-runtime-static-image-inspection=1 -swift-stdlib-threading-package=none swift-stdlib-single-threaded-concurrency=1 swift-stdlib-concurrency-tracing=0 swift-stdlib-os-versioning=0 @@ -2522,6 +2521,7 @@ swift-stdlib-enable-vector-types=0 swift-stdlib-experimental-hermetic-seal-at-link=1 swift-stdlib-disable-instantiation-caches=1 swift-stdlib-has-type-printing=0 +swift-threading-package=none build-swift-stdlib-unicode-data=0 build-swift-stdlib-static-print=1 darwin-crash-reporter-client=0 From 4eca62a5ea2f60d07a469dc652c99eff4a0b05a1 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Fri, 22 Apr 2022 13:52:47 +0100 Subject: [PATCH 13/40] [Threading][Windows] Fix missing close brace. Apparently I missed a close brace from the end of Win32.h. rdar://90776105 --- include/swift/Threading/Impl/Win32.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/swift/Threading/Impl/Win32.h b/include/swift/Threading/Impl/Win32.h index f03f7adb5bc32..4b9019f0b74ab 100644 --- a/include/swift/Threading/Impl/Win32.h +++ b/include/swift/Threading/Impl/Win32.h @@ -124,6 +124,8 @@ inline void tls_set(tls_key key, void *value) { FlsSetValue(key, value); } -} +} // namespace threading_impl + +} // namespace swift #endif // SWIFT_THREADING_IMPL_WIN32_H From 9d5736e1e12e62b906e0edcd268f3f3216866ecd Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Fri, 22 Apr 2022 14:26:04 +0100 Subject: [PATCH 14/40] [Threading][Windows] Fix another Windows niggle. Looks like I forgot to update the Win32.h implementation. rdar://90776105 --- include/swift/Threading/Impl/Win32.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/swift/Threading/Impl/Win32.h b/include/swift/Threading/Impl/Win32.h index 4b9019f0b74ab..3515bea2143a4 100644 --- a/include/swift/Threading/Impl/Win32.h +++ b/include/swift/Threading/Impl/Win32.h @@ -64,8 +64,8 @@ inline void mutex_unsafe_unlock(mutex_handle &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 constexpr lazy_mutex_handle lazy_mutex_initializer() { + return SRWLOCK_INIT; } inline void lazy_mutex_destroy(lazy_mutex_handle &handle) { } From d76f80d6385ef1f013ae094934be321418818f81 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Fri, 22 Apr 2022 15:00:37 +0100 Subject: [PATCH 15/40] [Threading][Windows] More header file fixes. rdar://90776105 --- include/swift/Threading/Impl/Win32.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/include/swift/Threading/Impl/Win32.h b/include/swift/Threading/Impl/Win32.h index 3515bea2143a4..e0f0b4cde7ac0 100644 --- a/include/swift/Threading/Impl/Win32.h +++ b/include/swift/Threading/Impl/Win32.h @@ -102,14 +102,18 @@ inline void once_impl(once_t &predicate, void (*fn)(void *), void *context) { // .. Thread local storage ................................................... -#if __cplusplus >= 201103L || __has_feature(cxx_thread_local) -#define SWIFT_THREAD_LOCAL thread_local +#ifdef __clang__ +# if __has_feature(cxx_thread_local) +# define SWIFT_THREAD_LOCAL thread_local +# endif +#elif __cplusplus >= 201103L +# 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 *); +using tls_dtor = PFLS_CALLBACK_FUNCTION; inline bool tls_alloc(tls_key &key, tls_dtor dtor) { key = FlsAlloc(dtor); From a7e42d041a0c390a5b0ae45cef36067b44138fce Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Tue, 26 Apr 2022 12:02:50 +0100 Subject: [PATCH 16/40] [Threading][Windows] Undefine Yield and ERROR. `windows.h` defines a couple of very unhelpfully named macros. Undefine them after including it. rdar://90776105 --- include/swift/Threading/Impl/Win32.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/swift/Threading/Impl/Win32.h b/include/swift/Threading/Impl/Win32.h index e0f0b4cde7ac0..d7dd8d3f044cc 100644 --- a/include/swift/Threading/Impl/Win32.h +++ b/include/swift/Threading/Impl/Win32.h @@ -21,6 +21,10 @@ #define NOMINMAX #include +// defines some unhelpful macros +#undef Yield +#undef ERROR + #include namespace swift { From 05cccf939b5be8a92c92f2af4b7c85e97071e5bd Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Tue, 26 Apr 2022 14:54:54 +0100 Subject: [PATCH 17/40] [Runtime][Windows] Need to link with Synchronization.lib. We're using some functions from Synchronization.lib now, after the threading changes. rdar://90776105 --- stdlib/public/Concurrency/CMakeLists.txt | 8 ++++++-- stdlib/public/core/CMakeLists.txt | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/stdlib/public/Concurrency/CMakeLists.txt b/stdlib/public/Concurrency/CMakeLists.txt index 4251e1ccf07cc..433293ea4171e 100644 --- a/stdlib/public/Concurrency/CMakeLists.txt +++ b/stdlib/public/Concurrency/CMakeLists.txt @@ -25,6 +25,11 @@ endif() set(SWIFT_RUNTIME_CONCURRENCY_C_FLAGS) set(SWIFT_RUNTIME_CONCURRENCY_SWIFT_FLAGS) +set(swift_concurrency_private_link_libraries swiftThreading) +if(CMAKE_SYSTEM_NAME STREQUAL Windows) + list(APPEND swift_concurrency_private_link_libraries Synchronization) +endif() + if("${SWIFT_CONCURRENCY_GLOBAL_EXECUTOR}" STREQUAL "dispatch") if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin) include_directories(AFTER @@ -44,7 +49,6 @@ else() message(FATAL_ERROR "Invalid value for SWIFT_CONCURRENCY_GLOBAL_EXECUTOR (\"${SWIFT_CONCURRENCY_GLOBAL_EXECUTOR}\").") endif() - if(NOT SWIFT_CONCURRENCY_USES_DISPATCH) endif() @@ -127,7 +131,7 @@ add_swift_target_library(swift_Concurrency ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} I SWIFT_MODULE_DEPENDS_HAIKU Glibc SWIFT_MODULE_DEPENDS_WINDOWS CRT - PRIVATE_LINK_LIBRARIES swiftThreading + PRIVATE_LINK_LIBRARIES ${swift_concurrency_private_link_libraries} LINK_LIBRARIES ${swift_concurrency_link_libraries} diff --git a/stdlib/public/core/CMakeLists.txt b/stdlib/public/core/CMakeLists.txt index 3d6a88aba9bea..3f983d5dc3812 100644 --- a/stdlib/public/core/CMakeLists.txt +++ b/stdlib/public/core/CMakeLists.txt @@ -260,7 +260,7 @@ elseif(SWIFT_PRIMARY_VARIANT_SDK STREQUAL LINUX) list(APPEND swift_core_private_link_libraries) endif() elseif(SWIFT_PRIMARY_VARIANT_SDK STREQUAL WINDOWS) - list(APPEND swift_core_private_link_libraries shell32;DbgHelp) + list(APPEND swift_core_private_link_libraries shell32;DbgHelp;Synchronization) endif() option(SWIFT_CHECK_ESSENTIAL_STDLIB From 2e28ac4f01037966296608a4a1e9a90a7563df98 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Wed, 27 Apr 2022 10:15:51 +0100 Subject: [PATCH 18/40] [Threading][Windows] Don't include We can't safely include because it defines a large number of macros, some of which clash with things in the Swift source tree, and others of which clash with things in the LLVM source tree. Sadly we *also* can't just include the Windows headers we need, because they pull in some of the problematic macros. In this instance, the best thing seems to be to grab the definitions for the types and functions we are going to use and put them in their own header file. If we define them correctly, then #including before or after this header won't have any adverse effects. rdar://90776105 --- include/swift/Threading/Impl/Win32.h | 44 +++++------- .../swift/Threading/Impl/Win32/Win32Defs.h | 71 +++++++++++++++++++ 2 files changed, 90 insertions(+), 25 deletions(-) create mode 100644 include/swift/Threading/Impl/Win32/Win32Defs.h diff --git a/include/swift/Threading/Impl/Win32.h b/include/swift/Threading/Impl/Win32.h index d7dd8d3f044cc..acbc1237e375f 100644 --- a/include/swift/Threading/Impl/Win32.h +++ b/include/swift/Threading/Impl/Win32.h @@ -17,13 +17,7 @@ #ifndef SWIFT_THREADING_IMPL_WIN32_H #define SWIFT_THREADING_IMPL_WIN32_H -#define WIN32_LEAN_AND_MEAN -#define NOMINMAX -#include - -// defines some unhelpful macros -#undef Yield -#undef ERROR +#include "Win32/Win32Defs.h" #include @@ -32,7 +26,7 @@ namespace threading_impl { // .. Thread related things .................................................. -using thread_id = DWORD; +using thread_id = ::DWORD; inline thread_id thread_get_current() { return ::GetCurrentThreadId(); } thread_id thread_get_main(); @@ -41,7 +35,7 @@ inline bool threads_same(thread_id a, thread_id b) { return a == b; } // .. Mutex support .......................................................... -using mutex_handle = SRWLOCK; +using mutex_handle = ::SRWLOCK; inline void mutex_init(mutex_handle &handle, bool checked=false) { handle = SRWLOCK_INIT; @@ -49,23 +43,23 @@ inline void mutex_init(mutex_handle &handle, bool checked=false) { inline void mutex_destroy(mutex_handle &handle) { } inline void mutex_lock(mutex_handle &handle) { - AcquireSRWLockExclusive(&handle); + ::AcquireSRWLockExclusive(&handle); } inline void mutex_unlock(mutex_handle &handle) { - ReleaseSRWLockExclusive(&handle); + ::ReleaseSRWLockExclusive(&handle); } inline bool mutex_try_lock(mutex_handle &handle) { - return !!TryAcquireSRWLockExclusive(&handle); + return !!::TryAcquireSRWLockExclusive(&handle); } inline void mutex_unsafe_lock(mutex_handle &handle) { - AcquireSRWLockExclusive(&handle); + ::AcquireSRWLockExclusive(&handle); } inline void mutex_unsafe_unlock(mutex_handle &handle) { - ReleaseSRWLockExclusive(&handle); + ::ReleaseSRWLockExclusive(&handle); } -using lazy_mutex_handle = SRWLOCK; +using lazy_mutex_handle = ::SRWLOCK; // We don't need to be lazy here because Win32 has SRWLOCK_INIT. inline constexpr lazy_mutex_handle lazy_mutex_initializer() { @@ -74,20 +68,20 @@ inline constexpr lazy_mutex_handle lazy_mutex_initializer() { inline void lazy_mutex_destroy(lazy_mutex_handle &handle) { } inline void lazy_mutex_lock(lazy_mutex_handle &handle) { - AcquireSRWLockExclusive(&handle); + ::AcquireSRWLockExclusive(&handle); } inline void lazy_mutex_unlock(lazy_mutex_handle &handle) { - ReleaseSRWLockExclusive(&handle); + ::ReleaseSRWLockExclusive(&handle); } inline bool lazy_mutex_try_lock(lazy_mutex_handle &handle) { - return !!TryAcquireSRWLockExclusive(&handle); + return !!::TryAcquireSRWLockExclusive(&handle); } inline void lazy_mutex_unsafe_lock(lazy_mutex_handle &handle) { - AcquireSRWLockExclusive(&handle); + ::AcquireSRWLockExclusive(&handle); } inline void lazy_mutex_unsafe_unlock(lazy_mutex_handle &handle) { - ReleaseSRWLockExclusive(&handle); + ::ReleaseSRWLockExclusive(&handle); } // .. Once ................................................................... @@ -116,20 +110,20 @@ inline void once_impl(once_t &predicate, void (*fn)(void *), void *context) { #define SWIFT_TLS_DECLARE_DTOR(name) void NTAPI name(void *) -using tls_key = DWORD; -using tls_dtor = PFLS_CALLBACK_FUNCTION; +using tls_key = ::DWORD; +using tls_dtor = ::PFLS_CALLBACK_FUNCTION; inline bool tls_alloc(tls_key &key, tls_dtor dtor) { - key = FlsAlloc(dtor); + key = ::FlsAlloc(dtor); return key != FLS_OUT_OF_INDEXES; } inline void *tls_get(tls_key key) { - return FlsGetValue(key); + return ::FlsGetValue(key); } inline void tls_set(tls_key key, void *value) { - FlsSetValue(key, value); + ::FlsSetValue(key, value); } } // namespace threading_impl diff --git a/include/swift/Threading/Impl/Win32/Win32Defs.h b/include/swift/Threading/Impl/Win32/Win32Defs.h new file mode 100644 index 0000000000000..21fc091c30ab0 --- /dev/null +++ b/include/swift/Threading/Impl/Win32/Win32Defs.h @@ -0,0 +1,71 @@ +//==--- Win32Defs.h - Windows API definitions ------------------ -*-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 +// +//===----------------------------------------------------------------------===// +// +// We cannot include from the Threading headers because they get +// included all over the place and defines a large number of +// obnoxious macros. Instead, this header declares *just* what we need. +// +// If you need in a file, please make sure to include it *before* +// this file, or you'll get errors about RTL_SRWLOCK. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_THREADING_IMPL_WIN32_DEFS_H +#define SWIFT_THREADING_IMPL_WIN32_DEFS_H + +#define DECLSPEC_IMPORT __declspec(dllimport) +#define WINBASEAPI DECLSPEC_IMPORT +#define WINAPI __stdcall +#define NTAPI __stdcall + +// #defines VOID rather than typedefing it(!) Changing that +// to use a typedef instead isn't problematic later on, so let's do that. +#undef VOID + +typedef void VOID, *PVOID; +typedef unsigned char BYTE; +typedef BYTE BOOLEAN; +typedef int BOOL; +typedef unsigned long DWORD; + +typedef VOID (NTAPI* PFLS_CALLBACK_FUNCTION)(PVOID lpFlsData); + +// We can't define this struct if already did so +#ifndef _WINNT_ +struct _RTL_SRWLOCK { + PVOID Ptr; +}; +#endif // _WINNT_ + +typedef struct _RTL_SRWLOCK RTL_SRWLOCK, *PRTL_SRWLOCK; +typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK; + +// These have to be #defines, to avoid problems with +#define RTL_SRWLOCK_INIT {0} +#define SRWLOCK_INIT RTL_SRWLOCK_INIT +#define FLS_OUT_OF_INDEXES ((DWORD)0xFFFFFFFF) + +extern "C" { + WINBASEAPI DWORD WINAPI GetCurrentThreadId(VOID); + + WINBASEAPI VOID WINAPI InitializeSRWLock(PSRWLOCK SRWLock); + WINBASEAPI VOID WINAPI ReleaseSRWLockExclusive(PSRWLOCK SRWLock); + WINBASEAPI VOID WINAPI AcquireSRWLockExclusive(PSRWLOCK SRWLock); + WINBASEAPI BOOLEAN WINAPI TryAcquireSRWLockExclusive(PSRWLOCK SRWLock); + + WINBASEAPI DWORD WINAPI FlsAlloc(PFLS_CALLBACK_FUNCTION lpCallback); + WINBASEAPI PVOID WINAPI FlsGetValue(DWORD dwFlsIndex); + WINBASEAPI BOOL WINAPI FlsSetValue(DWORD dwFlsIndex, PVOID lpFlsData); + WINBASEAPI BOOL WINAPI FlsFree(DWORD dwFlsIndex); +} + +#endif // SWIFT_THREADING_IMPL_WIN32_DEFS_H From 66f6eb6bc6c8993fb0623fe30c8360225ff0f52b Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Wed, 27 Apr 2022 14:06:01 +0100 Subject: [PATCH 19/40] [Runtime][Windows] A couple of files need to include We shouldn't include implicitly from .cpp files, but should do it directly so that we know it's there. Also, if we're including , do it at the top of the file. rdar://90776105 --- lib/Threading/Win32.cpp | 4 ++++ stdlib/public/Concurrency/TaskPrivate.h | 13 +++++++------ stdlib/public/runtime/Errors.cpp | 4 ++++ stdlib/public/runtime/Metadata.cpp | 13 +++++++------ 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/lib/Threading/Win32.cpp b/lib/Threading/Win32.cpp index 6e7f4a9d8dbee..1937dd0da3484 100644 --- a/lib/Threading/Win32.cpp +++ b/lib/Threading/Win32.cpp @@ -16,6 +16,10 @@ #if SWIFT_THREADING_WIN32 +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX +#include + #include "swift/Threading/Errors.h" #include "swift/Threading/Impl/Win32.h" diff --git a/stdlib/public/Concurrency/TaskPrivate.h b/stdlib/public/Concurrency/TaskPrivate.h index 36ee085fcc983..c2de6efb709b7 100644 --- a/stdlib/public/Concurrency/TaskPrivate.h +++ b/stdlib/public/Concurrency/TaskPrivate.h @@ -17,6 +17,13 @@ #ifndef SWIFT_CONCURRENCY_TASKPRIVATE_H #define SWIFT_CONCURRENCY_TASKPRIVATE_H +#if defined(_WIN32) +#define WIN32_LEAN_AND_MEAN +#define VC_EXTRA_LEAN +#define NOMINMAX +#include +#endif + #include "Error.h" #include "Tracing.h" #include "swift/ABI/Metadata.h" @@ -36,12 +43,6 @@ #if HAVE_PTHREAD_H #include #endif -#if defined(_WIN32) -#define WIN32_LEAN_AND_MEAN -#define VC_EXTRA_LEAN -#define NOMINMAX -#include -#endif namespace swift { diff --git a/stdlib/public/runtime/Errors.cpp b/stdlib/public/runtime/Errors.cpp index cb665d46ada56..84a6b6a47ec03 100644 --- a/stdlib/public/runtime/Errors.cpp +++ b/stdlib/public/runtime/Errors.cpp @@ -15,6 +15,10 @@ //===----------------------------------------------------------------------===// #if defined(_WIN32) +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX +#include + #include #endif diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp index 0f02a2f103a92..0be2c0e410b53 100644 --- a/stdlib/public/runtime/Metadata.cpp +++ b/stdlib/public/runtime/Metadata.cpp @@ -14,6 +14,13 @@ // //===----------------------------------------------------------------------===// +#if defined(_WIN32) +#define WIN32_LEAN_AND_MEAN +// Avoid defining macro max(), min() which conflict with std::max(), std::min() +#define NOMINMAX +#include +#endif + #include "swift/Runtime/Metadata.h" #include "MetadataCache.h" #include "swift/Basic/Lazy.h" @@ -37,12 +44,6 @@ #include #include #include -#if defined(_WIN32) -#define WIN32_LEAN_AND_MEAN -// Avoid defining macro max(), min() which conflict with std::max(), std::min() -#define NOMINMAX -#include -#endif #if SWIFT_PTRAUTH #include #endif From 14a4bd45b6b164e82679570b2fe649128c0dd8e6 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Wed, 27 Apr 2022 20:26:27 +0100 Subject: [PATCH 20/40] [Concurrency][Threading] Remove use of platform thread functions. The concurrency library can use the new threading library functions, which avoids the problem of including . rdar://90776105 --- include/swift/Threading/Thread.h | 9 +++- lib/Threading/CMakeLists.txt | 1 + lib/Threading/Darwin.cpp | 57 +++++++++++++++++++++++++ stdlib/public/Concurrency/Actor.cpp | 34 +-------------- stdlib/public/Concurrency/TaskPrivate.h | 29 +------------ stdlib/public/Threading/CMakeLists.txt | 1 + 6 files changed, 71 insertions(+), 60 deletions(-) create mode 100644 lib/Threading/Darwin.cpp diff --git a/include/swift/Threading/Thread.h b/include/swift/Threading/Thread.h index 063cf77b0b63d..7aa1ced913248 100644 --- a/include/swift/Threading/Thread.h +++ b/include/swift/Threading/Thread.h @@ -25,11 +25,15 @@ namespace swift { /// Identifies a thread class Thread { +public: + using Id = threading_impl::thread_id; + private: - threading_impl::thread_id id_; + Id id_; public: Thread() {} + explicit Thread(Id platformId) : id_(platformId) {} Thread(const Thread& other) : id_(other.id_) {} Thread(Thread&& other) : id_(std::move(other.id_)) {} @@ -43,6 +47,9 @@ class Thread { return *this; } + /// Returns the platform specific thread ID + Id platformThreadId() const { return id_; } + /// Returns the currently executing thread static Thread current() { return Thread(threading_impl::thread_get_current()); diff --git a/lib/Threading/CMakeLists.txt b/lib/Threading/CMakeLists.txt index 4ded5235438c5..206fcc6e3c357 100644 --- a/lib/Threading/CMakeLists.txt +++ b/lib/Threading/CMakeLists.txt @@ -1,5 +1,6 @@ add_swift_host_library(swiftThreading STATIC C11.cpp + Darwin.cpp Linux.cpp Nothreads.cpp Pthreads.cpp diff --git a/lib/Threading/Darwin.cpp b/lib/Threading/Darwin.cpp new file mode 100644 index 0000000000000..5f1dd8bffc87b --- /dev/null +++ b/lib/Threading/Darwin.cpp @@ -0,0 +1,57 @@ +//==--- Darwin.cpp - 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 Darwin +// +//===----------------------------------------------------------------------===// + +#if SWIFT_THREADING_DARWIN + +#include + +#include "swift/Threading/Errors.h" +#include "swift/Threading/Impl/Darwin.h" + +namespace { + +#pragma clang diagnostic push +#pragma GCC diagnostic ignored "-Wglobal-constructors" + +class MainThreadRememberer { +private: + pthread_t mainThread_; +public: + MainThreadRememberer() { mainThread_ = pthread_self(); } + + pthread_t main_thread() const { return mainThread_; } +}; + +MainThreadRememberer rememberer; + +#pragma clang diagnostic pop + +} + +using namespace swift; +using namespace threading_impl; + +thread_id +swift::threading_impl::thread_get_main() { + return rememberer.main_thread(); +} + +bool +swift::threading_impl::thread_is_main() { + return pthread_main_np(); +} + +#endif // SWIFT_THREADING_DARWIN diff --git a/stdlib/public/Concurrency/Actor.cpp b/stdlib/public/Concurrency/Actor.cpp index 0820a853fef1d..dda8d0fb9d98d 100644 --- a/stdlib/public/Concurrency/Actor.cpp +++ b/stdlib/public/Concurrency/Actor.cpp @@ -35,6 +35,7 @@ #include "swift/Threading/Once.h" #include "swift/Threading/Mutex.h" #include "swift/Threading/ThreadLocalStorage.h" +#include "swift/Threading/Thread.h" #include "swift/ABI/Task.h" #include "swift/ABI/Actor.h" #include "swift/Basic/ListMerger.h" @@ -67,21 +68,6 @@ #include #endif -#if defined(_POSIX_THREADS) -#include - -// Only use __has_include since HAVE_PTHREAD_NP_H is not provided. -#if __has_include() -#include -#endif -#endif - -#if defined(_WIN32) -#include -#include -#include -#endif - #if SWIFT_OBJC_INTEROP extern "C" void *objc_autoreleasePoolPush(); extern "C" void objc_autoreleasePoolPop(void *); @@ -278,29 +264,13 @@ static ExecutorRef swift_task_getCurrentExecutorImpl() { return result; } -#if defined(_WIN32) -static HANDLE __initialPthread = INVALID_HANDLE_VALUE; -#endif - /// Determine whether we are currently executing on the main thread /// independently of whether we know that we are on the main actor. static bool isExecutingOnMainThread() { #if SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY return true; -#elif defined(__linux__) - return syscall(SYS_gettid) == getpid(); -#elif defined(_WIN32) - if (__initialPthread == INVALID_HANDLE_VALUE) { - DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), - GetCurrentProcess(), &__initialPthread, 0, FALSE, - DUPLICATE_SAME_ACCESS); - } - - return __initialPthread == GetCurrentThread(); -#elif defined(__wasi__) - return true; #else - return pthread_main_np() == 1; + return Thread::onMainThread(); #endif } diff --git a/stdlib/public/Concurrency/TaskPrivate.h b/stdlib/public/Concurrency/TaskPrivate.h index c2de6efb709b7..d66f6907ca064 100644 --- a/stdlib/public/Concurrency/TaskPrivate.h +++ b/stdlib/public/Concurrency/TaskPrivate.h @@ -17,13 +17,6 @@ #ifndef SWIFT_CONCURRENCY_TASKPRIVATE_H #define SWIFT_CONCURRENCY_TASKPRIVATE_H -#if defined(_WIN32) -#define WIN32_LEAN_AND_MEAN -#define VC_EXTRA_LEAN -#define NOMINMAX -#include -#endif - #include "Error.h" #include "Tracing.h" #include "swift/ABI/Metadata.h" @@ -34,16 +27,13 @@ #include "swift/Runtime/Error.h" #include "swift/Runtime/Exclusivity.h" #include "swift/Runtime/HeapObject.h" +#include "swift/Threading/Thread.h" #include #include #define SWIFT_FATAL_ERROR swift_Concurrency_fatalError #include "../runtime/StackAllocator.h" -#if HAVE_PTHREAD_H -#include -#endif - namespace swift { // Set to 1 to enable helpful debug spew to stderr @@ -51,24 +41,9 @@ namespace swift { #if 0 #define SWIFT_TASK_DEBUG_LOG(fmt, ...) \ fprintf(stderr, "[%lu] [%s:%d](%s) " fmt "\n", \ - (unsigned long)_swift_get_thread_id(), \ + (unsigned long)Thread::current()::platformThreadId(), \ __FILE__, __LINE__, __FUNCTION__, \ __VA_ARGS__) - -#if defined(_WIN32) -using ThreadID = decltype(GetCurrentThreadId()); -#else -using ThreadID = decltype(pthread_self()); -#endif - -inline ThreadID _swift_get_thread_id() { -#if defined(_WIN32) - return GetCurrentThreadId(); -#else - return pthread_self(); -#endif -} - #else #define SWIFT_TASK_DEBUG_LOG(fmt, ...) (void)0 #endif diff --git a/stdlib/public/Threading/CMakeLists.txt b/stdlib/public/Threading/CMakeLists.txt index a4f14655233fe..928dd32776327 100644 --- a/stdlib/public/Threading/CMakeLists.txt +++ b/stdlib/public/Threading/CMakeLists.txt @@ -1,5 +1,6 @@ add_swift_target_library(swiftThreading OBJECT_LIBRARY "${SWIFT_SOURCE_DIR}/lib/Threading/C11.cpp" + "${SWIFT_SOURCE_DIR}/lib/Threading/Darwin.cpp" "${SWIFT_SOURCE_DIR}/lib/Threading/Linux.cpp" "${SWIFT_SOURCE_DIR}/lib/Threading/Nothreads.cpp" "${SWIFT_SOURCE_DIR}/lib/Threading/Pthreads.cpp" From d6cff94e7f5b35e725ecef0bfa2b2f1f52d34c5a Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Thu, 28 Apr 2022 07:19:28 +0100 Subject: [PATCH 21/40] [Threading][Windows] Try to avoid declaring _RTL_SRWLOCK Declaring _RTL_SRWLOCK ourselves causes clashes with . Rather than doing that, declare an equivalent struct, and some overloads. rdar://90776105 --- include/swift/Threading/Impl/Win32.h | 24 ++++++------ .../swift/Threading/Impl/Win32/Win32Defs.h | 38 ++++++++++++++----- 2 files changed, 41 insertions(+), 21 deletions(-) diff --git a/include/swift/Threading/Impl/Win32.h b/include/swift/Threading/Impl/Win32.h index acbc1237e375f..cc563b701cfb0 100644 --- a/include/swift/Threading/Impl/Win32.h +++ b/include/swift/Threading/Impl/Win32.h @@ -35,7 +35,7 @@ inline bool threads_same(thread_id a, thread_id b) { return a == b; } // .. Mutex support .......................................................... -using mutex_handle = ::SRWLOCK; +using mutex_handle = SWIFT_SRWLOCK; inline void mutex_init(mutex_handle &handle, bool checked=false) { handle = SRWLOCK_INIT; @@ -43,23 +43,23 @@ inline void mutex_init(mutex_handle &handle, bool checked=false) { inline void mutex_destroy(mutex_handle &handle) { } inline void mutex_lock(mutex_handle &handle) { - ::AcquireSRWLockExclusive(&handle); + AcquireSRWLockExclusive(&handle); } inline void mutex_unlock(mutex_handle &handle) { - ::ReleaseSRWLockExclusive(&handle); + ReleaseSRWLockExclusive(&handle); } inline bool mutex_try_lock(mutex_handle &handle) { - return !!::TryAcquireSRWLockExclusive(&handle); + return !!TryAcquireSRWLockExclusive(&handle); } inline void mutex_unsafe_lock(mutex_handle &handle) { - ::AcquireSRWLockExclusive(&handle); + AcquireSRWLockExclusive(&handle); } inline void mutex_unsafe_unlock(mutex_handle &handle) { - ::ReleaseSRWLockExclusive(&handle); + ReleaseSRWLockExclusive(&handle); } -using lazy_mutex_handle = ::SRWLOCK; +using lazy_mutex_handle = SWIFT_SRWLOCK; // We don't need to be lazy here because Win32 has SRWLOCK_INIT. inline constexpr lazy_mutex_handle lazy_mutex_initializer() { @@ -68,20 +68,20 @@ inline constexpr lazy_mutex_handle lazy_mutex_initializer() { inline void lazy_mutex_destroy(lazy_mutex_handle &handle) { } inline void lazy_mutex_lock(lazy_mutex_handle &handle) { - ::AcquireSRWLockExclusive(&handle); + AcquireSRWLockExclusive(&handle); } inline void lazy_mutex_unlock(lazy_mutex_handle &handle) { - ::ReleaseSRWLockExclusive(&handle); + ReleaseSRWLockExclusive(&handle); } inline bool lazy_mutex_try_lock(lazy_mutex_handle &handle) { - return !!::TryAcquireSRWLockExclusive(&handle); + return !!TryAcquireSRWLockExclusive(&handle); } inline void lazy_mutex_unsafe_lock(lazy_mutex_handle &handle) { - ::AcquireSRWLockExclusive(&handle); + AcquireSRWLockExclusive(&handle); } inline void lazy_mutex_unsafe_unlock(lazy_mutex_handle &handle) { - ::ReleaseSRWLockExclusive(&handle); + ReleaseSRWLockExclusive(&handle); } // .. Once ................................................................... diff --git a/include/swift/Threading/Impl/Win32/Win32Defs.h b/include/swift/Threading/Impl/Win32/Win32Defs.h index 21fc091c30ab0..e2a4d561d8b49 100644 --- a/include/swift/Threading/Impl/Win32/Win32Defs.h +++ b/include/swift/Threading/Impl/Win32/Win32Defs.h @@ -39,15 +39,8 @@ typedef unsigned long DWORD; typedef VOID (NTAPI* PFLS_CALLBACK_FUNCTION)(PVOID lpFlsData); -// We can't define this struct if already did so -#ifndef _WINNT_ -struct _RTL_SRWLOCK { - PVOID Ptr; -}; -#endif // _WINNT_ - -typedef struct _RTL_SRWLOCK RTL_SRWLOCK, *PRTL_SRWLOCK; -typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK; +typedef struct _RTL_SRWLOCK *PRTL_SRWLOCK; +typedef PRTL_SRWLOCK PSRWLOCK; // These have to be #defines, to avoid problems with #define RTL_SRWLOCK_INIT {0} @@ -68,4 +61,31 @@ extern "C" { WINBASEAPI BOOL WINAPI FlsFree(DWORD dwFlsIndex); } +namespace swift { +namespace threading_impl { + +// We do this because we can't declare _RTL_SRWLOCK here in case someone +// later includes +struct SWIFT_SRWLOCK { + PVOID Ptr; +}; + +typedef SWIFT_SRWLOCK *PSWIFT_SRWLOCK; + +inline VOID InitializeSRWLock(PSWIFT_SRWLOCK SRWLock) { + ::InitializeSRWLock(reinterpret_cast(SRWLock)); +} +inline VOID ReleaseSRWLockExclusive(PSWIFT_SRWLOCK SRWLock) { + ::ReleaseSRWLockExclusive(reinterpret_cast(SRWLock)); +} +inline VOID AcquireSRWLockExclusive(PSWIFT_SRWLOCK SRWLock) { + ::AcquireSRWLockExclusive(reinterpret_cast(SRWLock)); +} +inline BOOLEAN TryAcquireSRWLockExclusive(PSWIFT_SRWLOCK SRWLock) { + return ::TryAcquireSRWLockExclusive(reinterpret_cast(SRWLock)); +} + +} +} + #endif // SWIFT_THREADING_IMPL_WIN32_DEFS_H From e305a7dcf6068c6c2188248ef7416e0eae109fab Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Thu, 28 Apr 2022 09:46:17 +0100 Subject: [PATCH 22/40] [Concurrency][Windows] Add a couple of includes for Windows. Actor.cpp does need still, and Task.cpp should have been including rdar://90776105 --- stdlib/public/Concurrency/Actor.cpp | 12 ++++-------- stdlib/public/Concurrency/Task.cpp | 6 ++++++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/stdlib/public/Concurrency/Actor.cpp b/stdlib/public/Concurrency/Actor.cpp index dda8d0fb9d98d..b4fce7d20d4a9 100644 --- a/stdlib/public/Concurrency/Actor.cpp +++ b/stdlib/public/Concurrency/Actor.cpp @@ -19,14 +19,6 @@ #include #include -#ifdef _WIN32 -// On Windows, an include below triggers an indirect include of minwindef.h -// which contains a definition of the `max` macro, generating an error in our -// use of std::max in this file. This define prevents those macros from being -// defined. -#define NOMINMAX -#endif - #include "../CompatibilityOverride/CompatibilityOverride.h" #include "swift/Runtime/Atomic.h" #include "swift/Runtime/AccessibleFunction.h" @@ -68,6 +60,10 @@ #include #endif +#if defined(_WIN32) +#include +#endif + #if SWIFT_OBJC_INTEROP extern "C" void *objc_autoreleasePoolPush(); extern "C" void objc_autoreleasePoolPop(void *); diff --git a/stdlib/public/Concurrency/Task.cpp b/stdlib/public/Concurrency/Task.cpp index 74282940d253a..78e59f05ed460 100644 --- a/stdlib/public/Concurrency/Task.cpp +++ b/stdlib/public/Concurrency/Task.cpp @@ -14,6 +14,12 @@ // //===----------------------------------------------------------------------===// +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX +#include +#endif + #include "../CompatibilityOverride/CompatibilityOverride.h" #include "swift/Runtime/Concurrency.h" #include "swift/ABI/Task.h" From ef2e40a937c7aa0d6d2b51de6710b48458e27e2f Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Thu, 28 Apr 2022 10:59:16 +0100 Subject: [PATCH 23/40] [Concurrency][Windows] Remove unnecessary includes. TaskLocal.cpp doesn't need or , both of which want , which isn't included any more. rdar://90776105 --- stdlib/public/Concurrency/TaskLocal.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/stdlib/public/Concurrency/TaskLocal.cpp b/stdlib/public/Concurrency/TaskLocal.cpp index 05b2d9b10f713..03db55db7f589 100644 --- a/stdlib/public/Concurrency/TaskLocal.cpp +++ b/stdlib/public/Concurrency/TaskLocal.cpp @@ -36,8 +36,6 @@ #if defined(_WIN32) #include -#include -#include #endif using namespace swift; From 3bfc7e073152a2192296ad7085fb3f37c12a49dc Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Thu, 28 Apr 2022 12:02:04 +0100 Subject: [PATCH 24/40] [Threading][Windows] Link the unit test against Synchronization.lib We need to link the threading unit test against Synchronization.lib to pick up the Win32 APIs we're using. rdar://90776105 --- unittests/Threading/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/unittests/Threading/CMakeLists.txt b/unittests/Threading/CMakeLists.txt index 2de1814a6e16f..d0e6084a6a2ad 100644 --- a/unittests/Threading/CMakeLists.txt +++ b/unittests/Threading/CMakeLists.txt @@ -10,3 +10,7 @@ target_link_libraries(SwiftThreadingTests swiftThreading${SWIFT_PRIMARY_VARIANT_SUFFIX} swiftCore${SWIFT_PRIMARY_VARIANT_SUFFIX} ) + +if(CMAKE_SYSTEM_NAME STREQUAL Windows) + target_link_libraries(SwiftThreadingTests PRIVATE Synchronization) +endif() From 210b772800759a953e56c28fe52f9a057e5ca5de Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Thu, 28 Apr 2022 12:54:20 +0100 Subject: [PATCH 25/40] [UnitTests][Windows] Link with Synchronization.lib The runtime unit tests also need to link with Synchronization.lib. rdar://90776105 --- unittests/Basic/CMakeLists.txt | 4 +++ unittests/Threading/CMakeLists.txt | 29 ++++++++++++---------- unittests/runtime/CMakeLists.txt | 2 +- unittests/runtime/LongTests/CMakeLists.txt | 2 +- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/unittests/Basic/CMakeLists.txt b/unittests/Basic/CMakeLists.txt index 72c954e1d3b40..547751e6cac8f 100644 --- a/unittests/Basic/CMakeLists.txt +++ b/unittests/Basic/CMakeLists.txt @@ -48,3 +48,7 @@ target_link_libraries(SwiftBasicTests clangBasic LLVMTestingSupport ) + +if(SWIFT_HOST_VARIANT STREQUAL windows) + target_link_libraries(SwiftBasicTests PRIVATE Synchronization) +endif() diff --git a/unittests/Threading/CMakeLists.txt b/unittests/Threading/CMakeLists.txt index d0e6084a6a2ad..b82f2bce677ff 100644 --- a/unittests/Threading/CMakeLists.txt +++ b/unittests/Threading/CMakeLists.txt @@ -1,16 +1,19 @@ -add_swift_unittest(SwiftThreadingTests - Mutex.cpp - Once.cpp - LinuxUlock.cpp - Fatal.cpp - ) +if(("${SWIFT_HOST_VARIANT_SDK}" STREQUAL "${SWIFT_PRIMARY_VARIANT_SDK}") AND + ("${SWIFT_HOST_VARIANT_ARCH}" STREQUAL "${SWIFT_PRIMARY_VARIANT_ARCH}")) + add_swift_unittest(SwiftThreadingTests + Mutex.cpp + Once.cpp + LinuxUlock.cpp + Fatal.cpp + ) -target_link_libraries(SwiftThreadingTests - PRIVATE - swiftThreading${SWIFT_PRIMARY_VARIANT_SUFFIX} - swiftCore${SWIFT_PRIMARY_VARIANT_SUFFIX} - ) + target_link_libraries(SwiftThreadingTests + PRIVATE + swiftThreading${SWIFT_PRIMARY_VARIANT_SUFFIX} + swiftCore${SWIFT_PRIMARY_VARIANT_SUFFIX} + ) -if(CMAKE_SYSTEM_NAME STREQUAL Windows) - target_link_libraries(SwiftThreadingTests PRIVATE Synchronization) + if(SWIFT_HOST_VARIANT STREQUAL windows) + target_link_libraries(SwiftThreadingTests PRIVATE Synchronization) + endif() endif() diff --git a/unittests/runtime/CMakeLists.txt b/unittests/runtime/CMakeLists.txt index e45b0bdbaa6c7..79df463c0edb0 100644 --- a/unittests/runtime/CMakeLists.txt +++ b/unittests/runtime/CMakeLists.txt @@ -64,7 +64,7 @@ if(("${SWIFT_HOST_VARIANT_SDK}" STREQUAL "${SWIFT_PRIMARY_VARIANT_SDK}") AND ${EXECINFO_LIBRARY} ) elseif(SWIFT_HOST_VARIANT STREQUAL windows) - list(APPEND PLATFORM_TARGET_LINK_LIBRARIES DbgHelp) + list(APPEND PLATFORM_TARGET_LINK_LIBRARIES DbgHelp;Synchronization) endif() if(SWIFT_ENABLE_EXPERIMENTAL_CONCURRENCY) diff --git a/unittests/runtime/LongTests/CMakeLists.txt b/unittests/runtime/LongTests/CMakeLists.txt index 35f7ef727ff52..592e532f8cf53 100644 --- a/unittests/runtime/LongTests/CMakeLists.txt +++ b/unittests/runtime/LongTests/CMakeLists.txt @@ -31,7 +31,7 @@ if(("${SWIFT_HOST_VARIANT_SDK}" STREQUAL "${SWIFT_PRIMARY_VARIANT_SDK}") AND ${EXECINFO_LIBRARY} ) elseif(SWIFT_HOST_VARIANT STREQUAL windows) - list(APPEND PLATFORM_TARGET_LINK_LIBRARIES DbgHelp) + list(APPEND PLATFORM_TARGET_LINK_LIBRARIES DbgHelp;Synchronization) endif() add_swift_unittest(SwiftRuntimeLongTests From f3a412dd538db886928aa47f8b8f735a2155a647 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Thu, 28 Apr 2022 16:20:34 +0100 Subject: [PATCH 26/40] [Threading] Remove thread_get_main(). Removing thread_get_main() means we don't need a static initializer on Darwin, which means we can delete Darwin.cpp as well. We can also delete Nothreads.cpp while we're about it, because there's nothing in that file. rdar://90776105 --- include/swift/Threading/Impl/C11.h | 1 - include/swift/Threading/Impl/Darwin.h | 3 +- include/swift/Threading/Impl/Linux.h | 1 - include/swift/Threading/Impl/Nothreads.h | 1 - include/swift/Threading/Impl/Pthreads.h | 1 - include/swift/Threading/Impl/Win32.h | 1 - include/swift/Threading/Thread.h | 5 --- lib/Threading/C11.cpp | 7 +-- lib/Threading/CMakeLists.txt | 5 ++- lib/Threading/Darwin.cpp | 57 ------------------------ lib/Threading/Linux.cpp | 7 +-- lib/Threading/Nothreads.cpp | 21 --------- lib/Threading/Pthreads.cpp | 7 +-- lib/Threading/Win32.cpp | 7 +-- stdlib/public/Threading/CMakeLists.txt | 5 ++- 15 files changed, 11 insertions(+), 118 deletions(-) delete mode 100644 lib/Threading/Darwin.cpp delete mode 100644 lib/Threading/Nothreads.cpp diff --git a/include/swift/Threading/Impl/C11.h b/include/swift/Threading/Impl/C11.h index 53d46060be016..99e48f46c50f4 100644 --- a/include/swift/Threading/Impl/C11.h +++ b/include/swift/Threading/Impl/C11.h @@ -49,7 +49,6 @@ do { \ 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); diff --git a/include/swift/Threading/Impl/Darwin.h b/include/swift/Threading/Impl/Darwin.h index 6aeed2d0d1867..b171a7a8dba01 100644 --- a/include/swift/Threading/Impl/Darwin.h +++ b/include/swift/Threading/Impl/Darwin.h @@ -32,8 +32,7 @@ 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 thread_is_main() { return pthread_main_np(); } inline bool threads_same(thread_id a, thread_id b) { return ::pthread_equal(a, b); diff --git a/include/swift/Threading/Impl/Linux.h b/include/swift/Threading/Impl/Linux.h index e651b53d9d0ae..7ada98e09a6ec 100644 --- a/include/swift/Threading/Impl/Linux.h +++ b/include/swift/Threading/Impl/Linux.h @@ -55,7 +55,6 @@ 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) { diff --git a/include/swift/Threading/Impl/Nothreads.h b/include/swift/Threading/Impl/Nothreads.h index ce4ee05cb670b..bf4aef25f36e8 100644 --- a/include/swift/Threading/Impl/Nothreads.h +++ b/include/swift/Threading/Impl/Nothreads.h @@ -25,7 +25,6 @@ namespace threading_impl { 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; } diff --git a/include/swift/Threading/Impl/Pthreads.h b/include/swift/Threading/Impl/Pthreads.h index 24ab686d0be81..57dfef88d5ac0 100644 --- a/include/swift/Threading/Impl/Pthreads.h +++ b/include/swift/Threading/Impl/Pthreads.h @@ -54,7 +54,6 @@ 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) { diff --git a/include/swift/Threading/Impl/Win32.h b/include/swift/Threading/Impl/Win32.h index cc563b701cfb0..a9c77827e4303 100644 --- a/include/swift/Threading/Impl/Win32.h +++ b/include/swift/Threading/Impl/Win32.h @@ -29,7 +29,6 @@ namespace threading_impl { 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; } diff --git a/include/swift/Threading/Thread.h b/include/swift/Threading/Thread.h index 7aa1ced913248..123abb3c45d54 100644 --- a/include/swift/Threading/Thread.h +++ b/include/swift/Threading/Thread.h @@ -55,11 +55,6 @@ class Thread { 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(); diff --git a/lib/Threading/C11.cpp b/lib/Threading/C11.cpp index 2a54d42e7ac78..efeb15f319567 100644 --- a/lib/Threading/C11.cpp +++ b/lib/Threading/C11.cpp @@ -64,14 +64,9 @@ C11ThreadingHelper helper; using namespace swift; using namespace threading_impl; -thread_id -swift::threading_impl::thread_get_main() { - return helper.main_thread(); -} - bool swift::threading_impl::thread_is_main() { - return thrd_equal(thrd_current(), thread_get_main()); + return thrd_equal(thrd_current(), helper.main_thread()); } void diff --git a/lib/Threading/CMakeLists.txt b/lib/Threading/CMakeLists.txt index 206fcc6e3c357..2e16b262a44b8 100644 --- a/lib/Threading/CMakeLists.txt +++ b/lib/Threading/CMakeLists.txt @@ -1,7 +1,8 @@ +# If you update this, you also need to update the CMakeLists.txt file in +# stdlib/public/Threading + add_swift_host_library(swiftThreading STATIC C11.cpp - Darwin.cpp Linux.cpp - Nothreads.cpp Pthreads.cpp Win32.cpp) diff --git a/lib/Threading/Darwin.cpp b/lib/Threading/Darwin.cpp deleted file mode 100644 index 5f1dd8bffc87b..0000000000000 --- a/lib/Threading/Darwin.cpp +++ /dev/null @@ -1,57 +0,0 @@ -//==--- Darwin.cpp - 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 Darwin -// -//===----------------------------------------------------------------------===// - -#if SWIFT_THREADING_DARWIN - -#include - -#include "swift/Threading/Errors.h" -#include "swift/Threading/Impl/Darwin.h" - -namespace { - -#pragma clang diagnostic push -#pragma GCC diagnostic ignored "-Wglobal-constructors" - -class MainThreadRememberer { -private: - pthread_t mainThread_; -public: - MainThreadRememberer() { mainThread_ = pthread_self(); } - - pthread_t main_thread() const { return mainThread_; } -}; - -MainThreadRememberer rememberer; - -#pragma clang diagnostic pop - -} - -using namespace swift; -using namespace threading_impl; - -thread_id -swift::threading_impl::thread_get_main() { - return rememberer.main_thread(); -} - -bool -swift::threading_impl::thread_is_main() { - return pthread_main_np(); -} - -#endif // SWIFT_THREADING_DARWIN diff --git a/lib/Threading/Linux.cpp b/lib/Threading/Linux.cpp index 9d51a61328173..2fc512f8bd60e 100644 --- a/lib/Threading/Linux.cpp +++ b/lib/Threading/Linux.cpp @@ -42,14 +42,9 @@ MainThreadRememberer rememberer; using namespace swift; using namespace threading_impl; -thread_id -swift::threading_impl::thread_get_main() { - return rememberer.main_thread(); -} - bool swift::threading_impl::thread_is_main() { - return pthread_equal(pthread_self(), thread_get_main()); + return pthread_equal(pthread_self(), rememberer.main_thread()); } void diff --git a/lib/Threading/Nothreads.cpp b/lib/Threading/Nothreads.cpp deleted file mode 100644 index 60cfe3071e601..0000000000000 --- a/lib/Threading/Nothreads.cpp +++ /dev/null @@ -1,21 +0,0 @@ -//==--- Nothreads.cpp - 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 -// -//===----------------------------------------------------------------------===// - -#if SWIFT_THREADING_NONE - -#include "swift/Threading/Impl/Nothreads.h" - -#endif // SWIFT_THREADING_NONE diff --git a/lib/Threading/Pthreads.cpp b/lib/Threading/Pthreads.cpp index a77b4819d0bb1..72ccd60552c0a 100644 --- a/lib/Threading/Pthreads.cpp +++ b/lib/Threading/Pthreads.cpp @@ -44,14 +44,9 @@ pthread_cond_t onceCond = PTHREAD_COND_INITIALIZER; using namespace swift; using namespace threading_impl; -thread_id -swift::threading_impl::thread_get_main() { - return rememberer.main_thread(); -} - bool swift::threading_impl::thread_is_main() { - return pthread_equal(pthread_self(), thread_get_main()); + return pthread_equal(pthread_self(), rememberer.main_thread()); } void diff --git a/lib/Threading/Win32.cpp b/lib/Threading/Win32.cpp index 1937dd0da3484..8a1e88b641eca 100644 --- a/lib/Threading/Win32.cpp +++ b/lib/Threading/Win32.cpp @@ -52,14 +52,9 @@ CONDITION_VARIABLE onceCond = CONDITION_VARIABLE_INIT; using namespace swift; using namespace threading_impl; -thread_id -swift::threading_impl::thread_get_main() { - return rememberer.main_thread(); -} - bool swift::threading_impl::thread_is_main() { - return ::GetCurrentThreadId() == thread_get_main(); + return ::GetCurrentThreadId() == rememberer.main_thread(); } void diff --git a/stdlib/public/Threading/CMakeLists.txt b/stdlib/public/Threading/CMakeLists.txt index 928dd32776327..2f8e248b05456 100644 --- a/stdlib/public/Threading/CMakeLists.txt +++ b/stdlib/public/Threading/CMakeLists.txt @@ -1,8 +1,9 @@ +# This is the counterpart to lib/Threading/CMakeLists.txt. Any updates +# need to be reflected in both places. + add_swift_target_library(swiftThreading OBJECT_LIBRARY "${SWIFT_SOURCE_DIR}/lib/Threading/C11.cpp" - "${SWIFT_SOURCE_DIR}/lib/Threading/Darwin.cpp" "${SWIFT_SOURCE_DIR}/lib/Threading/Linux.cpp" - "${SWIFT_SOURCE_DIR}/lib/Threading/Nothreads.cpp" "${SWIFT_SOURCE_DIR}/lib/Threading/Pthreads.cpp" "${SWIFT_SOURCE_DIR}/lib/Threading/Win32.cpp" INSTALL_IN_COMPONENT never_install) From 0e9318cec5bcddfc213a3e1feb649adacf8e9e75 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Thu, 28 Apr 2022 17:44:03 +0100 Subject: [PATCH 27/40] [Threading] Put everything through git clang-format. Just formatting changes. rdar://90776105 --- include/swift/Basic/Compiler.h | 6 +- include/swift/Runtime/Concurrent.h | 12 ++-- include/swift/Runtime/EnvironmentVariables.h | 8 +-- include/swift/Runtime/VoucherShims.h | 3 +- include/swift/Threading/Errors.h | 4 +- include/swift/Threading/Impl.h | 39 ++++++------ include/swift/Threading/Impl/C11.h | 59 ++++++++--------- include/swift/Threading/Impl/Darwin.h | 52 ++++++++------- include/swift/Threading/Impl/Linux.h | 52 ++++++++------- include/swift/Threading/Impl/Linux/ulock.h | 27 ++++---- include/swift/Threading/Impl/Nothreads.h | 22 +++---- include/swift/Threading/Impl/Pthreads.h | 50 +++++++-------- include/swift/Threading/Impl/Win32.h | 22 +++---- .../swift/Threading/Impl/Win32/Win32Defs.h | 41 ++++++------ include/swift/Threading/Mutex.h | 3 +- include/swift/Threading/Once.h | 5 +- include/swift/Threading/Thread.h | 16 +++-- include/swift/Threading/ThreadLocalStorage.h | 63 ++++++++++++------- lib/Threading/C11.cpp | 33 ++++------ lib/Threading/Linux.cpp | 14 ++--- lib/Threading/Pthreads.cpp | 18 +++--- lib/Threading/Win32.cpp | 12 ++-- stdlib/public/Concurrency/Actor.cpp | 30 +++++---- stdlib/public/Concurrency/AsyncLet.cpp | 8 +-- stdlib/public/Concurrency/AsyncStream.cpp | 14 +---- stdlib/public/Concurrency/Error.cpp | 6 +- stdlib/public/Concurrency/Error.h | 8 ++- stdlib/public/Concurrency/Task.cpp | 14 ++--- stdlib/public/Concurrency/TaskGroup.cpp | 19 +++--- stdlib/public/Concurrency/TaskLocal.cpp | 15 +++-- stdlib/public/Concurrency/TaskPrivate.h | 5 +- stdlib/public/Concurrency/TaskStatus.cpp | 13 ++-- stdlib/public/runtime/Casting.cpp | 6 +- stdlib/public/runtime/Errors.cpp | 2 +- stdlib/public/runtime/HeapObject.cpp | 13 ++-- stdlib/public/runtime/Metadata.cpp | 15 +++-- stdlib/public/runtime/MetadataCache.h | 12 ++-- stdlib/public/runtime/MetadataLookup.cpp | 12 ++-- stdlib/public/runtime/Once.cpp | 2 +- .../runtime/RuntimeInvocationsTracking.cpp | 2 +- stdlib/public/runtime/SwiftTLSContext.cpp | 11 ++-- stdlib/public/stubs/OptionalBridgingHelper.mm | 4 +- stdlib/public/stubs/Random.cpp | 2 +- stdlib/public/stubs/Stubs.cpp | 22 +++---- stdlib/public/stubs/ThreadLocalStorage.cpp | 13 ++-- .../Compatibility50/ProtocolConformance.cpp | 2 +- .../DynamicReplaceable.cpp | 6 +- unittests/Threading/LockingHelpers.h | 18 ++++-- unittests/Threading/Once.cpp | 21 ++++--- 49 files changed, 415 insertions(+), 441 deletions(-) diff --git a/include/swift/Basic/Compiler.h b/include/swift/Basic/Compiler.h index eec7da704c3e7..e2ad49ec4aa2d 100644 --- a/include/swift/Basic/Compiler.h +++ b/include/swift/Basic/Compiler.h @@ -165,15 +165,15 @@ // SWIFT_FORMAT(fmt,first) marks a function as taking a format string argument // at argument `fmt`, with the first argument for the format string as `first`. #if __has_attribute(format) -#define SWIFT_FORMAT(fmt,first) __attribute__((format(printf, fmt, first))) +#define SWIFT_FORMAT(fmt, first) __attribute__((format(printf, fmt, first))) #else -#define SWIFT_FORMAT(fmt,first) +#define SWIFT_FORMAT(fmt, first) #endif // SWIFT_VFORMAT(fmt) marks a function as taking a format string argument at // argument `fmt`, with the arguments in a `va_list`. #if __has_attribute(format) -#define SWIFT_VFORMAT(fmt) __attribute__((format(printf, fmt, 0))) +#define SWIFT_VFORMAT(fmt) __attribute__((format(printf, fmt, 0))) #else #define SWIFT_VFORMAT(fmt) #endif diff --git a/include/swift/Runtime/Concurrent.h b/include/swift/Runtime/Concurrent.h index 3221eb558214a..400b6a9f3f316 100644 --- a/include/swift/Runtime/Concurrent.h +++ b/include/swift/Runtime/Concurrent.h @@ -11,17 +11,17 @@ //===----------------------------------------------------------------------===// #ifndef SWIFT_RUNTIME_CONCURRENTUTILS_H #define SWIFT_RUNTIME_CONCURRENTUTILS_H -#include +#include "Atomic.h" +#include "Debug.h" +#include "swift/Threading/Mutex.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/Support/Allocator.h" #include #include #include +#include #include #include -#include "llvm/ADT/Hashing.h" -#include "llvm/Support/Allocator.h" -#include "Atomic.h" -#include "Debug.h" -#include "swift/Threading/Mutex.h" #if defined(__FreeBSD__) || defined(__CYGWIN__) || defined(__HAIKU__) #include diff --git a/include/swift/Runtime/EnvironmentVariables.h b/include/swift/Runtime/EnvironmentVariables.h index 5cf45b1f41220..d462e3b5a6312 100644 --- a/include/swift/Runtime/EnvironmentVariables.h +++ b/include/swift/Runtime/EnvironmentVariables.h @@ -29,10 +29,10 @@ extern swift::once_t initializeToken; #include "../../../stdlib/public/runtime/EnvironmentVariables.def" // Define getter functions. -#define VARIABLE(name, type, defaultValue, help) \ - inline type name() { \ - swift::once(initializeToken, initialize, nullptr); \ - return name ## _variable; \ +#define VARIABLE(name, type, defaultValue, help) \ + inline type name() { \ + swift::once(initializeToken, initialize, nullptr); \ + return name##_variable; \ } #include "../../../stdlib/public/runtime/EnvironmentVariables.def" diff --git a/include/swift/Runtime/VoucherShims.h b/include/swift/Runtime/VoucherShims.h index e0fdadbf23295..997cb07b991be 100644 --- a/include/swift/Runtime/VoucherShims.h +++ b/include/swift/Runtime/VoucherShims.h @@ -22,8 +22,7 @@ // swift-corelibs-libdispatch has os/voucher_private.h but it doesn't work for // us yet, so only look for it on Apple platforms. We also don't need vouchers // in the single threaded concurrency runtime. -#if __APPLE__ && !SWIFT_THREADING_NONE \ - && __has_include() +#if __APPLE__ && !SWIFT_THREADING_NONE && __has_include() #define SWIFT_HAS_VOUCHER_HEADER 1 #include #endif diff --git a/include/swift/Threading/Errors.h b/include/swift/Threading/Errors.h index f656b003bec28..34dec45d67d6b 100644 --- a/include/swift/Threading/Errors.h +++ b/include/swift/Threading/Errors.h @@ -29,7 +29,7 @@ SWIFT_ATTRIBUTE_NORETURN SWIFT_FORMAT(1, 2) void fatal(const char *msg, ...); -} -} +} // namespace threading +} // namespace swift #endif // SWIFT_THREADING_ERRORS_H diff --git a/include/swift/Threading/Impl.h b/include/swift/Threading/Impl.h index e40ee97f8138c..6d66096980276 100644 --- a/include/swift/Threading/Impl.h +++ b/include/swift/Threading/Impl.h @@ -19,27 +19,24 @@ #define SWIFT_THREADING_IMPL_H // Try to autodetect if we aren't told what to do -#if !SWIFT_THREADING_NONE && \ - !SWIFT_THREADING_DARWIN && \ - !SWIFT_THREADING_LINUX && \ - !SWIFT_THREADING_PTHREADS && \ - !SWIFT_THREADING_C11 && \ - !SWIFT_THREADING_WIN32 - #ifdef __APPLE__ - #define SWIFT_THREADING_DARWIN 1 - #elif defined(__linux__) - #define SWIFT_THREADING_LINUX 1 - #elif defined(_WIN32) - #define SWIFT_THREADING_WIN32 1 - #elif defined(__wasi__) - #define SWIFT_THREADING_NONE 1 - #elif __has_include() - #define SWIFT_THREADING_C11 1 - #elif __has_include() - #define SWIFT_THREADING_PTHREADS 1 - #else - #error Unable to autodetect threading package. Please define SWIFT_THREADING_x as appropriate for your platform. - #endif +#if !SWIFT_THREADING_NONE && !SWIFT_THREADING_DARWIN && \ + !SWIFT_THREADING_LINUX && !SWIFT_THREADING_PTHREADS && \ + !SWIFT_THREADING_C11 && !SWIFT_THREADING_WIN32 +#ifdef __APPLE__ +#define SWIFT_THREADING_DARWIN 1 +#elif defined(__linux__) +#define SWIFT_THREADING_LINUX 1 +#elif defined(_WIN32) +#define SWIFT_THREADING_WIN32 1 +#elif defined(__wasi__) +#define SWIFT_THREADING_NONE 1 +#elif __has_include() +#define SWIFT_THREADING_C11 1 +#elif __has_include() +#define SWIFT_THREADING_PTHREADS 1 +#else +#error Unable to autodetect threading package. Please define SWIFT_THREADING_x as appropriate for your platform. +#endif #endif #if SWIFT_THREADING_NONE diff --git a/include/swift/Threading/Impl/C11.h b/include/swift/Threading/Impl/C11.h index 99e48f46c50f4..fee6532f523bb 100644 --- a/include/swift/Threading/Impl/C11.h +++ b/include/swift/Threading/Impl/C11.h @@ -17,32 +17,31 @@ #ifndef SWIFT_THREADING_IMPL_C11_H #define SWIFT_THREADING_IMPL_C11_H -#include #include +#include 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) - +#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 .................................................. @@ -58,7 +57,7 @@ inline bool threads_same(thread_id a, thread_id b) { using mutex_handle = ::mtx_t; -inline void mutex_init(mutex_handle &handle, bool checked=false) { +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) { @@ -83,8 +82,8 @@ inline void mutex_unsafe_unlock(mutex_handle &handle) { } struct lazy_mutex_handle { - ::mtx_t mutex; - ::atomic_int once; // -1 = initialized, 0 = uninitialized, 1 = initializing + ::mtx_t mutex; + ::atomic_int once; // -1 = initialized, 0 = uninitialized, 1 = initializing }; inline constexpr lazy_mutex_handle lazy_mutex_initializer() { @@ -95,9 +94,7 @@ inline void lazy_mutex_init(lazy_mutex_handle &handle) { if (::atomic_load_explicit(&handle.once, ::memory_order_acquire) < 0) return; - if (::atomic_compare_exchange_strong_explicit(&handle.once, - &(int){ 0 }, - 1, + 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)); @@ -164,13 +161,9 @@ 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_get(tls_key key) { return ::tss_get(key); } -inline void tls_set(tls_key key, void *ptr) { - ::tss_set(key, ptr); -} +inline void tls_set(tls_key key, void *ptr) { ::tss_set(key, ptr); } } // namespace threading_impl diff --git a/include/swift/Threading/Impl/Darwin.h b/include/swift/Threading/Impl/Darwin.h index b171a7a8dba01..df27dd42f6237 100644 --- a/include/swift/Threading/Impl/Darwin.h +++ b/include/swift/Threading/Impl/Darwin.h @@ -17,9 +17,9 @@ #ifndef SWIFT_THREADING_IMPL_DARWIN_H #define SWIFT_THREADING_IMPL_DARWIN_H -#include -#include #include +#include +#include #include "swift/Threading/Errors.h" @@ -42,14 +42,12 @@ inline bool threads_same(thread_id a, thread_id b) { using mutex_handle = ::os_unfair_lock; -inline void mutex_init(mutex_handle &handle, bool checked=false) { +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_destroy(mutex_handle &handle) {} -inline void mutex_lock(mutex_handle &handle) { - ::os_unfair_lock_lock(&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); } @@ -70,7 +68,7 @@ using lazy_mutex_handle = ::os_unfair_lock; 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_destroy(lazy_mutex_handle &handle) {} inline void lazy_mutex_lock(lazy_mutex_handle &handle) { ::os_unfair_lock_lock(&handle); @@ -118,29 +116,29 @@ inline void once_impl(once_t &predicate, void (*fn)(void *), void *context) { 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); - } +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_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 *) diff --git a/include/swift/Threading/Impl/Linux.h b/include/swift/Threading/Impl/Linux.h index 7ada98e09a6ec..c447bcb80e81d 100644 --- a/include/swift/Threading/Impl/Linux.h +++ b/include/swift/Threading/Impl/Linux.h @@ -17,8 +17,8 @@ #ifndef SWIFT_THREADING_IMPL_LINUX_H #define SWIFT_THREADING_IMPL_LINUX_H -#include #include +#include #include @@ -29,25 +29,25 @@ 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_LINUXTHREADS_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) +#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_LINUXTHREADS_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 .................................................. @@ -65,14 +65,14 @@ inline bool threads_same(thread_id a, thread_id b) { using mutex_handle = ::pthread_mutex_t; -inline void mutex_init(mutex_handle &handle, bool checked=false) { +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_settype(&attr, PTHREAD_MUTEX_ERRORCHECK)); SWIFT_LINUXTHREADS_CHECK(::pthread_mutex_init(&handle, &attr)); SWIFT_LINUXTHREADS_CHECK(::pthread_mutexattr_destroy(&attr)); } @@ -130,7 +130,7 @@ inline void lazy_mutex_unsafe_unlock(lazy_mutex_handle &handle) { struct once_t { std::atomic flag; - linux::ulock_t lock; + linux::ulock_t lock; }; void once_slow(once_t &predicate, void (*fn)(void *), void *context); @@ -156,9 +156,7 @@ 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_get(tls_key key) { return pthread_getspecific(key); } inline void tls_set(tls_key key, void *value) { pthread_setspecific(key, value); diff --git a/include/swift/Threading/Impl/Linux/ulock.h b/include/swift/Threading/Impl/Linux/ulock.h index 04cfba9205877..1219c52a1d91b 100644 --- a/include/swift/Threading/Impl/Linux/ulock.h +++ b/include/swift/Threading/Impl/Linux/ulock.h @@ -26,9 +26,9 @@ // various GCC/Clang extensions here. #include +#include #include #include -#include #include #include @@ -40,8 +40,8 @@ namespace linux { typedef std::int32_t ulock_t; -#define ULOCK_INITIALIZER 0 -#define ulock_fastpath(x) __builtin_expect((x), true) +#define ULOCK_INITIALIZER 0 +#define ulock_fastpath(x) __builtin_expect((x), true) inline int ulock_get_tid(void) { static __thread int tid; @@ -51,18 +51,16 @@ inline int ulock_get_tid(void) { } inline int ulock_futex(ulock_t *lock, int op) { - return syscall(SYS_futex, lock, op | FUTEX_PRIVATE_FLAG, - 0, nullptr, nullptr, 0); + 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))) + if (ulock_fastpath(__atomic_compare_exchange_n( + lock, &zero, tid, true, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))) return; } while (ulock_futex(lock, FUTEX_LOCK_PI) != 0); @@ -70,9 +68,8 @@ inline void ulock_lock(ulock_t *lock) { 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, + if (ulock_fastpath(__atomic_compare_exchange_n(lock, &zero, ulock_get_tid(), + true, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))) return true; @@ -83,10 +80,8 @@ 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))) + if (ulock_fastpath(__atomic_compare_exchange_n( + lock, &expected, 0, true, __ATOMIC_RELEASE, __ATOMIC_RELAXED))) return; } while (ulock_futex(lock, FUTEX_UNLOCK_PI) != 0); diff --git a/include/swift/Threading/Impl/Nothreads.h b/include/swift/Threading/Impl/Nothreads.h index bf4aef25f36e8..c50382de68d00 100644 --- a/include/swift/Threading/Impl/Nothreads.h +++ b/include/swift/Threading/Impl/Nothreads.h @@ -32,25 +32,25 @@ inline bool threads_same(thread_id a, thread_id b) { return a == b; } 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 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) { } +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 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) { } +inline void lazy_mutex_unsafe_lock(lazy_mutex_handle &handle) {} +inline void lazy_mutex_unsafe_unlock(lazy_mutex_handle &handle) {} // .. Once ................................................................... diff --git a/include/swift/Threading/Impl/Pthreads.h b/include/swift/Threading/Impl/Pthreads.h index 57dfef88d5ac0..83139ab07f421 100644 --- a/include/swift/Threading/Impl/Pthreads.h +++ b/include/swift/Threading/Impl/Pthreads.h @@ -17,8 +17,8 @@ #ifndef SWIFT_THREADING_IMPL_PTHREADS_H #define SWIFT_THREADING_IMPL_PTHREADS_H -#include #include +#include #include #include @@ -28,25 +28,25 @@ 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) +#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 .................................................. @@ -64,14 +64,14 @@ inline bool threads_same(thread_id a, thread_id b) { using mutex_handle = ::pthread_mutex_t; -inline void mutex_init(mutex_handle &handle, bool checked=false) { +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_settype(&attr, PTHREAD_MUTEX_ERRORCHECK)); SWIFT_PTHREADS_CHECK(::pthread_mutex_init(&handle, &attr)); SWIFT_PTHREADS_CHECK(::pthread_mutexattr_destroy(&attr)); } @@ -152,9 +152,7 @@ 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_get(tls_key key) { return pthread_getspecific(key); } inline void tls_set(tls_key key, void *value) { pthread_setspecific(key, value); diff --git a/include/swift/Threading/Impl/Win32.h b/include/swift/Threading/Impl/Win32.h index a9c77827e4303..3f0d7258af9ee 100644 --- a/include/swift/Threading/Impl/Win32.h +++ b/include/swift/Threading/Impl/Win32.h @@ -36,10 +36,10 @@ inline bool threads_same(thread_id a, thread_id b) { return a == b; } using mutex_handle = SWIFT_SRWLOCK; -inline void mutex_init(mutex_handle &handle, bool checked=false) { +inline void mutex_init(mutex_handle &handle, bool checked = false) { handle = SRWLOCK_INIT; } -inline void mutex_destroy(mutex_handle &handle) { } +inline void mutex_destroy(mutex_handle &handle) {} inline void mutex_lock(mutex_handle &handle) { AcquireSRWLockExclusive(&handle); @@ -64,7 +64,7 @@ using lazy_mutex_handle = SWIFT_SRWLOCK; inline constexpr lazy_mutex_handle lazy_mutex_initializer() { return SRWLOCK_INIT; } -inline void lazy_mutex_destroy(lazy_mutex_handle &handle) { } +inline void lazy_mutex_destroy(lazy_mutex_handle &handle) {} inline void lazy_mutex_lock(lazy_mutex_handle &handle) { AcquireSRWLockExclusive(&handle); @@ -100,11 +100,11 @@ inline void once_impl(once_t &predicate, void (*fn)(void *), void *context) { // .. Thread local storage ................................................... #ifdef __clang__ -# if __has_feature(cxx_thread_local) -# define SWIFT_THREAD_LOCAL thread_local -# endif +#if __has_feature(cxx_thread_local) +#define SWIFT_THREAD_LOCAL thread_local +#endif #elif __cplusplus >= 201103L -# define SWIFT_THREAD_LOCAL thread_local +#define SWIFT_THREAD_LOCAL thread_local #endif #define SWIFT_TLS_DECLARE_DTOR(name) void NTAPI name(void *) @@ -117,13 +117,9 @@ inline bool tls_alloc(tls_key &key, tls_dtor dtor) { return key != FLS_OUT_OF_INDEXES; } -inline void *tls_get(tls_key key) { - return ::FlsGetValue(key); -} +inline void *tls_get(tls_key key) { return ::FlsGetValue(key); } -inline void tls_set(tls_key key, void *value) { - ::FlsSetValue(key, value); -} +inline void tls_set(tls_key key, void *value) { ::FlsSetValue(key, value); } } // namespace threading_impl diff --git a/include/swift/Threading/Impl/Win32/Win32Defs.h b/include/swift/Threading/Impl/Win32/Win32Defs.h index e2a4d561d8b49..644e27ff4609d 100644 --- a/include/swift/Threading/Impl/Win32/Win32Defs.h +++ b/include/swift/Threading/Impl/Win32/Win32Defs.h @@ -23,42 +23,43 @@ #define SWIFT_THREADING_IMPL_WIN32_DEFS_H #define DECLSPEC_IMPORT __declspec(dllimport) -#define WINBASEAPI DECLSPEC_IMPORT -#define WINAPI __stdcall -#define NTAPI __stdcall +#define WINBASEAPI DECLSPEC_IMPORT +#define WINAPI __stdcall +#define NTAPI __stdcall // #defines VOID rather than typedefing it(!) Changing that // to use a typedef instead isn't problematic later on, so let's do that. #undef VOID -typedef void VOID, *PVOID; +typedef void VOID, *PVOID; typedef unsigned char BYTE; -typedef BYTE BOOLEAN; -typedef int BOOL; +typedef BYTE BOOLEAN; +typedef int BOOL; typedef unsigned long DWORD; -typedef VOID (NTAPI* PFLS_CALLBACK_FUNCTION)(PVOID lpFlsData); +typedef VOID(NTAPI *PFLS_CALLBACK_FUNCTION)(PVOID lpFlsData); typedef struct _RTL_SRWLOCK *PRTL_SRWLOCK; typedef PRTL_SRWLOCK PSRWLOCK; // These have to be #defines, to avoid problems with -#define RTL_SRWLOCK_INIT {0} -#define SRWLOCK_INIT RTL_SRWLOCK_INIT +#define RTL_SRWLOCK_INIT \ + { 0 } +#define SRWLOCK_INIT RTL_SRWLOCK_INIT #define FLS_OUT_OF_INDEXES ((DWORD)0xFFFFFFFF) extern "C" { - WINBASEAPI DWORD WINAPI GetCurrentThreadId(VOID); +WINBASEAPI DWORD WINAPI GetCurrentThreadId(VOID); - WINBASEAPI VOID WINAPI InitializeSRWLock(PSRWLOCK SRWLock); - WINBASEAPI VOID WINAPI ReleaseSRWLockExclusive(PSRWLOCK SRWLock); - WINBASEAPI VOID WINAPI AcquireSRWLockExclusive(PSRWLOCK SRWLock); - WINBASEAPI BOOLEAN WINAPI TryAcquireSRWLockExclusive(PSRWLOCK SRWLock); +WINBASEAPI VOID WINAPI InitializeSRWLock(PSRWLOCK SRWLock); +WINBASEAPI VOID WINAPI ReleaseSRWLockExclusive(PSRWLOCK SRWLock); +WINBASEAPI VOID WINAPI AcquireSRWLockExclusive(PSRWLOCK SRWLock); +WINBASEAPI BOOLEAN WINAPI TryAcquireSRWLockExclusive(PSRWLOCK SRWLock); - WINBASEAPI DWORD WINAPI FlsAlloc(PFLS_CALLBACK_FUNCTION lpCallback); - WINBASEAPI PVOID WINAPI FlsGetValue(DWORD dwFlsIndex); - WINBASEAPI BOOL WINAPI FlsSetValue(DWORD dwFlsIndex, PVOID lpFlsData); - WINBASEAPI BOOL WINAPI FlsFree(DWORD dwFlsIndex); +WINBASEAPI DWORD WINAPI FlsAlloc(PFLS_CALLBACK_FUNCTION lpCallback); +WINBASEAPI PVOID WINAPI FlsGetValue(DWORD dwFlsIndex); +WINBASEAPI BOOL WINAPI FlsSetValue(DWORD dwFlsIndex, PVOID lpFlsData); +WINBASEAPI BOOL WINAPI FlsFree(DWORD dwFlsIndex); } namespace swift { @@ -85,7 +86,7 @@ inline BOOLEAN TryAcquireSRWLockExclusive(PSWIFT_SRWLOCK SRWLock) { return ::TryAcquireSRWLockExclusive(reinterpret_cast(SRWLock)); } -} -} +} // namespace threading_impl +} // namespace swift #endif // SWIFT_THREADING_IMPL_WIN32_DEFS_H diff --git a/include/swift/Threading/Mutex.h b/include/swift/Threading/Mutex.h index 13cd8e9cd6961..49fefae2df5c0 100644 --- a/include/swift/Threading/Mutex.h +++ b/include/swift/Threading/Mutex.h @@ -29,7 +29,8 @@ namespace swift { /// Compile time adjusted stack based object that locks/unlocks the supplied /// Mutex type. Use the provided typedefs instead of this directly. -template class ScopedLockT { +template +class ScopedLockT { ScopedLockT() = delete; ScopedLockT(const ScopedLockT &) = delete; ScopedLockT &operator=(const ScopedLockT &) = delete; diff --git a/include/swift/Threading/Once.h b/include/swift/Threading/Once.h index 253995ac2104a..5471976a4ed17 100644 --- a/include/swift/Threading/Once.h +++ b/include/swift/Threading/Once.h @@ -26,10 +26,11 @@ 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) { +inline void once(once_t &predicate, void (*fn)(void *), + void *context = nullptr) { threading_impl::once_impl(predicate, fn, context); } -} +} // namespace swift #endif // SWIFT_THREADING_ONCE_H diff --git a/include/swift/Threading/Thread.h b/include/swift/Threading/Thread.h index 123abb3c45d54..e2c500b50aeda 100644 --- a/include/swift/Threading/Thread.h +++ b/include/swift/Threading/Thread.h @@ -34,15 +34,15 @@ class Thread { public: Thread() {} explicit Thread(Id platformId) : id_(platformId) {} - Thread(const Thread& other) : id_(other.id_) {} - Thread(Thread&& other) : id_(std::move(other.id_)) {} + Thread(const Thread &other) : id_(other.id_) {} + Thread(Thread &&other) : id_(std::move(other.id_)) {} - Thread& operator=(const Thread& other) { + Thread &operator=(const Thread &other) { id_ = other.id_; return *this; } - Thread& operator=(Thread&& other) { + Thread &operator=(Thread &&other) { id_ = other.id_; return *this; } @@ -56,15 +56,13 @@ class Thread { } /// Returns true iff executed on the main thread - static bool onMainThread() { - return threading_impl::thread_is_main(); - } + static bool onMainThread() { return threading_impl::thread_is_main(); } /// Returns true if the two Thread values are equal - bool operator==(const Thread& other) const { + bool operator==(const Thread &other) const { return threading_impl::threads_same(id_, other.id_); } - bool operator!=(const Thread& other) const { + bool operator!=(const Thread &other) const { return !threading_impl::threads_same(id_, other.id_); } }; diff --git a/include/swift/Threading/ThreadLocalStorage.h b/include/swift/Threading/ThreadLocalStorage.h index cd56ac15e8a56..890ff5e15227d 100644 --- a/include/swift/Threading/ThreadLocalStorage.h +++ b/include/swift/Threading/ThreadLocalStorage.h @@ -1,4 +1,5 @@ -//===--- ThreadLocalStorage.h - Thread-local storage interface. --*- C++ -*-===// +//===--- ThreadLocalStorage.h - Thread-local storage interface. --*- C++ +//-*-===// // // This source file is part of the Swift.org open source project // @@ -15,9 +16,9 @@ #include +#include "Errors.h" #include "Impl.h" #include "Once.h" -#include "Errors.h" namespace swift { @@ -32,12 +33,19 @@ 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(ctx); - if (!tls_init(pinfo->k, pinfo->d)) - swift::threading::fatal("tls_init_once() failed to set destructor"); - }, (void *)&info); + 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(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 @@ -47,12 +55,19 @@ 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(ctx); - if (!tls_alloc(pinfo->k, pinfo->d)) - swift::threading::fatal("tls_alloc_once() failed to allocate key"); - }, (void *)&info); + 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(ctx); + if (!tls_alloc(pinfo->k, pinfo->d)) + swift::threading::fatal("tls_alloc_once() failed to allocate key"); + }, + (void *)&info); } #endif // !SWIFT_THREADING_NONE @@ -103,15 +118,18 @@ class ThreadLocal { class ThreadLocalKey { // We rely on the zero-initialization of objects with static storage // duration. - once_t onceFlag; + once_t onceFlag; tls_key key; public: threading_impl::tls_key getKey() { - once(onceFlag, [](void *ctx) { - tls_key *pkey = reinterpret_cast(ctx); - tls_alloc(*pkey, nullptr); - }, &key); + once( + onceFlag, + [](void *ctx) { + tls_key *pkey = reinterpret_cast(ctx); + tls_alloc(*pkey, nullptr); + }, + &key); return key; } }; @@ -162,15 +180,14 @@ class ThreadLocal { /// 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) \ +#define SWIFT_THREAD_LOCAL_TYPE(TYPE, KEY) \ SWIFT_THREAD_LOCAL swift::ThreadLocal #elif SWIFT_THREADING_USE_RESERVED_TLS_KEYS -#define SWIFT_THREAD_LOCAL_TYPE(TYPE, KEY) \ +#define SWIFT_THREAD_LOCAL_TYPE(TYPE, KEY) \ swift::ThreadLocal> #else -#define SWIFT_THREAD_LOCAL_TYPE(TYPE, KEY) \ +#define SWIFT_THREAD_LOCAL_TYPE(TYPE, KEY) \ swift::ThreadLocal #endif - #endif // SWIFT_THREADING_THREADLOCALSTORAGE_H diff --git a/lib/Threading/C11.cpp b/lib/Threading/C11.cpp index efeb15f319567..f2f006a78848d 100644 --- a/lib/Threading/C11.cpp +++ b/lib/Threading/C11.cpp @@ -16,8 +16,8 @@ #if SWIFT_THREADING_C11 -#include "swift/Threading/Errors.h" #include "swift/Threading/Impl/C11.h" +#include "swift/Threading/Errors.h" namespace { @@ -27,8 +27,8 @@ namespace { class C11ThreadingHelper { private: thrd_t mainThread_; - mut_t onceMutex_; - cnd_t onceCond_; + mut_t onceMutex_; + cnd_t onceCond_; public: C11ThreadingHelper() { @@ -39,15 +39,9 @@ class C11ThreadingHelper { thrd_t main_thread() const { return mainThread_; } - void once_lock() { - SWIFT_C11THREADS_CHECK(mtx_lock(&onceMutex_)); - } - void once_unlock() { - SWIFT_C11THREADS_CHECK(mtx_unlock(&onceMutex_)); - } - void once_broadcast() { - SWIFT_C11THREADS_CHECK(cnd_broadcast(&onceCond_)); - } + void once_lock() { SWIFT_C11THREADS_CHECK(mtx_lock(&onceMutex_)); } + void once_unlock() { SWIFT_C11THREADS_CHECK(mtx_unlock(&onceMutex_)); } + void once_broadcast() { SWIFT_C11THREADS_CHECK(cnd_broadcast(&onceCond_)); } void once_wait() { SWIFT_C11THREADS_CHECK(mtx_lock(&onceMutex_)); SWIFT_C11THREADS_CHECK(cnd_wait(&onceCond_, &onceMutex_)); @@ -59,23 +53,18 @@ C11ThreadingHelper helper; #pragma clang diagnostic pop -} +} // namespace using namespace swift; using namespace threading_impl; -bool -swift::threading_impl::thread_is_main() { +bool swift::threading_impl::thread_is_main() { return thrd_equal(thrd_current(), helper.main_thread()); } -void -swift::threading_impl::once_slow(once_t &predicate, - void (*fn)(void *), - void *context) { - if (::atomic_compare_exchange_strong_explicit(&predicate, - &(int){ 0 }, - 1, +void swift::threading_impl::once_slow(once_t &predicate, void (*fn)(void *), + void *context) { + if (::atomic_compare_exchange_strong_explicit(&predicate, &(int){0}, 1, ::memory_order_relaxed, ::memory_order_relaxed)) { fn(context); diff --git a/lib/Threading/Linux.cpp b/lib/Threading/Linux.cpp index 2fc512f8bd60e..b61299aa72b7a 100644 --- a/lib/Threading/Linux.cpp +++ b/lib/Threading/Linux.cpp @@ -16,8 +16,8 @@ #if SWIFT_THREADING_LINUX -#include "swift/Threading/Errors.h" #include "swift/Threading/Impl/Linux.h" +#include "swift/Threading/Errors.h" namespace { @@ -27,6 +27,7 @@ namespace { class MainThreadRememberer { private: pthread_t mainThread_; + public: MainThreadRememberer() { mainThread_ = pthread_self(); } @@ -37,20 +38,17 @@ MainThreadRememberer rememberer; #pragma clang diagnostic pop -} +} // namespace using namespace swift; using namespace threading_impl; -bool -swift::threading_impl::thread_is_main() { +bool swift::threading_impl::thread_is_main() { return pthread_equal(pthread_self(), rememberer.main_thread()); } -void -swift::threading_impl::once_slow(once_t &predicate, - void (*fn)(void *), - void *context) { +void swift::threading_impl::once_slow(once_t &predicate, void (*fn)(void *), + void *context) { linux::ulock_lock(&predicate.lock); if (predicate.flag.load(std::memory_order_acquire) == 0) { fn(context); diff --git a/lib/Threading/Pthreads.cpp b/lib/Threading/Pthreads.cpp index 72ccd60552c0a..0e4db24d780da 100644 --- a/lib/Threading/Pthreads.cpp +++ b/lib/Threading/Pthreads.cpp @@ -16,8 +16,8 @@ #if SWIFT_THREADING_PTHREADS -#include "swift/Threading/Errors.h" #include "swift/Threading/Impl/Pthreads.h" +#include "swift/Threading/Errors.h" namespace { @@ -27,6 +27,7 @@ namespace { class MainThreadRememberer { private: pthread_t mainThread_; + public: MainThreadRememberer() { mainThread_ = pthread_self(); } @@ -34,25 +35,22 @@ class MainThreadRememberer { }; MainThreadRememberer rememberer; -pthread_mutex_t onceMutex = PTHREAD_MUTEX_INITIALIZER; -pthread_cond_t onceCond = PTHREAD_COND_INITIALIZER; +pthread_mutex_t onceMutex = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t onceCond = PTHREAD_COND_INITIALIZER; #pragma clang diagnostic pop -} +} // namespace using namespace swift; using namespace threading_impl; -bool -swift::threading_impl::thread_is_main() { +bool swift::threading_impl::thread_is_main() { return pthread_equal(pthread_self(), rememberer.main_thread()); } -void -swift::threading_impl::once_slow(once_t &predicate, - void (*fn)(void *), - void *context) { +void swift::threading_impl::once_slow(once_t &predicate, void (*fn)(void *), + void *context) { std::int64_t zero = 0; if (predicate.compare_exchange_strong(zero, (std::int64_t)1, std::memory_order_relaxed, diff --git a/lib/Threading/Win32.cpp b/lib/Threading/Win32.cpp index 8a1e88b641eca..442f3ae9b6b82 100644 --- a/lib/Threading/Win32.cpp +++ b/lib/Threading/Win32.cpp @@ -31,6 +31,7 @@ namespace { class MainThreadRememberer { private: DWORD dwMainThread_; + public: MainThreadRememberer() { dwMainThread_ = ::GetCurrentThreadId(); } @@ -47,20 +48,17 @@ CONDITION_VARIABLE onceCond = CONDITION_VARIABLE_INIT; #pragma clang diagnostic pop -} +} // namespace using namespace swift; using namespace threading_impl; -bool -swift::threading_impl::thread_is_main() { +bool swift::threading_impl::thread_is_main() { return ::GetCurrentThreadId() == rememberer.main_thread(); } -void -swift::threading_impl::once_slow(once_t &predicate, - void (*fn)(void *), - void *context) { +void swift::threading_impl::once_slow(once_t &predicate, void (*fn)(void *), + void *context) { std::int64_t expected = 0; if (predicate.compare_exchange_strong(expected, (std::int64_t)1, std::memory_order_relaxed, diff --git a/stdlib/public/Concurrency/Actor.cpp b/stdlib/public/Concurrency/Actor.cpp index b4fce7d20d4a9..b81e4b71c32c9 100644 --- a/stdlib/public/Concurrency/Actor.cpp +++ b/stdlib/public/Concurrency/Actor.cpp @@ -20,18 +20,18 @@ #include #include "../CompatibilityOverride/CompatibilityOverride.h" -#include "swift/Runtime/Atomic.h" +#include "swift/ABI/Actor.h" +#include "swift/ABI/Task.h" +#include "swift/Basic/ListMerger.h" +#include "swift/Concurrency/Actor.h" #include "swift/Runtime/AccessibleFunction.h" +#include "swift/Runtime/Atomic.h" #include "swift/Runtime/Casting.h" #include "swift/Runtime/DispatchShims.h" -#include "swift/Threading/Once.h" #include "swift/Threading/Mutex.h" -#include "swift/Threading/ThreadLocalStorage.h" +#include "swift/Threading/Once.h" #include "swift/Threading/Thread.h" -#include "swift/ABI/Task.h" -#include "swift/ABI/Actor.h" -#include "swift/Basic/ListMerger.h" -#include "swift/Concurrency/Actor.h" +#include "swift/Threading/ThreadLocalStorage.h" #ifdef SWIFT_CONCURRENCY_BACK_DEPLOYMENT // All platforms where we care about back deployment have a known // configurations. @@ -107,9 +107,9 @@ class ExecutorTrackingInfo { /// the right executor. It would make sense for that to be a /// separate thread-local variable (or whatever is most efficient /// on the target platform). - static SWIFT_THREAD_LOCAL_TYPE( - Pointer, - SWIFT_CONCURRENCY_EXECUTOR_TRACKING_INFO_KEY) ActiveInfoInThread; + static SWIFT_THREAD_LOCAL_TYPE(Pointer, + SWIFT_CONCURRENCY_EXECUTOR_TRACKING_INFO_KEY) + ActiveInfoInThread; /// The active executor. ExecutorRef ActiveExecutor = ExecutorRef::generic(); @@ -184,13 +184,11 @@ class ActiveTask { }; /// Define the thread-locals. -SWIFT_THREAD_LOCAL_TYPE( - Pointer, - SWIFT_CONCURRENCY_TASK_KEY) ActiveTask::Value; +SWIFT_THREAD_LOCAL_TYPE(Pointer, SWIFT_CONCURRENCY_TASK_KEY) +ActiveTask::Value; -SWIFT_THREAD_LOCAL_TYPE( - Pointer, - SWIFT_CONCURRENCY_EXECUTOR_TRACKING_INFO_KEY) +SWIFT_THREAD_LOCAL_TYPE(Pointer, + SWIFT_CONCURRENCY_EXECUTOR_TRACKING_INFO_KEY) ExecutorTrackingInfo::ActiveInfoInThread; } // end anonymous namespace diff --git a/stdlib/public/Concurrency/AsyncLet.cpp b/stdlib/public/Concurrency/AsyncLet.cpp index 4d24a6e8aa835..47db4e81574ed 100644 --- a/stdlib/public/Concurrency/AsyncLet.cpp +++ b/stdlib/public/Concurrency/AsyncLet.cpp @@ -14,18 +14,18 @@ // //===----------------------------------------------------------------------===// -#include "../CompatibilityOverride/CompatibilityOverride.h" -#include "swift/Runtime/Concurrency.h" #include "swift/ABI/AsyncLet.h" +#include "../CompatibilityOverride/CompatibilityOverride.h" +#include "Debug.h" +#include "TaskPrivate.h" #include "swift/ABI/Metadata.h" #include "swift/ABI/Task.h" #include "swift/ABI/TaskOptions.h" +#include "swift/Runtime/Concurrency.h" #include "swift/Runtime/Heap.h" #include "swift/Runtime/HeapObject.h" #include "swift/Threading/Mutex.h" #include "llvm/ADT/PointerIntPair.h" -#include "TaskPrivate.h" -#include "Debug.h" #if !defined(_WIN32) && !defined(__wasi__) && __has_include() #include diff --git a/stdlib/public/Concurrency/AsyncStream.cpp b/stdlib/public/Concurrency/AsyncStream.cpp index d6ada4cabcbec..389ebd3d7389a 100644 --- a/stdlib/public/Concurrency/AsyncStream.cpp +++ b/stdlib/public/Concurrency/AsyncStream.cpp @@ -23,19 +23,11 @@ size_t _swift_async_stream_lock_size() { return words; } -extern "C" -void _swift_async_stream_lock_init(Mutex &lock) { +extern "C" void _swift_async_stream_lock_init(Mutex &lock) { new (&lock) Mutex(); } -extern "C" -void _swift_async_stream_lock_lock(Mutex &lock) { - lock.lock(); -} - -extern "C" -void _swift_async_stream_lock_unlock(Mutex &lock) { - lock.unlock(); -} +extern "C" void _swift_async_stream_lock_lock(Mutex &lock) { lock.lock(); } +extern "C" void _swift_async_stream_lock_unlock(Mutex &lock) { lock.unlock(); } } diff --git a/stdlib/public/Concurrency/Error.cpp b/stdlib/public/Concurrency/Error.cpp index 0afb619e2cee5..7a1983a295779 100644 --- a/stdlib/public/Concurrency/Error.cpp +++ b/stdlib/public/Concurrency/Error.cpp @@ -19,14 +19,16 @@ // internal function instead. SWIFT_NORETURN SWIFT_VFORMAT(2) -void swift::swift_Concurrency_fatalErrorv(uint32_t flags, const char *format, va_list val) { +void swift::swift_Concurrency_fatalErrorv(uint32_t flags, const char *format, + va_list val) { vfprintf(stderr, format, val); abort(); } SWIFT_NORETURN SWIFT_FORMAT(2, 3) -void swift::swift_Concurrency_fatalError(uint32_t flags, const char *format, ...) { +void swift::swift_Concurrency_fatalError(uint32_t flags, const char *format, + ...) { va_list val; va_start(val, format); diff --git a/stdlib/public/Concurrency/Error.h b/stdlib/public/Concurrency/Error.h index 20b96467fc896..85e8a621399a1 100644 --- a/stdlib/public/Concurrency/Error.h +++ b/stdlib/public/Concurrency/Error.h @@ -20,14 +20,16 @@ #include "swift/Basic/Compiler.h" #include "../SwiftShims/Visibility.h" +#include #include #include -#include namespace swift { -SWIFT_NORETURN SWIFT_FORMAT(2, 3) void swift_Concurrency_fatalError(uint32_t flags, const char *format, ...); -SWIFT_NORETURN SWIFT_VFORMAT(2) void swift_Concurrency_fatalErrorv(uint32_t flags, const char *format, va_list val); +SWIFT_NORETURN SWIFT_FORMAT(2, 3) void swift_Concurrency_fatalError( + uint32_t flags, const char *format, ...); +SWIFT_NORETURN SWIFT_VFORMAT(2) void swift_Concurrency_fatalErrorv( + uint32_t flags, const char *format, va_list val); } // namespace swift diff --git a/stdlib/public/Concurrency/Task.cpp b/stdlib/public/Concurrency/Task.cpp index 78e59f05ed460..3aca194ebf3ca 100644 --- a/stdlib/public/Concurrency/Task.cpp +++ b/stdlib/public/Concurrency/Task.cpp @@ -21,18 +21,18 @@ #endif #include "../CompatibilityOverride/CompatibilityOverride.h" -#include "swift/Runtime/Concurrency.h" +#include "Debug.h" +#include "Error.h" +#include "TaskGroupPrivate.h" +#include "TaskPrivate.h" +#include "Tracing.h" +#include "swift/ABI/Metadata.h" #include "swift/ABI/Task.h" #include "swift/ABI/TaskLocal.h" #include "swift/ABI/TaskOptions.h" -#include "swift/ABI/Metadata.h" +#include "swift/Runtime/Concurrency.h" #include "swift/Runtime/HeapObject.h" #include "swift/Threading/Mutex.h" -#include "TaskGroupPrivate.h" -#include "TaskPrivate.h" -#include "Tracing.h" -#include "Debug.h" -#include "Error.h" #include #include diff --git a/stdlib/public/Concurrency/TaskGroup.cpp b/stdlib/public/Concurrency/TaskGroup.cpp index 6bbb6454bad5f..ce4bd34991748 100644 --- a/stdlib/public/Concurrency/TaskGroup.cpp +++ b/stdlib/public/Concurrency/TaskGroup.cpp @@ -16,22 +16,22 @@ #include "../CompatibilityOverride/CompatibilityOverride.h" -#include "swift/ABI/TaskGroup.h" -#include "swift/ABI/Task.h" -#include "swift/ABI/Metadata.h" -#include "swift/ABI/HeapObject.h" -#include "TaskPrivate.h" +#include "Debug.h" #include "TaskGroupPrivate.h" +#include "TaskPrivate.h" +#include "bitset" +#include "queue" // TODO: remove and replace with usage of our mpsc queue +#include "string" +#include "swift/ABI/HeapObject.h" +#include "swift/ABI/Metadata.h" +#include "swift/ABI/Task.h" +#include "swift/ABI/TaskGroup.h" #include "swift/Basic/RelativePointer.h" #include "swift/Basic/STLExtras.h" #include "swift/Runtime/Concurrency.h" #include "swift/Runtime/Config.h" #include "swift/Runtime/HeapObject.h" #include "swift/Threading/Mutex.h" -#include "Debug.h" -#include "bitset" -#include "string" -#include "queue" // TODO: remove and replace with usage of our mpsc queue #include #include @@ -284,7 +284,6 @@ class TaskGroupImpl: public TaskGroupTaskStatusRecord { }; private: - #if !SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY // TODO: move to lockless via the status atomic (make readyQueue an mpsc_queue_t) mutable std::mutex mutex_; diff --git a/stdlib/public/Concurrency/TaskLocal.cpp b/stdlib/public/Concurrency/TaskLocal.cpp index 03db55db7f589..ea48ee1cadd18 100644 --- a/stdlib/public/Concurrency/TaskLocal.cpp +++ b/stdlib/public/Concurrency/TaskLocal.cpp @@ -10,17 +10,17 @@ // //===----------------------------------------------------------------------===// +#include "swift/ABI/TaskLocal.h" #include "../CompatibilityOverride/CompatibilityOverride.h" +#include "TaskPrivate.h" +#include "swift/ABI/Actor.h" +#include "swift/ABI/Metadata.h" +#include "swift/ABI/Task.h" #include "swift/Runtime/Atomic.h" #include "swift/Runtime/Casting.h" #include "swift/Runtime/Concurrency.h" #include "swift/Threading/ThreadLocalStorage.h" -#include "swift/ABI/TaskLocal.h" -#include "swift/ABI/Task.h" -#include "swift/ABI/Actor.h" -#include "swift/ABI/Metadata.h" #include "llvm/ADT/PointerIntPair.h" -#include "TaskPrivate.h" #include #include @@ -64,9 +64,8 @@ class FallbackTaskLocalStorage { }; /// Define the thread-locals. -SWIFT_THREAD_LOCAL_TYPE( - Pointer, - SWIFT_CONCURRENCY_FALLBACK_TASK_LOCAL_STORAGE_KEY) +SWIFT_THREAD_LOCAL_TYPE(Pointer, + SWIFT_CONCURRENCY_FALLBACK_TASK_LOCAL_STORAGE_KEY) FallbackTaskLocalStorage::Value; // ==== ABI -------------------------------------------------------------------- diff --git a/stdlib/public/Concurrency/TaskPrivate.h b/stdlib/public/Concurrency/TaskPrivate.h index d66f6907ca064..f9c3906319440 100644 --- a/stdlib/public/Concurrency/TaskPrivate.h +++ b/stdlib/public/Concurrency/TaskPrivate.h @@ -41,9 +41,8 @@ namespace swift { #if 0 #define SWIFT_TASK_DEBUG_LOG(fmt, ...) \ fprintf(stderr, "[%lu] [%s:%d](%s) " fmt "\n", \ - (unsigned long)Thread::current()::platformThreadId(), \ - __FILE__, __LINE__, __FUNCTION__, \ - __VA_ARGS__) + (unsigned long)Thread::current()::platformThreadId(), __FILE__, \ + __LINE__, __FUNCTION__, __VA_ARGS__) #else #define SWIFT_TASK_DEBUG_LOG(fmt, ...) (void)0 #endif diff --git a/stdlib/public/Concurrency/TaskStatus.cpp b/stdlib/public/Concurrency/TaskStatus.cpp index efbdd14f61467..99dc553eb1b26 100644 --- a/stdlib/public/Concurrency/TaskStatus.cpp +++ b/stdlib/public/Concurrency/TaskStatus.cpp @@ -15,12 +15,12 @@ // //===----------------------------------------------------------------------===// +#include "swift/ABI/TaskStatus.h" #include "../CompatibilityOverride/CompatibilityOverride.h" -#include "swift/Runtime/Concurrency.h" +#include "TaskPrivate.h" #include "swift/Runtime/AtomicWaitQueue.h" +#include "swift/Runtime/Concurrency.h" #include "swift/Threading/Mutex.h" -#include "swift/ABI/TaskStatus.h" -#include "TaskPrivate.h" #include using namespace swift; @@ -61,9 +61,9 @@ namespace { /// it sees that the locked bit is set in the `Status` field, it /// must acquire the global status-record lock, find this record /// (which should be the innermost record), and wait for an unlock. -class StatusRecordLockRecord : - public AtomicWaitQueue, - public TaskStatusRecord { +class StatusRecordLockRecord + : public AtomicWaitQueue, + public TaskStatusRecord { public: StatusRecordLockRecord(TaskStatusRecord *parent) : TaskStatusRecord(TaskStatusRecordKind::Private_RecordLock, parent) { @@ -77,7 +77,6 @@ class StatusRecordLockRecord : return record->getKind() == TaskStatusRecordKind::Private_RecordLock; } }; - } /// Wait for a task's status record lock to be unlocked. diff --git a/stdlib/public/runtime/Casting.cpp b/stdlib/public/runtime/Casting.cpp index 4943af0282110..4c46d9a653355 100644 --- a/stdlib/public/runtime/Casting.cpp +++ b/stdlib/public/runtime/Casting.cpp @@ -16,14 +16,15 @@ //===----------------------------------------------------------------------===// #include "swift/Runtime/Casting.h" -#include "../SwiftShims/RuntimeShims.h" -#include "../SwiftShims/GlobalObjects.h" #include "../CompatibilityOverride/CompatibilityOverride.h" +#include "../SwiftShims/GlobalObjects.h" +#include "../SwiftShims/RuntimeShims.h" #include "ErrorObject.h" #include "ExistentialMetadataImpl.h" #include "Private.h" #include "SwiftHashableSupport.h" #include "swift/Basic/Lazy.h" +#include "swift/Basic/Unreachable.h" #include "swift/Demangling/Demangler.h" #include "swift/Runtime/Config.h" #include "swift/Runtime/Debug.h" @@ -32,7 +33,6 @@ #include "swift/Runtime/HeapObject.h" #include "swift/Runtime/Metadata.h" #include "swift/Threading/Mutex.h" -#include "swift/Basic/Unreachable.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PointerIntPair.h" #if SWIFT_OBJC_INTEROP diff --git a/stdlib/public/runtime/Errors.cpp b/stdlib/public/runtime/Errors.cpp index 84a6b6a47ec03..ba386a5fc8020 100644 --- a/stdlib/public/runtime/Errors.cpp +++ b/stdlib/public/runtime/Errors.cpp @@ -33,11 +33,11 @@ #include #include "ImageInspection.h" +#include "swift/Demangling/Demangle.h" #include "swift/Runtime/Debug.h" #include "swift/Runtime/Portability.h" #include "swift/Threading/Errors.h" #include "swift/Threading/Mutex.h" -#include "swift/Demangling/Demangle.h" #include "llvm/ADT/StringRef.h" #if defined(_MSC_VER) diff --git a/stdlib/public/runtime/HeapObject.cpp b/stdlib/public/runtime/HeapObject.cpp index d0aeb466f32fd..42d88e5ca2bf4 100644 --- a/stdlib/public/runtime/HeapObject.cpp +++ b/stdlib/public/runtime/HeapObject.cpp @@ -174,11 +174,14 @@ swift::swift_initStaticObject(HeapMetadata const *metadata, // refcount to 1 while another thread already incremented it - and would // decrement it to 0 afterwards. InitStaticObjectContext Ctx = { object, metadata }; - swift::once(*token, [](void *OpaqueCtx) { - InitStaticObjectContext *Ctx = (InitStaticObjectContext *)OpaqueCtx; - Ctx->object->metadata = Ctx->metadata; - Ctx->object->refCounts.initImmortal(); - }, &Ctx); + swift::once( + *token, + [](void *OpaqueCtx) { + InitStaticObjectContext *Ctx = (InitStaticObjectContext *)OpaqueCtx; + Ctx->object->metadata = Ctx->metadata; + Ctx->object->refCounts.initImmortal(); + }, + &Ctx); return object; } diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp index 0be2c0e410b53..c9215ca634681 100644 --- a/stdlib/public/runtime/Metadata.cpp +++ b/stdlib/public/runtime/Metadata.cpp @@ -21,17 +21,17 @@ #include #endif -#include "swift/Runtime/Metadata.h" #include "MetadataCache.h" +#include "swift/ABI/TypeIdentity.h" #include "swift/Basic/Lazy.h" #include "swift/Basic/Range.h" #include "swift/Basic/STLExtras.h" #include "swift/Demangling/Demangler.h" -#include "swift/ABI/TypeIdentity.h" #include "swift/Runtime/Casting.h" #include "swift/Runtime/EnvironmentVariables.h" #include "swift/Runtime/ExistentialContainer.h" #include "swift/Runtime/HeapObject.h" +#include "swift/Runtime/Metadata.h" #include "swift/Runtime/Once.h" #include "swift/Runtime/Portability.h" #include "swift/Strings.h" @@ -3150,10 +3150,13 @@ _swift_initClassMetadataImpl(ClassMetadata *self, // Register our custom implementation of class_getImageName. static swift::once_t onceToken; - swift::once(onceToken, [](void *unused) { - (void)unused; - setUpObjCRuntimeGetImageNameFromClass(); - }, nullptr); + swift::once( + onceToken, + [](void *unused) { + (void)unused; + setUpObjCRuntimeGetImageNameFromClass(); + }, + nullptr); #endif // Copy field offsets, generic arguments and (if necessary) vtable entries diff --git a/stdlib/public/runtime/MetadataCache.h b/stdlib/public/runtime/MetadataCache.h index 2c1af5ed74862..67fc9583b746b 100644 --- a/stdlib/public/runtime/MetadataCache.h +++ b/stdlib/public/runtime/MetadataCache.h @@ -12,13 +12,16 @@ #ifndef SWIFT_RUNTIME_METADATACACHE_H #define SWIFT_RUNTIME_METADATACACHE_H -#include "llvm/ADT/Hashing.h" -#include "llvm/ADT/STLExtras.h" +#include "swift/Runtime/AtomicWaitQueue.h" #include "swift/Runtime/Concurrent.h" #include "swift/Runtime/Metadata.h" -#include "swift/Runtime/AtomicWaitQueue.h" #include "swift/Threading/Mutex.h" + #include "../SwiftShims/Visibility.h" + +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/STLExtras.h" + #include #include @@ -169,8 +172,7 @@ class LockingConcurrentMapStorage { // TargetGenericMetadataInstantiationCache::PrivateData. On 32-bit archs, that // space is not large enough to accommodate a Mutex along with everything // else. There, use a SmallMutex to squeeze into the available space. - using MutexTy = - std::conditional_t; + using MutexTy = std::conditional_t; StableAddressConcurrentReadableHashMap, MutexTy> Map; diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp index 57c44bf1630b8..2bf5ea412a219 100644 --- a/stdlib/public/runtime/MetadataLookup.cpp +++ b/stdlib/public/runtime/MetadataLookup.cpp @@ -14,11 +14,14 @@ // //===----------------------------------------------------------------------===// +#include "../CompatibilityOverride/CompatibilityOverride.h" +#include "ImageInspection.h" +#include "Private.h" +#include "swift/ABI/TypeIdentity.h" #include "swift/Basic/Lazy.h" #include "swift/Demangling/Demangler.h" #include "swift/Demangling/TypeDecoder.h" #include "swift/Reflection/Records.h" -#include "swift/ABI/TypeIdentity.h" #include "swift/Runtime/Casting.h" #include "swift/Runtime/Concurrent.h" #include "swift/Runtime/Debug.h" @@ -32,14 +35,11 @@ #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/StringExtras.h" -#include "Private.h" -#include "../CompatibilityOverride/CompatibilityOverride.h" -#include "ImageInspection.h" +#include #include -#include #include #include -#include +#include using namespace swift; using namespace Demangle; diff --git a/stdlib/public/runtime/Once.cpp b/stdlib/public/runtime/Once.cpp index e450b5547e994..7286b53b03cb7 100644 --- a/stdlib/public/runtime/Once.cpp +++ b/stdlib/public/runtime/Once.cpp @@ -14,8 +14,8 @@ // //===----------------------------------------------------------------------===// -#include "Private.h" #include "swift/Threading/Once.h" +#include "Private.h" #include "swift/Runtime/Debug.h" #include diff --git a/stdlib/public/runtime/RuntimeInvocationsTracking.cpp b/stdlib/public/runtime/RuntimeInvocationsTracking.cpp index 1d803ffce1950..a5851c42b02ba 100644 --- a/stdlib/public/runtime/RuntimeInvocationsTracking.cpp +++ b/stdlib/public/runtime/RuntimeInvocationsTracking.cpp @@ -15,11 +15,11 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/DenseMap.h" #include "RuntimeInvocationsTracking.h" #include "swift/Basic/Lazy.h" #include "swift/Runtime/HeapObject.h" #include "swift/Threading/Mutex.h" +#include "llvm/ADT/DenseMap.h" #if defined(SWIFT_ENABLE_RUNTIME_FUNCTION_COUNTERS) diff --git a/stdlib/public/runtime/SwiftTLSContext.cpp b/stdlib/public/runtime/SwiftTLSContext.cpp index 5d18e7e10ab27..ff5b248e0b49e 100644 --- a/stdlib/public/runtime/SwiftTLSContext.cpp +++ b/stdlib/public/runtime/SwiftTLSContext.cpp @@ -23,15 +23,15 @@ SwiftTLSContext &SwiftTLSContext::get() { #if SWIFT_THREADING_USE_RESERVED_TLS_KEYS // If we have reserved keys, use those - SwiftTLSContext *ctx - = static_cast(swift::tls_get(SWIFT_RUNTIME_TLS_KEY)); + SwiftTLSContext *ctx = + static_cast(swift::tls_get(SWIFT_RUNTIME_TLS_KEY)); if (ctx) return *ctx; static swift::once_t token; swift::tls_init_once(token, SWIFT_RUNTIME_TLS_KEY, [](void *pointer) { delete static_cast(pointer); - }); + }); ctx = new SwiftTLSContext(); swift::tls_set(SWIFT_RUNTIME_TLS_KEY, ctx); @@ -54,8 +54,8 @@ SwiftTLSContext &SwiftTLSContext::get() { delete static_cast(pointer); }); - SwiftTLSContext *ctx - = static_cast(swift::tls_get(runtimeKey)); + SwiftTLSContext *ctx = + static_cast(swift::tls_get(runtimeKey)); if (ctx) return *ctx; @@ -64,5 +64,4 @@ SwiftTLSContext &SwiftTLSContext::get() { return *ctx; #endif - } diff --git a/stdlib/public/stubs/OptionalBridgingHelper.mm b/stdlib/public/stubs/OptionalBridgingHelper.mm index 2182f6b4b6c5a..ae4e400d50372 100644 --- a/stdlib/public/stubs/OptionalBridgingHelper.mm +++ b/stdlib/public/stubs/OptionalBridgingHelper.mm @@ -18,9 +18,9 @@ #include "swift/Runtime/ObjCBridge.h" #include "swift/Runtime/Portability.h" #include "swift/Threading/Mutex.h" -#include -#import #import +#import +#include using namespace swift; diff --git a/stdlib/public/stubs/Random.cpp b/stdlib/public/stubs/Random.cpp index c6a247ccd1328..4a44682761656 100644 --- a/stdlib/public/stubs/Random.cpp +++ b/stdlib/public/stubs/Random.cpp @@ -41,9 +41,9 @@ #include +#include "SwiftShims/Random.h" #include "swift/Runtime/Debug.h" #include "swift/Threading/Mutex.h" -#include "SwiftShims/Random.h" #include // required for std::min diff --git a/stdlib/public/stubs/Stubs.cpp b/stdlib/public/stubs/Stubs.cpp index bb593781b94a4..5ec2bc9e60e30 100644 --- a/stdlib/public/stubs/Stubs.cpp +++ b/stdlib/public/stubs/Stubs.cpp @@ -562,23 +562,23 @@ __swift_bool _swift_stdlib_getCurrentStackBounds(__swift_uintptr_t *outBegin, #elif SWIFT_THREADING_WIN32 -# if _WIN32_WINNT >= 0x0602 +#if _WIN32_WINNT >= 0x0602 ULONG_PTR lowLimit = 0; ULONG_PTR highLimit = 0; GetCurrentThreadStackLimits(&lowLimit, &highLimit); *outBegin = lowLimit; *outEnd = highLimit; return true; -# else +#else // Need _WIN32_WINNT to be 0x0602 or higher to use // GetCurrentThreadStackLimits(). We could use VirtualQuery() instead, // and give it the address of a page we know is on the stack? return false; -# endif +#endif #elif SWIFT_THREADING_PTHREADS || SWIFT_THREADING_LINUX -# if defined(__OpenBSD__) +#if defined(__OpenBSD__) stack_t sinfo; if (pthread_stackseg_np(pthread_self(), &sinfo) != 0) { return false; @@ -587,18 +587,18 @@ __swift_bool _swift_stdlib_getCurrentStackBounds(__swift_uintptr_t *outBegin, *outBegin = (uintptr_t)sinfo.ss_sp - sinfo.ss_size; *outEnd = (uintptr_t)sinfo.ss_sp; return true; -# elif defined(__FreeBSD__) || defined(__ANDROID__) || defined(__linux__) +#elif defined(__FreeBSD__) || defined(__ANDROID__) || defined(__linux__) pthread_attr_t attr; -# if defined(__FreeBSD__) +#if defined(__FreeBSD__) if (0 != pthread_attr_init(&attr) || 0 != pthread_attr_get_np(pthread_self(), &attr)) { return false; } -# else +#else if (0 != pthread_getattr_np(pthread_self(), &attr)) { return false; } -# endif +#endif void *begin = nullptr; size_t size = 0; @@ -609,10 +609,10 @@ __swift_bool _swift_stdlib_getCurrentStackBounds(__swift_uintptr_t *outBegin, pthread_attr_destroy(&attr); return success; -# else -# warning Please teach _swift_stdlib_getCurrentStackBounds() about your platform +#else +#warning Please teach _swift_stdlib_getCurrentStackBounds() about your platform return false; -# endif +#endif #else # error Unknown threading package selected; please teach _swift_stdlib_getCurrentStackBounds() what to do. diff --git a/stdlib/public/stubs/ThreadLocalStorage.cpp b/stdlib/public/stubs/ThreadLocalStorage.cpp index 958e89c349633..f347bd2c2bccd 100644 --- a/stdlib/public/stubs/ThreadLocalStorage.cpp +++ b/stdlib/public/stubs/ThreadLocalStorage.cpp @@ -13,8 +13,8 @@ #include #include "SwiftShims/ThreadLocalStorage.h" -#include "swift/Threading/ThreadLocalStorage.h" #include "swift/Runtime/Debug.h" +#include "swift/Threading/ThreadLocalStorage.h" SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API void _stdlib_destroyTLS(void *); @@ -40,9 +40,8 @@ _swift_stdlib_threadLocalStorageGet(void) { return value; static swift::once_t token; - swift::tls_init_once(token, SWIFT_STDLIB_TLS_KEY, [](void *pointer) { - _stdlib_destroyTLS(pointer); - }); + swift::tls_init_once(token, SWIFT_STDLIB_TLS_KEY, + [](void *pointer) { _stdlib_destroyTLS(pointer); }); value = _stdlib_createTLS(); swift::tls_set(SWIFT_STDLIB_TLS_KEY, value); @@ -54,9 +53,8 @@ _swift_stdlib_threadLocalStorageGet(void) { static swift::tls_key key; static swift::once_t token; - swift::tls_alloc_once(token, key, [](void *pointer) { - _stdlib_destroyTLS(pointer); - }); + swift::tls_alloc_once(token, key, + [](void *pointer) { _stdlib_destroyTLS(pointer); }); void *value = swift::tls_get(key); if (!value) { @@ -66,5 +64,4 @@ _swift_stdlib_threadLocalStorageGet(void) { return value; #endif - } diff --git a/stdlib/toolchain/Compatibility50/ProtocolConformance.cpp b/stdlib/toolchain/Compatibility50/ProtocolConformance.cpp index 51bb7aee766b6..81a52a8dd278d 100644 --- a/stdlib/toolchain/Compatibility50/ProtocolConformance.cpp +++ b/stdlib/toolchain/Compatibility50/ProtocolConformance.cpp @@ -17,8 +17,8 @@ // //===----------------------------------------------------------------------===// -#include "Overrides.h" #include "../../public/runtime/Private.h" +#include "Overrides.h" #include "swift/Threading/Once.h" #include #include diff --git a/stdlib/toolchain/CompatibilityDynamicReplacements/DynamicReplaceable.cpp b/stdlib/toolchain/CompatibilityDynamicReplacements/DynamicReplaceable.cpp index 7067319589e42..2c12a8ad4792c 100644 --- a/stdlib/toolchain/CompatibilityDynamicReplacements/DynamicReplaceable.cpp +++ b/stdlib/toolchain/CompatibilityDynamicReplacements/DynamicReplaceable.cpp @@ -39,8 +39,7 @@ extern "C" char *swift_getFunctionReplacement50(char **ReplFnPtr, char *CurrFn) if (RawReplFn == CurrFn) return nullptr; - auto origKey = - (uintptr_t)swift::tls_get(SWIFT_COMPATIBILITY_50_TLS_KEY); + auto origKey = (uintptr_t)swift::tls_get(SWIFT_COMPATIBILITY_50_TLS_KEY); if ((origKey & 0x1) != 0) { auto mask = ((uintptr_t)-1) < 1; auto resetKey = origKey & mask; @@ -57,8 +56,7 @@ extern "C" char *swift_getOrigOfReplaceable50(char **OrigFnPtr) { return swift_getOrigOfReplaceable(OrigFnPtr); char *OrigFn = *OrigFnPtr; - auto origKey = - (uintptr_t)swift::tls_get(SWIFT_COMPATIBILITY_50_TLS_KEY); + auto origKey = (uintptr_t)swift::tls_get(SWIFT_COMPATIBILITY_50_TLS_KEY); auto newKey = origKey | 0x1; swift::tls_set(SWIFT_COMPATIBILITY_50_TLS_KEY, (void *)newKey); return OrigFn; diff --git a/unittests/Threading/LockingHelpers.h b/unittests/Threading/LockingHelpers.h index 0929a1eeaa0bb..151fa7a3ec715 100644 --- a/unittests/Threading/LockingHelpers.h +++ b/unittests/Threading/LockingHelpers.h @@ -16,7 +16,8 @@ #include "ThreadingHelpers.h" // Test that a Mutex object can be locked and unlocked from a single thread -template void basicLockable(M &mutex) { +template +void basicLockable(M &mutex) { // We can lock, unlock, lock and unlock an unlocked lock mutex.lock(); mutex.unlock(); @@ -25,7 +26,8 @@ template void basicLockable(M &mutex) { } // Test that a Mutex object's try_lock() method works. -template void tryLockable(M &mutex) { +template +void tryLockable(M &mutex) { bool ret; // We can lock an unlocked lock @@ -40,7 +42,8 @@ template void tryLockable(M &mutex) { } // Test that a Mutex object can be locked and unlocked -template void basicLockableThreaded(M &mutex) { +template +void basicLockableThreaded(M &mutex) { int count1 = 0; int count2 = 0; @@ -59,7 +62,8 @@ template void basicLockableThreaded(M &mutex) { } // More extensive tests -template void lockableThreaded(M &mutex) { +template +void lockableThreaded(M &mutex) { mutex.lock(); threadedExecute(5, [&](int) { ASSERT_FALSE(mutex.try_lock()); }); mutex.unlock(); @@ -88,7 +92,8 @@ template void lockableThreaded(M &mutex) { } // Test a scoped lock implementation -template void scopedLockThreaded(M &mutex) { +template +void scopedLockThreaded(M &mutex) { int count1 = 0; int count2 = 0; @@ -130,7 +135,8 @@ void scopedUnlockUnderScopedLockThreaded(M &mutex) { } // Test a critical section -template void criticalSectionThreaded(M &mutex) { +template +void criticalSectionThreaded(M &mutex) { int count1 = 0; int count2 = 0; diff --git a/unittests/Threading/Once.cpp b/unittests/Threading/Once.cpp index 3bca18f93bf77..f4618169dfd8e 100644 --- a/unittests/Threading/Once.cpp +++ b/unittests/Threading/Once.cpp @@ -22,12 +22,15 @@ using namespace swift; // Check that swift::once calls the function, with the correct argument TEST(OnceTest, once_calls_function) { static swift::once_t predicate; - bool wasCalled = false; + bool wasCalled = false; - swift::once(predicate, [](void *ctx) { - bool *pWasCalled = static_cast(ctx); - *pWasCalled = true; - }, &wasCalled); + swift::once( + predicate, + [](void *ctx) { + bool *pWasCalled = static_cast(ctx); + *pWasCalled = true; + }, + &wasCalled); ASSERT_TRUE(wasCalled); } @@ -35,7 +38,7 @@ TEST(OnceTest, once_calls_function) { // Check that calling swift::once twice only calls the function once TEST(OnceTest, once_calls_only_once) { static swift::once_t predicate; - unsigned callCount = 0; + unsigned callCount = 0; void (*fn)(void *) = [](void *ctx) { unsigned *pCallCount = static_cast(ctx); @@ -57,15 +60,13 @@ TEST(OnceTest, once_threaded) { for (unsigned tries = 0; tries < 1000; ++tries) { swift::once_t predicate; - unsigned callCount = 0; + unsigned callCount = 0; // We're being naughty here; swift::once_t is supposed to be global/static, // but since we know what we're doing, this should be OK. std::memset(&predicate, 0, sizeof(predicate)); - threadedExecute(16, [&](int) { - swift::once(predicate, fn, &callCount); - }); + threadedExecute(16, [&](int) { swift::once(predicate, fn, &callCount); }); ASSERT_EQ(1u, callCount); } From c7c1c1be80086991a1faf5a174a8b1768ffcd23b Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Fri, 29 Apr 2022 17:48:45 +0100 Subject: [PATCH 28/40] [Threading] Fix some problems with the C11 threading code. These changes are needed to get things building with a C11 threads shim header on macOS. rdar://90776105 --- include/swift/Threading/Impl/C11.h | 44 ++++++++++++------- include/swift/Threading/ThreadLocalStorage.h | 20 ++++----- lib/FrontendTool/CMakeLists.txt | 3 +- lib/Threading/C11.cpp | 16 ++++--- lib/Threading/CMakeLists.txt | 7 ++- lib/Threading/Errors.cpp | 41 +++++++++++++++++ stdlib/public/Concurrency/AsyncLet.cpp | 6 ++- stdlib/public/Threading/CMakeLists.txt | 9 ++++ .../runtime/RuntimeInvocationsTracking.cpp | 16 ++++--- stdlib/public/stubs/Stubs.cpp | 2 +- .../toolchain/Compatibility50/CMakeLists.txt | 1 + .../toolchain/Compatibility51/CMakeLists.txt | 1 + .../CompatibilityConcurrency/CMakeLists.txt | 1 + .../CMakeLists.txt | 1 + .../DynamicReplaceable.cpp | 19 ++++++-- 15 files changed, 136 insertions(+), 51 deletions(-) create mode 100644 lib/Threading/Errors.cpp diff --git a/include/swift/Threading/Impl/C11.h b/include/swift/Threading/Impl/C11.h index fee6532f523bb..16aeca2b9efb8 100644 --- a/include/swift/Threading/Impl/C11.h +++ b/include/swift/Threading/Impl/C11.h @@ -17,9 +17,12 @@ #ifndef SWIFT_THREADING_IMPL_C11_H #define SWIFT_THREADING_IMPL_C11_H -#include +#include +#include #include +#include "swift/Threading/Errors.h" + namespace swift { namespace threading_impl { @@ -58,11 +61,9 @@ inline bool threads_same(thread_id a, thread_id b) { 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)); + SWIFT_C11THREADS_CHECK(::mtx_init(&handle, ::mtx_plain)); } +inline void mutex_destroy(mutex_handle &handle) { ::mtx_destroy(&handle); } inline void mutex_lock(mutex_handle &handle) { SWIFT_C11THREADS_CHECK(::mtx_lock(&handle)); @@ -83,33 +84,38 @@ inline void mutex_unsafe_unlock(mutex_handle &handle) { struct lazy_mutex_handle { ::mtx_t mutex; - ::atomic_int once; // -1 = initialized, 0 = uninitialized, 1 = initializing + std::int32_t once; // -1 = initialized, 0 = uninitialized, 1 = initializing }; inline constexpr lazy_mutex_handle lazy_mutex_initializer() { - return (lazy_mutex_handle){0}; + return (lazy_mutex_handle){}; } 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) + if (std::atomic_load_explicit((std::atomic *)&handle.once, + std::memory_order_acquire) < 0) return; - if (::atomic_compare_exchange_strong_explicit(&handle.once, &(int){0}, 1, - ::memory_order_relaxed, - ::memory_order_relaxed)) { + int zero = 0; + if (std::atomic_compare_exchange_strong_explicit( + (std::atomic *)&handle.once, &zero, 1, + std::memory_order_relaxed, std::memory_order_relaxed)) { SWIFT_C11THREADS_CHECK(::mtx_init(&handle.mutex, ::mtx_plain)); - ::atomic_store_explicit(&handle.once, -1, ::memory_order_release); + std::atomic_store_explicit((std::atomic *)&handle.once, -1, + std::memory_order_release); return; } - while (::atomic_load_explicit(&handle.once, memory_order_acquire) >= 0) { + while (std::atomic_load_explicit((std::atomic *)&handle.once, + std::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)); + if (std::atomic_load_explicit((std::atomic *)&handle.once, + std::memory_order_acquire) < 0) + ::mtx_destroy(&handle.mutex); } inline void lazy_mutex_lock(lazy_mutex_handle &handle) { @@ -136,13 +142,13 @@ inline void lazy_mutex_unsafe_unlock(lazy_mutex_handle &handle) { // .. Once ................................................................... -typedef ::atomic_int once_t; +typedef std::atomic once_t; void once_slow(once_t &predicate, void (*fn)(void *), void *context); inline void once_impl(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) + if (std::atomic_load_explicit(&predicate, std::memory_order_acquire) < 0) return; once_slow(predicate, fn, context); @@ -150,6 +156,10 @@ inline void once_impl(once_t &predicate, void (*fn)(void *), void *context) { // .. Thread local storage ................................................... +// Get rid of this, because it causes clashes with TokenKinds.def +#undef thread_local + +// We *can* use the C++ version though #if __cplusplus >= 201103L || __has_feature(cxx_thread_local) #define SWIFT_THREAD_LOCAL thread_local #endif diff --git a/include/swift/Threading/ThreadLocalStorage.h b/include/swift/Threading/ThreadLocalStorage.h index 890ff5e15227d..e681fc1a18e9d 100644 --- a/include/swift/Threading/ThreadLocalStorage.h +++ b/include/swift/Threading/ThreadLocalStorage.h @@ -86,20 +86,18 @@ inline void tls_alloc_once(once_t &token, tls_key &key, tls_dtor dtor) { // 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 +// - On platforms that define SWIFT_THREAD_LOCAL, an object of this type +// is declared with SWIFT_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. +// for which SWIFT_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_THREAD_LOCAL +// - On platforms that don't define SWIFT_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 ThreadLocal { VALIDATE_THREAD_LOCAL_TYPE(T) @@ -179,7 +177,7 @@ class ThreadLocal { /// Because of the fallback path, the default-initialization of the /// type must be equivalent to a bitwise zero-initialization, and the /// type must be small and trivially copyable and destructible. -#if SWIFT_THREAD_LOCAL +#ifdef SWIFT_THREAD_LOCAL #define SWIFT_THREAD_LOCAL_TYPE(TYPE, KEY) \ SWIFT_THREAD_LOCAL swift::ThreadLocal #elif SWIFT_THREADING_USE_RESERVED_TLS_KEYS diff --git a/lib/FrontendTool/CMakeLists.txt b/lib/FrontendTool/CMakeLists.txt index 6976fc2e9d919..ec94b5fc8b121 100644 --- a/lib/FrontendTool/CMakeLists.txt +++ b/lib/FrontendTool/CMakeLists.txt @@ -26,6 +26,7 @@ target_link_libraries(swiftFrontendTool PRIVATE swiftSIL swiftSILGen swiftSILOptimizer - swiftTBDGen) + swiftTBDGen + swiftThreading) set_swift_llvm_is_available(swiftFrontendTool) diff --git a/lib/Threading/C11.cpp b/lib/Threading/C11.cpp index f2f006a78848d..779e1dbacc5f6 100644 --- a/lib/Threading/C11.cpp +++ b/lib/Threading/C11.cpp @@ -22,12 +22,12 @@ namespace { #pragma clang diagnostic push -#pragma GCC diagnostic ignored "-Wglobal-constructors" +#pragma clang diagnostic ignored "-Wglobal-constructors" class C11ThreadingHelper { private: thrd_t mainThread_; - mut_t onceMutex_; + mtx_t onceMutex_; cnd_t onceCond_; public: @@ -64,12 +64,13 @@ bool swift::threading_impl::thread_is_main() { void swift::threading_impl::once_slow(once_t &predicate, void (*fn)(void *), void *context) { - if (::atomic_compare_exchange_strong_explicit(&predicate, &(int){0}, 1, - ::memory_order_relaxed, - ::memory_order_relaxed)) { + std::int64_t zero = 0; + if (std::atomic_compare_exchange_strong_explicit(&predicate, &zero, 1, + std::memory_order_relaxed, + std::memory_order_relaxed)) { fn(context); - ::atomic_store_explicit(&predicate, -1, ::memory_order_release); + std::atomic_store_explicit(&predicate, -1, std::memory_order_release); helper.once_lock(); helper.once_unlock(); @@ -78,7 +79,8 @@ void swift::threading_impl::once_slow(once_t &predicate, void (*fn)(void *), } helper.once_lock(); - while (::atomic_load_explicit(&predicate, memory_order_acquire) >= 0) { + while (std::atomic_load_explicit(&predicate, std::memory_order_acquire) >= + 0) { helper.once_wait(); } helper.once_unlock(); diff --git a/lib/Threading/CMakeLists.txt b/lib/Threading/CMakeLists.txt index 2e16b262a44b8..c43deec244bef 100644 --- a/lib/Threading/CMakeLists.txt +++ b/lib/Threading/CMakeLists.txt @@ -1,8 +1,13 @@ # If you update this, you also need to update the CMakeLists.txt file in # stdlib/public/Threading +# Note that it is *not* an error that Errors.cpp is only listed here. +# It shouldn't be in stdlib/public/Threading because that is an OBJECT_LIBRARY +# and things that use that should be defining their own fatal error handler. + add_swift_host_library(swiftThreading STATIC C11.cpp Linux.cpp Pthreads.cpp - Win32.cpp) + Win32.cpp + Errors.cpp) diff --git a/lib/Threading/Errors.cpp b/lib/Threading/Errors.cpp new file mode 100644 index 0000000000000..7897b5155866f --- /dev/null +++ b/lib/Threading/Errors.cpp @@ -0,0 +1,41 @@ +//==--- Errors.cpp - 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 +// +//===----------------------------------------------------------------------===// +// +// Provides a fallback definition of swift::threading::fatal(). You may +// care to provide your own definition elsewhere, to tie the threading code's +// error handling into the relevant code. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include + +#include "swift/Threading/Errors.h" + +namespace swift { +namespace threading { + +SWIFT_ATTRIBUTE_NORETURN +SWIFT_FORMAT(1, 2) +void fatal(const char *msg, ...) { + std::va_list val; + + va_start(val, msg); + std::vfprintf(stderr, msg, val); + va_end(val); + + std::abort(); +} + +} // namespace threading +} // namespace swift diff --git a/stdlib/public/Concurrency/AsyncLet.cpp b/stdlib/public/Concurrency/AsyncLet.cpp index 47db4e81574ed..55759a512b551 100644 --- a/stdlib/public/Concurrency/AsyncLet.cpp +++ b/stdlib/public/Concurrency/AsyncLet.cpp @@ -14,14 +14,16 @@ // //===----------------------------------------------------------------------===// -#include "swift/ABI/AsyncLet.h" +#include "swift/Runtime/Concurrency.h" + #include "../CompatibilityOverride/CompatibilityOverride.h" #include "Debug.h" #include "TaskPrivate.h" + +#include "swift/ABI/AsyncLet.h" #include "swift/ABI/Metadata.h" #include "swift/ABI/Task.h" #include "swift/ABI/TaskOptions.h" -#include "swift/Runtime/Concurrency.h" #include "swift/Runtime/Heap.h" #include "swift/Runtime/HeapObject.h" #include "swift/Threading/Mutex.h" diff --git a/stdlib/public/Threading/CMakeLists.txt b/stdlib/public/Threading/CMakeLists.txt index 2f8e248b05456..8ff2d19825939 100644 --- a/stdlib/public/Threading/CMakeLists.txt +++ b/stdlib/public/Threading/CMakeLists.txt @@ -7,3 +7,12 @@ add_swift_target_library(swiftThreading OBJECT_LIBRARY "${SWIFT_SOURCE_DIR}/lib/Threading/Pthreads.cpp" "${SWIFT_SOURCE_DIR}/lib/Threading/Win32.cpp" INSTALL_IN_COMPONENT never_install) + +# This is only used by the compatibility libraries +add_swift_target_library(swiftThreadingWithFatal OBJECT_LIBRARY + "${SWIFT_SOURCE_DIR}/lib/Threading/C11.cpp" + "${SWIFT_SOURCE_DIR}/lib/Threading/Linux.cpp" + "${SWIFT_SOURCE_DIR}/lib/Threading/Pthreads.cpp" + "${SWIFT_SOURCE_DIR}/lib/Threading/Win32.cpp" + "${SWIFT_SOURCE_DIR}/lib/Threading/Errors.cpp" + INSTALL_IN_COMPONENT never_install) diff --git a/stdlib/public/runtime/RuntimeInvocationsTracking.cpp b/stdlib/public/runtime/RuntimeInvocationsTracking.cpp index a5851c42b02ba..bf5812b4ba100 100644 --- a/stdlib/public/runtime/RuntimeInvocationsTracking.cpp +++ b/stdlib/public/runtime/RuntimeInvocationsTracking.cpp @@ -15,6 +15,8 @@ // //===----------------------------------------------------------------------===// +#include + #include "RuntimeInvocationsTracking.h" #include "swift/Basic/Lazy.h" #include "swift/Runtime/HeapObject.h" @@ -32,7 +34,7 @@ namespace swift { // functions. struct RuntimeFunctionCountersState { #define FUNCTION_TO_TRACK(RT_FUNCTION) \ - uint32_t SWIFT_RT_FUNCTION_INVOCATION_COUNTER_NAME(RT_FUNCTION) = 0; + std::uint32_t SWIFT_RT_FUNCTION_INVOCATION_COUNTER_NAME(RT_FUNCTION) = 0; // Provide one counter per runtime function being tracked. #include "RuntimeInvocationsTracking.def" }; @@ -73,7 +75,7 @@ static const char *RuntimeFunctionNames[] { /// Define an enum where each enumerator corresponds to a runtime function being /// tracked. Their order is the same as the order of the counters in the /// RuntimeObjectState structure. -enum RuntimeFunctionNamesIDs : uint32_t { +enum RuntimeFunctionNamesIDs : std::uint32_t { /// Defines names of enum cases for each function being tracked. #define FUNCTION_TO_TRACK(RT_FUNCTION) RT_FUNCTION_ID(RT_FUNCTION), #include "RuntimeInvocationsTracking.def" @@ -87,10 +89,10 @@ static RuntimeFunctionCountersUpdateHandler /// The offsets of the runtime function counters being tracked inside the /// RuntimeObjectState structure. The array is indexed by /// the enumerators from RuntimeFunctionNamesIDs. -static uint16_t RuntimeFunctionCountersOffsets[] = { +static std::uint16_t RuntimeFunctionCountersOffsets[] = { /// Define offset for each function being tracked. #define FUNCTION_TO_TRACK(RT_FUNCTION) \ - (sizeof(uint16_t) * (unsigned)RT_FUNCTION_ID(RT_FUNCTION)), + (sizeof(std::uint16_t) * (unsigned)RT_FUNCTION_ID(RT_FUNCTION)), #include "RuntimeInvocationsTracking.def" }; @@ -169,17 +171,17 @@ const char **_swift_getRuntimeFunctionNames() { /// Return the offsets of the runtime function counters being tracked. /// Their order is the same as the order of the counters in the /// RuntimeObjectState structure. -const uint16_t *_swift_getRuntimeFunctionCountersOffsets() { +const std::uint16_t *_swift_getRuntimeFunctionCountersOffsets() { return RuntimeFunctionCountersOffsets; } /// Return the number of runtime functions being tracked. -uint64_t _swift_getNumRuntimeFunctionCounters() { +std::uint64_t _swift_getNumRuntimeFunctionCounters() { return ID_LastRuntimeFunctionName; } static void _swift_dumpRuntimeCounters(RuntimeFunctionCountersState *State) { - uint32_t tmp; + std::uint32_t tmp; /// Define how to dump the counter for a given runtime function. #define FUNCTION_TO_TRACK(RT_FUNCTION) \ tmp = State->SWIFT_RT_FUNCTION_INVOCATION_COUNTER_NAME(RT_FUNCTION); \ diff --git a/stdlib/public/stubs/Stubs.cpp b/stdlib/public/stubs/Stubs.cpp index 5ec2bc9e60e30..e16af535164fc 100644 --- a/stdlib/public/stubs/Stubs.cpp +++ b/stdlib/public/stubs/Stubs.cpp @@ -558,7 +558,7 @@ __swift_bool _swift_stdlib_getCurrentStackBounds(__swift_uintptr_t *outBegin, #elif SWIFT_THREADING_C11 // We don't know any way to do this for C11 threads - return false + return false; #elif SWIFT_THREADING_WIN32 diff --git a/stdlib/toolchain/Compatibility50/CMakeLists.txt b/stdlib/toolchain/Compatibility50/CMakeLists.txt index 16824da43b5bf..c12446f9110d3 100644 --- a/stdlib/toolchain/Compatibility50/CMakeLists.txt +++ b/stdlib/toolchain/Compatibility50/CMakeLists.txt @@ -8,6 +8,7 @@ add_swift_target_library("${library_name}" STATIC C_COMPILE_FLAGS ${CXX_COMPILE_FLAGS} LINK_FLAGS ${CXX_LINK_FLAGS} + INCORPORATE_OBJECT_LIBRARIES swiftThreadingWithFatal SWIFT_COMPILE_FLAGS ${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS} DEPLOYMENT_VERSION_OSX ${COMPATIBILITY_MINIMUM_DEPLOYMENT_VERSION_OSX} DEPLOYMENT_VERSION_IOS ${COMPATIBILITY_MINIMUM_DEPLOYMENT_VERSION_IOS} diff --git a/stdlib/toolchain/Compatibility51/CMakeLists.txt b/stdlib/toolchain/Compatibility51/CMakeLists.txt index aeea7ae896874..a6df604936207 100644 --- a/stdlib/toolchain/Compatibility51/CMakeLists.txt +++ b/stdlib/toolchain/Compatibility51/CMakeLists.txt @@ -9,6 +9,7 @@ add_swift_target_library("${library_name}" STATIC C_COMPILE_FLAGS ${CXX_COMPILE_FLAGS} LINK_FLAGS ${CXX_LINK_FLAGS} + INCORPORATE_OBJECT_LIBRARIES swiftThreadingWithFatal SWIFT_COMPILE_FLAGS ${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS} DEPLOYMENT_VERSION_OSX ${COMPATIBILITY_MINIMUM_DEPLOYMENT_VERSION_OSX} DEPLOYMENT_VERSION_IOS ${COMPATIBILITY_MINIMUM_DEPLOYMENT_VERSION_IOS} diff --git a/stdlib/toolchain/CompatibilityConcurrency/CMakeLists.txt b/stdlib/toolchain/CompatibilityConcurrency/CMakeLists.txt index 6f08bc91dd550..6bb2590bde853 100644 --- a/stdlib/toolchain/CompatibilityConcurrency/CMakeLists.txt +++ b/stdlib/toolchain/CompatibilityConcurrency/CMakeLists.txt @@ -7,6 +7,7 @@ add_swift_target_library("${library_name}" STATIC C_COMPILE_FLAGS ${CXX_COMPILE_FLAGS} LINK_FLAGS ${CXX_LINK_FLAGS} + INCORPORATE_OBJECT_LIBRARIES swiftThreadingWithFatal SWIFT_COMPILE_FLAGS ${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS} DEPLOYMENT_VERSION_OSX ${COMPATIBILITY_MINIMUM_DEPLOYMENT_VERSION_OSX} DEPLOYMENT_VERSION_IOS ${COMPATIBILITY_MINIMUM_DEPLOYMENT_VERSION_IOS} diff --git a/stdlib/toolchain/CompatibilityDynamicReplacements/CMakeLists.txt b/stdlib/toolchain/CompatibilityDynamicReplacements/CMakeLists.txt index db63a04992504..7448ab47add54 100644 --- a/stdlib/toolchain/CompatibilityDynamicReplacements/CMakeLists.txt +++ b/stdlib/toolchain/CompatibilityDynamicReplacements/CMakeLists.txt @@ -7,6 +7,7 @@ add_swift_target_library("${library_name}" STATIC C_COMPILE_FLAGS ${CXX_COMPILE_FLAGS} LINK_FLAGS ${CXX_LINK_FLAGS} + INCORPORATE_OBJECT_LIBRARIES swiftThreadingWithFatal SWIFT_COMPILE_FLAGS ${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS} DEPLOYMENT_VERSION_OSX ${COMPATIBILITY_MINIMUM_DEPLOYMENT_VERSION_OSX} DEPLOYMENT_VERSION_IOS ${COMPATIBILITY_MINIMUM_DEPLOYMENT_VERSION_IOS} diff --git a/stdlib/toolchain/CompatibilityDynamicReplacements/DynamicReplaceable.cpp b/stdlib/toolchain/CompatibilityDynamicReplacements/DynamicReplaceable.cpp index 2c12a8ad4792c..a9b2668432f09 100644 --- a/stdlib/toolchain/CompatibilityDynamicReplacements/DynamicReplaceable.cpp +++ b/stdlib/toolchain/CompatibilityDynamicReplacements/DynamicReplaceable.cpp @@ -23,6 +23,17 @@ using namespace swift; +namespace { + +// Some threading libraries will need a global constructor here; that is +// unavoidable in the general case, so turn off the warning just for this line. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wglobal-constructors" +SWIFT_THREAD_LOCAL_TYPE(uintptr_t, SWIFT_COMPATIBILITY_50_TLS_KEY) compat50Key; +#pragma clang diagnostic pop + +} // namespace + __attribute__((visibility("hidden"), weak)) extern "C" char *swift_getFunctionReplacement50(char **ReplFnPtr, char *CurrFn) { // Call the current implementation if it is available. @@ -39,11 +50,11 @@ extern "C" char *swift_getFunctionReplacement50(char **ReplFnPtr, char *CurrFn) if (RawReplFn == CurrFn) return nullptr; - auto origKey = (uintptr_t)swift::tls_get(SWIFT_COMPATIBILITY_50_TLS_KEY); + auto origKey = compat50Key.get(); if ((origKey & 0x1) != 0) { auto mask = ((uintptr_t)-1) < 1; auto resetKey = origKey & mask; - swift::tls_set(SWIFT_COMPATIBILITY_50_TLS_KEY, (void *)resetKey); + compat50Key.set(resetKey); return nullptr; } return ReplFn; @@ -56,9 +67,9 @@ extern "C" char *swift_getOrigOfReplaceable50(char **OrigFnPtr) { return swift_getOrigOfReplaceable(OrigFnPtr); char *OrigFn = *OrigFnPtr; - auto origKey = (uintptr_t)swift::tls_get(SWIFT_COMPATIBILITY_50_TLS_KEY); + auto origKey = compat50Key.get(); auto newKey = origKey | 0x1; - swift::tls_set(SWIFT_COMPATIBILITY_50_TLS_KEY, (void *)newKey); + compat50Key.set(newKey); return OrigFn; } From eb4c81d60e2a4decaffdbadccb6099db5e07e8ea Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Wed, 4 May 2022 11:08:09 +0100 Subject: [PATCH 29/40] [Threading] Don't use TLS keys as template arguments. There's no guarantee that e.g. pthread_key_t is an integral type. It could be some kind of struct, or some other thing that isn't valid as a template argument. rdar://90776105 --- include/swift/Threading/Impl.h | 2 + include/swift/Threading/Impl/C11.h | 10 ++-- include/swift/Threading/Impl/Darwin.h | 53 ++++++++++++------- include/swift/Threading/Impl/Linux.h | 10 ++-- include/swift/Threading/Impl/Pthreads.h | 10 ++-- include/swift/Threading/Impl/Win32.h | 10 ++-- include/swift/Threading/TLSKeys.h | 29 ++++++++++ include/swift/Threading/ThreadLocalStorage.h | 37 +++++++------ stdlib/public/Concurrency/Actor.cpp | 8 +-- stdlib/public/Concurrency/TaskLocal.cpp | 7 ++- stdlib/public/runtime/SwiftTLSContext.cpp | 8 +-- stdlib/public/stubs/ThreadLocalStorage.cpp | 8 +-- .../DynamicReplaceable.cpp | 2 +- 13 files changed, 123 insertions(+), 71 deletions(-) create mode 100644 include/swift/Threading/TLSKeys.h diff --git a/include/swift/Threading/Impl.h b/include/swift/Threading/Impl.h index 6d66096980276..f25c6fb633036 100644 --- a/include/swift/Threading/Impl.h +++ b/include/swift/Threading/Impl.h @@ -18,6 +18,8 @@ #ifndef SWIFT_THREADING_IMPL_H #define SWIFT_THREADING_IMPL_H +#include "TLSKeys.h" + // Try to autodetect if we aren't told what to do #if !SWIFT_THREADING_NONE && !SWIFT_THREADING_DARWIN && \ !SWIFT_THREADING_LINUX && !SWIFT_THREADING_PTHREADS && \ diff --git a/include/swift/Threading/Impl/C11.h b/include/swift/Threading/Impl/C11.h index 16aeca2b9efb8..ae080709eb2b7 100644 --- a/include/swift/Threading/Impl/C11.h +++ b/include/swift/Threading/Impl/C11.h @@ -164,16 +164,16 @@ inline void once_impl(once_t &predicate, void (*fn)(void *), void *context) { #define SWIFT_THREAD_LOCAL thread_local #endif -using tls_key = ::tss_t; -using tls_dtor = void (*)(void *); +using tls_key_t = ::tss_t; +using tls_dtor_t = void (*)(void *); -inline bool tls_alloc(tls_key &key, tls_dtor dtor) { +inline bool tls_alloc(tls_key_t &key, tls_dtor_t dtor) { return ::tss_create(&key, dtor) == thrd_success; } -inline void *tls_get(tls_key key) { return ::tss_get(key); } +inline void *tls_get(tls_key_t key) { return ::tss_get(key); } -inline void tls_set(tls_key key, void *ptr) { ::tss_set(key, ptr); } +inline void tls_set(tls_key_t key, void *ptr) { ::tss_set(key, ptr); } } // namespace threading_impl diff --git a/include/swift/Threading/Impl/Darwin.h b/include/swift/Threading/Impl/Darwin.h index df27dd42f6237..4f68e973be8a9 100644 --- a/include/swift/Threading/Impl/Darwin.h +++ b/include/swift/Threading/Impl/Darwin.h @@ -128,45 +128,60 @@ inline void _pthread_setspecific_direct(pthread_key_t k, void *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) { +using tls_key_t = pthread_key_t; +using tls_dtor_t = void (*)(void *); + +inline tls_key_t tls_get_key(tls_key k) { + switch (k) { + case tls_key::runtime: + return __PTK_FRAMEWORK_SWIFT_KEY0; + case tls_key::stdlib: + return __PTK_FRAMEWORK_SWIFT_KEY1; + case tls_key::compatibility50: + return __PTK_FRAMEWORK_SWIFT_KEY2; + case tls_key::concurrency_task: + return __PTK_FRAMEWORK_SWIFT_KEY3; + case tls_key::concurrency_executor_tracking_info: + return __PTK_FRAMEWORK_SWIFT_KEY4; + case tls_key::concurrency_fallback: + return __PTK_FRAMEWORK_SWIFT_KEY5; + } +} + +inline bool tls_init(tls_key_t key, tls_dtor_t dtor) { return pthread_key_init_np(key, dtor) == 0; } -inline bool tls_alloc(tls_key &key, tls_dtor dtor) { +inline bool tls_init(tls_key key, tls_dtor_t dtor) { + return tls_init(tls_get_key(key), dtor); +} + +inline bool tls_alloc(tls_key_t &key, tls_dtor_t dtor) { return pthread_key_create(&key, dtor) == 0; } -inline void *tls_get(tls_key key) { +inline void *tls_get(tls_key_t 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) { +inline void *tls_get(tls_key key) { return tls_get(tls_get_key(key)); } + +inline void tls_set(tls_key_t key, void *value) { if (_pthread_has_direct_tsd()) _pthread_setspecific_direct(key, value); else pthread_setspecific(key, value); } +inline void tls_set(tls_key key, void *value) { + tls_set(tls_get_key(key), value); +} + } // namespace threading_impl } // namespace swift diff --git a/include/swift/Threading/Impl/Linux.h b/include/swift/Threading/Impl/Linux.h index c447bcb80e81d..000a8bf48b310 100644 --- a/include/swift/Threading/Impl/Linux.h +++ b/include/swift/Threading/Impl/Linux.h @@ -149,16 +149,16 @@ inline void once_impl(once_t &predicate, void (*fn)(void *), void *context) { #define SWIFT_THREAD_LOCAL thread_local #endif -using tls_key = pthread_key_t; -using tls_dtor = void (*)(void *); +using tls_key_t = pthread_key_t; +using tls_dtor_t = void (*)(void *); -inline bool tls_alloc(tls_key &key, tls_dtor dtor) { +inline bool tls_alloc(tls_key_t &key, tls_dtor_t dtor) { return pthread_key_create(&key, dtor) == 0; } -inline void *tls_get(tls_key key) { return pthread_getspecific(key); } +inline void *tls_get(tls_key_t key) { return pthread_getspecific(key); } -inline void tls_set(tls_key key, void *value) { +inline void tls_set(tls_key_t key, void *value) { pthread_setspecific(key, value); } diff --git a/include/swift/Threading/Impl/Pthreads.h b/include/swift/Threading/Impl/Pthreads.h index 83139ab07f421..f07dd47b0849e 100644 --- a/include/swift/Threading/Impl/Pthreads.h +++ b/include/swift/Threading/Impl/Pthreads.h @@ -145,16 +145,16 @@ inline void once_impl(once_t &predicate, void (*fn)(void *), void *context) { #define SWIFT_THREAD_LOCAL thread_local #endif -using tls_key = pthread_key_t; -using tls_dtor = void (*)(void *); +using tls_key_t = pthread_key_t; +using tls_dtor_t = void (*)(void *); -inline bool tls_alloc(tls_key &key, tls_dtor dtor) { +inline bool tls_alloc(tls_key_t &key, tls_dtor_t dtor) { return pthread_key_create(&key, dtor) == 0; } -inline void *tls_get(tls_key key) { return pthread_getspecific(key); } +inline void *tls_get(tls_key_t key) { return pthread_getspecific(key); } -inline void tls_set(tls_key key, void *value) { +inline void tls_set(tls_key_t key, void *value) { pthread_setspecific(key, value); } diff --git a/include/swift/Threading/Impl/Win32.h b/include/swift/Threading/Impl/Win32.h index 3f0d7258af9ee..ae2ed58a5ebca 100644 --- a/include/swift/Threading/Impl/Win32.h +++ b/include/swift/Threading/Impl/Win32.h @@ -109,17 +109,17 @@ inline void once_impl(once_t &predicate, void (*fn)(void *), void *context) { #define SWIFT_TLS_DECLARE_DTOR(name) void NTAPI name(void *) -using tls_key = ::DWORD; -using tls_dtor = ::PFLS_CALLBACK_FUNCTION; +using tls_key_t = ::DWORD; +using tls_dtor_t = ::PFLS_CALLBACK_FUNCTION; -inline bool tls_alloc(tls_key &key, tls_dtor dtor) { +inline bool tls_alloc(tls_key_t &key, tls_dtor_t dtor) { key = ::FlsAlloc(dtor); return key != FLS_OUT_OF_INDEXES; } -inline void *tls_get(tls_key key) { return ::FlsGetValue(key); } +inline void *tls_get(tls_key_t key) { return ::FlsGetValue(key); } -inline void tls_set(tls_key key, void *value) { ::FlsSetValue(key, value); } +inline void tls_set(tls_key_t key, void *value) { ::FlsSetValue(key, value); } } // namespace threading_impl diff --git a/include/swift/Threading/TLSKeys.h b/include/swift/Threading/TLSKeys.h new file mode 100644 index 0000000000000..a9feaae389aea --- /dev/null +++ b/include/swift/Threading/TLSKeys.h @@ -0,0 +1,29 @@ +//===--- TLSKeys.h - Reserved TLS keys ------------------------ -*- 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_TLSKEYS_H +#define SWIFT_THREADING_TLSKEYS_H + +namespace swift { + +enum class tls_key { + runtime, + stdlib, + compatibility50, + concurrency_task, + concurrency_executor_tracking_info, + concurrency_fallback +}; + +} // namespace swift + +#endif // SWIFT_THREADING_TLSKEYS_H diff --git a/include/swift/Threading/ThreadLocalStorage.h b/include/swift/Threading/ThreadLocalStorage.h index e681fc1a18e9d..0bbf0fae55bc7 100644 --- a/include/swift/Threading/ThreadLocalStorage.h +++ b/include/swift/Threading/ThreadLocalStorage.h @@ -1,5 +1,4 @@ -//===--- ThreadLocalStorage.h - Thread-local storage interface. --*- C++ -//-*-===// +//===--- ThreadLocalStorage.h - Thread-local storage interface. -*- C++ -*-===// // // This source file is part of the Swift.org open source project // @@ -19,23 +18,25 @@ #include "Errors.h" #include "Impl.h" #include "Once.h" +#include "TLSKeys.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; +using tls_key_t = threading_impl::tls_key_t; +using tls_dtor_t = threading_impl::tls_dtor_t; #if SWIFT_THREADING_USE_RESERVED_TLS_KEYS +using threading_impl::tls_get_key; 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) { +inline void tls_init_once(once_t &token, tls_key_t key, tls_dtor_t dtor) { const struct tls_init_info { - tls_key &k; - tls_dtor d; + tls_key_t &k; + tls_dtor_t d; } info = {key, dtor}; once( token, @@ -47,6 +48,10 @@ inline void tls_init_once(once_t &token, tls_key key, tls_dtor dtor) { }, (void *)&info); } + +inline void tls_init_once(once_t &token, tls_key key, tls_dtor_t dtor) { + tls_init_once(token, tls_get_key(key), dtor); +} #endif // SWIFT_THREADING_USE_RESERVED_TLS_KEYS using threading_impl::tls_alloc; @@ -54,10 +59,10 @@ 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) { +inline void tls_alloc_once(once_t &token, tls_key_t &key, tls_dtor_t dtor) { const struct tls_init_info { - tls_key &k; - tls_dtor d; + tls_key_t &k; + tls_dtor_t d; } info = {key, dtor}; once( token, @@ -117,14 +122,14 @@ class ThreadLocalKey { // We rely on the zero-initialization of objects with static storage // duration. once_t onceFlag; - tls_key key; + tls_key_t key; public: - threading_impl::tls_key getKey() { + threading_impl::tls_key_t getKey() { once( onceFlag, [](void *ctx) { - tls_key *pkey = reinterpret_cast(ctx); + tls_key_t *pkey = reinterpret_cast(ctx); tls_alloc(*pkey, nullptr); }, &key); @@ -132,13 +137,15 @@ class ThreadLocalKey { } }; +#if SWIFT_THREADING_USE_RESERVED_TLS_KEYS // A type representing a constant TLS key, for use on platforms // that provide reserved keys. template class ConstantThreadLocalKey { public: - tls_key getKey() { return constantKey; } + tls_key_t getKey() { return tls_get_key(constantKey); } }; +#endif template class ThreadLocal { @@ -172,7 +179,7 @@ class ThreadLocal { /// /// For example /// -/// static SWIFT_THREAD_LOCAL_TYPE(int, SWIFT_RESERVED_TLS_KEY_9) frobble; +/// static SWIFT_THREAD_LOCAL_TYPE(int, SWIFT_RESERVED_TLS_KEY_T_9) frobble; /// /// Because of the fallback path, the default-initialization of the /// type must be equivalent to a bitwise zero-initialization, and the diff --git a/stdlib/public/Concurrency/Actor.cpp b/stdlib/public/Concurrency/Actor.cpp index b81e4b71c32c9..ddeef8578791b 100644 --- a/stdlib/public/Concurrency/Actor.cpp +++ b/stdlib/public/Concurrency/Actor.cpp @@ -108,7 +108,7 @@ class ExecutorTrackingInfo { /// separate thread-local variable (or whatever is most efficient /// on the target platform). static SWIFT_THREAD_LOCAL_TYPE(Pointer, - SWIFT_CONCURRENCY_EXECUTOR_TRACKING_INFO_KEY) + tls_key::concurrency_executor_tracking_info) ActiveInfoInThread; /// The active executor. @@ -176,7 +176,7 @@ class ActiveTask { /// A thread-local variable pointing to the active tracking /// information about the current thread, if any. static SWIFT_THREAD_LOCAL_TYPE(Pointer, - SWIFT_CONCURRENCY_TASK_KEY) Value; + tls_key::concurrency_task) Value; public: static void set(AsyncTask *task) { Value.set(task); } @@ -184,11 +184,11 @@ class ActiveTask { }; /// Define the thread-locals. -SWIFT_THREAD_LOCAL_TYPE(Pointer, SWIFT_CONCURRENCY_TASK_KEY) +SWIFT_THREAD_LOCAL_TYPE(Pointer, tls_key::concurrency_task) ActiveTask::Value; SWIFT_THREAD_LOCAL_TYPE(Pointer, - SWIFT_CONCURRENCY_EXECUTOR_TRACKING_INFO_KEY) + tls_key::concurrency_executor_tracking_info) ExecutorTrackingInfo::ActiveInfoInThread; } // end anonymous namespace diff --git a/stdlib/public/Concurrency/TaskLocal.cpp b/stdlib/public/Concurrency/TaskLocal.cpp index ea48ee1cadd18..c6799ee1f06e0 100644 --- a/stdlib/public/Concurrency/TaskLocal.cpp +++ b/stdlib/public/Concurrency/TaskLocal.cpp @@ -54,9 +54,8 @@ template struct Pointer { /// THIS IS RUNTIME INTERNAL AND NOT ABI. class FallbackTaskLocalStorage { - static SWIFT_THREAD_LOCAL_TYPE( - Pointer, - SWIFT_CONCURRENCY_FALLBACK_TASK_LOCAL_STORAGE_KEY) Value; + static SWIFT_THREAD_LOCAL_TYPE(Pointer, + tls_key::concurrency_fallback) Value; public: static void set(TaskLocal::Storage *task) { Value.set(task); } @@ -65,7 +64,7 @@ class FallbackTaskLocalStorage { /// Define the thread-locals. SWIFT_THREAD_LOCAL_TYPE(Pointer, - SWIFT_CONCURRENCY_FALLBACK_TASK_LOCAL_STORAGE_KEY) + tls_key::concurrency_fallback) FallbackTaskLocalStorage::Value; // ==== ABI -------------------------------------------------------------------- diff --git a/stdlib/public/runtime/SwiftTLSContext.cpp b/stdlib/public/runtime/SwiftTLSContext.cpp index ff5b248e0b49e..8a627566cb58d 100644 --- a/stdlib/public/runtime/SwiftTLSContext.cpp +++ b/stdlib/public/runtime/SwiftTLSContext.cpp @@ -24,17 +24,17 @@ SwiftTLSContext &SwiftTLSContext::get() { // If we have reserved keys, use those SwiftTLSContext *ctx = - static_cast(swift::tls_get(SWIFT_RUNTIME_TLS_KEY)); + static_cast(swift::tls_get(swift::tls_key::runtime)); if (ctx) return *ctx; static swift::once_t token; - swift::tls_init_once(token, SWIFT_RUNTIME_TLS_KEY, [](void *pointer) { + swift::tls_init_once(token, swift::tls_key::runtime, [](void *pointer) { delete static_cast(pointer); }); ctx = new SwiftTLSContext(); - swift::tls_set(SWIFT_RUNTIME_TLS_KEY, ctx); + swift::tls_set(swift::tls_key::runtime, ctx); return *ctx; #elif defined(SWIFT_THREAD_LOCAL) @@ -47,7 +47,7 @@ SwiftTLSContext &SwiftTLSContext::get() { #else // Otherwise, allocate ourselves a key and use that - static swift::tls_key runtimeKey; + static swift::tls_key_t runtimeKey; static swift::once_t token; swift::tls_alloc_once(token, runtimeKey, [](void *pointer) { diff --git a/stdlib/public/stubs/ThreadLocalStorage.cpp b/stdlib/public/stubs/ThreadLocalStorage.cpp index f347bd2c2bccd..d357263fc9dea 100644 --- a/stdlib/public/stubs/ThreadLocalStorage.cpp +++ b/stdlib/public/stubs/ThreadLocalStorage.cpp @@ -35,22 +35,22 @@ _swift_stdlib_threadLocalStorageGet(void) { #elif SWIFT_THREADING_USE_RESERVED_TLS_KEYS // If we have reserved keys, use those - void *value = swift::tls_get(SWIFT_STDLIB_TLS_KEY); + void *value = swift::tls_get(swift::tls_key::stdlib); if (value) return value; static swift::once_t token; - swift::tls_init_once(token, SWIFT_STDLIB_TLS_KEY, + swift::tls_init_once(token, swift::tls_key::stdlib, [](void *pointer) { _stdlib_destroyTLS(pointer); }); value = _stdlib_createTLS(); - swift::tls_set(SWIFT_STDLIB_TLS_KEY, value); + swift::tls_set(swift::tls_key::stdlib, value); return value; #else // Threaded, but not using reserved keys // Register a key and use it - static swift::tls_key key; + static swift::tls_key_t key; static swift::once_t token; swift::tls_alloc_once(token, key, diff --git a/stdlib/toolchain/CompatibilityDynamicReplacements/DynamicReplaceable.cpp b/stdlib/toolchain/CompatibilityDynamicReplacements/DynamicReplaceable.cpp index a9b2668432f09..63785be88af64 100644 --- a/stdlib/toolchain/CompatibilityDynamicReplacements/DynamicReplaceable.cpp +++ b/stdlib/toolchain/CompatibilityDynamicReplacements/DynamicReplaceable.cpp @@ -29,7 +29,7 @@ namespace { // unavoidable in the general case, so turn off the warning just for this line. #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wglobal-constructors" -SWIFT_THREAD_LOCAL_TYPE(uintptr_t, SWIFT_COMPATIBILITY_50_TLS_KEY) compat50Key; +SWIFT_THREAD_LOCAL_TYPE(uintptr_t, tls_key::compatibility50) compat50Key; #pragma clang diagnostic pop } // namespace From b5c8b79556d7573a42a396e062378e7c1ebfc935 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Fri, 6 May 2022 10:59:48 +0100 Subject: [PATCH 30/40] [Threading] Move stack bounds fetching into the threading library. Fetching the current stack bounds is done using threading functions, so should be in the threading library. rdar://90776105 --- include/swift/Threading/Impl.h | 12 ++++ include/swift/Threading/Impl/C11.h | 4 ++ include/swift/Threading/Impl/Darwin.h | 13 ++++ include/swift/Threading/Impl/Linux.h | 2 + include/swift/Threading/Impl/Nothreads.h | 4 ++ include/swift/Threading/Impl/Pthreads.h | 2 + include/swift/Threading/Impl/Win32.h | 1 + include/swift/Threading/Thread.h | 6 ++ lib/Threading/Linux.cpp | 19 +++++ lib/Threading/Pthreads.cpp | 43 ++++++++++++ lib/Threading/Win32.cpp | 22 ++++++ stdlib/public/stubs/Stubs.cpp | 88 ++---------------------- 12 files changed, 134 insertions(+), 82 deletions(-) diff --git a/include/swift/Threading/Impl.h b/include/swift/Threading/Impl.h index f25c6fb633036..f734a310b5928 100644 --- a/include/swift/Threading/Impl.h +++ b/include/swift/Threading/Impl.h @@ -20,6 +20,18 @@ #include "TLSKeys.h" +namespace swift { +namespace threading_impl { + +struct stack_bounds { + void *low; + void *high; +}; + +} // namespace swift +} // namespace threading_impl + + // Try to autodetect if we aren't told what to do #if !SWIFT_THREADING_NONE && !SWIFT_THREADING_DARWIN && \ !SWIFT_THREADING_LINUX && !SWIFT_THREADING_PTHREADS && \ diff --git a/include/swift/Threading/Impl/C11.h b/include/swift/Threading/Impl/C11.h index ae080709eb2b7..6d609ea71876c 100644 --- a/include/swift/Threading/Impl/C11.h +++ b/include/swift/Threading/Impl/C11.h @@ -55,6 +55,10 @@ bool thread_is_main(); inline bool threads_same(thread_id a, thread_id b) { return ::thrd_equal(a, b); } +inline stack_bounds thread_get_current_stack_bounds() { + stack_bounds zero = { nullptr, nullptr }; + return zero; +} // .. Mutex support .......................................................... diff --git a/include/swift/Threading/Impl/Darwin.h b/include/swift/Threading/Impl/Darwin.h index 4f68e973be8a9..ca30c683e53fd 100644 --- a/include/swift/Threading/Impl/Darwin.h +++ b/include/swift/Threading/Impl/Darwin.h @@ -38,6 +38,19 @@ inline bool threads_same(thread_id a, thread_id b) { return ::pthread_equal(a, b); } +inline stack_bounds thread_get_current_stack_bounds() { + stack_bounds result; + pthread_t thread = pthread_self(); + + // On Apple platforms, pthread_get_stackaddr_np() gets the address of the + // *end* of the stack (i.e. the highest address in stack space), *NOT* the + // address of the *base* of the stack (the lowest address). + result.high = pthread_get_stackaddr_np(thread); + result.low = (char *)result.high - pthread_get_stacksize_np(thread); + + return result; +} + // .. Mutex support .......................................................... using mutex_handle = ::os_unfair_lock; diff --git a/include/swift/Threading/Impl/Linux.h b/include/swift/Threading/Impl/Linux.h index 000a8bf48b310..63cf2902e0a78 100644 --- a/include/swift/Threading/Impl/Linux.h +++ b/include/swift/Threading/Impl/Linux.h @@ -61,6 +61,8 @@ inline bool threads_same(thread_id a, thread_id b) { return ::pthread_equal(a, b); } +stack_bounds thread_get_current_stack_bounds(); + // .. Mutex support .......................................................... using mutex_handle = ::pthread_mutex_t; diff --git a/include/swift/Threading/Impl/Nothreads.h b/include/swift/Threading/Impl/Nothreads.h index c50382de68d00..84d1d8d171fce 100644 --- a/include/swift/Threading/Impl/Nothreads.h +++ b/include/swift/Threading/Impl/Nothreads.h @@ -27,6 +27,10 @@ using thread_id = unsigned; inline thread_id thread_get_current() { return 0; } inline bool thread_is_main() { return true; } inline bool threads_same(thread_id a, thread_id b) { return a == b; } +inline stack_bounds thread_get_current_stack_bounds() { + stack_bounds zero = { nullptr, nullptr }; + return zero; +} // .. Mutex support .......................................................... diff --git a/include/swift/Threading/Impl/Pthreads.h b/include/swift/Threading/Impl/Pthreads.h index f07dd47b0849e..3fd636760d279 100644 --- a/include/swift/Threading/Impl/Pthreads.h +++ b/include/swift/Threading/Impl/Pthreads.h @@ -60,6 +60,8 @@ inline bool threads_same(thread_id a, thread_id b) { return ::pthread_equal(a, b); } +stack_bounds thread_get_current_stack_bounds(); + // .. Mutex support .......................................................... using mutex_handle = ::pthread_mutex_t; diff --git a/include/swift/Threading/Impl/Win32.h b/include/swift/Threading/Impl/Win32.h index ae2ed58a5ebca..cd18e0d2f086c 100644 --- a/include/swift/Threading/Impl/Win32.h +++ b/include/swift/Threading/Impl/Win32.h @@ -31,6 +31,7 @@ using thread_id = ::DWORD; inline thread_id thread_get_current() { return ::GetCurrentThreadId(); } bool thread_is_main(); inline bool threads_same(thread_id a, thread_id b) { return a == b; } +stack_bounds thread_get_current_stack_bounds(); // .. Mutex support .......................................................... diff --git a/include/swift/Threading/Thread.h b/include/swift/Threading/Thread.h index e2c500b50aeda..1d09c8d79c192 100644 --- a/include/swift/Threading/Thread.h +++ b/include/swift/Threading/Thread.h @@ -27,6 +27,7 @@ namespace swift { class Thread { public: using Id = threading_impl::thread_id; + using StackBounds = threading_impl::stack_bounds; private: Id id_; @@ -65,6 +66,11 @@ class Thread { bool operator!=(const Thread &other) const { return !threading_impl::threads_same(id_, other.id_); } + + // Retrieve the bounds of the current thread's stack + static StackBounds stackBounds() { + return threading_impl::thread_get_current_stack_bounds(); + } }; } // namespace swift diff --git a/lib/Threading/Linux.cpp b/lib/Threading/Linux.cpp index b61299aa72b7a..52a2c31b9b846 100644 --- a/lib/Threading/Linux.cpp +++ b/lib/Threading/Linux.cpp @@ -57,4 +57,23 @@ void swift::threading_impl::once_slow(once_t &predicate, void (*fn)(void *), linux::ulock_unlock(&predicate.lock); } +swift::threading_impl::stack_bounds +swift::threading_impl::thread_get_current_stack_bounds() { + stack_bounds result = { nullptr, nullptr }; + pthread_attr_t attr; + size_t size = 0; + void *begin = nullptr; + + if (!pthread_getattr_np(pthread_self(), &attr)) { + if (!pthread_attr_getstack(&attr, &begin, &size)) { + result.low = begin; + result.high = (char *)begin + size; + } + + pthread_attr_destroy(&attr); + } + + return result; +} + #endif // SWIFT_THREADING_LINUX diff --git a/lib/Threading/Pthreads.cpp b/lib/Threading/Pthreads.cpp index 0e4db24d780da..15e710c6877f0 100644 --- a/lib/Threading/Pthreads.cpp +++ b/lib/Threading/Pthreads.cpp @@ -16,6 +16,10 @@ #if SWIFT_THREADING_PTHREADS +#if defined(__FreeBSD__) || defined(__OpenBSD__) +#include +#endif + #include "swift/Threading/Impl/Pthreads.h" #include "swift/Threading/Errors.h" @@ -72,4 +76,43 @@ void swift::threading_impl::once_slow(once_t &predicate, void (*fn)(void *), pthread_mutex_unlock(&onceMutex); } +#if defined(__OpenBSD__) +swift::threading_impl::stack_bounds +swift::threading_impl::thread_get_current_stack_bounds() { + stack_bounds result = { nullptr, nullptr }; + stack_t sinfo; + + if (!pthread_stackseg_np(pthread_self(), &sinfo)) { + result.low = (char *)sinfo.ss_sp - sinfo.ss_size; + result.high = sinfo.ss_sp; + } + + return result; +} +#else +swift::threading_impl::stack_bounds +swift::threading_impl::thread_get_current_stack_bounds() { + stack_bounds result = { nullptr, nullptr }; + pthread_attr_t attr; + size_t size = 0; + void *begin = nullptr; + +#if defined(__FreeBSD__) + if (pthread_attr_init(&attr)) + return result; +#endif + + if (!pthread_getattr_np(pthread_self(), &attr)) { + if (!pthread_attr_getstack(&attr, &begin, &size)) { + result.low = begin; + result.high = (char *)begin + size; + } + + pthread_attr_destroy(&attr); + } + + return result; +} +#endif + #endif // SWIFT_THREADING_PTHREADS diff --git a/lib/Threading/Win32.cpp b/lib/Threading/Win32.cpp index 442f3ae9b6b82..8771ed78c5010 100644 --- a/lib/Threading/Win32.cpp +++ b/lib/Threading/Win32.cpp @@ -97,4 +97,26 @@ void swift::threading_impl::once_slow(once_t &predicate, void (*fn)(void *), #endif } +swift::threading_impl::stack_bounds +swift::threading_impl::thread_get_current_stack_bounds() { +#if _WIN32_WINNT >= 0x0602 + ULONG_PTR lowLimit = 0; + ULONG_PTR highLimit = 0; + + GetCurrentThreadStackLimits(&lowLimit, &highLimit); + + stack_bounds result = { (void *)lowLimit, (void *)highLimit }; +#else + MEMORY_BASIC_INFORMATION mbi; + VirtualQuery(&mbi, &mbi, sizeof(mbi)); + + stack_bounds result = { + mbi.AllocationBase, + (char *)mbi.BaseAddress + mbi.RegionSize + }; +#endif + + return result; +} + #endif // SWIFT_THREADING_WIN32 diff --git a/stdlib/public/stubs/Stubs.cpp b/stdlib/public/stubs/Stubs.cpp index e16af535164fc..5af7e9b5c504c 100644 --- a/stdlib/public/stubs/Stubs.cpp +++ b/stdlib/public/stubs/Stubs.cpp @@ -64,14 +64,12 @@ #include #endif -#if defined(__FreeBSD__) || defined(__OpenBSD__) -#include -#endif - #include "swift/Runtime/Debug.h" #include "swift/Runtime/SwiftDtoa.h" #include "swift/Basic/Lazy.h" +#include "swift/Threading/Thread.h" + #include "SwiftShims/LibcShims.h" #include "SwiftShims/RuntimeShims.h" #include "SwiftShims/RuntimeStubs.h" @@ -537,84 +535,10 @@ __swift_bool swift_stdlib_isStackAllocationSafe(__swift_size_t byteCount, __swift_bool _swift_stdlib_getCurrentStackBounds(__swift_uintptr_t *outBegin, __swift_uintptr_t *outEnd) { -#if SWIFT_THREADING_NONE - // This platform does not support threads, so the API we'd call to get stack - // bounds (i.e. libpthread) is not going to be usable. - return false; - -#elif SWIFT_THREADING_DARWIN - pthread_t thread = pthread_self(); - - // On Apple platforms, pthread_get_stackaddr_np() gets the address of the - // *end* of the stack (i.e. the highest address in stack space), *NOT* the - // address of the *base* of the stack (the lowest address). - void *end = pthread_get_stackaddr_np(thread); - if (!end) { - return false; - } - *outEnd = (uintptr_t)end; - *outBegin = *outEnd - pthread_get_stacksize_np(thread); - return true; - -#elif SWIFT_THREADING_C11 - // We don't know any way to do this for C11 threads - return false; - -#elif SWIFT_THREADING_WIN32 - -#if _WIN32_WINNT >= 0x0602 - ULONG_PTR lowLimit = 0; - ULONG_PTR highLimit = 0; - GetCurrentThreadStackLimits(&lowLimit, &highLimit); - *outBegin = lowLimit; - *outEnd = highLimit; - return true; -#else - // Need _WIN32_WINNT to be 0x0602 or higher to use - // GetCurrentThreadStackLimits(). We could use VirtualQuery() instead, - // and give it the address of a page we know is on the stack? - return false; -#endif - -#elif SWIFT_THREADING_PTHREADS || SWIFT_THREADING_LINUX - -#if defined(__OpenBSD__) - stack_t sinfo; - if (pthread_stackseg_np(pthread_self(), &sinfo) != 0) { + swift::Thread::StackBounds bounds = swift::Thread::stackBounds(); + if (!bounds.low) return false; - } - - *outBegin = (uintptr_t)sinfo.ss_sp - sinfo.ss_size; - *outEnd = (uintptr_t)sinfo.ss_sp; + *outBegin = (uintptr_t)bounds.low; + *outEnd = (uintptr_t)bounds.high; return true; -#elif defined(__FreeBSD__) || defined(__ANDROID__) || defined(__linux__) - pthread_attr_t attr; - -#if defined(__FreeBSD__) - if (0 != pthread_attr_init(&attr) || 0 != pthread_attr_get_np(pthread_self(), &attr)) { - return false; - } -#else - if (0 != pthread_getattr_np(pthread_self(), &attr)) { - return false; - } -#endif - - void *begin = nullptr; - size_t size = 0; - bool success = (0 == pthread_attr_getstack(&attr, &begin, &size)); - - *outBegin = (uintptr_t)begin; - *outEnd = *outBegin + size; - - pthread_attr_destroy(&attr); - return success; -#else -#warning Please teach _swift_stdlib_getCurrentStackBounds() about your platform - return false; -#endif - -#else -# error Unknown threading package selected; please teach _swift_stdlib_getCurrentStackBounds() what to do. -#endif } From 48255788dd3601faf47bfb1d8bac533f0dccbb0b Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Fri, 6 May 2022 12:03:31 +0100 Subject: [PATCH 31/40] [Concurrency] Remove redundant include. Clean up an unnecesary include. rdar://90776105 --- stdlib/public/Concurrency/TaskLocal.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/stdlib/public/Concurrency/TaskLocal.cpp b/stdlib/public/Concurrency/TaskLocal.cpp index c6799ee1f06e0..8512fc271ed2d 100644 --- a/stdlib/public/Concurrency/TaskLocal.cpp +++ b/stdlib/public/Concurrency/TaskLocal.cpp @@ -30,10 +30,6 @@ #include #endif -#if HAVE_PTHREAD_H -#include -#endif - #if defined(_WIN32) #include #endif From dc809f8723668cb4a726c60b870dcf3455f0b25d Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Fri, 6 May 2022 14:26:44 +0100 Subject: [PATCH 32/40] [Threading] A few include tweaks. The threading implementations need to include Impl.h, not just their specific variant, to pick up the `stack_bounds` type. Also fix a newly exposed problem with Atomic.h. rdar://90776105 --- include/swift/Runtime/Atomic.h | 3 ++- lib/Threading/C11.cpp | 2 +- lib/Threading/Linux.cpp | 2 +- lib/Threading/Pthreads.cpp | 2 +- lib/Threading/Win32.cpp | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/include/swift/Runtime/Atomic.h b/include/swift/Runtime/Atomic.h index 378fc8481cce9..e5509995d6cfc 100644 --- a/include/swift/Runtime/Atomic.h +++ b/include/swift/Runtime/Atomic.h @@ -20,6 +20,7 @@ #include "swift/Runtime/Config.h" #include #include +#include #if defined(_WIN64) #include #endif @@ -48,7 +49,7 @@ namespace impl { /// /// TODO: should we make this use non-atomic operations when the runtime /// is single-threaded? -template +template class alignas(Size) atomic_impl { std::atomic value; public: diff --git a/lib/Threading/C11.cpp b/lib/Threading/C11.cpp index 779e1dbacc5f6..d1f5b20b1c75a 100644 --- a/lib/Threading/C11.cpp +++ b/lib/Threading/C11.cpp @@ -16,7 +16,7 @@ #if SWIFT_THREADING_C11 -#include "swift/Threading/Impl/C11.h" +#include "swift/Threading/Impl.h" #include "swift/Threading/Errors.h" namespace { diff --git a/lib/Threading/Linux.cpp b/lib/Threading/Linux.cpp index 52a2c31b9b846..75875d32dd99c 100644 --- a/lib/Threading/Linux.cpp +++ b/lib/Threading/Linux.cpp @@ -16,7 +16,7 @@ #if SWIFT_THREADING_LINUX -#include "swift/Threading/Impl/Linux.h" +#include "swift/Threading/Impl.h" #include "swift/Threading/Errors.h" namespace { diff --git a/lib/Threading/Pthreads.cpp b/lib/Threading/Pthreads.cpp index 15e710c6877f0..2e3a899ba1963 100644 --- a/lib/Threading/Pthreads.cpp +++ b/lib/Threading/Pthreads.cpp @@ -20,7 +20,7 @@ #include #endif -#include "swift/Threading/Impl/Pthreads.h" +#include "swift/Threading/Impl.h" #include "swift/Threading/Errors.h" namespace { diff --git a/lib/Threading/Win32.cpp b/lib/Threading/Win32.cpp index 8771ed78c5010..4719290477902 100644 --- a/lib/Threading/Win32.cpp +++ b/lib/Threading/Win32.cpp @@ -21,7 +21,7 @@ #include #include "swift/Threading/Errors.h" -#include "swift/Threading/Impl/Win32.h" +#include "swift/Threading/Impl.h" namespace { From 6962758c8c08e0fe6947101b1deff292c16a38cf Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Tue, 24 May 2022 13:52:12 +0100 Subject: [PATCH 33/40] [Threading] Add the ability to use any C++ callable in swift::once(). This allows the use of C++ lambdas and functors, in addition to plain old functions. rdar://90776105 --- include/swift/Threading/Once.h | 11 +++++++++++ unittests/Threading/Once.cpp | 15 +++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/include/swift/Threading/Once.h b/include/swift/Threading/Once.h index 5471976a4ed17..4291126bb0610 100644 --- a/include/swift/Threading/Once.h +++ b/include/swift/Threading/Once.h @@ -31,6 +31,17 @@ inline void once(once_t &predicate, void (*fn)(void *), threading_impl::once_impl(predicate, fn, context); } +/// Executes the given callable exactly once. +/// The predicate argument must refer to a global or static variable of static +/// extent of type swift::once_t. +template +inline void once(once_t &predicate, const Callable &callable) { + once(predicate, [](void *ctx) { + const Callable &callable = *(const Callable*)(ctx); + callable(); + }, (void *)(&callable)); +} + } // namespace swift #endif // SWIFT_THREADING_ONCE_H diff --git a/unittests/Threading/Once.cpp b/unittests/Threading/Once.cpp index f4618169dfd8e..ecfd30fa5d523 100644 --- a/unittests/Threading/Once.cpp +++ b/unittests/Threading/Once.cpp @@ -71,3 +71,18 @@ TEST(OnceTest, once_threaded) { ASSERT_EQ(1u, callCount); } } + +// Check that swift::once works with a C++ lambda +TEST(OnceTest, once_lambda) { + static swift::once_t predicate; + unsigned callCount = 0; + + auto fn = [&callCount]() { + ++callCount; + }; + + swift::once(predicate, fn); + swift::once(predicate, fn); + + ASSERT_EQ(1u, callCount); +} From 668bcbce4fb6d84a8432ea7436be5eab046f7f43 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Tue, 24 May 2022 16:42:36 +0100 Subject: [PATCH 34/40] [Threading] Fix a few things following rebase. After rebasing, a few things broke. Fix them. rdar://90776105 --- stdlib/public/runtime/Bincompat.cpp | 7 ++++--- stdlib/toolchain/Compatibility50/CMakeLists.txt | 2 +- stdlib/toolchain/Compatibility51/CMakeLists.txt | 2 +- stdlib/toolchain/CompatibilityConcurrency/CMakeLists.txt | 2 +- .../CompatibilityDynamicReplacements/CMakeLists.txt | 2 +- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/stdlib/public/runtime/Bincompat.cpp b/stdlib/public/runtime/Bincompat.cpp index 31c1fef243c2c..40002e1807bf8 100644 --- a/stdlib/public/runtime/Bincompat.cpp +++ b/stdlib/public/runtime/Bincompat.cpp @@ -16,8 +16,9 @@ #include "swift/Runtime/Config.h" #include "swift/Runtime/Bincompat.h" -#include "swift/Runtime/Once.h" +#include "swift/Runtime/Debug.h" #include "swift/Runtime/EnvironmentVariables.h" +#include "swift/Threading/Once.h" #include "../SwiftShims/RuntimeShims.h" #include @@ -96,8 +97,8 @@ static void checkBinCompatEnvironmentVariable(void *context) { extern "C" __swift_bool _swift_stdlib_isExecutableLinkedOnOrAfter( _SwiftStdlibVersion version ) { - static OnceToken_t getenvToken; - SWIFT_ONCE_F(getenvToken, checkBinCompatEnvironmentVariable, nullptr); + static once_t getenvToken; + swift::once(getenvToken, checkBinCompatEnvironmentVariable, nullptr); if (binCompatVersionOverride._value > 0) { return version._value <= binCompatVersionOverride._value; diff --git a/stdlib/toolchain/Compatibility50/CMakeLists.txt b/stdlib/toolchain/Compatibility50/CMakeLists.txt index c12446f9110d3..43cc1efc1ba4e 100644 --- a/stdlib/toolchain/Compatibility50/CMakeLists.txt +++ b/stdlib/toolchain/Compatibility50/CMakeLists.txt @@ -8,7 +8,7 @@ add_swift_target_library("${library_name}" STATIC C_COMPILE_FLAGS ${CXX_COMPILE_FLAGS} LINK_FLAGS ${CXX_LINK_FLAGS} - INCORPORATE_OBJECT_LIBRARIES swiftThreadingWithFatal + INCORPORATE_OBJECT_LIBRARIES swiftThreading SWIFT_COMPILE_FLAGS ${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS} DEPLOYMENT_VERSION_OSX ${COMPATIBILITY_MINIMUM_DEPLOYMENT_VERSION_OSX} DEPLOYMENT_VERSION_IOS ${COMPATIBILITY_MINIMUM_DEPLOYMENT_VERSION_IOS} diff --git a/stdlib/toolchain/Compatibility51/CMakeLists.txt b/stdlib/toolchain/Compatibility51/CMakeLists.txt index a6df604936207..90d11bea1f6f8 100644 --- a/stdlib/toolchain/Compatibility51/CMakeLists.txt +++ b/stdlib/toolchain/Compatibility51/CMakeLists.txt @@ -9,7 +9,7 @@ add_swift_target_library("${library_name}" STATIC C_COMPILE_FLAGS ${CXX_COMPILE_FLAGS} LINK_FLAGS ${CXX_LINK_FLAGS} - INCORPORATE_OBJECT_LIBRARIES swiftThreadingWithFatal + INCORPORATE_OBJECT_LIBRARIES swiftThreading SWIFT_COMPILE_FLAGS ${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS} DEPLOYMENT_VERSION_OSX ${COMPATIBILITY_MINIMUM_DEPLOYMENT_VERSION_OSX} DEPLOYMENT_VERSION_IOS ${COMPATIBILITY_MINIMUM_DEPLOYMENT_VERSION_IOS} diff --git a/stdlib/toolchain/CompatibilityConcurrency/CMakeLists.txt b/stdlib/toolchain/CompatibilityConcurrency/CMakeLists.txt index 6bb2590bde853..33227ebc88e0d 100644 --- a/stdlib/toolchain/CompatibilityConcurrency/CMakeLists.txt +++ b/stdlib/toolchain/CompatibilityConcurrency/CMakeLists.txt @@ -7,7 +7,7 @@ add_swift_target_library("${library_name}" STATIC C_COMPILE_FLAGS ${CXX_COMPILE_FLAGS} LINK_FLAGS ${CXX_LINK_FLAGS} - INCORPORATE_OBJECT_LIBRARIES swiftThreadingWithFatal + INCORPORATE_OBJECT_LIBRARIES swiftThreading SWIFT_COMPILE_FLAGS ${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS} DEPLOYMENT_VERSION_OSX ${COMPATIBILITY_MINIMUM_DEPLOYMENT_VERSION_OSX} DEPLOYMENT_VERSION_IOS ${COMPATIBILITY_MINIMUM_DEPLOYMENT_VERSION_IOS} diff --git a/stdlib/toolchain/CompatibilityDynamicReplacements/CMakeLists.txt b/stdlib/toolchain/CompatibilityDynamicReplacements/CMakeLists.txt index 7448ab47add54..b8322103dafa5 100644 --- a/stdlib/toolchain/CompatibilityDynamicReplacements/CMakeLists.txt +++ b/stdlib/toolchain/CompatibilityDynamicReplacements/CMakeLists.txt @@ -7,7 +7,7 @@ add_swift_target_library("${library_name}" STATIC C_COMPILE_FLAGS ${CXX_COMPILE_FLAGS} LINK_FLAGS ${CXX_LINK_FLAGS} - INCORPORATE_OBJECT_LIBRARIES swiftThreadingWithFatal + INCORPORATE_OBJECT_LIBRARIES swiftThreading SWIFT_COMPILE_FLAGS ${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS} DEPLOYMENT_VERSION_OSX ${COMPATIBILITY_MINIMUM_DEPLOYMENT_VERSION_OSX} DEPLOYMENT_VERSION_IOS ${COMPATIBILITY_MINIMUM_DEPLOYMENT_VERSION_IOS} From c401cc34fd7d58b9bce88e51fff3ab2857b5c623 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Tue, 24 May 2022 17:46:33 +0100 Subject: [PATCH 35/40] [Threading] Use llvm::Optional<> rather than making a zero lower bound special. While most systems aren't going to have their stack bottom at zero, using llvm::Optional<> here is cleaner. rdar://90776105 --- include/swift/Threading/Impl/C11.h | 8 +++++--- include/swift/Threading/Impl/Darwin.h | 4 +++- include/swift/Threading/Impl/Linux.h | 5 ++++- include/swift/Threading/Impl/Nothreads.h | 7 ++++--- include/swift/Threading/Impl/Pthreads.h | 4 +++- include/swift/Threading/Impl/Win32.h | 4 +++- include/swift/Threading/Thread.h | 4 +++- lib/Threading/Linux.cpp | 12 +++++++----- lib/Threading/Pthreads.cpp | 24 +++++++++++++----------- lib/Threading/Win32.cpp | 2 +- stdlib/public/stubs/Stubs.cpp | 9 +++++---- 11 files changed, 51 insertions(+), 32 deletions(-) diff --git a/include/swift/Threading/Impl/C11.h b/include/swift/Threading/Impl/C11.h index 6d609ea71876c..40782c233f714 100644 --- a/include/swift/Threading/Impl/C11.h +++ b/include/swift/Threading/Impl/C11.h @@ -19,8 +19,11 @@ #include #include + #include +#include "llvm/ADT/Optional.h" + #include "swift/Threading/Errors.h" namespace swift { @@ -55,9 +58,8 @@ bool thread_is_main(); inline bool threads_same(thread_id a, thread_id b) { return ::thrd_equal(a, b); } -inline stack_bounds thread_get_current_stack_bounds() { - stack_bounds zero = { nullptr, nullptr }; - return zero; +inline llvm::Optional thread_get_current_stack_bounds() { + return {}; } // .. Mutex support .......................................................... diff --git a/include/swift/Threading/Impl/Darwin.h b/include/swift/Threading/Impl/Darwin.h index ca30c683e53fd..cdbb90c4a89cb 100644 --- a/include/swift/Threading/Impl/Darwin.h +++ b/include/swift/Threading/Impl/Darwin.h @@ -21,6 +21,8 @@ #include #include +#include "llvm/ADT/Optional.h" + #include "swift/Threading/Errors.h" namespace swift { @@ -38,7 +40,7 @@ inline bool threads_same(thread_id a, thread_id b) { return ::pthread_equal(a, b); } -inline stack_bounds thread_get_current_stack_bounds() { +inline llvm::Optional thread_get_current_stack_bounds() { stack_bounds result; pthread_t thread = pthread_self(); diff --git a/include/swift/Threading/Impl/Linux.h b/include/swift/Threading/Impl/Linux.h index 63cf2902e0a78..f631dc9fb4061 100644 --- a/include/swift/Threading/Impl/Linux.h +++ b/include/swift/Threading/Impl/Linux.h @@ -21,6 +21,9 @@ #include #include +#include + +#include "llvm/ADT/Optional.h" #include "swift/Threading/Errors.h" @@ -61,7 +64,7 @@ inline bool threads_same(thread_id a, thread_id b) { return ::pthread_equal(a, b); } -stack_bounds thread_get_current_stack_bounds(); +llvm::Optional thread_get_current_stack_bounds(); // .. Mutex support .......................................................... diff --git a/include/swift/Threading/Impl/Nothreads.h b/include/swift/Threading/Impl/Nothreads.h index 84d1d8d171fce..576f1e2f87dad 100644 --- a/include/swift/Threading/Impl/Nothreads.h +++ b/include/swift/Threading/Impl/Nothreads.h @@ -17,6 +17,8 @@ #ifndef SWIFT_THREADING_IMPL_NOTHREADS_H #define SWIFT_THREADING_IMPL_NOTHREADS_H +#include "llvm/ADT/Optional.h" + namespace swift { namespace threading_impl { @@ -27,9 +29,8 @@ using thread_id = unsigned; inline thread_id thread_get_current() { return 0; } inline bool thread_is_main() { return true; } inline bool threads_same(thread_id a, thread_id b) { return a == b; } -inline stack_bounds thread_get_current_stack_bounds() { - stack_bounds zero = { nullptr, nullptr }; - return zero; +inline llvm::Optional thread_get_current_stack_bounds() { + return {}; } // .. Mutex support .......................................................... diff --git a/include/swift/Threading/Impl/Pthreads.h b/include/swift/Threading/Impl/Pthreads.h index 3fd636760d279..09dd4816b9b3a 100644 --- a/include/swift/Threading/Impl/Pthreads.h +++ b/include/swift/Threading/Impl/Pthreads.h @@ -23,6 +23,8 @@ #include #include +#include "llvm/ADT/Optional.h" + #include "swift/Threading/Errors.h" namespace swift { @@ -60,7 +62,7 @@ inline bool threads_same(thread_id a, thread_id b) { return ::pthread_equal(a, b); } -stack_bounds thread_get_current_stack_bounds(); +llvm::Optional thread_get_current_stack_bounds(); // .. Mutex support .......................................................... diff --git a/include/swift/Threading/Impl/Win32.h b/include/swift/Threading/Impl/Win32.h index cd18e0d2f086c..8ae8cc181defd 100644 --- a/include/swift/Threading/Impl/Win32.h +++ b/include/swift/Threading/Impl/Win32.h @@ -21,6 +21,8 @@ #include +#include "llvm/ADT/Optional.h" + namespace swift { namespace threading_impl { @@ -31,7 +33,7 @@ using thread_id = ::DWORD; inline thread_id thread_get_current() { return ::GetCurrentThreadId(); } bool thread_is_main(); inline bool threads_same(thread_id a, thread_id b) { return a == b; } -stack_bounds thread_get_current_stack_bounds(); +llvm::Optional thread_get_current_stack_bounds(); // .. Mutex support .......................................................... diff --git a/include/swift/Threading/Thread.h b/include/swift/Threading/Thread.h index 1d09c8d79c192..ecf96ef82429e 100644 --- a/include/swift/Threading/Thread.h +++ b/include/swift/Threading/Thread.h @@ -19,6 +19,8 @@ #ifndef SWIFT_THREADING_THREAD_H #define SWIFT_THREADING_THREAD_H +#include "llvm/ADT/Optional.h" + #include "Impl.h" namespace swift { @@ -68,7 +70,7 @@ class Thread { } // Retrieve the bounds of the current thread's stack - static StackBounds stackBounds() { + static llvm::Optional stackBounds() { return threading_impl::thread_get_current_stack_bounds(); } }; diff --git a/lib/Threading/Linux.cpp b/lib/Threading/Linux.cpp index 75875d32dd99c..0a9876ece908f 100644 --- a/lib/Threading/Linux.cpp +++ b/lib/Threading/Linux.cpp @@ -57,23 +57,25 @@ void swift::threading_impl::once_slow(once_t &predicate, void (*fn)(void *), linux::ulock_unlock(&predicate.lock); } -swift::threading_impl::stack_bounds +llvm::Optional swift::threading_impl::thread_get_current_stack_bounds() { - stack_bounds result = { nullptr, nullptr }; pthread_attr_t attr; size_t size = 0; void *begin = nullptr; if (!pthread_getattr_np(pthread_self(), &attr)) { if (!pthread_attr_getstack(&attr, &begin, &size)) { - result.low = begin; - result.high = (char *)begin + size; + stack_bounds result = { begin, (char *)begin + size }; + + pthread_attr_destroy(&attr); + + return result; } pthread_attr_destroy(&attr); } - return result; + return {}; } #endif // SWIFT_THREADING_LINUX diff --git a/lib/Threading/Pthreads.cpp b/lib/Threading/Pthreads.cpp index 2e3a899ba1963..21f34f86953e8 100644 --- a/lib/Threading/Pthreads.cpp +++ b/lib/Threading/Pthreads.cpp @@ -77,41 +77,43 @@ void swift::threading_impl::once_slow(once_t &predicate, void (*fn)(void *), } #if defined(__OpenBSD__) -swift::threading_impl::stack_bounds +llvm::Optional swift::threading_impl::thread_get_current_stack_bounds() { - stack_bounds result = { nullptr, nullptr }; stack_t sinfo; if (!pthread_stackseg_np(pthread_self(), &sinfo)) { - result.low = (char *)sinfo.ss_sp - sinfo.ss_size; - result.high = sinfo.ss_sp; + stack_bounds result = { + (char *)sinfo.ss_sp - sinfo.ss_size, + sinfo.ss_sp + }; + return result; } - return result; + return {}; } #else -swift::threading_impl::stack_bounds +llvm::Optional swift::threading_impl::thread_get_current_stack_bounds() { - stack_bounds result = { nullptr, nullptr }; pthread_attr_t attr; size_t size = 0; void *begin = nullptr; #if defined(__FreeBSD__) if (pthread_attr_init(&attr)) - return result; + return {}; #endif if (!pthread_getattr_np(pthread_self(), &attr)) { if (!pthread_attr_getstack(&attr, &begin, &size)) { - result.low = begin; - result.high = (char *)begin + size; + stack_bounds result = { begin, (char *)begin + size }; + pthread_attr_destroy(&attr); + return result; } pthread_attr_destroy(&attr); } - return result; + return {}; } #endif diff --git a/lib/Threading/Win32.cpp b/lib/Threading/Win32.cpp index 4719290477902..a1fb7a3e7636b 100644 --- a/lib/Threading/Win32.cpp +++ b/lib/Threading/Win32.cpp @@ -97,7 +97,7 @@ void swift::threading_impl::once_slow(once_t &predicate, void (*fn)(void *), #endif } -swift::threading_impl::stack_bounds +llvm::Optional swift::threading_impl::thread_get_current_stack_bounds() { #if _WIN32_WINNT >= 0x0602 ULONG_PTR lowLimit = 0; diff --git a/stdlib/public/stubs/Stubs.cpp b/stdlib/public/stubs/Stubs.cpp index 5af7e9b5c504c..fe734ea08cdfb 100644 --- a/stdlib/public/stubs/Stubs.cpp +++ b/stdlib/public/stubs/Stubs.cpp @@ -535,10 +535,11 @@ __swift_bool swift_stdlib_isStackAllocationSafe(__swift_size_t byteCount, __swift_bool _swift_stdlib_getCurrentStackBounds(__swift_uintptr_t *outBegin, __swift_uintptr_t *outEnd) { - swift::Thread::StackBounds bounds = swift::Thread::stackBounds(); - if (!bounds.low) + llvm::Optional bounds = + swift::Thread::stackBounds(); + if (!bounds) return false; - *outBegin = (uintptr_t)bounds.low; - *outEnd = (uintptr_t)bounds.high; + *outBegin = (uintptr_t)bounds->low; + *outEnd = (uintptr_t)bounds->high; return true; } From 33f103f03e1d6fc7d9678a7b8623f62442a3ebc5 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Tue, 31 May 2022 16:08:20 +0100 Subject: [PATCH 36/40] [Build] Fix some issues with the standalone library build. When we're building static libraries, we don't need to include the threading objects in both Concurrency and Core, and we also don't need two copies of the threading library's fatal error handler. rdar://90776105 --- stdlib/public/Concurrency/CMakeLists.txt | 14 ++++++++++++-- stdlib/public/Concurrency/Error.cpp | 2 ++ stdlib/public/core/CMakeLists.txt | 3 ++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/stdlib/public/Concurrency/CMakeLists.txt b/stdlib/public/Concurrency/CMakeLists.txt index 433293ea4171e..639be3d381db7 100644 --- a/stdlib/public/Concurrency/CMakeLists.txt +++ b/stdlib/public/Concurrency/CMakeLists.txt @@ -25,11 +25,16 @@ endif() set(SWIFT_RUNTIME_CONCURRENCY_C_FLAGS) set(SWIFT_RUNTIME_CONCURRENCY_SWIFT_FLAGS) -set(swift_concurrency_private_link_libraries swiftThreading) +set(swift_concurrency_private_link_libraries) if(CMAKE_SYSTEM_NAME STREQUAL Windows) list(APPEND swift_concurrency_private_link_libraries Synchronization) endif() +set(swift_concurrency_incorporate_object_libraries) +if(NOT SWIFT_BUILD_STATIC_STDLIB) + list(APPEND swift_concurrency_incorporate_object_libraries swiftThreading) +endif() + if("${SWIFT_CONCURRENCY_GLOBAL_EXECUTOR}" STREQUAL "dispatch") if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin) include_directories(AFTER @@ -72,6 +77,11 @@ endif() list(APPEND SWIFT_RUNTIME_CONCURRENCY_C_FLAGS "-D__STDC_WANT_LIB_EXT1__=1") +if(SWIFT_BUILD_STATIC_STDLIB) + list(APPEND SWIFT_RUNTIME_CONCURRENCY_C_FLAGS + "-DSWIFT_BUILD_STATIC_STDLIB=1") +endif() + add_swift_target_library(swift_Concurrency ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS_STDLIB ../CompatibilityOverride/CompatibilityOverride.cpp Actor.cpp @@ -132,7 +142,7 @@ add_swift_target_library(swift_Concurrency ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} I SWIFT_MODULE_DEPENDS_WINDOWS CRT PRIVATE_LINK_LIBRARIES ${swift_concurrency_private_link_libraries} - + INCORPORATE_OBJECT_LIBRARIES ${swift_concurrency_incorporate_object_libraries} LINK_LIBRARIES ${swift_concurrency_link_libraries} C_COMPILE_FLAGS diff --git a/stdlib/public/Concurrency/Error.cpp b/stdlib/public/Concurrency/Error.cpp index 7a1983a295779..f297c385eae09 100644 --- a/stdlib/public/Concurrency/Error.cpp +++ b/stdlib/public/Concurrency/Error.cpp @@ -35,6 +35,7 @@ void swift::swift_Concurrency_fatalError(uint32_t flags, const char *format, swift_Concurrency_fatalErrorv(flags, format, val); } +#if !SWIFT_BUILD_STATIC_STDLIB // Handle fatal errors from the threading library SWIFT_ATTRIBUTE_NORETURN SWIFT_FORMAT(1, 2) @@ -44,3 +45,4 @@ void swift::threading::fatal(const char *format, ...) { va_start(val, format); swift_Concurrency_fatalErrorv(0, format, val); } +#endif // !SWIFT_BUILD_STATIC_STDLIB diff --git a/stdlib/public/core/CMakeLists.txt b/stdlib/public/core/CMakeLists.txt index 3f983d5dc3812..3c457451fdca6 100644 --- a/stdlib/public/core/CMakeLists.txt +++ b/stdlib/public/core/CMakeLists.txt @@ -245,7 +245,7 @@ endif() set(GROUP_INFO_JSON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/GroupInfo.json) set(swift_core_link_flags "${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}") set(swift_core_framework_depends) -set(swift_core_private_link_libraries swiftThreading) +set(swift_core_private_link_libraries) set(swift_stdlib_compile_flags "${SWIFT_RUNTIME_SWIFT_COMPILE_FLAGS}") if(SWIFT_PRIMARY_VARIANT_SDK STREQUAL CYGWIN) @@ -299,6 +299,7 @@ list(APPEND swift_core_incorporate_object_libraries swiftRuntime) list(APPEND swift_core_incorporate_object_libraries swiftLLVMSupport) list(APPEND swift_core_incorporate_object_libraries swiftDemangling) list(APPEND swift_core_incorporate_object_libraries swiftStdlibStubs) +list(APPEND swift_core_incorporate_object_libraries swiftThreading) if(SWIFT_STDLIB_HAS_COMMANDLINE) list(APPEND swift_core_incorporate_object_libraries swiftCommandLineSupport) endif() From 124581a8105e1b3093b4c5db57703523bd057d88 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Wed, 1 Jun 2022 13:25:48 +0100 Subject: [PATCH 37/40] [Build][Concurrency] Fix Concurrency build to work for Linux. `SWIFT_BUILD_STATIC_STDLIB` is not mutually exclusive with `SWIFT_BUILD_DYNAMIC_STDLIB`, and Linux sets both, so we can't use `SWIFT_BUILD_STATIC_STDLIB` to conditionalise things. The linker error about duplicate definitions for the threading error handler was happening because we were forced to include the object containing that symbol; moving it to another object should fix that. And it turns out there's a way to get CMake to include the threading object library only when building a shared object, so use that too. rdar://90776105 --- stdlib/public/Concurrency/CMakeLists.txt | 14 +++-------- stdlib/public/Concurrency/Error.cpp | 12 --------- stdlib/public/Concurrency/ThreadingError.cpp | 26 ++++++++++++++++++++ 3 files changed, 30 insertions(+), 22 deletions(-) create mode 100644 stdlib/public/Concurrency/ThreadingError.cpp diff --git a/stdlib/public/Concurrency/CMakeLists.txt b/stdlib/public/Concurrency/CMakeLists.txt index 639be3d381db7..d41069b01546a 100644 --- a/stdlib/public/Concurrency/CMakeLists.txt +++ b/stdlib/public/Concurrency/CMakeLists.txt @@ -30,10 +30,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL Windows) list(APPEND swift_concurrency_private_link_libraries Synchronization) endif() -set(swift_concurrency_incorporate_object_libraries) -if(NOT SWIFT_BUILD_STATIC_STDLIB) - list(APPEND swift_concurrency_incorporate_object_libraries swiftThreading) -endif() +set(swift_concurrency_incorporate_object_libraries_so swiftThreading) if("${SWIFT_CONCURRENCY_GLOBAL_EXECUTOR}" STREQUAL "dispatch") if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin) @@ -77,11 +74,6 @@ endif() list(APPEND SWIFT_RUNTIME_CONCURRENCY_C_FLAGS "-D__STDC_WANT_LIB_EXT1__=1") -if(SWIFT_BUILD_STATIC_STDLIB) - list(APPEND SWIFT_RUNTIME_CONCURRENCY_C_FLAGS - "-DSWIFT_BUILD_STATIC_STDLIB=1") -endif() - add_swift_target_library(swift_Concurrency ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS_STDLIB ../CompatibilityOverride/CompatibilityOverride.cpp Actor.cpp @@ -125,6 +117,7 @@ add_swift_target_library(swift_Concurrency ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} I TaskLocal.swift TaskSleep.swift ThreadSanitizer.cpp + ThreadingError.cpp TracingSignpost.cpp AsyncStreamBuffer.swift AsyncStream.swift @@ -142,7 +135,8 @@ add_swift_target_library(swift_Concurrency ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} I SWIFT_MODULE_DEPENDS_WINDOWS CRT PRIVATE_LINK_LIBRARIES ${swift_concurrency_private_link_libraries} - INCORPORATE_OBJECT_LIBRARIES ${swift_concurrency_incorporate_object_libraries} + INCORPORATE_OBJECT_LIBRARIES_SHARED_ONLY + ${swift_concurrency_incorporate_object_libraries_so} LINK_LIBRARIES ${swift_concurrency_link_libraries} C_COMPILE_FLAGS diff --git a/stdlib/public/Concurrency/Error.cpp b/stdlib/public/Concurrency/Error.cpp index f297c385eae09..fa427552853f0 100644 --- a/stdlib/public/Concurrency/Error.cpp +++ b/stdlib/public/Concurrency/Error.cpp @@ -34,15 +34,3 @@ void swift::swift_Concurrency_fatalError(uint32_t flags, const char *format, va_start(val, format); swift_Concurrency_fatalErrorv(flags, format, val); } - -#if !SWIFT_BUILD_STATIC_STDLIB -// Handle fatal errors from the threading library -SWIFT_ATTRIBUTE_NORETURN -SWIFT_FORMAT(1, 2) -void swift::threading::fatal(const char *format, ...) { - va_list val; - - va_start(val, format); - swift_Concurrency_fatalErrorv(0, format, val); -} -#endif // !SWIFT_BUILD_STATIC_STDLIB diff --git a/stdlib/public/Concurrency/ThreadingError.cpp b/stdlib/public/Concurrency/ThreadingError.cpp new file mode 100644 index 0000000000000..512bd1128beca --- /dev/null +++ b/stdlib/public/Concurrency/ThreadingError.cpp @@ -0,0 +1,26 @@ +//===--- ThreadingError.cpp - Error handling support code -----------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "swift/Threading/Errors.h" +#include + +#include "Error.h" + +// Handle fatal errors from the threading library +SWIFT_ATTRIBUTE_NORETURN +SWIFT_FORMAT(1, 2) +void swift::threading::fatal(const char *format, ...) { + va_list val; + + va_start(val, format); + swift_Concurrency_fatalErrorv(0, format, val); +} From aa0265b03ed5cac1513b4004bdc617740b2b7859 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 2 Jun 2022 06:25:37 +0000 Subject: [PATCH 38/40] [Threading] Use raw gettid syscall for older glibc compatibility `gettid` wrapper was added in glibc 2.30, and Ubuntu 18.04 uses glibc 2.27, so use raw syscall instead of it. --- include/swift/Threading/Impl/Linux/ulock.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/swift/Threading/Impl/Linux/ulock.h b/include/swift/Threading/Impl/Linux/ulock.h index 1219c52a1d91b..a9020965ec5d4 100644 --- a/include/swift/Threading/Impl/Linux/ulock.h +++ b/include/swift/Threading/Impl/Linux/ulock.h @@ -46,7 +46,7 @@ typedef std::int32_t ulock_t; inline int ulock_get_tid(void) { static __thread int tid; if (tid == 0) - tid = gettid(); + tid = syscall(SYS_gettid); return tid; } From c46d4af0e99a865989097905494afc1ae8a2e9e3 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Mon, 6 Jun 2022 22:50:07 +0100 Subject: [PATCH 39/40] [Build] Explicitly include threading library when not building stdlib. The threading code is required by some of the compatibility modules, but we weren't pulling it in unless we were building the standard library. That breaks the build when the standard library build is disabled, so explicitly include it. rdar://90776105 --- CMakeLists.txt | 3 +++ stdlib/public/Threading/CMakeLists.txt | 3 +++ 2 files changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index ec702f0b7e39b..830cd631038bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1126,6 +1126,9 @@ endif() if(SWIFT_BUILD_STDLIB) add_subdirectory(stdlib) else() + # Some of the things below depend on the threading library + add_subdirectory(stdlib/public/Threading) + if(SWIFT_BUILD_STDLIB_EXTRA_TOOLCHAIN_CONTENT) add_subdirectory(stdlib/toolchain) endif() diff --git a/stdlib/public/Threading/CMakeLists.txt b/stdlib/public/Threading/CMakeLists.txt index 8ff2d19825939..e6f193bd01074 100644 --- a/stdlib/public/Threading/CMakeLists.txt +++ b/stdlib/public/Threading/CMakeLists.txt @@ -1,6 +1,9 @@ # This is the counterpart to lib/Threading/CMakeLists.txt. Any updates # need to be reflected in both places. +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules") +include(AddSwiftStdlib) + add_swift_target_library(swiftThreading OBJECT_LIBRARY "${SWIFT_SOURCE_DIR}/lib/Threading/C11.cpp" "${SWIFT_SOURCE_DIR}/lib/Threading/Linux.cpp" From ede4010cc36110b385aef392b0bde4cbb26955f4 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Tue, 7 Jun 2022 15:45:36 +0100 Subject: [PATCH 40/40] [BackDeployConcurrency] Fix to use the new threading library. A copy of the older Concurrency sources was just added to BackDeployConcurrency, replacing the `add_subdirectory(../Concurrency)` trick it was using previously. These need to be adjusted to work with the threading library. Fortunately, the necessary adjustments are the same as those required for the existing Concurrency library, give or take. rdar://90776105 --- stdlib/public/BackDeployConcurrency/Actor.cpp | 82 ++++++------------- .../public/BackDeployConcurrency/AsyncLet.cpp | 3 +- .../BackDeployConcurrency/AsyncStream.cpp | 22 ++--- .../BackDeployConcurrency/CMakeLists.txt | 5 +- .../{Mutex.cpp => ConditionVariable.cpp} | 54 +++++++++--- .../BackDeployConcurrency/ConditionVariable.h | 2 +- .../DispatchGlobalExecutor.inc | 2 +- stdlib/public/BackDeployConcurrency/Error.cpp | 19 ++++- stdlib/public/BackDeployConcurrency/Error.h | 10 ++- .../BackDeployConcurrency/Executor.swift | 2 +- stdlib/public/BackDeployConcurrency/Task.cpp | 2 +- .../BackDeployConcurrency/TaskGroup.cpp | 4 +- .../BackDeployConcurrency/TaskLocal.cpp | 23 ++---- .../BackDeployConcurrency/TaskPrivate.h | 19 +---- .../BackDeployConcurrency/TaskStatus.cpp | 6 +- .../BackDeployConcurrency/ThreadingError.cpp | 26 ++++++ 16 files changed, 154 insertions(+), 127 deletions(-) rename stdlib/public/BackDeployConcurrency/{Mutex.cpp => ConditionVariable.cpp} (54%) create mode 100644 stdlib/public/BackDeployConcurrency/ThreadingError.cpp diff --git a/stdlib/public/BackDeployConcurrency/Actor.cpp b/stdlib/public/BackDeployConcurrency/Actor.cpp index c14628bfd445c..31722e4c8c658 100644 --- a/stdlib/public/BackDeployConcurrency/Actor.cpp +++ b/stdlib/public/BackDeployConcurrency/Actor.cpp @@ -17,22 +17,14 @@ #include "ConcurrencyRuntime.h" -#ifdef _WIN32 -// On Windows, an include below triggers an indirect include of minwindef.h -// which contains a definition of the `max` macro, generating an error in our -// use of std::max in this file. This define prevents those macros from being -// defined. -#define NOMINMAX -#endif - #include "CompatibilityOverride.h" +#include "swift/Basic/ListMerger.h" #include "swift/Runtime/Atomic.h" #include "swift/Runtime/Casting.h" -#include "swift/Runtime/Once.h" -#include "swift/Runtime/Mutex.h" -#include "swift/Runtime/ThreadLocal.h" -#include "swift/Runtime/ThreadLocalStorage.h" -#include "swift/Basic/ListMerger.h" +#include "swift/Threading/Once.h" +#include "swift/Threading/Mutex.h" +#include "swift/Threading/Thread.h" +#include "swift/Threading/ThreadLocalStorage.h" #ifndef SWIFT_CONCURRENCY_BACK_DEPLOYMENT #include "llvm/Config/config.h" #else @@ -71,19 +63,8 @@ #include #endif -#if HAVE_PTHREAD_H -#include - -// Only use __has_include since HAVE_PTHREAD_NP_H is not provided. -#if __has_include() -#include -#endif -#endif - #if defined(_WIN32) #include -#include -#include #endif #if SWIFT_OBJC_INTEROP @@ -129,9 +110,9 @@ class ExecutorTrackingInfo { /// the right executor. It would make sense for that to be a /// separate thread-local variable (or whatever is most efficient /// on the target platform). - static SWIFT_RUNTIME_DECLARE_THREAD_LOCAL( - Pointer, ActiveInfoInThread, - SWIFT_CONCURRENCY_EXECUTOR_TRACKING_INFO_KEY); + static SWIFT_THREAD_LOCAL_TYPE(Pointer, + tls_key::concurrency_executor_tracking_info) + ActiveInfoInThread; /// The active executor. ExecutorRef ActiveExecutor = ExecutorRef::generic(); @@ -154,7 +135,7 @@ class ExecutorTrackingInfo { /// Unconditionally initialize a fresh tracking state on the /// current state, shadowing any previous tracking state. - /// leave() must be called beforet the object goes out of scope. + /// leave() must be called before the object goes out of scope. void enterAndShadow(ExecutorRef currentExecutor) { ActiveExecutor = currentExecutor; SavedInfo = ActiveInfoInThread.get(); @@ -197,8 +178,8 @@ class ExecutorTrackingInfo { class ActiveTask { /// A thread-local variable pointing to the active tracking /// information about the current thread, if any. - static SWIFT_RUNTIME_DECLARE_THREAD_LOCAL(Pointer, Value, - SWIFT_CONCURRENCY_TASK_KEY); + static SWIFT_THREAD_LOCAL_TYPE(Pointer, + tls_key::concurrency_task) Value; public: static void set(AsyncTask *task) { Value.set(task); } @@ -206,15 +187,12 @@ class ActiveTask { }; /// Define the thread-locals. -SWIFT_RUNTIME_DECLARE_THREAD_LOCAL( - Pointer, - ActiveTask::Value, - SWIFT_CONCURRENCY_TASK_KEY); +SWIFT_THREAD_LOCAL_TYPE(Pointer, tls_key::concurrency_task) +ActiveTask::Value; -SWIFT_RUNTIME_DECLARE_THREAD_LOCAL( - Pointer, - ExecutorTrackingInfo::ActiveInfoInThread, - SWIFT_CONCURRENCY_EXECUTOR_TRACKING_INFO_KEY); +SWIFT_THREAD_LOCAL_TYPE(Pointer, + tls_key::concurrency_executor_tracking_info) +ExecutorTrackingInfo::ActiveInfoInThread; } // end anonymous namespace @@ -238,7 +216,7 @@ void swift::runJobInEstablishedExecutorContext(Job *job) { task->runInFullyEstablishedContext(); assert(ActiveTask::get() == nullptr && - "active task wasn't cleared before susspending?"); + "active task wasn't cleared before suspending?"); } else { // There's no extra bookkeeping to do for simple jobs besides swapping in // the voucher. @@ -281,30 +259,20 @@ static ExecutorRef swift_task_getCurrentExecutorImpl() { return result; } -#if defined(_WIN32) -static HANDLE __initialPthread = INVALID_HANDLE_VALUE; -#endif - /// Determine whether we are currently executing on the main thread /// independently of whether we know that we are on the main actor. static bool isExecutingOnMainThread() { -#if defined(__linux__) - return syscall(SYS_gettid) == getpid(); -#elif defined(_WIN32) - if (__initialPthread == INVALID_HANDLE_VALUE) { - DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), - GetCurrentProcess(), &__initialPthread, 0, FALSE, - DUPLICATE_SAME_ACCESS); - } - - return __initialPthread == GetCurrentThread(); +#if SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY + return true; #else - return pthread_main_np() == 1; + return Thread::onMainThread(); #endif } JobPriority swift::swift_task_getCurrentThreadPriority() { -#if defined(__APPLE__) +#if SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY + return JobPriority::UserInitiated; +#elif defined(__APPLE__) return static_cast(qos_class_self()); #else if (isExecutingOnMainThread()) @@ -344,8 +312,8 @@ void swift::swift_task_reportUnexpectedExecutor( const unsigned char *file, uintptr_t fileLength, bool fileIsASCII, uintptr_t line, ExecutorRef executor) { // Make sure we have an appropriate log level. - static swift_once_t logLevelToken; - swift_once(&logLevelToken, checkUnexpectedExecutorLogLevel, nullptr); + static swift::once_t logLevelToken; + swift::once(logLevelToken, checkUnexpectedExecutorLogLevel, nullptr); bool isFatalError = false; switch (unexpectedExecutorLogLevel) { diff --git a/stdlib/public/BackDeployConcurrency/AsyncLet.cpp b/stdlib/public/BackDeployConcurrency/AsyncLet.cpp index 048ed25c16a51..e994e08b6dd30 100644 --- a/stdlib/public/BackDeployConcurrency/AsyncLet.cpp +++ b/stdlib/public/BackDeployConcurrency/AsyncLet.cpp @@ -17,8 +17,9 @@ #include "CompatibilityOverride.h" #include "ConcurrencyRuntime.h" #include "swift/ABI/Metadata.h" -#include "swift/Runtime/Mutex.h" +#include "swift/Runtime/Heap.h" #include "swift/Runtime/HeapObject.h" +#include "swift/Threading/Mutex.h" #include "llvm/ADT/PointerIntPair.h" #include "AsyncLet.h" #include "Debug.h" diff --git a/stdlib/public/BackDeployConcurrency/AsyncStream.cpp b/stdlib/public/BackDeployConcurrency/AsyncStream.cpp index 14b7caf0ad463..389ebd3d7389a 100644 --- a/stdlib/public/BackDeployConcurrency/AsyncStream.cpp +++ b/stdlib/public/BackDeployConcurrency/AsyncStream.cpp @@ -10,30 +10,24 @@ // //===----------------------------------------------------------------------===// -#include "swift/Runtime/Mutex.h" +#include + +#include "swift/Threading/Mutex.h" namespace swift { // return the size in words for the given mutex primitive extern "C" size_t _swift_async_stream_lock_size() { - size_t words = sizeof(MutexHandle) / sizeof(void *); + size_t words = sizeof(Mutex) / sizeof(void *); if (words < 1) { return 1; } return words; } -extern "C" -void _swift_async_stream_lock_init(MutexHandle &lock) { - MutexPlatformHelper::init(lock); +extern "C" void _swift_async_stream_lock_init(Mutex &lock) { + new (&lock) Mutex(); } -extern "C" -void _swift_async_stream_lock_lock(MutexHandle &lock) { - MutexPlatformHelper::lock(lock); -} - -extern "C" -void _swift_async_stream_lock_unlock(MutexHandle &lock) { - MutexPlatformHelper::unlock(lock); -} +extern "C" void _swift_async_stream_lock_lock(Mutex &lock) { lock.lock(); } +extern "C" void _swift_async_stream_lock_unlock(Mutex &lock) { lock.unlock(); } } diff --git a/stdlib/public/BackDeployConcurrency/CMakeLists.txt b/stdlib/public/BackDeployConcurrency/CMakeLists.txt index a6f24ae406c92..740aefe472f76 100644 --- a/stdlib/public/BackDeployConcurrency/CMakeLists.txt +++ b/stdlib/public/BackDeployConcurrency/CMakeLists.txt @@ -99,6 +99,7 @@ add_swift_target_library(swift_Concurrency ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} I AsyncThrowingFlatMapSequence.swift AsyncThrowingMapSequence.swift AsyncThrowingPrefixWhileSequence.swift + ConditionVariable.cpp GlobalActor.swift MainActor.swift PartialAsyncTask.swift @@ -114,7 +115,7 @@ add_swift_target_library(swift_Concurrency ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} I TaskLocal.swift TaskSleep.swift ThreadSanitizer.cpp - Mutex.cpp + ThreadingError.cpp AsyncStreamBuffer.swift AsyncStream.swift AsyncThrowingStream.swift @@ -123,6 +124,8 @@ add_swift_target_library(swift_Concurrency ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} I ${swift_concurrency_extra_sources} ../Concurrency/linker-support/magic-symbols-for-install-name.c + INCORPORATE_OBJECT_LIBRARIES_SHARED_ONLY + swiftThreading LINK_LIBRARIES ${swift_concurrency_link_libraries} C_COMPILE_FLAGS diff --git a/stdlib/public/BackDeployConcurrency/Mutex.cpp b/stdlib/public/BackDeployConcurrency/ConditionVariable.cpp similarity index 54% rename from stdlib/public/BackDeployConcurrency/Mutex.cpp rename to stdlib/public/BackDeployConcurrency/ConditionVariable.cpp index f42d21ee0a385..b9472290239ff 100644 --- a/stdlib/public/BackDeployConcurrency/Mutex.cpp +++ b/stdlib/public/BackDeployConcurrency/ConditionVariable.cpp @@ -1,4 +1,4 @@ -//===--- Mutex.cpp - Mutex support code -----------------------------------===// +//===--- ConditionVariable.cpp - A condition variable ---------------------===// // // This source file is part of the Swift.org open source project // @@ -11,21 +11,51 @@ //===----------------------------------------------------------------------===// #include "Error.h" - -#define SWIFT_FATAL_ERROR swift_Concurrency_fatalError - -// Include the runtime's mutex support code. -// FIXME: figure out some reasonable way to share this stuff - #include "ConditionVariable.h" -#include "../runtime/MutexPThread.cpp" -#include "../runtime/MutexWin32.cpp" -#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME - #include "swift/Runtime/MutexSingleThreaded.h" -#endif using namespace swift; +#define fatalError swift_Concurrency_fatalError + +#define reportError(PThreadFunction) \ + do { \ + int errorcode = PThreadFunction; \ + if (errorcode != 0) { \ + fatalError(/* flags = */ 0, "'%s' failed with error '%s'(%d)\n", \ + #PThreadFunction, errorName(errorcode), errorcode); \ + } \ + } while (false) + +#define returnTrueOrReportError(PThreadFunction, returnFalseOnEBUSY) \ + do { \ + int errorcode = PThreadFunction; \ + if (errorcode == 0) \ + return true; \ + if (returnFalseOnEBUSY && errorcode == EBUSY) \ + return false; \ + fatalError(/* flags = */ 0, "'%s' failed with error '%s'(%d)\n", \ + #PThreadFunction, errorName(errorcode), errorcode); \ + } while (false) + +static const char *errorName(int errorcode) { + switch (errorcode) { + case EINVAL: + return "EINVAL"; + case EPERM: + return "EPERM"; + case EDEADLK: + return "EDEADLK"; + case ENOMEM: + return "ENOMEM"; + case EAGAIN: + return "EAGAIN"; + case EBUSY: + return "EBUSY"; + default: + return ""; + } +} + void ConditionPlatformHelper::init(pthread_cond_t &condition) { reportError(pthread_cond_init(&condition, nullptr)); } diff --git a/stdlib/public/BackDeployConcurrency/ConditionVariable.h b/stdlib/public/BackDeployConcurrency/ConditionVariable.h index acc5360d6531f..7a157032f53ee 100644 --- a/stdlib/public/BackDeployConcurrency/ConditionVariable.h +++ b/stdlib/public/BackDeployConcurrency/ConditionVariable.h @@ -18,7 +18,7 @@ #ifndef SWIFT_RUNTIME_CONDITION_VARIABLE_H #define SWIFT_RUNTIME_CONDITION_VARIABLE_H -#include "swift/Runtime/Mutex.h" +#include "swift/Threading/Mutex.h" #include #include diff --git a/stdlib/public/BackDeployConcurrency/DispatchGlobalExecutor.inc b/stdlib/public/BackDeployConcurrency/DispatchGlobalExecutor.inc index acbe281a6a2b1..0b01d4d7b9299 100644 --- a/stdlib/public/BackDeployConcurrency/DispatchGlobalExecutor.inc +++ b/stdlib/public/BackDeployConcurrency/DispatchGlobalExecutor.inc @@ -118,7 +118,7 @@ extern "C" void dispatch_queue_set_width(dispatch_queue_t dq, long width); static dispatch_queue_t getGlobalQueue(JobPriority priority) { size_t numericPriority = static_cast(priority); if (numericPriority >= globalQueueCacheCount) - swift_Concurrency_fatalError(0, "invalid job priority %#zx"); + swift_Concurrency_fatalError(0, "invalid job priority %#zx", numericPriority); #ifdef SWIFT_CONCURRENCY_BACK_DEPLOYMENT std::memory_order loadOrder = std::memory_order_acquire; diff --git a/stdlib/public/BackDeployConcurrency/Error.cpp b/stdlib/public/BackDeployConcurrency/Error.cpp index 2fbe4b0865c0b..fa427552853f0 100644 --- a/stdlib/public/BackDeployConcurrency/Error.cpp +++ b/stdlib/public/BackDeployConcurrency/Error.cpp @@ -10,10 +10,27 @@ // //===----------------------------------------------------------------------===// +#include "swift/Threading/Errors.h" +#include + #include "Error.h" // swift::fatalError is not exported from libswiftCore and not shared, so define another // internal function instead. -SWIFT_NORETURN void swift::swift_Concurrency_fatalError(uint32_t flags, const char *format, ...) { +SWIFT_NORETURN +SWIFT_VFORMAT(2) +void swift::swift_Concurrency_fatalErrorv(uint32_t flags, const char *format, + va_list val) { + vfprintf(stderr, format, val); abort(); } + +SWIFT_NORETURN +SWIFT_FORMAT(2, 3) +void swift::swift_Concurrency_fatalError(uint32_t flags, const char *format, + ...) { + va_list val; + + va_start(val, format); + swift_Concurrency_fatalErrorv(flags, format, val); +} diff --git a/stdlib/public/BackDeployConcurrency/Error.h b/stdlib/public/BackDeployConcurrency/Error.h index 1e0fd3ffd339c..85e8a621399a1 100644 --- a/stdlib/public/BackDeployConcurrency/Error.h +++ b/stdlib/public/BackDeployConcurrency/Error.h @@ -17,13 +17,19 @@ #ifndef SWIFT_CONCURRENCY_ERRORS_H #define SWIFT_CONCURRENCY_ERRORS_H +#include "swift/Basic/Compiler.h" + #include "../SwiftShims/Visibility.h" +#include #include -#include +#include namespace swift { -SWIFT_NORETURN void swift_Concurrency_fatalError(uint32_t flags, const char *format, ...); +SWIFT_NORETURN SWIFT_FORMAT(2, 3) void swift_Concurrency_fatalError( + uint32_t flags, const char *format, ...); +SWIFT_NORETURN SWIFT_VFORMAT(2) void swift_Concurrency_fatalErrorv( + uint32_t flags, const char *format, va_list val); } // namespace swift diff --git a/stdlib/public/BackDeployConcurrency/Executor.swift b/stdlib/public/BackDeployConcurrency/Executor.swift index 35862d5bf223f..13e2811b83ef5 100644 --- a/stdlib/public/BackDeployConcurrency/Executor.swift +++ b/stdlib/public/BackDeployConcurrency/Executor.swift @@ -93,7 +93,7 @@ func _checkExpectedExecutor(_filenameStart: Builtin.RawPointer, _filenameStart, _filenameLength, _filenameIsASCII, _line, _executor) } -#if !SWIFT_STDLIB_SINGLE_THREADED_RUNTIME +#if !SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY // This must take a DispatchQueueShim, not something like AnyObject, // or else SILGen will emit a retain/release in unoptimized builds, // which won't work because DispatchQueues aren't actually diff --git a/stdlib/public/BackDeployConcurrency/Task.cpp b/stdlib/public/BackDeployConcurrency/Task.cpp index 86f0f5e5958d4..4f44c4bb7ed7d 100644 --- a/stdlib/public/BackDeployConcurrency/Task.cpp +++ b/stdlib/public/BackDeployConcurrency/Task.cpp @@ -17,8 +17,8 @@ #include "CompatibilityOverride.h" #include "ConcurrencyRuntime.h" #include "swift/ABI/Metadata.h" -#include "swift/Runtime/Mutex.h" #include "swift/Runtime/HeapObject.h" +#include "swift/Threading/Mutex.h" #include "Task.h" #include "TaskGroupPrivate.h" #include "TaskLocal.h" diff --git a/stdlib/public/BackDeployConcurrency/TaskGroup.cpp b/stdlib/public/BackDeployConcurrency/TaskGroup.cpp index a0bfd8768f401..359d2d8603dcb 100644 --- a/stdlib/public/BackDeployConcurrency/TaskGroup.cpp +++ b/stdlib/public/BackDeployConcurrency/TaskGroup.cpp @@ -26,8 +26,8 @@ #include "swift/Basic/STLExtras.h" #include "ConcurrencyRuntime.h" #include "swift/Runtime/Config.h" -#include "swift/Runtime/Mutex.h" #include "swift/Runtime/HeapObject.h" +#include "swift/Threading/Mutex.h" #include "Debug.h" #include "bitset" #include "string" @@ -42,6 +42,8 @@ #include #endif +#include + using namespace swift; /******************************************************************************/ diff --git a/stdlib/public/BackDeployConcurrency/TaskLocal.cpp b/stdlib/public/BackDeployConcurrency/TaskLocal.cpp index 31ba53a669931..520f3efcb4ea3 100644 --- a/stdlib/public/BackDeployConcurrency/TaskLocal.cpp +++ b/stdlib/public/BackDeployConcurrency/TaskLocal.cpp @@ -14,10 +14,9 @@ #include "swift/Runtime/Atomic.h" #include "swift/Runtime/Casting.h" #include "swift/Runtime/Once.h" -#include "swift/Runtime/Mutex.h" #include "ConcurrencyRuntime.h" -#include "swift/Runtime/ThreadLocal.h" -#include "swift/Runtime/ThreadLocalStorage.h" +#include "swift/Threading/Mutex.h" +#include "swift/Threading/ThreadLocalStorage.h" #include "swift/ABI/Metadata.h" #include "llvm/ADT/PointerIntPair.h" #include "Actor.h" @@ -32,14 +31,8 @@ #include #endif -#if HAVE_PTHREAD_H -#include -#endif - #if defined(_WIN32) #include -#include -#include #endif using namespace swift; @@ -58,9 +51,8 @@ template struct Pointer { /// THIS IS RUNTIME INTERNAL AND NOT ABI. class FallbackTaskLocalStorage { - static SWIFT_RUNTIME_DECLARE_THREAD_LOCAL( - Pointer, Value, - SWIFT_CONCURRENCY_FALLBACK_TASK_LOCAL_STORAGE_KEY); + static SWIFT_THREAD_LOCAL_TYPE(Pointer, + tls_key::concurrency_fallback) Value; public: static void set(TaskLocal::Storage *task) { Value.set(task); } @@ -68,9 +60,10 @@ class FallbackTaskLocalStorage { }; /// Define the thread-locals. -SWIFT_RUNTIME_DECLARE_THREAD_LOCAL( - Pointer, FallbackTaskLocalStorage::Value, - SWIFT_CONCURRENCY_FALLBACK_TASK_LOCAL_STORAGE_KEY); +SWIFT_THREAD_LOCAL_TYPE( + Pointer, + tls_key::concurrency_fallback) +FallbackTaskLocalStorage::Value; // ==== ABI -------------------------------------------------------------------- diff --git a/stdlib/public/BackDeployConcurrency/TaskPrivate.h b/stdlib/public/BackDeployConcurrency/TaskPrivate.h index 71a773e40a287..8e581202ae6cf 100644 --- a/stdlib/public/BackDeployConcurrency/TaskPrivate.h +++ b/stdlib/public/BackDeployConcurrency/TaskPrivate.h @@ -24,6 +24,7 @@ #include "swift/Runtime/Error.h" #include "swift/Runtime/Exclusivity.h" #include "swift/Runtime/HeapObject.h" +#include "swift/Threading/Thread.h" #include "Task.h" #define SWIFT_FATAL_ERROR swift_Concurrency_fatalError @@ -46,27 +47,13 @@ namespace swift { #if 0 #define SWIFT_TASK_DEBUG_LOG(fmt, ...) \ fprintf(stderr, "[%lu] [%s:%d](%s) " fmt "\n", \ - (unsigned long)_swift_get_thread_id(), \ + (unsigned long)Thread::current()::platformThreadId(), \ __FILE__, __LINE__, __FUNCTION__, \ __VA_ARGS__) #else #define SWIFT_TASK_DEBUG_LOG(fmt, ...) (void)0 #endif -#if defined(_WIN32) -using ThreadID = decltype(GetCurrentThreadId()); -#else -using ThreadID = decltype(pthread_self()); -#endif - -inline ThreadID _swift_get_thread_id() { -#if defined(_WIN32) - return GetCurrentThreadId(); -#else - return pthread_self(); -#endif -} - class AsyncTask; class TaskGroup; @@ -109,7 +96,7 @@ void _swift_tsan_release(void *addr); /// executors. #define DISPATCH_QUEUE_GLOBAL_EXECUTOR (void *)1 -#if !defined(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) +#if !defined(SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY) inline SerialExecutorWitnessTable * _swift_task_getDispatchQueueSerialExecutorWitnessTable() { extern SerialExecutorWitnessTable wtable diff --git a/stdlib/public/BackDeployConcurrency/TaskStatus.cpp b/stdlib/public/BackDeployConcurrency/TaskStatus.cpp index b85f378913a0b..10195bd3d86b8 100644 --- a/stdlib/public/BackDeployConcurrency/TaskStatus.cpp +++ b/stdlib/public/BackDeployConcurrency/TaskStatus.cpp @@ -17,8 +17,8 @@ #include "CompatibilityOverride.h" #include "ConcurrencyRuntime.h" -#include "swift/Runtime/Mutex.h" #include "swift/Runtime/AtomicWaitQueue.h" +#include "swift/Threading/Mutex.h" #include "TaskStatus.h" #include "TaskPrivate.h" #include @@ -36,7 +36,7 @@ ActiveTaskStatus::getStatusRecordParent(TaskStatusRecord *ptr) { /// A lock used to protect management of task-specific status /// record locks. -static StaticMutex StatusRecordLockLock; +static LazyMutex StatusRecordLockLock; namespace { @@ -62,7 +62,7 @@ namespace { /// must acquire the global status-record lock, find this record /// (which should be the innermost record), and wait for an unlock. class StatusRecordLockRecord : - public AtomicWaitQueue, + public AtomicWaitQueue, public TaskStatusRecord { public: StatusRecordLockRecord(TaskStatusRecord *parent) diff --git a/stdlib/public/BackDeployConcurrency/ThreadingError.cpp b/stdlib/public/BackDeployConcurrency/ThreadingError.cpp new file mode 100644 index 0000000000000..512bd1128beca --- /dev/null +++ b/stdlib/public/BackDeployConcurrency/ThreadingError.cpp @@ -0,0 +1,26 @@ +//===--- ThreadingError.cpp - Error handling support code -----------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "swift/Threading/Errors.h" +#include + +#include "Error.h" + +// Handle fatal errors from the threading library +SWIFT_ATTRIBUTE_NORETURN +SWIFT_FORMAT(1, 2) +void swift::threading::fatal(const char *format, ...) { + va_list val; + + va_start(val, format); + swift_Concurrency_fatalErrorv(0, format, val); +}