Skip to content

Commit 77eb4f0

Browse files
authored
Merge pull request #80896 from al45tair/eng/PR-149346132
[Concurrency] Make initial executor construction fully thread safe.
2 parents 814d2f8 + 3d0d0b4 commit 77eb4f0

File tree

4 files changed

+31
-7
lines changed

4 files changed

+31
-7
lines changed

stdlib/public/Concurrency/Executor.swift

+12-6
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,14 @@ public func _createExecutors<F: ExecutorFactory>(factory: F.Type) {
546546
Task._defaultExecutor = factory.defaultExecutor
547547
}
548548

549+
@available(SwiftStdlib 6.2, *)
550+
@_silgen_name("swift_createDefaultExecutors")
551+
func _createDefaultExecutors() {
552+
if Task._defaultExecutor == nil {
553+
_createExecutors(factory: DefaultExecutorFactory.self)
554+
}
555+
}
556+
549557
#if !$Embedded && !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
550558
extension MainActor {
551559
@available(SwiftStdlib 6.2, *)
@@ -558,9 +566,8 @@ extension MainActor {
558566
/// executor is a fatal error.
559567
@available(SwiftStdlib 6.2, *)
560568
public static var executor: any MainExecutor {
561-
if _executor == nil {
562-
_executor = DefaultExecutorFactory.mainExecutor
563-
}
569+
// It would be good if there was a Swift way to do this
570+
_createDefaultExecutorsOnce()
564571
return _executor!
565572
}
566573
}
@@ -577,9 +584,8 @@ extension Task where Success == Never, Failure == Never {
577584
/// executor is a fatal error.
578585
@available(SwiftStdlib 6.2, *)
579586
public static var defaultExecutor: any TaskExecutor {
580-
if _defaultExecutor == nil {
581-
_defaultExecutor = DefaultExecutorFactory.defaultExecutor
582-
}
587+
// It would be good if there was a Swift way to do this
588+
_createDefaultExecutorsOnce()
583589
return _defaultExecutor!
584590
}
585591
}

stdlib/public/Concurrency/ExecutorBridge.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#include <dispatch/dispatch.h>
1515
#endif
1616

17+
#include "swift/Threading/Once.h"
18+
1719
#include "Error.h"
1820
#include "ExecutorBridge.h"
1921

@@ -27,6 +29,13 @@ void _swift_exit(int result) {
2729
exit(result);
2830
}
2931

32+
extern "C" SWIFT_CC(swift)
33+
void swift_createDefaultExecutorsOnce() {
34+
static swift::once_t createExecutorsOnce;
35+
36+
swift::once(createExecutorsOnce, swift_createDefaultExecutors);
37+
}
38+
3039
#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
3140
extern "C" SWIFT_CC(swift)
3241
SerialExecutorRef swift_getMainExecutor() {

stdlib/public/Concurrency/ExecutorBridge.h

+7-1
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,16 @@ void swift_destroyDispatchEventC(void *event);
3333
extern "C" SWIFT_CC(swift)
3434
void swift_signalDispatchEvent(void *event);
3535
#endif // !SWIFT_CONCURRENCY_EMBEDDED
36-
36+
3737
extern "C" SWIFT_CC(swift) __attribute__((noreturn))
3838
void swift_dispatchMain();
3939

40+
extern "C" SWIFT_CC(swift)
41+
void swift_createDefaultExecutors();
42+
43+
extern "C" SWIFT_CC(swift)
44+
void swift_createDefaultExecutorsOnce();
45+
4046
#pragma clang diagnostic pop
4147

4248
} // namespace swift

stdlib/public/Concurrency/ExecutorBridge.swift

+3
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,6 @@ internal func _dispatchEnqueueWithDeadline(_ global: CBool,
119119
@available(SwiftStdlib 6.2, *)
120120
@_silgen_name("swift_dispatchAssertMainQueue")
121121
internal func _dispatchAssertMainQueue()
122+
123+
@_silgen_name("swift_createDefaultExecutorsOnce")
124+
func _createDefaultExecutorsOnce()

0 commit comments

Comments
 (0)