Skip to content

Commit d6ce27b

Browse files
authored
Merge pull request #81326 from al45tair/eng/PR-150753884
[Concurrency] Make initial executor construction fully thread safe.
2 parents 009f868 + 418ae45 commit d6ce27b

File tree

4 files changed

+31
-7
lines changed

4 files changed

+31
-7
lines changed

stdlib/public/Concurrency/Executor.swift

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,14 @@ public func _createExecutors<F: ExecutorFactory>(factory: F.Type) {
594594
Task._defaultExecutor = factory.defaultExecutor
595595
}
596596

597+
@available(SwiftStdlib 6.2, *)
598+
@_silgen_name("swift_createDefaultExecutors")
599+
func _createDefaultExecutors() {
600+
if Task._defaultExecutor == nil {
601+
_createExecutors(factory: DefaultExecutorFactory.self)
602+
}
603+
}
604+
597605
#if !$Embedded && !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
598606
extension MainActor {
599607
@available(SwiftStdlib 6.2, *)
@@ -606,9 +614,8 @@ extension MainActor {
606614
/// executor is a fatal error.
607615
@available(SwiftStdlib 6.2, *)
608616
public static var executor: any MainExecutor {
609-
if _executor == nil {
610-
_executor = DefaultExecutorFactory.mainExecutor
611-
}
617+
// It would be good if there was a Swift way to do this
618+
_createDefaultExecutorsOnce()
612619
return _executor!
613620
}
614621
}
@@ -625,9 +632,8 @@ extension Task where Success == Never, Failure == Never {
625632
/// executor is a fatal error.
626633
@available(SwiftStdlib 6.2, *)
627634
public static var defaultExecutor: any TaskExecutor {
628-
if _defaultExecutor == nil {
629-
_defaultExecutor = DefaultExecutorFactory.defaultExecutor
630-
}
635+
// It would be good if there was a Swift way to do this
636+
_createDefaultExecutorsOnce()
631637
return _defaultExecutor!
632638
}
633639
}

stdlib/public/Concurrency/ExecutorBridge.cpp

Lines changed: 9 additions & 0 deletions
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
#include "TaskPrivate.h"
@@ -28,6 +30,13 @@ void _swift_exit(int result) {
2830
exit(result);
2931
}
3032

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

stdlib/public/Concurrency/ExecutorBridge.h

Lines changed: 7 additions & 1 deletion
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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,6 @@ internal func _dispatchAssertMainQueue()
132132
internal func _getDispatchQueueForExecutor(
133133
_ executor: UnownedSerialExecutor
134134
) -> OpaquePointer?
135+
136+
@_silgen_name("swift_createDefaultExecutorsOnce")
137+
func _createDefaultExecutorsOnce()

0 commit comments

Comments
 (0)