Skip to content

Commit 0e5a620

Browse files
authored
Merge pull request #40331 from al45tair/problem/84393438
[Runtime] Don't use threading APIs when building single threaded.
2 parents c77348c + 8e12275 commit 0e5a620

File tree

7 files changed

+43
-23
lines changed

7 files changed

+43
-23
lines changed

include/swift/Runtime/ThreadLocal.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@
2323

2424
/// SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL - Does the current configuration
2525
/// allow the use of SWIFT_RUNTIME_ATTRIBUTE_THREAD_LOCAL?
26-
#if defined(__APPLE__)
27-
// The pthread TLS APIs work better than C++ TLS on Apple platforms.
28-
#define SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL 0
29-
#elif defined(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME)
26+
#if SWIFT_STDLIB_SINGLE_THREADED_RUNTIME
3027
// We define SWIFT_RUNTIME_ATTRIBUTE_THREAD_LOCAL to nothing in this
3128
// configuration and just use a global variable, so this is okay.
3229
#define SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL 1
30+
#elif defined(__APPLE__)
31+
// The pthread TLS APIs work better than C++ TLS on Apple platforms.
32+
#define SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL 0
3333
#elif __has_feature(tls)
3434
// If __has_feature reports that TLS is available, use it.
3535
#define SWIFT_RUNTIME_SUPPORTS_THREAD_LOCAL 1
@@ -43,7 +43,7 @@
4343

4444
/// SWIFT_RUNTIME_THREAD_LOCAL - Declare that something is a
4545
/// thread-local variable in the runtime.
46-
#if defined(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME)
46+
#if SWIFT_STDLIB_SINGLE_THREADED_RUNTIME
4747
// In a single-threaded runtime, thread-locals are global.
4848
#define SWIFT_RUNTIME_ATTRIBUTE_THREAD_LOCAL
4949
#elif defined(__GNUC__)

include/swift/Runtime/VoucherShims.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020
#include "Config.h"
2121

2222
// swift-corelibs-libdispatch has os/voucher_private.h but it doesn't work for
23-
// us yet, so only look for it on Apple platforms.
24-
#if __APPLE__ && __has_include(<os/voucher_private.h>)
23+
// us yet, so only look for it on Apple platforms. We also don't need vouchers
24+
// in the single threaded concurrency runtime.
25+
#if __APPLE__ && !SWIFT_STDLIB_SINGLE_THREADED_RUNTIME \
26+
&& __has_include(<os/voucher_private.h>)
2527
#define SWIFT_HAS_VOUCHER_HEADER 1
2628
#include <os/voucher_private.h>
2729
#endif

