Skip to content

Commit 190cdb4

Browse files
authored
Merge pull request swiftlang#86738 from al45tair/eng/PR-168508495
[6.3][Concurrency] Mark custom executors entry points as SPI.
2 parents 4b85d79 + 353304b commit 190cdb4

29 files changed

+181
-145
lines changed

include/swift/AST/FeatureAvailability.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,10 @@ FEATURE(IsolatedDeinit, (6, 1))
8080

8181
FEATURE(ValueGenericType, (6, 2))
8282
FEATURE(InitRawStructMetadata2, (6, 2))
83-
FEATURE(CustomGlobalExecutors, (6, 2))
8483
FEATURE(TaskExecutor, (6, 2))
8584
FEATURE(TypedCoroAlloc, (6, 2))
8685

86+
FEATURE(CustomGlobalExecutors, FUTURE)
8787
FEATURE(Differentiation, FUTURE)
8888
FEATURE(ClearSensitive, FUTURE)
8989
FEATURE(UpdatePureObjCClassMetadata, FUTURE)

stdlib/public/Concurrency/Clock.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ internal func _getClockRes(
190190
nanoseconds: UnsafeMutablePointer<Int64>,
191191
clock: CInt)
192192

193-
@available(StdlibDeploymentTarget 6.2, *)
193+
@available(StdlibDeploymentTarget 6.3, *)
194194
@_silgen_name("swift_sleep")
195195
internal func _sleep(
196196
seconds: Int64,

stdlib/public/Concurrency/ContinuousClock.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ extension ContinuousClock: Clock {
113113
public func sleep(
114114
until deadline: Instant, tolerance: Swift.Duration? = nil
115115
) async throws {
116-
if #available(StdlibDeploymentTarget 6.2, *) {
116+
if #available(StdlibDeploymentTarget 6.3, *) {
117117
try await Task._sleep(until: deadline,
118118
tolerance: tolerance,
119119
clock: self)

stdlib/public/Concurrency/CooperativeExecutor.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import Swift
1717
// Store the Timestamp in the executor private data, if it will fit; otherwise,
1818
// use the allocator to allocate space for it and stash a pointer in the private
1919
// data area.
20-
@available(StdlibDeploymentTarget 6.2, *)
20+
@available(StdlibDeploymentTarget 6.3, *)
2121
extension ExecutorJob {
2222
fileprivate var cooperativeExecutorTimestampIsIndirect: Bool {
2323
return MemoryLayout<(Int, Int)>.size
@@ -99,7 +99,7 @@ extension ExecutorJob {
9999

100100
#if !$Embedded && !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
101101
/// A wait queue is a specialised priority queue used to run a timer.
102-
@available(StdlibDeploymentTarget 6.2, *)
102+
@available(StdlibDeploymentTarget 6.3, *)
103103
struct WaitQueue {
104104
var queue: PriorityQueue<UnownedJob>
105105
var clock: _ClockID
@@ -157,7 +157,7 @@ struct WaitQueue {
157157

158158
/// A co-operative executor that can be used as the main executor or as a
159159
/// task executor.
160-
@available(StdlibDeploymentTarget 6.2, *)
160+
@available(StdlibDeploymentTarget 6.3, *)
161161
final class CooperativeExecutor: Executor, @unchecked Sendable {
162162
var runQueue: PriorityQueue<UnownedJob>
163163
#if !$Embedded && !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
@@ -282,7 +282,7 @@ extension CooperativeExecutor: SchedulingExecutor {
282282
}
283283
#endif
284284

285-
@available(StdlibDeploymentTarget 6.2, *)
285+
@available(StdlibDeploymentTarget 6.3, *)
286286
extension CooperativeExecutor: RunLoopExecutor {
287287
public func run() throws {
288288
try runUntil { false }
@@ -340,13 +340,13 @@ extension CooperativeExecutor: RunLoopExecutor {
340340
}
341341
}
342342

343-
@available(StdlibDeploymentTarget 6.2, *)
343+
@available(StdlibDeploymentTarget 6.3, *)
344344
extension CooperativeExecutor: SerialExecutor {}
345345

346-
@available(StdlibDeploymentTarget 6.2, *)
346+
@available(StdlibDeploymentTarget 6.3, *)
347347
extension CooperativeExecutor: TaskExecutor {}
348348

349-
@available(StdlibDeploymentTarget 6.2, *)
349+
@available(StdlibDeploymentTarget 6.3, *)
350350
extension CooperativeExecutor: MainExecutor {}
351351

352352
#endif // !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY

stdlib/public/Concurrency/Executor.swift

Lines changed: 43 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public protocol Executor: AnyObject, Sendable {
3838

3939
#if os(WASI) || !$Embedded
4040
/// `true` if this is the main executor.
41-
@available(StdlibDeploymentTarget 6.2, *)
41+
@available(StdlibDeploymentTarget 6.3, *)
4242
var isMainExecutor: Bool { get }
4343
#endif // os(WASI) || !$Embedded
4444

@@ -49,12 +49,12 @@ public protocol Executor: AnyObject, Sendable {
4949
/// Executors that implement SchedulingExecutor should provide their
5050
/// own copy of this method, which will allow the compiler to avoid a
5151
/// potentially expensive runtime cast.
52-
@available(StdlibDeploymentTarget 6.2, *)
52+
@available(StdlibDeploymentTarget 6.3, *)
5353
var asSchedulingExecutor: (any SchedulingExecutor)? { get }
5454
#endif
5555
}
5656

57-
@available(StdlibDeploymentTarget 6.2, *)
57+
@available(StdlibDeploymentTarget 6.3, *)
5858
public protocol SchedulingExecutor: Executor {
5959

6060
#if !$Embedded && !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
@@ -74,7 +74,7 @@ public protocol SchedulingExecutor: Executor {
7474
/// - tolerance: The maximum additional delay permissible before the
7575
/// job is executed. `nil` means no limit.
7676
/// - clock: The clock used for the delay.
77-
@available(StdlibDeploymentTarget 6.2, *)
77+
@available(StdlibDeploymentTarget 6.3, *)
7878
func enqueue<C: Clock>(_ job: consuming ExecutorJob,
7979
after delay: C.Duration,
8080
tolerance: C.Duration?,
@@ -94,7 +94,7 @@ public protocol SchedulingExecutor: Executor {
9494
/// - tolerance: The maximum additional delay permissible before the
9595
/// job is executed. `nil` means no limit.
9696
/// - clock: The clock used for the delay.
97-
@available(StdlibDeploymentTarget 6.2, *)
97+
@available(StdlibDeploymentTarget 6.3, *)
9898
func enqueue<C: Clock>(_ job: consuming ExecutorJob,
9999
at instant: C.Instant,
100100
tolerance: C.Duration?,
@@ -138,7 +138,7 @@ extension Executor {
138138
/// Executors that implement SchedulingExecutor should provide their
139139
/// own copy of this method, which will allow the compiler to avoid a
140140
/// potentially expensive runtime cast.
141-
@available(StdlibDeploymentTarget 6.2, *)
141+
@available(StdlibDeploymentTarget 6.3, *)
142142
public var asSchedulingExecutor: (any SchedulingExecutor)? {
143143
return self as? SchedulingExecutor
144144
}
@@ -162,19 +162,19 @@ extension Executor {
162162
#if os(WASI) || !$Embedded
163163
// This defaults to `false` so that existing third-party Executor
164164
// implementations will work as expected.
165-
@available(StdlibDeploymentTarget 6.2, *)
165+
@available(StdlibDeploymentTarget 6.3, *)
166166
public var isMainExecutor: Bool { false }
167167
#endif // os(WASI) || !$Embedded
168168

169169
}
170170

171171
// Delay support
172-
@available(StdlibDeploymentTarget 6.2, *)
172+
@available(StdlibDeploymentTarget 6.3, *)
173173
extension SchedulingExecutor {
174174

175175
#if !$Embedded && !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
176176

177-
@available(StdlibDeploymentTarget 6.2, *)
177+
@available(StdlibDeploymentTarget 6.3, *)
178178
public func enqueue<C: Clock>(_ job: consuming ExecutorJob,
179179
after delay: C.Duration,
180180
tolerance: C.Duration? = nil,
@@ -185,7 +185,7 @@ extension SchedulingExecutor {
185185
tolerance: tolerance, clock: clock)
186186
}
187187

188-
@available(StdlibDeploymentTarget 6.2, *)
188+
@available(StdlibDeploymentTarget 6.3, *)
189189
public func enqueue<C: Clock>(_ job: consuming ExecutorJob,
190190
at instant: C.Instant,
191191
tolerance: C.Duration? = nil,
@@ -383,7 +383,7 @@ public protocol SerialExecutor: Executor {
383383
extension SerialExecutor {
384384

385385
#if os(WASI) || (!$Embedded && !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY)
386-
@available(StdlibDeploymentTarget 6.2, *)
386+
@available(StdlibDeploymentTarget 6.3, *)
387387
public var isMainExecutor: Bool { return MainActor.executor._isSameExecutor(self) }
388388
#endif // os(WASI) || (!$Embedded && !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY)
389389

@@ -397,13 +397,13 @@ extension SerialExecutor {
397397
}
398398

399399
#if SWIFT_CONCURRENCY_USES_DISPATCH
400-
@available(StdlibDeploymentTarget 6.2, *)
400+
@available(StdlibDeploymentTarget 6.3, *)
401401
private var _dispatchQueue: OpaquePointer? {
402402
return unsafe _getDispatchQueueForExecutor(self.asUnownedSerialExecutor())
403403
}
404404
#endif
405405

406-
@available(StdlibDeploymentTarget 6.2, *)
406+
@available(StdlibDeploymentTarget 6.3, *)
407407
internal func _isSameExecutor(_ rhs: some SerialExecutor) -> Bool {
408408
if rhs === self {
409409
return true
@@ -526,10 +526,10 @@ extension SerialExecutor {
526526

527527
}
528528

529-
@available(StdlibDeploymentTarget 6.2, *)
529+
@available(StdlibDeploymentTarget 6.3, *)
530530
extension SerialExecutor where Self: Equatable {
531531

532-
@available(StdlibDeploymentTarget 6.2, *)
532+
@available(StdlibDeploymentTarget 6.3, *)
533533
public func isSameExclusiveExecutionContext(other: Self) -> Bool {
534534
return self == other
535535
}
@@ -541,7 +541,8 @@ extension SerialExecutor where Self: Equatable {
541541
/// The idea here is that some executors may work by running a loop
542542
/// that processes events of some sort; we want a way to enter that loop,
543543
/// and we would also like a way to trigger the loop to exit.
544-
@available(StdlibDeploymentTarget 6.2, *)
544+
@_spi(ExperimentalCustomExecutors)
545+
@available(StdlibDeploymentTarget 6.3, *)
545546
public protocol RunLoopExecutor: Executor {
546547
/// Run the executor's run loop.
547548
///
@@ -572,7 +573,8 @@ public protocol RunLoopExecutor: Executor {
572573
func stop()
573574
}
574575

575-
@available(StdlibDeploymentTarget 6.2, *)
576+
@_spi(ExperimentalCustomExecutors)
577+
@available(StdlibDeploymentTarget 6.3, *)
576578
extension RunLoopExecutor {
577579

578580
public func runUntil(_ condition: () -> Bool) throws {
@@ -584,14 +586,16 @@ extension RunLoopExecutor {
584586

585587
/// The main executor must conform to these two protocols; we have to
586588
/// make this a protocol for compatibility with Embedded Swift.
587-
@available(StdlibDeploymentTarget 6.2, *)
589+
@_spi(ExperimentalCustomExecutors)
590+
@available(StdlibDeploymentTarget 6.3, *)
588591
public protocol MainExecutor: RunLoopExecutor, SerialExecutor {
589592
}
590593

591594

592595
/// An ExecutorFactory is used to create the default main and task
593596
/// executors.
594-
@available(StdlibDeploymentTarget 6.2, *)
597+
@_spi(ExperimentalCustomExecutors)
598+
@available(StdlibDeploymentTarget 6.3, *)
595599
public protocol ExecutorFactory {
596600
#if os(WASI) || !$Embedded
597601
/// Constructs and returns the main executor, which is started implicitly
@@ -607,7 +611,8 @@ public protocol ExecutorFactory {
607611
@available(StdlibDeploymentTarget 6.3, *)
608612
typealias DefaultExecutorFactory = PlatformExecutorFactory
609613

610-
@available(StdlibDeploymentTarget 6.2, *)
614+
@_spi(ExperimentalCustomExecutors)
615+
@available(StdlibDeploymentTarget 6.3, *)
611616
@_silgen_name("swift_createExecutors")
612617
public func _createExecutors<F: ExecutorFactory>(factory: F.Type) {
613618
#if os(WASI) || (!$Embedded && !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY)
@@ -626,23 +631,24 @@ func _createDefaultExecutors() {
626631

627632
#if os(WASI) || (!$Embedded && !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY)
628633
extension MainActor {
629-
@available(StdlibDeploymentTarget 6.2, *)
634+
@available(StdlibDeploymentTarget 6.3, *)
630635
static var _executor: (any MainExecutor)? = nil
631636

632637
/// The main executor, which is started implicitly by the `async main`
633638
/// entry point and owns the "main" thread.
634639
///
635640
/// Attempting to set this after the first `enqueue` on the main
636641
/// executor is a fatal error.
637-
@available(StdlibDeploymentTarget 6.2, *)
642+
@_spi(ExperimentalCustomExecutors)
643+
@available(StdlibDeploymentTarget 6.3, *)
638644
public static var executor: any MainExecutor {
639645
// It would be good if there was a Swift way to do this
640646
_createDefaultExecutorsOnce()
641647
return _executor!
642648
}
643649

644650
/// An unowned version of the above, for performance
645-
@available(StdlibDeploymentTarget 6.2, *)
651+
@available(StdlibDeploymentTarget 6.3, *)
646652
static var unownedExecutor: UnownedSerialExecutor {
647653
_createDefaultExecutorsOnce()
648654
return unsafe UnownedSerialExecutor(ordinary: _executor!)
@@ -651,23 +657,24 @@ extension MainActor {
651657
#endif // os(WASI) || (!$Embedded && !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY)
652658

653659
extension Task where Success == Never, Failure == Never {
654-
@available(StdlibDeploymentTarget 6.2, *)
660+
@available(StdlibDeploymentTarget 6.3, *)
655661
static var _defaultExecutor: (any TaskExecutor)? = nil
656662

657663
/// The default or global executor, which is the default place in which
658664
/// we run tasks.
659665
///
660666
/// Attempting to set this after the first `enqueue` on the global
661667
/// executor is a fatal error.
662-
@available(StdlibDeploymentTarget 6.2, *)
668+
@_spi(ExperimentalCustomExecutors)
669+
@available(StdlibDeploymentTarget 6.3, *)
663670
public static var defaultExecutor: any TaskExecutor {
664671
// It would be good if there was a Swift way to do this
665672
_createDefaultExecutorsOnce()
666673
return _defaultExecutor!
667674
}
668675

669676
/// An unowned version of the above, for performance
670-
@available(StdlibDeploymentTarget 6.2, *)
677+
@available(StdlibDeploymentTarget 6.3, *)
671678
static var unownedDefaultExecutor: UnownedTaskExecutor {
672679
_createDefaultExecutorsOnce()
673680
return unsafe UnownedTaskExecutor(_defaultExecutor!)
@@ -686,9 +693,9 @@ extension Task where Success == Never, Failure == Never {
686693
/// 3. The task executor for the current thread
687694
///
688695
/// If none of these exist, returns the default executor.
689-
@available(StdlibDeploymentTarget 6.2, *)
696+
@available(StdlibDeploymentTarget 6.3, *)
690697
@_unavailableInEmbedded
691-
public static var currentExecutor: any Executor {
698+
static var currentExecutor: any Executor {
692699
if let activeExecutor = unsafe _getActiveExecutor().asSerialExecutor() {
693700
return activeExecutor
694701
} else if let taskExecutor = unsafe _getPreferredTaskExecutor().asTaskExecutor() {
@@ -700,8 +707,8 @@ extension Task where Success == Never, Failure == Never {
700707
}
701708

702709
/// Get the preferred executor for the current `Task`, if any.
703-
@available(StdlibDeploymentTarget 6.2, *)
704-
public static var preferredExecutor: (any TaskExecutor)? {
710+
@available(StdlibDeploymentTarget 6.3, *)
711+
static var preferredExecutor: (any TaskExecutor)? {
705712
if let taskExecutor = unsafe _getPreferredTaskExecutor().asTaskExecutor() {
706713
return taskExecutor
707714
}
@@ -713,8 +720,8 @@ extension Task where Success == Never, Failure == Never {
713720
///
714721
/// This follows the same logic as `currentExecutor`, except that it ignores
715722
/// any executor that isn't a `SchedulingExecutor`.
716-
@available(StdlibDeploymentTarget 6.2, *)
717-
public static var currentSchedulingExecutor: (any SchedulingExecutor)? {
723+
@available(StdlibDeploymentTarget 6.3, *)
724+
static var currentSchedulingExecutor: (any SchedulingExecutor)? {
718725
if let activeExecutor = unsafe _getActiveExecutor().asSerialExecutor(),
719726
let scheduling = activeExecutor.asSchedulingExecutor {
720727
return scheduling
@@ -790,7 +797,7 @@ public struct UnownedSerialExecutor: Sendable {
790797

791798
/// Automatically opt-in to complex equality semantics if the Executor
792799
/// implements `Equatable`.
793-
@available(SwiftStdlib 6.2, *)
800+
@available(SwiftStdlib 6.3, *)
794801
@inlinable
795802
public init<E: SerialExecutor>(_ executor: __shared E) {
796803
if executor._isComplexEquality {
@@ -806,7 +813,7 @@ public struct UnownedSerialExecutor: Sendable {
806813
unsafe _executor_isComplexEquality(self)
807814
}
808815

809-
@available(StdlibDeploymentTarget 6.2, *)
816+
@available(StdlibDeploymentTarget 6.3, *)
810817
public func asSerialExecutor() -> (any SerialExecutor)? {
811818
// The low bits of the witness table are used to encode the executor kind.
812819
// any SerialExecutor needs a raw witness table pointer, so mask off the low
@@ -843,13 +850,13 @@ public struct UnownedTaskExecutor: Sendable {
843850
unsafe self.executor = Builtin.buildOrdinaryTaskExecutorRef(executor)
844851
}
845852

846-
@available(StdlibDeploymentTarget 6.2, *)
853+
@available(StdlibDeploymentTarget 6.3, *)
847854
@inlinable
848855
public init<E: TaskExecutor>(_ executor: __shared E) {
849856
unsafe self.executor = Builtin.buildOrdinaryTaskExecutorRef(executor)
850857
}
851858

852-
@available(StdlibDeploymentTarget 6.2, *)
859+
@available(StdlibDeploymentTarget 6.3, *)
853860
public func asTaskExecutor() -> (any TaskExecutor)? {
854861
return unsafe unsafeBitCast(executor, to: (any TaskExecutor)?.self)
855862
}

0 commit comments

Comments
 (0)