Skip to content

Commit 9c4adb7

Browse files
authored
Merge pull request #72830 from ktoso/pick-waitForAll-isolation
🌸[6.0][Concurrency] Remove _unsafeInheritExecutor from public APIs, use #isolation
2 parents 3cb184a + f2357ea commit 9c4adb7

File tree

13 files changed

+350
-32
lines changed

13 files changed

+350
-32
lines changed

stdlib/public/Concurrency/CheckedContinuation.swift

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -281,19 +281,37 @@ extension CheckedContinuation {
281281
/// - SeeAlso: `withCheckedThrowingContinuation(function:_:)`
282282
/// - SeeAlso: `withUnsafeContinuation(function:_:)`
283283
/// - SeeAlso: `withUnsafeThrowingContinuation(function:_:)`
284-
@available(SwiftStdlib 5.1, *)
285-
@_unsafeInheritExecutor // ABI compatibility with Swift 5.1
286284
@inlinable
287285
@_unavailableInEmbedded
286+
@available(SwiftStdlib 5.1, *)
287+
#if !$Embedded
288+
@backDeployed(before: SwiftStdlib 6.0)
289+
#endif
288290
public func withCheckedContinuation<T>(
289-
function: String = #function,
290-
_ body: (CheckedContinuation<T, Never>) -> Void
291+
isolation: isolated (any Actor)? = #isolation,
292+
function: String = #function,
293+
_ body: (CheckedContinuation<T, Never>) -> Void
294+
) async -> T {
295+
return await withUnsafeContinuation {
296+
body(CheckedContinuation(continuation: $0, function: function))
297+
}
298+
}
299+
300+
@available(SwiftStdlib 5.1, *)
301+
@usableFromInline
302+
@_unsafeInheritExecutor // ABI compatibility with Swift 5.1
303+
@_unavailableInEmbedded
304+
@_silgen_name("$ss23withCheckedContinuation8function_xSS_yScCyxs5NeverOGXEtYalF")
305+
internal func __abi_withCheckedContinuation<T>(
306+
function: String = #function,
307+
_ body: (CheckedContinuation<T, Never>) -> Void
291308
) async -> T {
292309
return await withUnsafeContinuation {
293310
body(CheckedContinuation(continuation: $0, function: function))
294311
}
295312
}
296313

314+
297315
/// Invokes the passed in closure with a checked continuation for the current task.
298316
///
299317
/// The body of the closure executes synchronously on the calling task, and once it returns
@@ -322,13 +340,30 @@ public func withCheckedContinuation<T>(
322340
/// - SeeAlso: `withCheckedContinuation(function:_:)`
323341
/// - SeeAlso: `withUnsafeContinuation(function:_:)`
324342
/// - SeeAlso: `withUnsafeThrowingContinuation(function:_:)`
325-
@available(SwiftStdlib 5.1, *)
326-
@_unsafeInheritExecutor // ABI compatibility with Swift 5.1
327343
@inlinable
328344
@_unavailableInEmbedded
345+
@available(SwiftStdlib 5.1, *)
346+
#if !$Embedded
347+
@backDeployed(before: SwiftStdlib 6.0)
348+
#endif
329349
public func withCheckedThrowingContinuation<T>(
330-
function: String = #function,
331-
_ body: (CheckedContinuation<T, Error>) -> Void
350+
isolation: isolated (any Actor)? = #isolation,
351+
function: String = #function,
352+
_ body: (CheckedContinuation<T, Error>) -> Void
353+
) async throws -> T {
354+
return try await withUnsafeThrowingContinuation {
355+
body(CheckedContinuation(continuation: $0, function: function))
356+
}
357+
}
358+
359+
@available(SwiftStdlib 5.1, *)
360+
@usableFromInline
361+
@_unsafeInheritExecutor // ABI compatibility with Swift 5.1
362+
@_unavailableInEmbedded
363+
@_silgen_name("$ss31withCheckedThrowingContinuation8function_xSS_yScCyxs5Error_pGXEtYaKlF")
364+
internal func __abi_withCheckedThrowingContinuation<T>(
365+
function: String = #function,
366+
_ body: (CheckedContinuation<T, Error>) -> Void
332367
) async throws -> T {
333368
return try await withUnsafeThrowingContinuation {
334369
body(CheckedContinuation(continuation: $0, function: function))

stdlib/public/Concurrency/PartialAsyncTask.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -598,9 +598,9 @@ internal func _resumeUnsafeThrowingContinuationWithError<T>(
598598
/// - SeeAlso: `withCheckedContinuation(function:_:)`
599599
/// - SeeAlso: `withCheckedThrowingContinuation(function:_:)`
600600
@available(SwiftStdlib 5.1, *)
601-
@_unsafeInheritExecutor
602601
@_alwaysEmitIntoClient
603602
public func withUnsafeContinuation<T>(
603+
isolation: isolated (any Actor)? = #isolation,
604604
_ fn: (UnsafeContinuation<T, Never>) -> Void
605605
) async -> T {
606606
return await Builtin.withUnsafeContinuation {
@@ -634,9 +634,9 @@ public func withUnsafeContinuation<T>(
634634
/// - SeeAlso: `withCheckedContinuation(function:_:)`
635635
/// - SeeAlso: `withCheckedThrowingContinuation(function:_:)`
636636
@available(SwiftStdlib 5.1, *)
637-
@_unsafeInheritExecutor
638637
@_alwaysEmitIntoClient
639638
public func withUnsafeThrowingContinuation<T>(
639+
isolation: isolated (any Actor)? = #isolation,
640640
_ fn: (UnsafeContinuation<T, Error>) -> Void
641641
) async throws -> T {
642642
return try await Builtin.withUnsafeThrowingContinuation {

stdlib/public/Concurrency/Task.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -346,9 +346,9 @@ static SerialExecutorRef executorForEnqueuedJob(Job *job) {
346346
return SerialExecutorRef::generic();
347347
#else
348348
void *jobQueue = job->SchedulerPrivate[Job::DispatchQueueIndex];
349-
if (jobQueue == DISPATCH_QUEUE_GLOBAL_EXECUTOR)
349+
if (jobQueue == DISPATCH_QUEUE_GLOBAL_EXECUTOR) {
350350
return SerialExecutorRef::generic();
351-
else
351+
} else
352352
return SerialExecutorRef::forOrdinary(reinterpret_cast<HeapObject*>(jobQueue),
353353
_swift_task_getDispatchQueueSerialExecutorWitnessTable());
354354
#endif

stdlib/public/Concurrency/TaskGroup.swift

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ public func withTaskGroup<ChildTaskResult, GroupResult>(
8080
// Run the withTaskGroup body.
8181
let result = await body(&group)
8282

83+
// TODO(concurrency): should get isolation from param from withThrowingTaskGroup
8384
await group.awaitAllRemainingTasks()
8485

8586
Builtin.destroyTaskGroup(_group)
@@ -183,13 +184,15 @@ public func withThrowingTaskGroup<ChildTaskResult, GroupResult>(
183184
// Run the withTaskGroup body.
184185
let result = try await body(&group)
185186

187+
// TODO(concurrency): should get isolation from param from withThrowingTaskGroup
186188
await group.awaitAllRemainingTasks()
187189
Builtin.destroyTaskGroup(_group)
188190

189191
return result
190192
} catch {
191193
group.cancelAll()
192194

195+
// TODO(concurrency): should get isolation from param from withThrowingTaskGroup
193196
await group.awaitAllRemainingTasks()
194197
Builtin.destroyTaskGroup(_group)
195198

@@ -563,22 +566,41 @@ public struct TaskGroup<ChildTaskResult: Sendable> {
563566
/// that method can't be called from a concurrent execution context like a child task.
564567
///
565568
/// - Returns: The value returned by the next child task that completes.
566-
public mutating func next() async -> ChildTaskResult? {
569+
@available(SwiftStdlib 5.1, *)
570+
@backDeployed(before: SwiftStdlib 6.0)
571+
public mutating func next(isolation: isolated (any Actor)? = #isolation) async -> ChildTaskResult? {
572+
// try!-safe because this function only exists for Failure == Never,
573+
// and as such, it is impossible to spawn a throwing child task.
574+
return try! await _taskGroupWaitNext(group: _group) // !-safe cannot throw, we're a non-throwing TaskGroup
575+
}
576+
577+
@usableFromInline
578+
@available(SwiftStdlib 5.1, *)
579+
@_silgen_name("$sScG4nextxSgyYaF")
580+
internal mutating func __abi_next() async -> ChildTaskResult? {
567581
// try!-safe because this function only exists for Failure == Never,
568582
// and as such, it is impossible to spawn a throwing child task.
569583
return try! await _taskGroupWaitNext(group: _group) // !-safe cannot throw, we're a non-throwing TaskGroup
570584
}
571585

572586
/// Await all of the pending tasks added this group.
573587
@usableFromInline
588+
@available(SwiftStdlib 5.1, *)
589+
@backDeployed(before: SwiftStdlib 6.0)
590+
internal mutating func awaitAllRemainingTasks(isolation: isolated (any Actor)? = #isolation) async {
591+
while let _ = await next(isolation: isolation) {}
592+
}
593+
594+
@usableFromInline
595+
@available(SwiftStdlib 5.1, *)
574596
internal mutating func awaitAllRemainingTasks() async {
575-
while let _ = await next() {}
597+
while let _ = await next(isolation: nil) {}
576598
}
577599

578600
/// Wait for all of the group's remaining tasks to complete.
579601
@_alwaysEmitIntoClient
580-
public mutating func waitForAll() async {
581-
await awaitAllRemainingTasks()
602+
public mutating func waitForAll(isolation: isolated (any Actor)? = #isolation) async {
603+
await awaitAllRemainingTasks(isolation: isolation)
582604
}
583605

584606
/// A Boolean value that indicates whether the group has any remaining tasks.
@@ -703,16 +725,24 @@ public struct ThrowingTaskGroup<ChildTaskResult: Sendable, Failure: Error> {
703725

704726
/// Await all the remaining tasks on this group.
705727
@usableFromInline
706-
internal mutating func awaitAllRemainingTasks() async {
728+
@available(SwiftStdlib 5.1, *)
729+
@backDeployed(before: SwiftStdlib 6.0)
730+
internal mutating func awaitAllRemainingTasks(isolation: isolated (any Actor)? = #isolation) async {
707731
while true {
708732
do {
709-
guard let _ = try await next() else {
733+
guard let _ = try await next(isolation: isolation) else {
710734
return
711735
}
712736
} catch {}
713737
}
714738
}
715739

740+
@usableFromInline
741+
@available(SwiftStdlib 5.1, *)
742+
internal mutating func awaitAllRemainingTasks() async {
743+
await awaitAllRemainingTasks(isolation: nil)
744+
}
745+
716746
@usableFromInline
717747
internal mutating func _waitForAll() async throws {
718748
await self.awaitAllRemainingTasks()
@@ -750,7 +780,7 @@ public struct ThrowingTaskGroup<ChildTaskResult: Sendable, Failure: Error> {
750780
/// - Throws: The *first* error that was thrown by a child task during draining all the tasks.
751781
/// This first error is stored until all other tasks have completed, and is re-thrown afterwards.
752782
@_alwaysEmitIntoClient
753-
public mutating func waitForAll() async throws {
783+
public mutating func waitForAll(isolation: isolated (any Actor)? = #isolation) async throws {
754784
var firstError: Error? = nil
755785

756786
// Make sure we loop until all child tasks have completed
@@ -999,7 +1029,16 @@ public struct ThrowingTaskGroup<ChildTaskResult: Sendable, Failure: Error> {
9991029
/// - Throws: The error thrown by the next child task that completes.
10001030
///
10011031
/// - SeeAlso: `nextResult()`
1002-
public mutating func next() async throws -> ChildTaskResult? {
1032+
@available(SwiftStdlib 5.1, *)
1033+
@backDeployed(before: SwiftStdlib 6.0)
1034+
public mutating func next(isolation: isolated (any Actor)? = #isolation) async throws -> ChildTaskResult? {
1035+
return try await _taskGroupWaitNext(group: _group)
1036+
}
1037+
1038+
@usableFromInline
1039+
@available(SwiftStdlib 5.1, *)
1040+
@_silgen_name("$sScg4nextxSgyYaKF")
1041+
internal mutating func __abi_next() async throws -> ChildTaskResult? {
10031042
return try await _taskGroupWaitNext(group: _group)
10041043
}
10051044

@@ -1052,7 +1091,7 @@ public struct ThrowingTaskGroup<ChildTaskResult: Sendable, Failure: Error> {
10521091
///
10531092
/// - SeeAlso: `next()`
10541093
@_alwaysEmitIntoClient
1055-
public mutating func nextResult() async -> Result<ChildTaskResult, Failure>? {
1094+
public mutating func nextResult(isolation: isolated (any Actor)? = #isolation) async -> Result<ChildTaskResult, Failure>? {
10561095
return try! await nextResultForABI()
10571096
}
10581097

@@ -1332,7 +1371,7 @@ func _taskGroupIsCancelled(group: Builtin.RawPointer) -> Bool
13321371

13331372
@available(SwiftStdlib 5.1, *)
13341373
@_silgen_name("swift_taskGroup_wait_next_throwing")
1335-
func _taskGroupWaitNext<T>(group: Builtin.RawPointer) async throws -> T?
1374+
public func _taskGroupWaitNext<T>(group: Builtin.RawPointer) async throws -> T?
13361375

13371376
@available(SwiftStdlib 5.1, *)
13381377
@_silgen_name("swift_task_hasTaskGroupStatusRecord")

stdlib/public/Concurrency/TaskLocal.swift

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -181,10 +181,27 @@ public final class TaskLocal<Value: Sendable>: Sendable, CustomStringConvertible
181181
/// the operation closure.
182182
@inlinable
183183
@discardableResult
184-
@_unsafeInheritExecutor
185-
@backDeployed(before: SwiftStdlib 5.8)
186-
public func withValue<R>(_ valueDuringOperation: Value, operation: () async throws -> R,
184+
@available(SwiftStdlib 5.1, *)
185+
@backDeployed(before: SwiftStdlib 6.0)
186+
public func withValue<R>(_ valueDuringOperation: Value,
187+
operation: () async throws -> R,
188+
isolation: isolated (any Actor)? = #isolation,
187189
file: String = #fileID, line: UInt = #line) async rethrows -> R {
190+
return try await withValueImpl(
191+
valueDuringOperation,
192+
operation: operation,
193+
isolation: isolation,
194+
file: file, line: line)
195+
}
196+
197+
@usableFromInline
198+
@discardableResult
199+
@_unsafeInheritExecutor // ABI compatibility with Swift 5.1
200+
@available(SwiftStdlib 5.1, *)
201+
@_silgen_name("$ss9TaskLocalC9withValue_9operation4file4lineqd__x_qd__yYaKXESSSutYaKlF")
202+
internal func __abi_withValue<R>(_ valueDuringOperation: Value,
203+
operation: () async throws -> R,
204+
file: String = #fileID, line: UInt = #line) async rethrows -> R {
188205
return try await withValueImpl(valueDuringOperation, operation: operation, file: file, line: line)
189206
}
190207

@@ -206,11 +223,30 @@ public final class TaskLocal<Value: Sendable>: Sendable, CustomStringConvertible
206223
/// to swift_task_de/alloc for the copy as follows:
207224
/// - withValue contains the compiler-emitted calls swift_task_de/alloc.
208225
/// - withValueImpl contains the calls to _taskLocalValuePush/Pop
226+
@inlinable
227+
@discardableResult
228+
@available(SwiftStdlib 5.1, *)
229+
@backDeployed(before: SwiftStdlib 6.0)
230+
internal func withValueImpl<R>(_ valueDuringOperation: __owned Value,
231+
operation: () async throws -> R,
232+
isolation: isolated (any Actor)?,
233+
file: String = #fileID, line: UInt = #line) async rethrows -> R {
234+
// check if we're not trying to bind a value from an illegal context; this may crash
235+
_checkIllegalTaskLocalBindingWithinWithTaskGroup(file: file, line: line)
236+
237+
_taskLocalValuePush(key: key, value: consume valueDuringOperation)
238+
defer { _taskLocalValuePop() }
239+
240+
return try await operation()
241+
}
242+
209243
@inlinable
210244
@discardableResult
211245
@_unsafeInheritExecutor
246+
@available(SwiftStdlib 5.1, *)
212247
@backDeployed(before: SwiftStdlib 5.9)
213-
internal func withValueImpl<R>(_ valueDuringOperation: __owned Value, operation: () async throws -> R,
248+
internal func withValueImpl<R>(_ valueDuringOperation: __owned Value,
249+
operation: () async throws -> R,
214250
file: String = #fileID, line: UInt = #line) async rethrows -> R {
215251
// check if we're not trying to bind a value from an illegal context; this may crash
216252
_checkIllegalTaskLocalBindingWithinWithTaskGroup(file: file, line: line)
@@ -221,6 +257,7 @@ public final class TaskLocal<Value: Sendable>: Sendable, CustomStringConvertible
221257
return try await operation()
222258
}
223259

260+
224261
/// Binds the task-local to the specific value for the duration of the
225262
/// synchronous operation.
226263
///

stdlib/toolchain/Compatibility56/Concurrency/Actor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ class ExecutorTrackingInfo {
6767

6868
/// Unconditionally initialize a fresh tracking state on the
6969
/// current state, shadowing any previous tracking state.
70-
/// leave() must be called beforet the object goes out of scope.
70+
/// leave() must be called before the object goes out of scope.
7171
void enterAndShadow(ExecutorRef currentExecutor) {
7272
ActiveExecutor = currentExecutor;
7373
SavedInfo = ActiveInfoInThread.get();

0 commit comments

Comments
 (0)