@@ -14,6 +14,28 @@ import Distributed
14
14
@preconcurrency import Dispatch
15
15
import StdlibUnittest
16
16
17
+ #if canImport(Darwin)
18
+ import Darwin
19
+ typealias ThreadID = pthread_t
20
+ func getCurrentThreadID( ) -> ThreadID { pthread_self ( ) }
21
+ func equalThreadIDs( _ a: ThreadID , _ b: ThreadID ) -> Bool { pthread_equal ( a, b) != 0 }
22
+ #elseif canImport(Glibc)
23
+ import Glibc
24
+ typealias ThreadID = pthread_t
25
+ func getCurrentThreadID( ) -> ThreadID { pthread_self ( ) }
26
+ func equalThreadIDs( _ a: ThreadID , _ b: ThreadID ) -> Bool { pthread_equal ( a, b) != 0 }
27
+ #elseif os(Windows)
28
+ import WinSDK
29
+ typealias ThreadID = UInt32
30
+ func getCurrentThreadID( ) -> ThreadID { GetCurrentThreadId ( ) }
31
+ func equalThreadIDs( _ a: ThreadID , _ b: ThreadID ) -> Bool { a == b }
32
+ #endif
33
+
34
+ var mainThread : ThreadID ?
35
+ func isMainThread( ) -> Bool {
36
+ return equalThreadIDs ( getCurrentThreadID ( ) , mainThread!)
37
+ }
38
+
17
39
// Look up a symbol using dlsym and cast the result to an arbitrary type.
18
40
func lookup< T> ( _ name: String ) -> T {
19
41
let RTLD_DEFAULT = UnsafeMutableRawPointer ( bitPattern: - 2 )
@@ -33,7 +55,7 @@ func isCurrent(_ a: AnyActor) -> Bool {
33
55
return isCurrentExecutor ( getExecutor ( a) )
34
56
}
35
57
36
- func isMainThread ( ) -> Bool {
58
+ func isMainExecutor ( ) -> Bool {
37
59
isCurrentExecutor ( getMainExecutor ( ) )
38
60
}
39
61
@@ -59,7 +81,7 @@ distributed actor DA_userDefined_nonisolated {
59
81
}
60
82
61
83
nonisolated deinit {
62
- print ( " Deinitializing \( self . id) remote: \( __isRemoteActor ( self ) ) isolated: \( isCurrent ( self ) ) " )
84
+ print ( " Deinitializing \( self . id) remote: \( __isRemoteActor ( self ) ) isolated: \( isCurrent ( self ) ) mainThread: \( isMainThread ( ) ) " )
63
85
}
64
86
}
65
87
@@ -69,7 +91,7 @@ distributed actor DA_userDefined_isolated {
69
91
}
70
92
71
93
deinit {
72
- print ( " Deinitializing \( self . id) remote: \( __isRemoteActor ( self ) ) isolated: \( isCurrent ( self ) ) " )
94
+ print ( " Deinitializing \( self . id) remote: \( __isRemoteActor ( self ) ) isolated: \( isCurrent ( self ) ) mainThread: \( isMainThread ( ) ) " )
73
95
}
74
96
}
75
97
@@ -84,7 +106,7 @@ distributed actor DA_state_nonisolated {
84
106
}
85
107
86
108
nonisolated deinit {
87
- print ( " Deinitializing \( self . id) name= \( name) age= \( age) remote: \( __isRemoteActor ( self ) ) isolated: \( isCurrent ( self ) ) " )
109
+ print ( " Deinitializing \( self . id) name= \( name) age= \( age) remote: \( __isRemoteActor ( self ) ) isolated: \( isCurrent ( self ) ) mainThread: \( isMainThread ( ) ) " )
88
110
return
89
111
}
90
112
}
@@ -100,7 +122,28 @@ distributed actor DA_state_isolated {
100
122
}
101
123
102
124
deinit {
103
- print ( " Deinitializing \( self . id) name= \( name) age= \( age) remote: \( __isRemoteActor ( self ) ) isolated: \( isCurrent ( self ) ) " )
125
+ print ( " Deinitializing \( self . id) name= \( name) age= \( age) remote: \( __isRemoteActor ( self ) ) isolated: \( isCurrent ( self ) ) mainThread: \( isMainThread ( ) ) " )
126
+ return
127
+ }
128
+ }
129
+
130
+ @globalActor actor AnotherActor : GlobalActor {
131
+ static let shared = AnotherActor ( )
132
+ }
133
+
134
+ distributed actor DA_state_isolated_on_another {
135
+ var name : String
136
+ var age : Int
137
+
138
+ init ( name: String , age: Int , system: FakeActorSystem ) {
139
+ self . name = name
140
+ self . age = age
141
+ self . actorSystem = system
142
+ }
143
+
144
+ @AnotherActor
145
+ deinit {
146
+ print ( " Deinitializing \( self . id) name= \( name) age= \( age) remote: \( __isRemoteActor ( self ) ) isolated-self: \( isCurrent ( self ) ) isolated-other: \( isCurrent ( AnotherActor . shared) ) mainThread: \( isMainThread ( ) ) " )
104
147
return
105
148
}
106
149
}
@@ -129,7 +172,7 @@ final class FakeActorSystem: @unchecked Sendable, DistributedActorSystem {
129
172
}
130
173
131
174
deinit {
132
- print ( " Deinit ActorSystem: mainThread= \( isMainThread ( ) ) " )
175
+ print ( " Deinit ActorSystem: mainExecutor= \( isMainExecutor ( ) ) mainThread=\( isMainThread ( ) ) " )
133
176
group. leave ( )
134
177
}
135
178
@@ -254,7 +297,7 @@ func test() {
254
297
// CHECK: assign type:DA, address:[[ADDRESS:.*]]
255
298
// CHECK: ready actor:main.DA, address:ActorAddress(address: "[[ADDR1:addr-[0-9]]]")
256
299
// CHECK: resign address:ActorAddress(address: "[[ADDR1]]")
257
- // CHECK-NEXT: Deinit ActorSystem: mainThread=true
300
+ // CHECK-NEXT: Deinit ActorSystem: mainExecutor=true mainThread=true
258
301
259
302
group. enter ( )
260
303
_ = { ( ) -> DA_userDefined in
@@ -264,7 +307,7 @@ func test() {
264
307
// CHECK: assign type:DA_userDefined, address:[[ADDRESS:.*]]
265
308
// CHECK: ready actor:main.DA_userDefined, address:ActorAddress(address: "[[ADDR2:addr-[0-9]]]")
266
309
// CHECK: resign address:ActorAddress(address: "[[ADDR2]]")
267
- // CHECK-NEXT: Deinit ActorSystem: mainThread=true
310
+ // CHECK-NEXT: Deinit ActorSystem: mainExecutor=true mainThread=true
268
311
269
312
// resign must happen as the _last thing_ after user-deinit completed
270
313
group. enter ( )
@@ -274,9 +317,9 @@ func test() {
274
317
group. wait ( )
275
318
// CHECK: assign type:DA_userDefined_nonisolated, address:[[ADDRESS:.*]]
276
319
// CHECK: ready actor:main.DA_userDefined_nonisolated, address:ActorAddress(address: "[[ADDR3:addr-[0-9]]]")
277
- // CHECK: Deinitializing ActorAddress(address: "[[ADDR3]]") remote:false isolated:false
320
+ // CHECK: Deinitializing ActorAddress(address: "[[ADDR3]]") remote:false isolated:false mainThread:true
278
321
// CHECK-NEXT: resign address:ActorAddress(address: "[[ADDR3]]")
279
- // CHECK-NEXT: Deinit ActorSystem: mainThread=true
322
+ // CHECK-NEXT: Deinit ActorSystem: mainExecutor=true mainThread=true
280
323
281
324
// resign must happen as the _last thing_ after user-deinit completed
282
325
group. enter ( )
@@ -286,9 +329,9 @@ func test() {
286
329
group. wait ( )
287
330
// CHECK: assign type:DA_userDefined_isolated, address:[[ADDRESS:.*]]
288
331
// CHECK: ready actor:main.DA_userDefined_isolated, address:ActorAddress(address: "[[ADDR4:addr-[0-9]]]")
289
- // CHECK: Deinitializing ActorAddress(address: "[[ADDR4]]") remote:false isolated:true
332
+ // CHECK: Deinitializing ActorAddress(address: "[[ADDR4]]") remote:false isolated:true mainThread:true
290
333
// CHECK-NEXT: resign address:ActorAddress(address: "[[ADDR4]]")
291
- // CHECK-NEXT: Deinit ActorSystem: mainThread =false
334
+ // CHECK-NEXT: Deinit ActorSystem: mainExecutor =false mainThread=true
292
335
293
336
// resign must happen as the _last thing_ after user-deinit completed
294
337
group. enter ( )
@@ -298,9 +341,9 @@ func test() {
298
341
group. wait ( )
299
342
// CHECK: assign type:DA_state_nonisolated, address:[[ADDRESS:.*]]
300
343
// CHECK: ready actor:main.DA_state_nonisolated, address:ActorAddress(address: "[[ADDR5:addr-[0-9]]]")
301
- // CHECK: Deinitializing ActorAddress(address: "[[ADDR5]]") name=Foo age=37 remote:false isolated:false
344
+ // CHECK: Deinitializing ActorAddress(address: "[[ADDR5]]") name=Foo age=37 remote:false isolated:false mainThread:true
302
345
// CHECK-NEXT: resign address:ActorAddress(address: "[[ADDR5]]")
303
- // CHECK-NEXT: Deinit ActorSystem: mainThread=true
346
+ // CHECK-NEXT: Deinit ActorSystem: mainExecutor=true mainThread=true
304
347
305
348
// resign must happen as the _last thing_ after user-deinit completed
306
349
group. enter ( )
@@ -310,9 +353,21 @@ func test() {
310
353
group. wait ( )
311
354
// CHECK: assign type:DA_state_isolated, address:[[ADDRESS:.*]]
312
355
// CHECK: ready actor:main.DA_state_isolated, address:ActorAddress(address: "[[ADDR6:addr-[0-9]]]")
313
- // CHECK: Deinitializing ActorAddress(address: "[[ADDR6]]") name=Bar age=42 remote:false isolated:true
356
+ // CHECK: Deinitializing ActorAddress(address: "[[ADDR6]]") name=Bar age=42 remote:false isolated:true mainThread:true
357
+ // CHECK-NEXT: resign address:ActorAddress(address: "[[ADDR6]]")
358
+ // CHECK-NEXT: Deinit ActorSystem: mainExecutor=false mainThread=true
359
+
360
+ // resign must happen as the _last thing_ after user-deinit completed
361
+ group. enter ( )
362
+ _ = { ( ) -> DA_state_isolated_on_another in
363
+ DA_state_isolated_on_another ( name: " Baz " , age: 57 , system: DefaultDistributedActorSystem ( group: group) )
364
+ } ( )
365
+ group. wait ( )
366
+ // CHECK: assign type:DA_state_isolated_on_another, address:[[ADDRESS:.*]]
367
+ // CHECK: ready actor:main.DA_state_isolated_on_another, address:ActorAddress(address: "[[ADDR6:addr-[0-9]]]")
368
+ // CHECK: Deinitializing ActorAddress(address: "[[ADDR6]]") name=Baz age=57 remote:false isolated-self:false isolated-other:true mainThread:false
314
369
// CHECK-NEXT: resign address:ActorAddress(address: "[[ADDR6]]")
315
- // CHECK-NEXT: Deinit ActorSystem: mainThread=false
370
+ // CHECK-NEXT: Deinit ActorSystem: mainExecutor=false mainThread=false
316
371
317
372
// a remote actor should not resign it's address, it was never "assigned" it
318
373
group. enter ( )
@@ -324,7 +379,7 @@ func test() {
324
379
// CHECK-NEXT: resolve type:DA_userDefined_nonisolated, address:ActorAddress(address: "remote-1")
325
380
// MUST NOT run deinit body for a remote distributed actor
326
381
// CHECK-NOT: Deinitializing ActorAddress(address: "remote-1")
327
- // CHECK-NEXT: Deinit ActorSystem: mainThread=true
382
+ // CHECK-NEXT: Deinit ActorSystem: mainExecutor=true mainThread=true
328
383
329
384
// a remote actor should not resign it's address, it was never "assigned" it
330
385
group. enter ( )
@@ -336,14 +391,27 @@ func test() {
336
391
// CHECK-NEXT: resolve type:DA_userDefined_isolated, address:ActorAddress(address: "remote-2")
337
392
// MUST NOT run deinit body for a remote distributed actor
338
393
// CHECK-NOT: Deinitializing ActorAddress(address: "remote-2")
339
- // CHECK-NEXT: Deinit ActorSystem: mainThread=true
394
+ // CHECK-NEXT: Deinit ActorSystem: mainExecutor=true mainThread=true
395
+
396
+ // a remote actor should not resign it's address, it was never "assigned" it
397
+ group. enter ( )
398
+ _ = { ( ) -> DA_state_isolated_on_another in
399
+ let address = ActorAddress ( parse: " remote-3 " )
400
+ return try ! DA_state_isolated_on_another . resolve ( id: address, using: DefaultDistributedActorSystem ( group: group) )
401
+ } ( )
402
+ group. wait ( )
403
+ // CHECK-NEXT: resolve type:DA_state_isolated_on_another, address:ActorAddress(address: "remote-3")
404
+ // MUST NOT run deinit body for a remote distributed actor
405
+ // CHECK-NOT: Deinitializing ActorAddress(address: "remote-3")
406
+ // CHECK-NEXT: Deinit ActorSystem: mainExecutor=true mainThread=true
340
407
341
408
print ( " DONE " )
342
409
// CHECK-NEXT: DONE
343
410
}
344
411
345
412
@main struct Main {
346
413
static func main( ) async {
414
+ mainThread = getCurrentThreadID ( )
347
415
test ( )
348
416
}
349
417
}
0 commit comments