Skip to content

Commit fbc829f

Browse files
committed
[Distributed] Don't hang, but throw when target accessor not found
1 parent c2f5d57 commit fbc829f

File tree

3 files changed

+93
-2
lines changed

3 files changed

+93
-2
lines changed

stdlib/public/Distributed/DistributedActor.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,11 @@ static void swift_distributed_execute_target_resume(
109109
return resumeInParent(parentCtx, error);
110110
}
111111

112+
SWIFT_CC(swift)
113+
SWIFT_EXPORT_FROM(swiftDistributed)
114+
SwiftError* swift_distributed_makeDistributedTargetAccessorNotFoundError(
115+
const char *targetNameStart, size_t targetNameLength);
116+
112117
SWIFT_CC(swiftasync)
113118
void swift_distributed_execute_target(
114119
SWIFT_ASYNC_CONTEXT AsyncContext *callerContext,
@@ -124,8 +129,12 @@ void swift_distributed_execute_target(
124129
void **decoderWitnessTable) {
125130
auto *accessor = findDistributedAccessor(targetNameStart, targetNameLength);
126131
if (!accessor) {
127-
assert(false && "no distributed accessor");
128-
return; // FIXME(distributed): return -1 here so the lib can fail the call
132+
SwiftError *error =
133+
swift_distributed_makeDistributedTargetAccessorNotFoundError(targetNameStart, targetNameLength);
134+
auto resumeInParent =
135+
reinterpret_cast<TargetExecutorSignature::ContinuationType *>(
136+
callerContext->ResumeParent);
137+
return resumeInParent(callerContext, error);
129138
}
130139

131140
auto *asyncFnPtr = reinterpret_cast<

stdlib/public/Distributed/DistributedMetadata.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,14 @@ func _getWitnessTablesFor(
108108
environment: UnsafeRawPointer,
109109
genericArguments: UnsafeRawPointer
110110
) -> (UnsafeRawPointer, Int)
111+
112+
@available(SwiftStdlib 5.7, *)
113+
@_silgen_name("swift_distributed_makeDistributedTargetAccessorNotFoundError")
114+
public // SPI Distributed
115+
func _makeDistributedTargetAccessorNotFoundError(
116+
_ targetNameStart: UnsafePointer<UInt8>,
117+
_ targetNameLength: UInt
118+
) -> Error {
119+
let name = String(decodingCString: targetNameStart, as: Unicode.UTF8.self)
120+
return ExecuteDistributedTargetError(message: "Could not find distributed accessor for target \(name)")
121+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -disable-availability-checking %S/../Inputs/FakeDistributedActorSystems.swift
3+
// RUN: %target-build-swift -module-name main -Xfrontend -disable-availability-checking -j2 -parse-as-library -I %t %s %S/../Inputs/FakeDistributedActorSystems.swift -o %t/a.out
4+
// RUN: %target-run %t/a.out | %FileCheck %s --color
5+
6+
// REQUIRES: executable_test
7+
// REQUIRES: concurrency
8+
// REQUIRES: distributed
9+
10+
// rdar://76038845
11+
// UNSUPPORTED: use_os_stdlib
12+
// UNSUPPORTED: back_deployment_runtime
13+
14+
// FIXME(distributed): Distributed actors currently have some issues on windows, isRemote always returns false. rdar://82593574
15+
// UNSUPPORTED: OS=windows-msvc
16+
17+
import Distributed
18+
import FakeDistributedActorSystems
19+
20+
typealias DefaultDistributedActorSystem = FakeRoundtripActorSystem
21+
22+
distributed actor Greeter {
23+
distributed func greet(name: String) -> String {
24+
"Hello, \(name)!"
25+
}
26+
}
27+
28+
func test() async throws {
29+
let system = DefaultDistributedActorSystem()
30+
let local = Greeter(actorSystem: system)
31+
let ref = try Greeter.resolve(id: local.id, using: system)
32+
33+
// Make sure normal call works ok:
34+
let greeting = try await ref.greet(name: "Caplin")
35+
print("\(greeting)")
36+
// CHECK: Hello, Caplin!
37+
38+
let correctTargetIdentifier = "$s4main7GreeterC5greet4nameS2S_tYaKFTE"
39+
_ = correctTargetIdentifier
40+
let badModuleTargetIdentifier = "$s9BADMODULE7GreeterC5greet4nameS2S_tYaKFTE"
41+
// the BADMODULE is a bad module, and we won't be able to find the distributed accessor
42+
// this should result in a failed call, but not hang the call.
43+
44+
var invocation = Greeter.ActorSystem.InvocationEncoder()
45+
invocation.arguments = ["BadCall"]
46+
invocation.returnType = String.self
47+
48+
let badTarget = RemoteCallTarget(badModuleTargetIdentifier)
49+
50+
do {
51+
// CHECK: >> remoteCall: on:main.Greeter, target:BADMODULE.Greeter.greet(name:)
52+
let call = try await system.remoteCall(
53+
on: local,
54+
target: badTarget,
55+
invocation: &invocation,
56+
throwing: Never.self,
57+
returning: String.self
58+
)
59+
} catch {
60+
// CHECK: << onThrow: ExecuteDistributedTargetError(message: "Could not find distributed accessor for target $s9BADMODULE7GreeterC5greet4nameS2S_tYaKFTE")
61+
// CHECK: << remoteCall throw: ExecuteDistributedTargetError(message: "Could not find distributed accessor for target $s9BADMODULE7GreeterC5greet4nameS2S_tYaKFTE")
62+
print("caught error: \(error)")
63+
// CHECK: caught error: ExecuteDistributedTargetError(message: "Could not find distributed accessor for target $s9BADMODULE7GreeterC5greet4nameS2S_tYaKFTE")
64+
}
65+
}
66+
67+
@main struct Main {
68+
static func main() async {
69+
try! await test()
70+
}
71+
}

0 commit comments

Comments
 (0)