9
9
//
10
10
//===----------------------------------------------------------------------===//
11
11
12
- import _CAsyncSequenceValidationSupport
12
+ @ preconcurrency import _CAsyncSequenceValidationSupport
13
13
import AsyncAlgorithms
14
14
15
15
@_silgen_name ( " swift_job_run " )
@@ -48,17 +48,17 @@ extension AsyncSequenceValidationDiagram {
48
48
do {
49
49
if let pastEnd = try await iterator. next ( ) {
50
50
let failure = ExpectationFailure (
51
- when: Context . clock!. now,
51
+ when: Context . state . withCriticalRegion ( \ . clock!. now) ,
52
52
kind: . specificationViolationGotValueAfterIteration( pastEnd) ,
53
53
specification: output)
54
- Context . specificationFailures. append ( failure)
54
+ Context . state . withCriticalRegion { $0 . specificationFailures. append ( failure) }
55
55
}
56
56
} catch {
57
57
let failure = ExpectationFailure (
58
- when: Context . clock!. now,
58
+ when: Context . state . withCriticalRegion ( \ . clock!. now) ,
59
59
kind: . specificationViolationGotFailureAfterIteration( error) ,
60
60
specification: output)
61
- Context . specificationFailures. append ( failure)
61
+ Context . state . withCriticalRegion { $0 . specificationFailures. append ( failure) }
62
62
}
63
63
} catch {
64
64
throw error
@@ -107,7 +107,7 @@ extension AsyncSequenceValidationDiagram {
107
107
}
108
108
}
109
109
110
- private static let _executor : AnyObject = {
110
+ private static let _executor : any SerialExecutor = {
111
111
if #available( macOS 14 . 0 , iOS 17 . 0 , watchOS 10 . 0 , tvOS 17 . 0 , * ) {
112
112
return ClockExecutor_5_9 ( )
113
113
} else {
@@ -116,19 +116,18 @@ extension AsyncSequenceValidationDiagram {
116
116
} ( )
117
117
118
118
static var unownedExecutor : UnownedSerialExecutor {
119
- ( _executor as! any SerialExecutor ) . asUnownedSerialExecutor ( )
119
+ _executor. asUnownedSerialExecutor ( )
120
120
}
121
121
#endif
122
122
123
- static var clock : Clock ?
124
-
125
-
126
-
127
- static var driver : TaskDriver ?
128
-
129
- static var currentJob : Job ?
130
-
131
- static var specificationFailures = [ ExpectationFailure] ( )
123
+ static let state = ManagedCriticalState ( State ( ) )
124
+
125
+ struct State {
126
+ var clock : Clock ?
127
+ var driver : TaskDriver ?
128
+ var currentJob : Job ?
129
+ var specificationFailures = [ ExpectationFailure] ( )
130
+ }
132
131
}
133
132
134
133
enum ActualResult {
@@ -158,9 +157,9 @@ extension AsyncSequenceValidationDiagram {
158
157
actual: [ ( Clock . Instant , Result < String ? , Error > ) ]
159
158
) -> ( ExpectationResult , [ ExpectationFailure ] ) {
160
159
let result = ExpectationResult ( expected: expected, actual: actual)
161
- var failures = Context . specificationFailures
162
- Context . specificationFailures. removeAll ( )
163
-
160
+ var failures = Context . state . withCriticalRegion ( \ . specificationFailures)
161
+ Context . state . withCriticalRegion { $0 . specificationFailures. removeAll ( ) }
162
+
164
163
let actualTimes = actual. map { when, _ in when }
165
164
let expectedTimes = expected. map { $0. when }
166
165
@@ -349,55 +348,58 @@ extension AsyncSequenceValidationDiagram {
349
348
}
350
349
351
350
let actual = ManagedCriticalState ( [ ( Clock . Instant , Result < String ? , Error > ) ] ( ) )
352
- Context . clock = clock
353
- Context . specificationFailures. removeAll ( )
354
- // This all needs to be isolated from potential Tasks (the caller function might be async!)
355
- Context . driver = TaskDriver ( queue: diagram. queue) { driver in
356
- swift_task_enqueueGlobal_hook = { job, original in
357
- Context . driver? . enqueue ( job)
358
- }
359
-
360
- let runner = Task {
361
- do {
362
- try await test. test ( with: clock, activeTicks: activeTicks, output: test. output) { event in
351
+ Context . state. withCriticalRegion { state in
352
+ state. clock = clock
353
+ state. specificationFailures. removeAll ( )
354
+ // This all needs to be isolated from potential Tasks (the caller function might be async!)
355
+ state. driver = TaskDriver ( queue: diagram. queue) { driver in
356
+ swift_task_enqueueGlobal_hook = { job, original in
357
+ Context . state. withCriticalRegion ( \. driver) ? . enqueue ( job)
358
+ }
359
+
360
+ let runner = Task {
361
+ do {
362
+ try await test. test ( with: clock, activeTicks: activeTicks, output: test. output) { event in
363
+ actual. withCriticalRegion { values in
364
+ values. append ( ( clock. now, . success( event) ) )
365
+ }
366
+ }
363
367
actual. withCriticalRegion { values in
364
- values. append ( ( clock. now, . success( event) ) )
368
+ values. append ( ( clock. now, . success( nil ) ) )
369
+ }
370
+ } catch {
371
+ actual. withCriticalRegion { values in
372
+ values. append ( ( clock. now, . failure( error) ) )
365
373
}
366
- }
367
- actual. withCriticalRegion { values in
368
- values. append ( ( clock. now, . success( nil ) ) )
369
- }
370
- } catch {
371
- actual. withCriticalRegion { values in
372
- values. append ( ( clock. now, . failure( error) ) )
373
374
}
374
375
}
375
- }
376
-
377
- // Drain off any initial work. Work may spawn additional work to be done.
378
- // If the driver ever becomes blocked on the clock, exit early out of that
379
- // drain, because the drain cant make any forward progress if it is blocked
380
- // by a needed clock advancement.
381
- diagram. queue. drain ( )
382
- // Next make sure to iterate a decent amount past the end of the maximum
383
- // scheduled things (that way we ensure any reasonable errors are caught)
384
- for _ in 0 ..< ( end. when. rawValue * 2 ) {
385
- if cancelEvents. contains ( diagram. queue. now. advanced ( by: . steps( 1 ) ) ) {
386
- runner. cancel ( )
376
+
377
+ // Drain off any initial work. Work may spawn additional work to be done.
378
+ // If the driver ever becomes blocked on the clock, exit early out of that
379
+ // drain, because the drain cant make any forward progress if it is blocked
380
+ // by a needed clock advancement.
381
+ diagram. queue. drain ( )
382
+ // Next make sure to iterate a decent amount past the end of the maximum
383
+ // scheduled things (that way we ensure any reasonable errors are caught)
384
+ for _ in 0 ..< ( end. when. rawValue * 2 ) {
385
+ if cancelEvents. contains ( diagram. queue. now. advanced ( by: . steps( 1 ) ) ) {
386
+ runner. cancel ( )
387
+ }
388
+ diagram. queue. advance ( )
387
389
}
388
- diagram. queue. advance ( )
390
+
391
+ runner. cancel ( )
392
+ Context . state. withCriticalRegion { $0. clock = nil }
393
+ swift_task_enqueueGlobal_hook = nil
389
394
}
390
-
391
- runner. cancel ( )
392
- Context . clock = nil
393
- swift_task_enqueueGlobal_hook = nil
394
395
}
395
- Context . driver? . start ( )
396
+ let driver = Context . state. withCriticalRegion ( \. driver)
397
+ driver? . start ( )
396
398
// This is only valid since we are doing tests here
397
399
// else wise this would cause QoS inversions
398
- Context . driver? . join ( )
399
- Context . driver = nil
400
-
400
+ driver? . join ( )
401
+ Context . state . withCriticalRegion { $0 . driver = nil }
402
+
401
403
return validate (
402
404
inputs: test. inputs,
403
405
output: test. output,
0 commit comments