1212
1313import Swift
1414
15+ // Store the Timestamp in the executor private data, if it will fit; otherwise,
16+ // use the allocator to allocate space for it and stash a pointer in the private
17+ // data area.
1518@available ( SwiftStdlib 6 . 2 , * )
1619extension ExecutorJob {
17- fileprivate var cooperativeExecutorTimestamp : CooperativeExecutor . Timestamp {
20+ fileprivate var cooperativeExecutorTimestampIsIndirect : Bool {
21+ return MemoryLayout < ( Int , Int ) > . size
22+ < MemoryLayout < CooperativeExecutor . Timestamp > . size
23+ }
24+
25+ fileprivate var cooperativeExecutorTimestampPointer : UnsafeMutablePointer < CooperativeExecutor . Timestamp > {
1826 get {
27+ assert ( cooperativeExecutorTimestampIsIndirect)
1928 return unsafe withUnsafeExecutorPrivateData {
20- return unsafe $0. assumingMemoryBound (
21- to : CooperativeExecutor . Timestamp . self
22- ) [ 0 ]
29+ unsafe $0. withMemoryRebound ( to : UnsafeMutablePointer < CooperativeExecutor . Timestamp > . self ) {
30+ return unsafe $0 [ 0 ]
31+ }
2332 }
2433 }
2534 set {
35+ assert ( cooperativeExecutorTimestampIsIndirect)
2636 unsafe withUnsafeExecutorPrivateData {
27- unsafe $0. withMemoryRebound ( to: CooperativeExecutor . Timestamp. self) {
37+ unsafe $0. withMemoryRebound ( to: UnsafeMutablePointer < CooperativeExecutor . Timestamp> . self ) {
2838 unsafe $0[ 0 ] = newValue
2939 }
3040 }
3141 }
3242 }
43+
44+ fileprivate var cooperativeExecutorTimestamp : CooperativeExecutor . Timestamp {
45+ get {
46+ if cooperativeExecutorTimestampIsIndirect {
47+ let ptr = unsafe cooperativeExecutorTimestampPointer
48+ return unsafe ptr. pointee
49+ } else {
50+ return unsafe withUnsafeExecutorPrivateData {
51+ return unsafe $0. assumingMemoryBound (
52+ to: CooperativeExecutor . Timestamp. self
53+ ) [ 0 ]
54+ }
55+ }
56+ }
57+ set {
58+ if cooperativeExecutorTimestampIsIndirect {
59+ let ptr = unsafe cooperativeExecutorTimestampPointer
60+ unsafe ptr. pointee = newValue
61+ } else {
62+ unsafe withUnsafeExecutorPrivateData {
63+ unsafe $0. withMemoryRebound ( to: CooperativeExecutor . Timestamp. self) {
64+ unsafe $0[ 0 ] = newValue
65+ }
66+ }
67+ }
68+ }
69+ }
70+
71+ fileprivate mutating func setupCooperativeExecutorTimestamp( ) {
72+ // If a Timestamp won't fit, allocate
73+ if cooperativeExecutorTimestampIsIndirect {
74+ let ptr = unsafe allocator! . allocate ( as: CooperativeExecutor . Timestamp. self)
75+ unsafe self. cooperativeExecutorTimestampPointer = ptr
76+ }
77+ }
78+
79+ fileprivate mutating func clearCooperativeExecutorTimestamp( ) {
80+ // If a Timestamp won't fit, deallocate
81+ if cooperativeExecutorTimestampIsIndirect {
82+ let ptr = unsafe self. cooperativeExecutorTimestampPointer
83+ unsafe allocator! . deallocate ( ptr)
84+ }
85+ }
3386}
3487
3588/// A co-operative executor that can be used as the main executor or as a
@@ -131,6 +184,7 @@ extension CooperativeExecutor: SchedulableExecutor {
131184 let duration = Duration ( from: clock. convert ( from: delay) !)
132185 let deadline = self . currentTime + duration
133186
187+ job. setupCooperativeExecutorTimestamp ( )
134188 job. cooperativeExecutorTimestamp = deadline
135189 waitQueue. push ( UnownedJob ( job) )
136190 }
@@ -150,6 +204,8 @@ extension CooperativeExecutor: RunLoopExecutor {
150204 while let job = waitQueue. pop ( when: {
151205 ExecutorJob ( $0) . cooperativeExecutorTimestamp <= now
152206 } ) {
207+ var theJob = ExecutorJob ( job)
208+ theJob. clearCooperativeExecutorTimestamp ( )
153209 runQueue. push ( job)
154210 }
155211
0 commit comments