@@ -64,6 +64,23 @@ actor MyGlobalActor {
6464 static let shared : MyGlobalActor = MyGlobalActor ( )
6565}
6666
67+ final class NaiveQueueExecutor : SerialExecutor {
68+ let queue : DispatchQueue
69+
70+ init ( queue: DispatchQueue ) {
71+ self . queue = queue
72+ }
73+
74+ public func enqueue( _ job: consuming ExecutorJob ) {
75+ let unowned = UnownedJob ( job)
76+ print ( " NaiveQueueExecutor( \( self . queue. label) ) enqueue... [thread: \( getCurrentThreadID ( ) ) ] " )
77+ queue. async {
78+ print ( " NaiveQueueExecutor( \( self . queue. label) ) enqueue: run [thread: \( getCurrentThreadID ( ) ) ] " )
79+ unowned. runSynchronously( on: self . asUnownedSerialExecutor ( ) )
80+ }
81+ }
82+ }
83+
6784// Test on all platforms
6885func syncOnMyGlobalActor( ) -> [ Task < Void , Never > ] {
6986 MyGlobalActor . shared. preconditionIsolated ( " Should be executing on the global actor here " )
@@ -189,7 +206,7 @@ syncOnNonTaskThread(synchronousTask: behavior)
189206// CHECK: after startSynchronously, outside; cancel (wakeup) the synchronous task! [thread:[[CALLING_THREAD3]]]
190207
191208print ( " \n \n ==== ------------------------------------------------------------------ " )
192- print ( " callActorFromStartSynchronousTask() " )
209+ print ( " callActorFromStartSynchronousTask() - not on specific queue " )
193210callActorFromStartSynchronousTask ( recipient: . recipient( Recipient ( ) ) )
194211
195212// CHECK: callActorFromStartSynchronousTask()
@@ -203,11 +220,6 @@ callActorFromStartSynchronousTask(recipient: .recipient(Recipient()))
203220// CHECK-NOT: ERROR!
204221// CHECK: inside startSynchronously, call rec.sync() done
205222
206- // CHECK-NOT: ERROR!
207- // CHECK: inside startSynchronously, call rec.async()
208- // CHECK-NOT: ERROR!
209- // CHECK: inside startSynchronously, call rec.async() done
210-
211223// CHECK-NOT: ERROR!
212224// CHECK: inside startSynchronously, done
213225
@@ -219,35 +231,20 @@ enum TargetActorToCall {
219231}
220232
221233protocol RecipientProtocol where Self: Actor {
222- func sync( syncTaskThreadID: ThreadID ) async
223- func async ( syncTaskThreadID: ThreadID ) async
234+ func callAndSuspend( syncTaskThreadID: ThreadID ) async
224235}
225236
226237// default actor, must not declare an 'unownedExecutor'
227- actor Recipient {
228- func sync( syncTaskThreadID: ThreadID ) {
229- self . preconditionIsolated ( )
230-
231- print ( " \( Recipient . self) / \( #function) Current actor thread id = \( getCurrentThreadID ( ) ) @ : \( #line) " )
232- if compareThreadIDs ( syncTaskThreadID, . equal, getCurrentThreadID ( ) ) {
233- print ( " NOTICE: Actor must not run on the synchronous task's thread : \( #line) " )
234- }
235- }
236-
237- func async ( syncTaskThreadID: ThreadID ) async {
238+ actor Recipient : RecipientProtocol {
239+ func callAndSuspend( syncTaskThreadID: ThreadID ) async {
238240 self . preconditionIsolated ( )
239241
240- // Dispatch may end up reusing the thread used to service the queue so we
241- // cannot truly assert exact thread identity in such tests.
242- // Usually this will be on a different thread by now though.
243242 print ( " \( Recipient . self) / \( #function) Current actor thread id = \( getCurrentThreadID ( ) ) @ : \( #line) " )
244243 if compareThreadIDs ( syncTaskThreadID, . equal, getCurrentThreadID ( ) ) {
245244 print ( " NOTICE: Actor must not run on the synchronous task's thread : \( #line) " )
246245 }
247246
248- await Task {
249- self . preconditionIsolated ( )
250- } . value
247+ try ? await Task . sleep ( for: . milliseconds( 100 ) )
251248 }
252249}
253250
@@ -274,8 +271,8 @@ func callActorFromStartSynchronousTask(recipient rec: TargetActorToCall) {
274271
275272 print ( " inside startSynchronously, call rec.sync() [thread: \( getCurrentThreadID ( ) ) ] @ : \( #line) " )
276273 switch rec {
277- case . recipient( let recipient) : await recipient. sync ( syncTaskThreadID: innerTID)
278- case . recipientOnQueue( let recipient) : await recipient. sync ( syncTaskThreadID: innerTID)
274+ case . recipient( let recipient) : await recipient. callAndSuspend ( syncTaskThreadID: innerTID)
275+ case . recipientOnQueue( let recipient) : await recipient. callAndSuspend ( syncTaskThreadID: innerTID)
279276 }
280277 print ( " inside startSynchronously, call rec.sync() done [thread: \( getCurrentThreadID ( ) ) ] @ : \( #line) " )
281278
@@ -290,22 +287,6 @@ func callActorFromStartSynchronousTask(recipient rec: TargetActorToCall) {
290287 print ( " NOTICE: Task resumed on same thread as it entered the synchronous task! " )
291288 }
292289
293- print ( " inside startSynchronously, call rec.async() [thread: \( getCurrentThreadID ( ) ) ] @ : \( #line) " )
294- switch rec {
295- case . recipient( let recipient) : await recipient. async ( syncTaskThreadID: innerTID)
296- case . recipientOnQueue( let recipient) : await recipient. async ( syncTaskThreadID: innerTID)
297- }
298- print ( " inside startSynchronously, call rec.async() done [thread: \( getCurrentThreadID ( ) ) ] @ : \( #line) " )
299-
300- print ( " Inner thread id = \( innerTID) " )
301- print ( " Current thread id = \( getCurrentThreadID ( ) ) " )
302- // Dispatch may end up reusing the thread used to service the queue so we
303- // cannot truly assert exact thread identity in such tests.
304- // Usually this will be on a different thread by now though.
305- if compareThreadIDs ( innerTID, . equal, getCurrentThreadID ( ) ) {
306- print ( " NOTICE: Task resumed on same thread as it entered the synchronous task! " )
307- }
308-
309290 print ( " inside startSynchronously, done [thread: \( getCurrentThreadID ( ) ) ] @ : \( #line) " )
310291 sem1. signal ( )
311292 }
@@ -323,6 +304,28 @@ print("callActorFromStartSynchronousTask() - actor in custom executor with its o
323304let actorQueue = DispatchQueue ( label: " recipient-actor-queue " )
324305callActorFromStartSynchronousTask ( recipient: . recipientOnQueue( RecipientOnQueue ( queue: actorQueue) ) )
325306
307+
308+ // 50: callActorFromStartSynchronousTask()
309+ // 51: before startSynchronously [thread:0x00007000054f5000] @ :366
310+ // 52: inside startSynchronously [thread:0x00007000054f5000] @ :372
311+ // 53: inside startSynchronously, call rec.sync() [thread:0x00007000054f5000] @ :380
312+ // 54: Recipient/sync(syncTaskThreadID:) Current actor thread id = 0x000070000567e000 @ :336
313+ // 55: inside startSynchronously, call rec.sync() done [thread:0x000070000567e000] @ :385
314+ // 56: Inner thread id = 0x00007000054f5000
315+ // 57: Current thread id = 0x000070000567e000
316+ // 60: after startSynchronously [thread:0x00007000054f5000] @ :418
317+ // 61: - async work on queue
318+ // 62: - async work on queue
319+ // 63: - async work on queue
320+ // 64: - async work on queue
321+ // 65: - async work on queue
322+ // 67: - async work on queue
323+ // 68: - async work on queue
324+ // 69: - async work on queue
325+ // 71: Inner thread id = 0x00007000054f5000
326+ // 72: Current thread id = 0x000070000567e000
327+ // 73: inside startSynchronously, done [thread:0x000070000567e000] @ :414
328+
326329// CHECK-LABEL: callActorFromStartSynchronousTask() - actor in custom executor with its own queue
327330// No interleaving allowed between "before" and "inside":
328331// CHECK: before startSynchronously [thread:[[CALLING_THREAD4:.*]]]
@@ -333,38 +336,14 @@ callActorFromStartSynchronousTask(recipient: .recipientOnQueue(RecipientOnQueue(
333336// allowing the 'after startSynchronously' to run.
334337//
335338// CHECK-NEXT: inside startSynchronously, call rec.sync() [thread:[[CALLING_THREAD4]]]
336- // CHECK: NaiveQueueExecutor(recipient-actor-queue) enqueue
337339// CHECK: after startSynchronously
338340// CHECK-NOT: ERROR!
339341// CHECK: inside startSynchronously, call rec.sync() done
340342
341- // CHECK-NOT: ERROR!
342- // CHECK: inside startSynchronously, call rec.async()
343- // CHECK: NaiveQueueExecutor(recipient-actor-queue) enqueue
344- // CHECK-NOT: ERROR!
345- // CHECK: inside startSynchronously, call rec.async() done
346-
347343// CHECK-NOT: ERROR!
348344// CHECK: inside startSynchronously, done
349345
350- final class NaiveQueueExecutor : SerialExecutor {
351- let queue : DispatchQueue
352-
353- init ( queue: DispatchQueue ) {
354- self . queue = queue
355- }
356-
357- public func enqueue( _ job: consuming ExecutorJob ) {
358- let unowned = UnownedJob ( job)
359- print ( " NaiveQueueExecutor( \( self . queue. label) ) enqueue... [thread: \( getCurrentThreadID ( ) ) ] " )
360- queue. async {
361- print ( " NaiveQueueExecutor( \( self . queue. label) ) enqueue: run [thread: \( getCurrentThreadID ( ) ) ] " )
362- unowned. runSynchronously( on: self . asUnownedSerialExecutor ( ) )
363- }
364- }
365- }
366-
367- actor RecipientOnQueue {
346+ actor RecipientOnQueue : RecipientProtocol {
368347 let executor : NaiveQueueExecutor
369348 nonisolated let unownedExecutor : UnownedSerialExecutor
370349
@@ -373,30 +352,15 @@ actor RecipientOnQueue {
373352 self . unownedExecutor = executor. asUnownedSerialExecutor ( )
374353 }
375354
376- func sync( syncTaskThreadID: ThreadID ) {
377- self . preconditionIsolated ( )
378- dispatchPrecondition ( condition: . onQueue( self . executor. queue) )
379-
380- print ( " \( Recipient . self) / \( #function) Current actor thread id = \( getCurrentThreadID ( ) ) @ : \( #line) " )
381- if compareThreadIDs ( syncTaskThreadID, . equal, getCurrentThreadID ( ) ) {
382- print ( " NOTICE: Actor must not run on the synchronous task's thread : \( #line) " )
383- }
384- }
385-
386- func async ( syncTaskThreadID: ThreadID ) async {
355+ func callAndSuspend( syncTaskThreadID: ThreadID ) async {
387356 self . preconditionIsolated ( )
388357 dispatchPrecondition ( condition: . onQueue( self . executor. queue) )
389358
390- // Dispatch may end up reusing the thread used to service the queue so we
391- // cannot truly assert exact thread identity in such tests.
392- // Usually this will be on a different thread by now though.
393359 print ( " \( Recipient . self) / \( #function) Current actor thread id = \( getCurrentThreadID ( ) ) @ : \( #line) " )
394360 if compareThreadIDs ( syncTaskThreadID, . equal, getCurrentThreadID ( ) ) {
395361 print ( " NOTICE: Actor must not run on the synchronous task's thread : \( #line) " )
396362 }
397363
398- await Task {
399- self . preconditionIsolated ( )
400- } . value
364+ try ? await Task . sleep ( for: . milliseconds( 100 ) )
401365 }
402366}
0 commit comments