stdlib/cmake/modules/SwiftSource.cmake

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,10 @@ function(_add_target_variant_swift_compile_flags
310310
list(APPEND result "-Xcc" "-DSWIFT_STDLIB_HAS_ENVIRON")
311311
endif()
312312

313+
if(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME)
314+
list(APPEND result "-D" "SWIFT_STDLIB_SINGLE_THREADED_RUNTIME")
315+
endif()
316+
313317
set("${result_var_name}" "${result}" PARENT_SCOPE)
314318
endfunction()
315319

stdlib/public/Concurrency/Actor.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,9 @@ static HANDLE __initialPthread = INVALID_HANDLE_VALUE;
288288
/// Determine whether we are currently executing on the main thread
289289
/// independently of whether we know that we are on the main actor.
290290
static bool isExecutingOnMainThread() {
291-
#if defined(__linux__)
291+
#if SWIFT_STDLIB_SINGLE_THREADED_RUNTIME
292+
return true;
293+
#elif defined(__linux__)
292294
return syscall(SYS_gettid) == getpid();
293295
#elif defined(_WIN32)
294296
if (__initialPthread == INVALID_HANDLE_VALUE) {
@@ -304,7 +306,9 @@ static bool isExecutingOnMainThread() {
304306
}
305307

306308
JobPriority swift::swift_task_getCurrentThreadPriority() {
307-
#if defined(__APPLE__)
309+
#if SWIFT_STDLIB_SINGLE_THREADED_RUNTIME
310+
return JobPriority::UserInitiated;
311+
#elif defined(__APPLE__)
308312
return static_cast<JobPriority>(qos_class_self());
309313
#else
310314
if (isExecutingOnMainThread())

stdlib/public/Concurrency/TaskGroup.cpp

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -279,8 +279,16 @@ class TaskGroupImpl: public TaskGroupTaskStatusRecord {
279279

280280
private:
281281

282+
#if !SWIFT_STDLIB_SINGLE_THREADED_RUNTIME
282283
// TODO: move to lockless via the status atomic (make readyQueue an mpsc_queue_t<ReadyQueueItem>)
283-
mutable std::mutex mutex;
284+
mutable std::mutex mutex_;
285+
286+
void lock() const { mutex_.lock(); }
287+
void unlock() const { mutex_.unlock(); }
288+
#else
289+
void lock() const {}
290+
void unlock() const {}
291+
#endif
284292

285293
/// Used for queue management, counting number of waiting and ready tasks
286294
std::atomic <uint64_t> status;
@@ -557,7 +565,7 @@ void TaskGroupImpl::offer(AsyncTask *completedTask, AsyncContext *context) {
557565
assert(completedTask->groupChildFragment()->getGroup() == asAbstract(this));
558566
SWIFT_TASK_DEBUG_LOG("offer task %p to group %p", completedTask, this);
559567

560-
mutex.lock(); // TODO: remove fragment lock, and use status for synchronization
568+
lock(); // TODO: remove fragment lock, and use status for synchronization
561569

562570
// Immediately increment ready count and acquire the status
563571
// Examples:
@@ -595,7 +603,7 @@ void TaskGroupImpl::offer(AsyncTask *completedTask, AsyncContext *context) {
595603
// Run the task.
596604
auto result = PollResult::get(completedTask, hadErrorResult);
597605

598-
mutex.unlock(); // TODO: remove fragment lock, and use status for synchronization
606+
unlock(); // TODO: remove fragment lock, and use status for synchronization
599607

600608
auto waitingContext =
601609
static_cast<TaskFutureWaitAsyncContext *>(
@@ -635,7 +643,7 @@ void TaskGroupImpl::offer(AsyncTask *completedTask, AsyncContext *context) {
635643
assert(completedTask == readyItem.getTask());
636644
assert(readyItem.getTask()->isFuture());
637645
readyQueue.enqueue(readyItem);
638-
mutex.unlock(); // TODO: remove fragment lock, and use status for synchronization
646+
unlock(); // TODO: remove fragment lock, and use status for synchronization
639647
return;
640648
}
641649

@@ -720,7 +728,7 @@ static void swift_taskGroup_wait_next_throwingImpl(
720728
}
721729

722730
PollResult TaskGroupImpl::poll(AsyncTask *waitingTask) {
723-
mutex.lock(); // TODO: remove group lock, and use status for synchronization
731+
lock(); // TODO: remove group lock, and use status for synchronization
724732
SWIFT_TASK_DEBUG_LOG("poll group = %p", this);
725733
auto assumed = statusMarkWaitingAssumeAcquire();
726734

@@ -738,7 +746,7 @@ PollResult TaskGroupImpl::poll(AsyncTask *waitingTask) {
738746
statusRemoveWaiting();
739747
result.status = PollStatus::Empty;
740748
result.successType = this->successType;
741-
mutex.unlock(); // TODO: remove group lock, and use status for synchronization
749+
unlock(); // TODO: remove group lock, and use status for synchronization
742750
return result;
743751
}
744752

@@ -785,7 +793,7 @@ PollResult TaskGroupImpl::poll(AsyncTask *waitingTask) {
785793
result.successType = futureFragment->getResultType();
786794
assert(result.retainedTask && "polled a task, it must be not null");
787795
_swift_tsan_acquire(static_cast<Job *>(result.retainedTask));
788-
mutex.unlock(); // TODO: remove fragment lock, and use status for synchronization
796+
unlock(); // TODO: remove fragment lock, and use status for synchronization
789797
return result;
790798

791799
case ReadyStatus::Error:
@@ -796,15 +804,15 @@ PollResult TaskGroupImpl::poll(AsyncTask *waitingTask) {
796804
result.successType = nullptr;
797805
assert(result.retainedTask && "polled a task, it must be not null");
798806
_swift_tsan_acquire(static_cast<Job *>(result.retainedTask));
799-
mutex.unlock(); // TODO: remove fragment lock, and use status for synchronization
807+
unlock(); // TODO: remove fragment lock, and use status for synchronization
800808
return result;
801809

802810
case ReadyStatus::Empty:
803811
result.status = PollStatus::Empty;
804812
result.storage = nullptr;
805813
result.retainedTask = nullptr;
806814
result.successType = this->successType;
807-
mutex.unlock(); // TODO: remove fragment lock, and use status for synchronization
815+
unlock(); // TODO: remove fragment lock, and use status for synchronization
808816
return result;
809817
}
810818
assert(false && "must return result when status compare-and-swap was successful");
@@ -824,7 +832,7 @@ PollResult TaskGroupImpl::poll(AsyncTask *waitingTask) {
824832
waitHead, waitingTask,
825833
/*success*/ std::memory_order_release,
826834
/*failure*/ std::memory_order_acquire)) {
827-
mutex.unlock(); // TODO: remove fragment lock, and use status for synchronization
835+
unlock(); // TODO: remove fragment lock, and use status for synchronization
828836
// no ready tasks, so we must wait.
829837
result.status = PollStatus::MustWait;
830838
_swift_task_clearCurrent();

test/lit.cfg

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -992,15 +992,17 @@ if run_vendor == 'apple':
992992

993993
# Auto-linking does not work when stdlib is built with LTO, because linked
994994
# libraries are discovered too late (after optimizations are applied), and
995-
# ld64 hits an assert and crashes. Until ld64 fixes this, let's workaround
996-
# it by explicitly -l linking all libraries needed in tests.
995+
# ld64 hits an assert and crashes, or worse, deadlocks. Until ld64 fixes
996+
# this, let's workaround it by explicitly -l linking all libraries needed in
997+
# tests.
998+
# rdar://70787171
997999
if "stdlib_lto" in config.available_features:
9981000
for library in ["swiftCore", "swiftStdlibUnittest",
9991001
"swiftStdlibUnicodeUnittest",
10001002
"swiftStdlibCollectionUnittest",
10011003
"swiftSwiftPrivateLibcExtras", "swiftSwiftPrivate",
10021004
"swiftDarwin", "swiftSwiftPrivateThreadExtras",
1003-
"swiftSwiftOnoneSupport"]:
1005+
"swiftSwiftOnoneSupport", "swift_Concurrency"]:
10041006
swift_execution_tests_extra_flags += ' -Xlinker -l%s'% library
10051007

10061008
swift_native_clang_tools_path = lit_config.params.get('swift_native_clang_tools_path', None)

utils/build-presets.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2513,7 +2513,7 @@ verbose-build
25132513

25142514
[preset: mixin_stdlib_minimal]
25152515
enable-experimental-differentiable-programming=0
2516-
enable-experimental-concurrency=0
2516+
enable-experimental-concurrency=1
25172517
enable-experimental-distributed=0
25182518
build-swift-dynamic-sdk-overlay=0
25192519
build-swift-dynamic-stdlib=0

0 commit comments

Comments
 (0)