Skip to content

[Concurrency] Remove last usages of @_unsafeInheritExecutor #73568

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion stdlib/public/Concurrency/Clock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ extension Clock {
}

@available(SwiftStdlib 5.7, *)
@_unsafeInheritExecutor
@_unsafeInheritExecutor // for ABI compatibility
@usableFromInline
internal func measure(
_ work: () async throws -> Void
Expand Down
69 changes: 67 additions & 2 deletions stdlib/public/Concurrency/DiscardingTaskGroup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,37 @@ import Swift
///
/// - SeeAlso: ``withThrowingDiscardingTaskGroup(returning:body:)
@available(SwiftStdlib 5.9, *)
@backDeployed(before: SwiftStdlib 6.0)
@inlinable
@_unsafeInheritExecutor
public func withDiscardingTaskGroup<GroupResult>(
returning returnType: GroupResult.Type = GroupResult.self,
isolation: isolated (any Actor)? = #isolation,
body: (inout DiscardingTaskGroup) async -> GroupResult
) async -> GroupResult {
#if compiler(>=5.5) && $BuiltinCreateTaskGroupWithFlags
let flags = taskGroupCreateFlags(
discardResults: true
)

let _group = Builtin.createTaskGroupWithFlags(flags, GroupResult.self)
var group = DiscardingTaskGroup(group: _group)
defer { Builtin.destroyTaskGroup(_group) }

let result = await body(&group)

try! await group.awaitAllRemainingTasks() // try!-safe, cannot throw since this is a non throwing group

return result
#else
fatalError("Swift compiler is incompatible with this SDK version")
#endif
}

@available(SwiftStdlib 5.9, *)
@usableFromInline
@_unsafeInheritExecutor // for ABI compatibility
@_silgen_name("$ss23withDiscardingTaskGroup9returning4bodyxxm_xs0bcD0VzYaXEtYalF")
internal func __abi_withDiscardingTaskGroup<GroupResult>(
returning returnType: GroupResult.Type = GroupResult.self,
body: (inout DiscardingTaskGroup) async -> GroupResult
) async -> GroupResult {
Expand Down Expand Up @@ -709,9 +737,46 @@ extension DiscardingTaskGroup: Sendable { }
/// }
/// ```
@available(SwiftStdlib 5.9, *)
@backDeployed(before: SwiftStdlib 6.0)
@inlinable
@_unsafeInheritExecutor
public func withThrowingDiscardingTaskGroup<GroupResult>(
returning returnType: GroupResult.Type = GroupResult.self,
isolation: isolated (any Actor)? = #isolation,
body: (inout ThrowingDiscardingTaskGroup<Error>) async throws -> GroupResult
) async throws -> GroupResult {
#if compiler(>=5.5) && $BuiltinCreateTaskGroupWithFlags
let flags = taskGroupCreateFlags(
discardResults: true
)

let _group = Builtin.createTaskGroupWithFlags(flags, GroupResult.self)
var group = ThrowingDiscardingTaskGroup<Error>(group: _group)
defer { Builtin.destroyTaskGroup(_group) }

let result: GroupResult
do {
result = try await body(&group)
} catch {
group.cancelAll()

try await group.awaitAllRemainingTasks(bodyError: error)

throw error
}

try await group.awaitAllRemainingTasks(bodyError: nil)

return result
#else
fatalError("Swift compiler is incompatible with this SDK version")
#endif
}

@available(SwiftStdlib 5.9, *)
@usableFromInline
@_unsafeInheritExecutor // for ABI compatibility
@_silgen_name("$ss31withThrowingDiscardingTaskGroup9returning4bodyxxm_xs0bcdE0Vys5Error_pGzYaKXEtYaKlF")
internal func __abi_withThrowingDiscardingTaskGroup<GroupResult>(
returning returnType: GroupResult.Type = GroupResult.self,
body: (inout ThrowingDiscardingTaskGroup<Error>) async throws -> GroupResult
) async throws -> GroupResult {
Expand Down
2 changes: 1 addition & 1 deletion stdlib/public/Concurrency/Task+TaskExecutor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ public func withTaskExecutorPreference<T, Failure>(

@_unavailableInEmbedded
@available(SwiftStdlib 6.0, *)
@_unsafeInheritExecutor // calling withTaskExecutor MUST NOT perform the "usual" hop to global
@_unsafeInheritExecutor // for ABI compatibility
@_silgen_name("$ss26withTaskExecutorPreference_9operationxSch_pSg_xyYaYbKXEtYaKs8SendableRzlF")
public func __abi__withTaskExecutorPreference<T: Sendable>(
_ taskExecutor: (any TaskExecutor)?,
Expand Down
20 changes: 18 additions & 2 deletions stdlib/public/Concurrency/TaskCancellation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,26 @@ import Swift
/// as resuming a continuation, may acquire these same internal locks.
/// Therefore, if a cancellation handler must acquire a lock, other code should
/// not cancel tasks or resume continuations while holding that lock.
@_unsafeInheritExecutor // the operation runs on the same executor as we start out with
@available(SwiftStdlib 5.1, *)
@backDeployed(before: SwiftStdlib 5.8)
@backDeployed(before: SwiftStdlib 6.0)
public func withTaskCancellationHandler<T>(
operation: () async throws -> T,
onCancel handler: @Sendable () -> Void,
isolation: isolated (any Actor)? = #isolation
) async rethrows -> T {
// unconditionally add the cancellation record to the task.
// if the task was already cancelled, it will be executed right away.
let record = _taskAddCancellationHandler(handler: handler)
defer { _taskRemoveCancellationHandler(record: record) }

return try await operation()
}

@_unsafeInheritExecutor // ABI compatibility with Swift 5.1
@available(SwiftStdlib 5.1, *)
@usableFromInline
@_silgen_name("$ss27withTaskCancellationHandler9operation8onCancelxxyYaKXE_yyYbXEtYaKlF")
internal func __abi_withTaskCancellationHandler<T>(
operation: () async throws -> T,
onCancel handler: @Sendable () -> Void
) async rethrows -> T {
Expand Down
72 changes: 66 additions & 6 deletions stdlib/public/Concurrency/TaskGroup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,36 @@ import Swift
/// such as returning the work completed so far, returning an empty result, or returning `nil`.
/// For tasks that need to handle cancellation by throwing an error,
/// use the `withThrowingTaskGroup(of:returning:body:)` method instead.
@available(SwiftStdlib 5.1, *)
@backDeployed(before: SwiftStdlib 6.0, *)
@inlinable
public func withTaskGroup<ChildTaskResult, GroupResult>(
of childTaskResultType: ChildTaskResult.Type,
returning returnType: GroupResult.Type = GroupResult.self,
isolation: isolated (any Actor)? = #isolation,
body: (inout TaskGroup<ChildTaskResult>) async -> GroupResult
) async -> GroupResult {
#if compiler(>=5.5) && $BuiltinTaskGroupWithArgument

let _group = Builtin.createTaskGroup(ChildTaskResult.self)
var group = TaskGroup<ChildTaskResult>(group: _group)

// Run the withTaskGroup body.
let result = await body(&group)

await group.awaitAllRemainingTasks()

Builtin.destroyTaskGroup(_group)
return result

#else
fatalError("Swift compiler is incompatible with this SDK version")
#endif
}

@available(SwiftStdlib 5.1, *)
@_silgen_name("$ss13withTaskGroup2of9returning4bodyq_xm_q_mq_ScGyxGzYaXEtYar0_lF")
@_unsafeInheritExecutor
@_unsafeInheritExecutor // for ABI compatibility
@inlinable
public func withTaskGroup<ChildTaskResult, GroupResult>(
of childTaskResultType: ChildTaskResult.Type,
Expand All @@ -80,7 +107,6 @@ public func withTaskGroup<ChildTaskResult, GroupResult>(
// Run the withTaskGroup body.
let result = await body(&group)

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

Builtin.destroyTaskGroup(_group)
Expand Down Expand Up @@ -167,10 +193,46 @@ public func withTaskGroup<ChildTaskResult, GroupResult>(
/// which gives you a chance to handle the individual error
/// or to let the group rethrow the error.
@available(SwiftStdlib 5.1, *)
@_silgen_name("$ss21withThrowingTaskGroup2of9returning4bodyq_xm_q_mq_Scgyxs5Error_pGzYaKXEtYaKr0_lF")
@_unsafeInheritExecutor
@backDeployed(before: SwiftStdlib 6.0)
@inlinable
public func withThrowingTaskGroup<ChildTaskResult, GroupResult>(
of childTaskResultType: ChildTaskResult.Type,
returning returnType: GroupResult.Type = GroupResult.self,
isolation: isolated (any Actor)? = #isolation,
body: (inout ThrowingTaskGroup<ChildTaskResult, Error>) async throws -> GroupResult
) async rethrows -> GroupResult {
#if compiler(>=5.5) && $BuiltinTaskGroupWithArgument

let _group = Builtin.createTaskGroup(ChildTaskResult.self)
var group = ThrowingTaskGroup<ChildTaskResult, Error>(group: _group)

do {
// Run the withTaskGroup body.
let result = try await body(&group)

await group.awaitAllRemainingTasks()
Builtin.destroyTaskGroup(_group)

return result
} catch {
group.cancelAll()

await group.awaitAllRemainingTasks()
Builtin.destroyTaskGroup(_group)

throw error
}

#else
fatalError("Swift compiler is incompatible with this SDK version")
#endif
}

@available(SwiftStdlib 5.1, *)
@_silgen_name("$ss21withThrowingTaskGroup2of9returning4bodyq_xm_q_mq_Scgyxs5Error_pGzYaKXEtYaKr0_lF")
@_unsafeInheritExecutor // for ABI compatibility
@usableFromInline
internal func withThrowingTaskGroup<ChildTaskResult, GroupResult>(
of childTaskResultType: ChildTaskResult.Type,
returning returnType: GroupResult.Type = GroupResult.self,
body: (inout ThrowingTaskGroup<ChildTaskResult, Error>) async throws -> GroupResult
Expand All @@ -184,15 +246,13 @@ public func withThrowingTaskGroup<ChildTaskResult, GroupResult>(
// Run the withTaskGroup body.
let result = try await body(&group)

// TODO(concurrency): should get isolation from param from withThrowingTaskGroup
await group.awaitAllRemainingTasks()
Builtin.destroyTaskGroup(_group)

return result
} catch {
group.cancelAll()

// TODO(concurrency): should get isolation from param from withThrowingTaskGroup
await group.awaitAllRemainingTasks()
Builtin.destroyTaskGroup(_group)

Expand Down
2 changes: 1 addition & 1 deletion stdlib/public/Concurrency/TaskLocal.swift
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ public final class TaskLocal<Value: Sendable>: Sendable, CustomStringConvertible

@inlinable
@discardableResult
@_unsafeInheritExecutor
@_unsafeInheritExecutor // internal for backwards compatibility; though may be able to be removed safely?
@available(SwiftStdlib 5.1, *)
@backDeployed(before: SwiftStdlib 5.9)
internal func withValueImpl<R>(_ valueDuringOperation: __owned Value,
Expand Down
24 changes: 23 additions & 1 deletion test/Concurrency/actor_withCancellationHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// REQUIRES: concurrency
// REQUIRES: asserts

actor foo {
actor Foo {
var t: Task<Void, Error>?

func access() {}
Expand All @@ -22,3 +22,25 @@ actor foo {
}
}
}

actor Container {
var num: Int = 0 // expected-note{{mutation of this property is only permitted within the actor}}
func test() async {

// no warnings:
await withTaskCancellationHandler {
num += 1
} onCancel: {
// nothing
}
}

func errors() async {
await withTaskCancellationHandler {
num += 1 // no error, this runs synchronously on caller context
} onCancel: {
// this should error because cancellation is invoked concurrently
num += 10 // expected-error{{actor-isolated property 'num' can not be mutated from a Sendable closure}}
}
}
}
27 changes: 27 additions & 0 deletions test/Concurrency/async_task_group_body_inherit_isolation.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// RUN: %target-swift-frontend -emit-sil -verify -o /dev/null -disable-availability-checking %s -swift-version 6 -strict-concurrency=complete

// REQUIRES: concurrency
// REQUIRES: asserts

actor A {
func g() { }
func h() throws { }

func f() async throws {
await withTaskGroup(of: Int.self, returning: Void.self) { group in
self.g()
}

try await withThrowingTaskGroup(of: String.self, returning: Void.self) { group in
try self.h()
}

await withDiscardingTaskGroup(returning: Void.self) { group in
self.g()
}

try await withThrowingDiscardingTaskGroup(returning: Void.self) { group in
try self.h()
}
}
}
19 changes: 0 additions & 19 deletions test/Concurrency/unsafe_inherit_executor_lib.swift

This file was deleted.

14 changes: 13 additions & 1 deletion test/abi/macOS/arm64/concurrency.swift
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,19 @@ Added: _$sScf13checkIsolatedyyFTj
// method descriptor for Swift.SerialExecutor.checkIsolated() -> ()
Added: _$sScf13checkIsolatedyyFTq

// #isolated adoption in TaskLocal.withValue
// #isolated adoption in multiple APIs
// withTaskCancellationHandler gains #isolated
Added: _$ss27withTaskCancellationHandler9operation8onCancel9isolationxxyYaKXE_yyYbXEScA_pSgYitYaKlF
Added: _$ss27withTaskCancellationHandler9operation8onCancel9isolationxxyYaKXE_yyYbXEScA_pSgYitYaKlFTu
// TaskGroup.with... APIs gain #isolated
Added: _$ss23withDiscardingTaskGroup9returning9isolation4bodyxxm_ScA_pSgYixs0bcD0VzYaXEtYalF
Added: _$ss23withDiscardingTaskGroup9returning9isolation4bodyxxm_ScA_pSgYixs0bcD0VzYaXEtYalFTu
Added: _$ss13withTaskGroup2of9returning9isolation4bodyq_xm_q_mScA_pSgYiq_ScGyxGzYaXEtYas8SendableRzr0_lF
Added: _$ss13withTaskGroup2of9returning9isolation4bodyq_xm_q_mScA_pSgYiq_ScGyxGzYaXEtYas8SendableRzr0_lFTu
Added: _$ss31withThrowingDiscardingTaskGroup9returning9isolation4bodyxxm_ScA_pSgYixs0bcdE0Vys5Error_pGzYaKXEtYaKlF
Added: _$ss31withThrowingDiscardingTaskGroup9returning9isolation4bodyxxm_ScA_pSgYixs0bcdE0Vys5Error_pGzYaKXEtYaKlFTu
Added: _$ss21withThrowingTaskGroup2of9returning9isolation4bodyq_xm_q_mScA_pSgYiq_Scgyxs5Error_pGzYaKXEtYaKs8SendableRzr0_lF
Added: _$ss21withThrowingTaskGroup2of9returning9isolation4bodyq_xm_q_mScA_pSgYiq_Scgyxs5Error_pGzYaKXEtYaKs8SendableRzr0_lFTu
// Swift.TaskLocal.withValueImpl<A>(_: __owned A, operation: () async throws -> A1, isolation: isolated Swift.Actor?, file: Swift.String, line: Swift.UInt) async throws -> A1
Added: _$ss9TaskLocalC13withValueImpl_9operation9isolation4file4lineqd__xn_qd__yYaKXEScA_pSgYiSSSutYaKlF
Added: _$ss9TaskLocalC13withValueImpl_9operation9isolation4file4lineqd__xn_qd__yYaKXEScA_pSgYiSSSutYaKlFTu
Expand Down
14 changes: 13 additions & 1 deletion test/abi/macOS/x86_64/concurrency.swift
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,19 @@ Added: _$sScf13checkIsolatedyyFTj
// method descriptor for Swift.SerialExecutor.checkIsolated() -> ()
Added: _$sScf13checkIsolatedyyFTq

// #isolated adoption in TaskLocal.withValue
// #isolated adoption in multiple APis
// withTaskCancellationHandler gains #isolated
Added: _$ss27withTaskCancellationHandler9operation8onCancel9isolationxxyYaKXE_yyYbXEScA_pSgYitYaKlF
Added: _$ss27withTaskCancellationHandler9operation8onCancel9isolationxxyYaKXE_yyYbXEScA_pSgYitYaKlFTu
// TaskGroup.with... APIs gain #isolated
Added: _$ss23withDiscardingTaskGroup9returning9isolation4bodyxxm_ScA_pSgYixs0bcD0VzYaXEtYalF
Added: _$ss23withDiscardingTaskGroup9returning9isolation4bodyxxm_ScA_pSgYixs0bcD0VzYaXEtYalFTu
Added: _$ss13withTaskGroup2of9returning9isolation4bodyq_xm_q_mScA_pSgYiq_ScGyxGzYaXEtYas8SendableRzr0_lF
Added: _$ss13withTaskGroup2of9returning9isolation4bodyq_xm_q_mScA_pSgYiq_ScGyxGzYaXEtYas8SendableRzr0_lFTu
Added: _$ss31withThrowingDiscardingTaskGroup9returning9isolation4bodyxxm_ScA_pSgYixs0bcdE0Vys5Error_pGzYaKXEtYaKlF
Added: _$ss31withThrowingDiscardingTaskGroup9returning9isolation4bodyxxm_ScA_pSgYixs0bcdE0Vys5Error_pGzYaKXEtYaKlFTu
Added: _$ss21withThrowingTaskGroup2of9returning9isolation4bodyq_xm_q_mScA_pSgYiq_Scgyxs5Error_pGzYaKXEtYaKs8SendableRzr0_lF
Added: _$ss21withThrowingTaskGroup2of9returning9isolation4bodyq_xm_q_mScA_pSgYiq_Scgyxs5Error_pGzYaKXEtYaKs8SendableRzr0_lFTu
// Swift.TaskLocal.withValueImpl<A>(_: __owned A, operation: () async throws -> A1, isolation: isolated Swift.Actor?, file: Swift.String, line: Swift.UInt) async throws -> A1
Added: _$ss9TaskLocalC13withValueImpl_9operation9isolation4file4lineqd__xn_qd__yYaKXEScA_pSgYiSSSutYaKlF
Added: _$ss9TaskLocalC13withValueImpl_9operation9isolation4file4lineqd__xn_qd__yYaKXEScA_pSgYiSSSutYaKlFTu
Expand Down
4 changes: 4 additions & 0 deletions test/api-digester/stability-concurrency-abi.test
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ Func withCheckedThrowingContinuation(function:_:) has mangled name changing from
Func withCheckedThrowingContinuation(function:_:) has parameter 0 type change from Swift.String to (any _Concurrency.Actor)?
Func withCheckedThrowingContinuation(function:_:) has parameter 1 type change from (_Concurrency.CheckedContinuation<τ_0_0, any Swift.Error>) -> () to Swift.String

// #isolation adoption for cancellation handlers; old APIs are kept ABI compatible
Func withTaskCancellationHandler(operation:onCancel:) has been renamed to Func withTaskCancellationHandler(operation:onCancel:isolation:)
Func withTaskCancellationHandler(operation:onCancel:) has mangled name changing from '_Concurrency.withTaskCancellationHandler<A>(operation: () async throws -> A, onCancel: @Sendable () -> ()) async throws -> A' to '_Concurrency.withTaskCancellationHandler<A>(operation: () async throws -> A, onCancel: @Sendable () -> (), isolation: isolated Swift.Optional<Swift.Actor>) async throws -> A'

// #isolated was adopted and the old methods kept: $ss31withCheckedThrowingContinuation8function_xSS_yScCyxs5Error_pGXEtYaKlF
Func withCheckedContinuation(function:_:) has been renamed to Func withCheckedContinuation(isolation:function:_:)
Func withCheckedContinuation(function:_:) has mangled name changing from '_Concurrency.withCheckedContinuation<A>(function: Swift.String, _: (Swift.CheckedContinuation<A, Swift.Never>) -> ()) async -> A' to '_Concurrency.withCheckedContinuation<A>(isolation: isolated Swift.Optional<Swift.Actor>, function: Swift.String, _: (Swift.CheckedContinuation<A, Swift.Never>) -> ()) async -> A'
Expand Down