Skip to content

Commit 8ef09ef

Browse files
committed
[Concurrency] Add clock traits.
Remove the hacky support for mapping clocks to a Dispatch clock ID, in favour of clocks publishing traits and having the Dispatch executor select the clock on the basis of those traits.
1 parent 84075fb commit 8ef09ef

File tree

5 files changed

+62
-24
lines changed

5 files changed

+62
-24
lines changed

stdlib/public/Concurrency/Clock.swift

+39-13
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,9 @@ public protocol Clock<Duration>: Sendable {
4242
func sleep(until deadline: Instant, tolerance: Instant.Duration?) async throws
4343
#endif
4444

45-
#if !$Embedded
46-
/// Choose which Dispatch clock to use with DispatchExecutor
47-
///
48-
/// This controls which Dispatch clock is used to enqueue delayed jobs
49-
/// when using this Clock.
45+
/// The traits associated with this clock instance.
5046
@available(SwiftStdlib 6.2, *)
51-
var dispatchClockID: DispatchClockID { get }
52-
#endif
47+
var traits: ClockTraits { get }
5348

5449
/// Convert a Clock-specific Duration to a Swift Duration
5550
///
@@ -138,12 +133,6 @@ extension Clock {
138133

139134
@available(SwiftStdlib 6.2, *)
140135
extension Clock {
141-
#if !$Embedded
142-
public var dispatchClockID: DispatchClockID {
143-
return .suspending
144-
}
145-
#endif
146-
147136
// For compatibility, return `nil` if this is not implemented
148137
public func convert(from duration: Duration) -> Swift.Duration? {
149138
return nil
@@ -198,6 +187,43 @@ extension Clock {
198187
}
199188
#endif
200189

190+
/// Represents traits of a particular Clock implementation.
191+
///
192+
/// Clocks may be of a number of different varieties; executors will likely
193+
/// have specific clocks that they can use to schedule jobs, and will
194+
/// therefore need to be able to convert timestamps to an appropriate clock
195+
/// when asked to enqueue a job with a delay or deadline.
196+
///
197+
/// Choosing a clock in general requires the ability to tell which of their
198+
/// clocks best matches the clock that the user is trying to specify a
199+
/// time or delay in. Executors are expected to do this on a best effort
200+
/// basis.
201+
@available(SwiftStdlib 6.2, *)
202+
public struct ClockTraits: OptionSet {
203+
public let rawValue: Int32
204+
205+
public init(rawValue: Int32) {
206+
self.rawValue = rawValue
207+
}
208+
209+
/// Clocks with this trait continue running while the machine is asleep.
210+
public static let continuous = ClockTraits(rawValue: 1 << 0)
211+
212+
/// Indicates that a clock's time will only ever increase.
213+
public static let monotonic = ClockTraits(rawValue: 1 << 1)
214+
215+
/// Clocks with this trait are tied to "wall time".
216+
public static let wallTime = ClockTraits(rawValue: 1 << 2)
217+
}
218+
219+
extension Clock {
220+
/// The traits associated with this clock instance.
221+
@available(SwiftStdlib 6.2, *)
222+
var traits: ClockTraits {
223+
return []
224+
}
225+
}
226+
201227
enum _ClockID: Int32 {
202228
case continuous = 1
203229
case suspending = 2

stdlib/public/Concurrency/ContinuousClock.swift

+6
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,12 @@ extension ContinuousClock: Clock {
100100
)
101101
}
102102

103+
/// The continuous clock is continuous and monotonic
104+
@available(SwiftStdlib 6.2, *)
105+
public var traits: ClockTraits {
106+
return [.continuous, .monotonic]
107+
}
108+
103109
#if !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
104110
/// Suspend task execution until a given deadline within a tolerance.
105111
/// If no tolerance is specified then the system may adjust the deadline

stdlib/public/Concurrency/DispatchExecutor.swift

+7-11
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,7 @@ protocol DispatchExecutor: Executor {
178178
}
179179

180180
/// An enumeration identifying one of the Dispatch-supported clocks
181-
@available(SwiftStdlib 6.2, *)
182-
public enum DispatchClockID: CInt {
181+
enum DispatchClockID: CInt {
183182
case suspending = 1
184183
case continuous = 2
185184
}
@@ -189,23 +188,20 @@ extension DispatchExecutor {
189188

190189
func timestamp<C: Clock>(for instant: C.Instant, clock: C)
191190
-> (clockID: DispatchClockID, seconds: Int64, nanoseconds: Int64) {
192-
let clockID = clock.dispatchClockID
193-
194-
switch clockID {
195-
case .suspending:
196-
let dispatchClock: SuspendingClock = .suspending
191+
if clock.traits.contains(.continuous) {
192+
let dispatchClock: ContinuousClock = .continuous
197193
let instant = dispatchClock.convert(instant: instant, from: clock)!
198194
let (seconds, attoseconds) = instant._value.components
199195
let nanoseconds = attoseconds / 1_000_000_000
200-
return (clockID: .suspending,
196+
return (clockID: .continuous,
201197
seconds: Int64(seconds),
202198
nanoseconds: Int64(nanoseconds))
203-
case .continuous:
204-
let dispatchClock: ContinuousClock = .continuous
199+
} else {
200+
let dispatchClock: SuspendingClock = .suspending
205201
let instant = dispatchClock.convert(instant: instant, from: clock)!
206202
let (seconds, attoseconds) = instant._value.components
207203
let nanoseconds = attoseconds / 1_000_000_000
208-
return (clockID: .continuous,
204+
return (clockID: .suspending,
209205
seconds: Int64(seconds),
210206
nanoseconds: Int64(nanoseconds))
211207
}

stdlib/public/Concurrency/SuspendingClock.swift

+6
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,12 @@ extension SuspendingClock: Clock {
8787
return Duration(_seconds: seconds, nanoseconds: nanoseconds)
8888
}
8989

90+
/// The suspending clock is monotonic
91+
@available(SwiftStdlib 6.2, *)
92+
public var traits: ClockTraits {
93+
return [.monotonic]
94+
}
95+
9096
#if !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
9197
/// Suspend task execution until a given deadline within a tolerance.
9298
/// If no tolerance is specified then the system may adjust the deadline

test/Concurrency/Runtime/clocks.swift

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import StdlibUnittest
1313

14+
@available(SwiftStdlib 6.2, *)
1415
struct TickingClock: Clock {
1516
struct Duration: DurationProtocol {
1617
var ticks: Int
@@ -57,6 +58,7 @@ struct TickingClock: Clock {
5758
private var _now: Instant
5859
var now: Instant { return _now }
5960
var minimumResolution: Duration { return Duration(ticks: 1) }
61+
var traits: ClockTraits { [.monotonic] }
6062

6163
init() {
6264
_now = Instant(ticksFromStart: 0)
@@ -87,6 +89,7 @@ struct TickingClock: Clock {
8789
}
8890
}
8991

92+
@available(SwiftStdlib 6.2, *)
9093
struct TockingClock: Clock {
9194
struct Duration: DurationProtocol {
9295
var tocks: Int
@@ -133,6 +136,7 @@ struct TockingClock: Clock {
133136
private var _now: Instant
134137
var now: Instant { return _now }
135138
var minimumResolution: Duration { return Duration(tocks: 1) }
139+
var traits: ClockTraits { [.monotonic] }
136140

137141
init() {
138142
_now = Instant(tocksFromStart: 1000)

0 commit comments

Comments
 (0)