Skip to content

Commit 9dcd6e4

Browse files
committed
[Distributed] implement more deinit tests
1 parent a99e935 commit 9dcd6e4

File tree

5 files changed

+260
-53
lines changed

5 files changed

+260
-53
lines changed

lol

-51.8 KB
Binary file not shown.

stdlib/public/Concurrency/Actor.cpp

Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -686,7 +686,7 @@ class DefaultActorImpl : public HeapObject {
686686
/// Properly construct an actor, except for the heap header.
687687
void initialize(bool isDistributedRemote = false) {
688688
auto flags = Flags();
689-
flags.setIsDistributedRemote(true);
689+
flags.setIsDistributedRemote(isDistributedRemote);
690690
new (&CurrentState) std::atomic<State>(State{JobRef(), flags});
691691
}
692692

@@ -1751,38 +1751,6 @@ void swift::swift_defaultActor_deallocateResilient(HeapObject *actor) {
17511751
metadata->getInstanceAlignMask());
17521752
}
17531753

1754-
OpaqueValue*
1755-
swift::swift_distributedActor_remote_initialize(const Metadata *actorType) {
1756-
auto *classMetadata = actorType->getClassObject();
1757-
1758-
// TODO(distributed): make this allocation smaller
1759-
// ==== Allocate the memory for the remote instance
1760-
HeapObject *alloc = swift_allocObject(classMetadata,
1761-
classMetadata->getInstanceSize(),
1762-
classMetadata->getInstanceAlignMask());
1763-
1764-
// TODO(distributed): a remote one does not have to have the "real"
1765-
// default actor body, e.g. we don't need an executor at all; so
1766-
// we can allocate more efficiently and only share the flags/status field
1767-
// between the both memory representations
1768-
// --- Currently we ride on the DefaultActorImpl to reuse the memory layout
1769-
// of the flags etc. So initialize the default actor into the allocation.
1770-
auto actor = asImpl(reinterpret_cast<DefaultActor*>(alloc));
1771-
actor->initialize(/*remote*/true);
1772-
assert(actor->isDistributedRemote());
1773-
1774-
return reinterpret_cast<OpaqueValue*>(actor);
1775-
}
1776-
1777-
void swift::swift_distributedActor_destroy(DefaultActor *_actor) {
1778-
// FIXME(distributed): if this is a proxy, we would destroy a bit differently I guess? less memory was allocated etc.
1779-
asImpl(_actor)->destroy(); // today we just replicate what defaultActor_destroy does
1780-
}
1781-
1782-
bool swift::swift_distributed_actor_is_remote(DefaultActor *_actor) {
1783-
return asImpl(_actor)->isDistributedRemote();
1784-
}
1785-
17861754
/// FIXME: only exists for the quick-and-dirtraKASASAasasy MainActor implementation.
17871755
namespace swift {
17881756
Metadata* MainActorMetadata = nullptr;
@@ -1988,11 +1956,44 @@ static void swift_task_enqueueImpl(Job *job, ExecutorRef executor) {
19881956
#define OVERRIDE_ACTOR COMPATIBILITY_OVERRIDE
19891957
#include COMPATIBILITY_OVERRIDE_INCLUDE_PATH
19901958

1959+
19911960
/*****************************************************************************/
19921961
/***************************** DISTRIBUTED ACTOR *****************************/
19931962
/*****************************************************************************/
19941963

1964+
OpaqueValue*
1965+
swift::swift_distributedActor_remote_initialize(const Metadata *actorType) {
1966+
auto *classMetadata = actorType->getClassObject();
1967+
1968+
// TODO(distributed): make this allocation smaller
1969+
// ==== Allocate the memory for the remote instance
1970+
HeapObject *alloc = swift_allocObject(classMetadata,
1971+
classMetadata->getInstanceSize(),
1972+
classMetadata->getInstanceAlignMask());
1973+
1974+
// TODO(distributed): a remote one does not have to have the "real"
1975+
// default actor body, e.g. we don't need an executor at all; so
1976+
// we can allocate more efficiently and only share the flags/status field
1977+
// between the both memory representations
1978+
// --- Currently we ride on the DefaultActorImpl to reuse the memory layout
1979+
// of the flags etc. So initialize the default actor into the allocation.
1980+
auto actor = asImpl(reinterpret_cast<DefaultActor*>(alloc));
1981+
actor->initialize(/*remote*/true);
1982+
assert(actor->isDistributedRemote());
1983+
1984+
return reinterpret_cast<OpaqueValue*>(actor);
1985+
}
1986+
1987+
void swift::swift_distributedActor_destroy(DefaultActor *_actor) {
1988+
// FIXME(distributed): if this is a proxy, we would destroy a bit differently I guess? less memory was allocated etc.
1989+
asImpl(_actor)->destroy(); // today we just replicate what defaultActor_destroy does
1990+
}
1991+
1992+
bool swift::swift_distributed_actor_is_remote(DefaultActor *_actor) {
1993+
return asImpl(_actor)->isDistributedRemote();
1994+
}
1995+
19951996
bool DefaultActorImpl::isDistributedRemote() {
19961997
auto state = CurrentState.load(std::memory_order_relaxed);
19971998
return state.Flags.isDistributedRemote();
1998-
}
1999+
}

test/Distributed/Runtime/distributed_actor_isRemote.swift

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,8 @@
55
// REQUIRES: distributed
66

77
// rdar://76038845
8-
// UN_SUPPORTED: use_os_stdlib
9-
// UN_SUPPORTED: back_deployment_runtime
10-
11-
// rdar://77798215
12-
// UN_SUPPORTED: OS=windows-msvc
8+
// UNSUPPORTED: use_os_stdlib
9+
// UNSUPPORTED: back_deployment_runtime
1310

1411
// RE_QUIRES: rdar78290608
1512

@@ -66,16 +63,16 @@ struct FakeTransport: ActorTransport {
6663
func assignIdentity<Act>(_ actorType: Act.Type) -> AnyActorIdentity
6764
where Act: DistributedActor {
6865
let id = ActorAddress(parse: "xxx")
69-
print("assign type:\(actorType), id:\(id)")
66+
print("assignIdentity type:\(actorType), id:\(id)")
7067
return .init(id)
7168
}
7269

7370
func actorReady<Act>(_ actor: Act) where Act: DistributedActor {
74-
print("ready actor:\(actor), id:\(actor.id)")
71+
print("actorReady actor:\(actor), id:\(actor.id)")
7572
}
7673

7774
func resignIdentity(_ id: AnyActorIdentity) {
78-
print("resign id:\(id)")
75+
print("resignIdentity id:\(id)")
7976
}
8077
}
8178

@@ -95,22 +92,22 @@ func test_remote() async {
9592
let address = ActorAddress(parse: "sact://127.0.0.1/example#1234")
9693
let transport = FakeTransport()
9794

98-
print("HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH")
99-
// let local = SomeSpecificDistributedActor(transport: transport)
100-
// assert(__isLocalActor(local) == true, "should be local")
101-
// assert(__isRemoteActor(local) == false, "should be local")
102-
// print("local.id = \(local.id)") // CHECK: NEIN
103-
// assert(AnyActorIdentity(address) == local.id)
95+
let local = SomeSpecificDistributedActor(transport: transport)
96+
assert(__isLocalActor(local) == true, "should be local")
97+
assert(__isRemoteActor(local) == false, "should be local")
98+
print("isRemote(local) = \(__isRemoteActor(local))") // CHECK: isRemote(local) = false
99+
print("local.id = \(local.id)") // CHECK: local.id = AnyActorIdentity(ActorAddress(address: "sact://127.0.0.1/example#1234"))
100+
print("local.transport = \(local.id)") // CHECK: local.transport = FakeTransport()
104101

105102
// assume it always makes a remote one
106103
let remote = try! SomeSpecificDistributedActor.resolve(.init(address), using: transport)
107-
// assert(__isLocalActor(remote) == false, "should be remote")
108-
// assert(__isRemoteActor(remote) == true, "should be remote")
104+
assert(__isLocalActor(remote) == false, "should be remote")
105+
assert(__isRemoteActor(remote) == true, "should be remote")
106+
print("isRemote(remote) = \(__isRemoteActor(remote))") // CHECK: isRemote(remote) = true
109107

110108
// Check the id and transport are the right values, and not trash memory
111-
print("remote.id = \(remote.id)") // CHECK: NEIN
112-
print("remote.transport = \(remote.actorTransport)") // CHECK: NEIN
113-
// assert(AnyActorIdentity(address) == remote.id)
109+
print("remote.id = \(remote.id)") // CHECK: remote.id = AnyActorIdentity(ActorAddress(address: "sact://127.0.0.1/example#1234"))
110+
print("remote.transport = \(remote.actorTransport)") // CHECK: remote.transport = FakeTransport()
114111

115112
print("done") // CHECK: done
116113
let xxx = remote
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// RUN: %target-run-simple-swift(-Onone -Xfrontend -g -Xfrontend -enable-experimental-distributed -parse-as-library) | %FileCheck %s --dump-input=always
2+
3+
// REQUIRES: executable_test
4+
// REQUIRES: concurrency
5+
// REQUIRES: distributed
6+
7+
// rdar://76038845
8+
// UNSUPPORTED: use_os_stdlib
9+
// UNSUPPORTED: back_deployment_runtime
10+
11+
// RE_QUIRES: rdar78290608
12+
13+
import _Distributed
14+
15+
@available(SwiftStdlib 5.5, *)
16+
distributed actor SomeSpecificDistributedActor {
17+
let name: String
18+
let surname: String
19+
let age: Int
20+
21+
init(name: String, transport: ActorTransport) {
22+
self.name = name
23+
self.surname = "Surname"
24+
self.age = 42
25+
}
26+
27+
deinit {
28+
print("deinit \(self.id)")
29+
}
30+
31+
distributed func hello() async throws -> String {
32+
"Hello, from \(name)"
33+
}
34+
}
35+
36+
// ==== Fake Transport ---------------------------------------------------------
37+
38+
@available(SwiftStdlib 5.5, *)
39+
struct FakeActorID: ActorIdentity {
40+
let id: UInt64
41+
}
42+
43+
@available(SwiftStdlib 5.5, *)
44+
enum FakeTransportError: ActorTransportError {
45+
case unsupportedActorIdentity(AnyActorIdentity)
46+
}
47+
48+
@available(SwiftStdlib 5.5, *)
49+
struct ActorAddress: ActorIdentity {
50+
let address: String
51+
init(parse address : String) {
52+
self.address = address
53+
}
54+
}
55+
56+
@available(SwiftStdlib 5.5, *)
57+
struct FakeTransport: ActorTransport {
58+
func decodeIdentity(from decoder: Decoder) throws -> AnyActorIdentity {
59+
fatalError("not implemented:\(#function)")
60+
}
61+
62+
func resolve<Act>(_ identity: AnyActorIdentity, as actorType: Act.Type)
63+
throws -> ActorResolved<Act>
64+
where Act: DistributedActor {
65+
.makeProxy
66+
}
67+
68+
func assignIdentity<Act>(_ actorType: Act.Type) -> AnyActorIdentity
69+
where Act: DistributedActor {
70+
let id = ActorAddress(parse: "xxx")
71+
print("assignIdentity type:\(actorType), id:\(id)")
72+
return .init(id)
73+
}
74+
75+
func actorReady<Act>(_ actor: Act) where Act: DistributedActor {
76+
print("actorReady actor:\(actor), id:\(actor.id)")
77+
}
78+
79+
func resignIdentity(_ id: AnyActorIdentity) {
80+
print("resignIdentity id:\(id)")
81+
}
82+
}
83+
84+
// ==== Execute ----------------------------------------------------------------
85+
86+
@available(SwiftStdlib 5.5, *)
87+
func test_remote() async {
88+
let address = ActorAddress(parse: "sact://127.0.0.1/example#1234")
89+
let transport = FakeTransport()
90+
91+
var remote: SomeSpecificDistributedActor? =
92+
try! SomeSpecificDistributedActor.resolve(.init(address), using: transport)
93+
// Check the id and transport are the right values, and not trash memory
94+
print("remote.id = \(remote!.id)") // CHECK: remote.id = AnyActorIdentity(ActorAddress(address: "sact://127.0.0.1/example#1234"))
95+
print("remote.transport = \(remote!.actorTransport)") // CHECK: remote.transport = FakeTransport()
96+
97+
remote = nil // CHECK: deinit AnyActorIdentity(ActorAddress(address: "sact://127.0.0.1/example#1234"))
98+
print("done") // CHECK: done
99+
}
100+
101+
@available(SwiftStdlib 5.5, *)
102+
@main struct Main {
103+
static func main() async {
104+
await test_remote()
105+
}
106+
}
107+
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// RUN: %target-run-simple-swift(-Xfrontend -enable-experimental-distributed -parse-as-library) | %FileCheck %s --dump-input=always
2+
3+
// REQUIRES: executable_test
4+
// REQUIRES: concurrency
5+
// REQUIRES: distributed
6+
7+
// rdar://76038845
8+
// UNSUPPORTED: use_os_stdlib
9+
// UNSUPPORTED: back_deployment_runtime
10+
11+
// RE_QUIRES: rdar78290608
12+
13+
import _Distributed
14+
15+
@available(SwiftStdlib 5.5, *)
16+
distributed actor SomeSpecificDistributedActor {
17+
deinit {
18+
print("deinit \(self.id)")
19+
}
20+
}
21+
22+
// ==== Fake Transport ---------------------------------------------------------
23+
24+
@available(SwiftStdlib 5.5, *)
25+
struct FakeActorID: ActorIdentity {
26+
let id: UInt64
27+
}
28+
29+
@available(SwiftStdlib 5.5, *)
30+
enum FakeTransportError: ActorTransportError {
31+
case unsupportedActorIdentity(AnyActorIdentity)
32+
}
33+
34+
@available(SwiftStdlib 5.5, *)
35+
struct ActorAddress: ActorIdentity {
36+
let address: String
37+
init(parse address : String) {
38+
self.address = address
39+
}
40+
}
41+
42+
@available(SwiftStdlib 5.5, *)
43+
final class FakeTransport: ActorTransport {
44+
45+
deinit {
46+
print("deinit \(self)")
47+
}
48+
49+
func decodeIdentity(from decoder: Decoder) throws -> AnyActorIdentity {
50+
fatalError("not implemented:\(#function)")
51+
}
52+
53+
func resolve<Act>(_ identity: AnyActorIdentity, as actorType: Act.Type)
54+
throws -> ActorResolved<Act>
55+
where Act: DistributedActor {
56+
.makeProxy
57+
}
58+
59+
func assignIdentity<Act>(_ actorType: Act.Type) -> AnyActorIdentity
60+
where Act: DistributedActor {
61+
let id = ActorAddress(parse: "xxx")
62+
print("assignIdentity type:\(actorType), id:\(id)")
63+
return .init(id)
64+
}
65+
66+
func actorReady<Act>(_ actor: Act) where Act: DistributedActor {
67+
print("actorReady actor:\(actor), id:\(actor.id)")
68+
}
69+
70+
func resignIdentity(_ id: AnyActorIdentity) {
71+
print("resignIdentity id:\(id)")
72+
}
73+
}
74+
75+
// ==== Execute ----------------------------------------------------------------
76+
77+
@available(SwiftStdlib 5.5, *)
78+
func test_remote() async {
79+
var address = ActorAddress(parse: "sact://127.0.0.1/example#1234")
80+
var transport: ActorTransport? = FakeTransport()
81+
82+
var remote = try! SomeSpecificDistributedActor.resolve(.init(address), using: transport!)
83+
84+
transport = nil
85+
print("done") // CHECK: done
86+
87+
print("remote.id = \(remote.id)") // CHECK: remote.id = AnyActorIdentity(ActorAddress(address: "sact://127.0.0.1/example#1234"))
88+
print("remote.transport = \(remote.actorTransport)") // CHECK: remote.transport = main.FakeTransport
89+
90+
// only once we exit the function and the remote is released, the transport has no more references
91+
// CHECK: deinit AnyActorIdentity(ActorAddress(address: "sact://127.0.0.1/example#1234"))
92+
// transport must deinit after the last actor using it does deinit
93+
// CHECK: deinit main.FakeTransport
94+
}
95+
96+
@available(SwiftStdlib 5.5, *)
97+
@main struct Main {
98+
static func main() async {
99+
await test_remote()
100+
}
101+
}
102+

0 commit comments

Comments
 (0)