From 5f9721c7fbb4da17e836ae3fdede0e31a0efb978 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Thu, 21 Oct 2021 23:26:02 -0700 Subject: [PATCH 1/4] Ensure that we hop off the main actor after MainActor.run. Asynchronous functions isolated to global actors hop to the global at the beginning of the function but do not hop back on return. For `MainActor.run`, this means that we would not "hop back" off the main actor after executing the closure, which lead to too much code running on the main thread. Dropping the "async" ensures that we hop back. While we my also want the general "hop back" semantics for asynchronous actor-isolated functions, for now this addresses the problem with `MainActor.run`. Fixes rdar://82138050. --- stdlib/public/Concurrency/MainActor.swift | 21 +++++++++++++++++-- .../stability-concurrency-abi.test | 1 - 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/stdlib/public/Concurrency/MainActor.swift b/stdlib/public/Concurrency/MainActor.swift index a5be79fd0305b..6b32ff09c869e 100644 --- a/stdlib/public/Concurrency/MainActor.swift +++ b/stdlib/public/Concurrency/MainActor.swift @@ -45,12 +45,29 @@ import Swift @available(SwiftStdlib 5.5, *) extension MainActor { /// Execute the given body closure on the main actor. - @_silgen_name("$sScM3run10resultType4bodyxxm_xyYbKScMYcXEtYaKlFZ") + /// + /// Historical ABI entry point, superceded by the Sendable version that is + /// also inlined to back-deploy a semantic fix where this operation would + /// not hop back at the end. + @usableFromInline + static func run( + resultType: T.Type = T.self, + body: @MainActor @Sendable () throws -> T + ) async rethrows -> T { + @MainActor func runOnMain(body: @MainActor @Sendable () throws -> T) rethrows -> T { + return try body() + } + + return try await runOnMain(body: body) + } + + /// Execute the given body closure on the main actor. + @_alwaysEmitIntoClient public static func run( resultType: T.Type = T.self, body: @MainActor @Sendable () throws -> T ) async rethrows -> T { - @MainActor func runOnMain(body: @MainActor @Sendable () throws -> T) async rethrows -> T { + @MainActor func runOnMain(body: @MainActor @Sendable () throws -> T) rethrows -> T { return try body() } diff --git a/test/api-digester/stability-concurrency-abi.test b/test/api-digester/stability-concurrency-abi.test index 54600f6772768..248e206fe3f08 100644 --- a/test/api-digester/stability-concurrency-abi.test +++ b/test/api-digester/stability-concurrency-abi.test @@ -50,5 +50,4 @@ // UNSUPPORTED: swift_evolve // *** DO NOT DISABLE OR XFAIL THIS TEST. *** (See comment above.) - // *** DO NOT DISABLE OR XFAIL THIS TEST. *** (See comment above.) From 2850b65bd933c8906c2eb56b38e724b951df8c31 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Fri, 22 Oct 2021 08:30:50 -0700 Subject: [PATCH 2/4] Simplify implementation and fix a test --- stdlib/public/Concurrency/MainActor.swift | 6 +----- test/api-digester/stability-concurrency-abi.test | 1 + 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/stdlib/public/Concurrency/MainActor.swift b/stdlib/public/Concurrency/MainActor.swift index 6b32ff09c869e..0c9d854813d60 100644 --- a/stdlib/public/Concurrency/MainActor.swift +++ b/stdlib/public/Concurrency/MainActor.swift @@ -67,10 +67,6 @@ extension MainActor { resultType: T.Type = T.self, body: @MainActor @Sendable () throws -> T ) async rethrows -> T { - @MainActor func runOnMain(body: @MainActor @Sendable () throws -> T) rethrows -> T { - return try body() - } - - return try await runOnMain(body: body) + return try await body() } } diff --git a/test/api-digester/stability-concurrency-abi.test b/test/api-digester/stability-concurrency-abi.test index 248e206fe3f08..6b7af2b0723b0 100644 --- a/test/api-digester/stability-concurrency-abi.test +++ b/test/api-digester/stability-concurrency-abi.test @@ -50,4 +50,5 @@ // UNSUPPORTED: swift_evolve // *** DO NOT DISABLE OR XFAIL THIS TEST. *** (See comment above.) +Func MainActor.run(resultType:body:) has generic signature change from to // *** DO NOT DISABLE OR XFAIL THIS TEST. *** (See comment above.) From 420e21a28790dac0d32485c2832251018a2afa36 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Fri, 22 Oct 2021 08:39:22 -0700 Subject: [PATCH 3/4] Fix the other implementation, too. --- stdlib/public/Concurrency/MainActor.swift | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/stdlib/public/Concurrency/MainActor.swift b/stdlib/public/Concurrency/MainActor.swift index 0c9d854813d60..1d036532e344e 100644 --- a/stdlib/public/Concurrency/MainActor.swift +++ b/stdlib/public/Concurrency/MainActor.swift @@ -54,11 +54,7 @@ extension MainActor { resultType: T.Type = T.self, body: @MainActor @Sendable () throws -> T ) async rethrows -> T { - @MainActor func runOnMain(body: @MainActor @Sendable () throws -> T) rethrows -> T { - return try body() - } - - return try await runOnMain(body: body) + return try await body() } /// Execute the given body closure on the main actor. From 150f32c6907b857c2f8dc9476ca9739c01b0cddf Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Fri, 22 Oct 2021 14:42:48 -0700 Subject: [PATCH 4/4] Fix resilience of global actor hops and test MainActor.run. --- lib/SILGen/SILGenProlog.cpp | 2 +- test/Concurrency/Runtime/mainactor.swift | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/SILGen/SILGenProlog.cpp b/lib/SILGen/SILGenProlog.cpp index da41bd035861c..6e1da3f062963 100644 --- a/lib/SILGen/SILGenProlog.cpp +++ b/lib/SILGen/SILGenProlog.cpp @@ -642,7 +642,7 @@ SILValue SILGenFunction::emitLoadGlobalActorExecutor(Type globalActor) { actorType->getTypeOfMember(SGM.SwiftModule, sharedInstanceDecl); auto metaRepr = - nominal->isResilient(SGM.SwiftModule, ResilienceExpansion::Maximal) + nominal->isResilient(SGM.SwiftModule, F.getResilienceExpansion()) ? MetatypeRepresentation::Thick : MetatypeRepresentation::Thin; diff --git a/test/Concurrency/Runtime/mainactor.swift b/test/Concurrency/Runtime/mainactor.swift index 061b3ec22b587..9927592657084 100644 --- a/test/Concurrency/Runtime/mainactor.swift +++ b/test/Concurrency/Runtime/mainactor.swift @@ -81,6 +81,10 @@ actor A { // CHECK-NOT: ERROR // CHECK: finished with return counter = 4 +// CHECK: detached task not on main queue +// CHECK: on main queue again +// CHECK: detached task hopped back + @main struct RunIt { static func main() async { print("starting") @@ -91,5 +95,25 @@ actor A { } let result = await someFunc() print("finished with return counter = \(result)") + + // Check actor hopping with MainActor.run. + let task = Task.detached { + if checkIfMainQueue(expectedAnswer: false) { + print("detached task not on main queue") + } else { + print("ERROR: detached task is on the main queue?") + } + + _ = await MainActor.run { + checkAnotherFn(1) + } + + if checkIfMainQueue(expectedAnswer: false) { + print("detached task hopped back") + } else { + print("ERROR: detached task is on the main queue?") + } + } + _ = await task.value } }