mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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.
This commit is contained in:
@@ -42,14 +42,9 @@ public protocol Clock<Duration>: Sendable {
|
||||
func sleep(until deadline: Instant, tolerance: Instant.Duration?) async throws
|
||||
#endif
|
||||
|
||||
#if !$Embedded
|
||||
/// Choose which Dispatch clock to use with DispatchExecutor
|
||||
///
|
||||
/// This controls which Dispatch clock is used to enqueue delayed jobs
|
||||
/// when using this Clock.
|
||||
/// The traits associated with this clock instance.
|
||||
@available(SwiftStdlib 6.2, *)
|
||||
var dispatchClockID: DispatchClockID { get }
|
||||
#endif
|
||||
var traits: ClockTraits { get }
|
||||
|
||||
/// Convert a Clock-specific Duration to a Swift Duration
|
||||
///
|
||||
@@ -138,12 +133,6 @@ extension Clock {
|
||||
|
||||
@available(SwiftStdlib 6.2, *)
|
||||
extension Clock {
|
||||
#if !$Embedded
|
||||
public var dispatchClockID: DispatchClockID {
|
||||
return .suspending
|
||||
}
|
||||
#endif
|
||||
|
||||
// For compatibility, return `nil` if this is not implemented
|
||||
public func convert(from duration: Duration) -> Swift.Duration? {
|
||||
return nil
|
||||
@@ -198,6 +187,43 @@ extension Clock {
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Represents traits of a particular Clock implementation.
|
||||
///
|
||||
/// Clocks may be of a number of different varieties; executors will likely
|
||||
/// have specific clocks that they can use to schedule jobs, and will
|
||||
/// therefore need to be able to convert timestamps to an appropriate clock
|
||||
/// when asked to enqueue a job with a delay or deadline.
|
||||
///
|
||||
/// Choosing a clock in general requires the ability to tell which of their
|
||||
/// clocks best matches the clock that the user is trying to specify a
|
||||
/// time or delay in. Executors are expected to do this on a best effort
|
||||
/// basis.
|
||||
@available(SwiftStdlib 6.2, *)
|
||||
public struct ClockTraits: OptionSet {
|
||||
public let rawValue: Int32
|
||||
|
||||
public init(rawValue: Int32) {
|
||||
self.rawValue = rawValue
|
||||
}
|
||||
|
||||
/// Clocks with this trait continue running while the machine is asleep.
|
||||
public static let continuous = ClockTraits(rawValue: 1 << 0)
|
||||
|
||||
/// Indicates that a clock's time will only ever increase.
|
||||
public static let monotonic = ClockTraits(rawValue: 1 << 1)
|
||||
|
||||
/// Clocks with this trait are tied to "wall time".
|
||||
public static let wallTime = ClockTraits(rawValue: 1 << 2)
|
||||
}
|
||||
|
||||
extension Clock {
|
||||
/// The traits associated with this clock instance.
|
||||
@available(SwiftStdlib 6.2, *)
|
||||
var traits: ClockTraits {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
enum _ClockID: Int32 {
|
||||
case continuous = 1
|
||||
case suspending = 2
|
||||
|
||||
@@ -100,6 +100,12 @@ extension ContinuousClock: Clock {
|
||||
)
|
||||
}
|
||||
|
||||
/// The continuous clock is continuous and monotonic
|
||||
@available(SwiftStdlib 6.2, *)
|
||||
public var traits: ClockTraits {
|
||||
return [.continuous, .monotonic]
|
||||
}
|
||||
|
||||
#if !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
|
||||
/// Suspend task execution until a given deadline within a tolerance.
|
||||
/// If no tolerance is specified then the system may adjust the deadline
|
||||
|
||||
@@ -178,8 +178,7 @@ protocol DispatchExecutor: Executor {
|
||||
}
|
||||
|
||||
/// An enumeration identifying one of the Dispatch-supported clocks
|
||||
@available(SwiftStdlib 6.2, *)
|
||||
public enum DispatchClockID: CInt {
|
||||
enum DispatchClockID: CInt {
|
||||
case suspending = 1
|
||||
case continuous = 2
|
||||
}
|
||||
@@ -189,18 +188,7 @@ extension DispatchExecutor {
|
||||
|
||||
func timestamp<C: Clock>(for instant: C.Instant, clock: C)
|
||||
-> (clockID: DispatchClockID, seconds: Int64, nanoseconds: Int64) {
|
||||
let clockID = clock.dispatchClockID
|
||||
|
||||
switch clockID {
|
||||
case .suspending:
|
||||
let dispatchClock: SuspendingClock = .suspending
|
||||
let instant = dispatchClock.convert(instant: instant, from: clock)!
|
||||
let (seconds, attoseconds) = instant._value.components
|
||||
let nanoseconds = attoseconds / 1_000_000_000
|
||||
return (clockID: .suspending,
|
||||
seconds: Int64(seconds),
|
||||
nanoseconds: Int64(nanoseconds))
|
||||
case .continuous:
|
||||
if clock.traits.contains(.continuous) {
|
||||
let dispatchClock: ContinuousClock = .continuous
|
||||
let instant = dispatchClock.convert(instant: instant, from: clock)!
|
||||
let (seconds, attoseconds) = instant._value.components
|
||||
@@ -208,6 +196,14 @@ extension DispatchExecutor {
|
||||
return (clockID: .continuous,
|
||||
seconds: Int64(seconds),
|
||||
nanoseconds: Int64(nanoseconds))
|
||||
} else {
|
||||
let dispatchClock: SuspendingClock = .suspending
|
||||
let instant = dispatchClock.convert(instant: instant, from: clock)!
|
||||
let (seconds, attoseconds) = instant._value.components
|
||||
let nanoseconds = attoseconds / 1_000_000_000
|
||||
return (clockID: .suspending,
|
||||
seconds: Int64(seconds),
|
||||
nanoseconds: Int64(nanoseconds))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -87,6 +87,12 @@ extension SuspendingClock: Clock {
|
||||
return Duration(_seconds: seconds, nanoseconds: nanoseconds)
|
||||
}
|
||||
|
||||
/// The suspending clock is monotonic
|
||||
@available(SwiftStdlib 6.2, *)
|
||||
public var traits: ClockTraits {
|
||||
return [.monotonic]
|
||||
}
|
||||
|
||||
#if !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
|
||||
/// Suspend task execution until a given deadline within a tolerance.
|
||||
/// If no tolerance is specified then the system may adjust the deadline
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
import StdlibUnittest
|
||||
|
||||
@available(SwiftStdlib 6.2, *)
|
||||
struct TickingClock: Clock {
|
||||
struct Duration: DurationProtocol {
|
||||
var ticks: Int
|
||||
@@ -57,6 +58,7 @@ struct TickingClock: Clock {
|
||||
private var _now: Instant
|
||||
var now: Instant { return _now }
|
||||
var minimumResolution: Duration { return Duration(ticks: 1) }
|
||||
var traits: ClockTraits { [.monotonic] }
|
||||
|
||||
init() {
|
||||
_now = Instant(ticksFromStart: 0)
|
||||
@@ -87,6 +89,7 @@ struct TickingClock: Clock {
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 6.2, *)
|
||||
struct TockingClock: Clock {
|
||||
struct Duration: DurationProtocol {
|
||||
var tocks: Int
|
||||
@@ -133,6 +136,7 @@ struct TockingClock: Clock {
|
||||
private var _now: Instant
|
||||
var now: Instant { return _now }
|
||||
var minimumResolution: Duration { return Duration(tocks: 1) }
|
||||
var traits: ClockTraits { [.monotonic] }
|
||||
|
||||
init() {
|
||||
_now = Instant(tocksFromStart: 1000)
|
||||
|
||||
Reference in New Issue
Block a user