Skip to content

Commit f08c993

Browse files
ktosoxedin
authored andcommitted
harden the startSynchronously.swift test a bit
(cherry picked from commit eee53aa)
1 parent 3c321ec commit f08c993

File tree

1 file changed

+49
-85
lines changed

1 file changed

+49
-85
lines changed

test/Concurrency/Runtime/startSynchronously.swift

Lines changed: 49 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -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
6885
func 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

191208
print("\n\n==== ------------------------------------------------------------------")
192-
print("callActorFromStartSynchronousTask()")
209+
print("callActorFromStartSynchronousTask() - not on specific queue")
193210
callActorFromStartSynchronousTask(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

221233
protocol 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
323304
let actorQueue = DispatchQueue(label: "recipient-actor-queue")
324305
callActorFromStartSynchronousTask(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

Comments
 (0)