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
|
func sleep(until deadline: Instant, tolerance: Instant.Duration?) async throws
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !$Embedded
|
/// The traits associated with this clock instance.
|
||||||
/// Choose which Dispatch clock to use with DispatchExecutor
|
|
||||||
///
|
|
||||||
/// This controls which Dispatch clock is used to enqueue delayed jobs
|
|
||||||
/// when using this Clock.
|
|
||||||
@available(SwiftStdlib 6.2, *)
|
@available(SwiftStdlib 6.2, *)
|
||||||
var dispatchClockID: DispatchClockID { get }
|
var traits: ClockTraits { get }
|
||||||
#endif
|
|
||||||
|
|
||||||
/// Convert a Clock-specific Duration to a Swift Duration
|
/// Convert a Clock-specific Duration to a Swift Duration
|
||||||
///
|
///
|
||||||
@@ -138,12 +133,6 @@ extension Clock {
|
|||||||
|
|
||||||
@available(SwiftStdlib 6.2, *)
|
@available(SwiftStdlib 6.2, *)
|
||||||
extension Clock {
|
extension Clock {
|
||||||
#if !$Embedded
|
|
||||||
public var dispatchClockID: DispatchClockID {
|
|
||||||
return .suspending
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// For compatibility, return `nil` if this is not implemented
|
// For compatibility, return `nil` if this is not implemented
|
||||||
public func convert(from duration: Duration) -> Swift.Duration? {
|
public func convert(from duration: Duration) -> Swift.Duration? {
|
||||||
return nil
|
return nil
|
||||||
@@ -198,6 +187,43 @@ extension Clock {
|
|||||||
}
|
}
|
||||||
#endif
|
#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 {
|
enum _ClockID: Int32 {
|
||||||
case continuous = 1
|
case continuous = 1
|
||||||
case suspending = 2
|
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
|
#if !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
|
||||||
/// Suspend task execution until a given deadline within a tolerance.
|
/// Suspend task execution until a given deadline within a tolerance.
|
||||||
/// If no tolerance is specified then the system may adjust the deadline
|
/// 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
|
/// An enumeration identifying one of the Dispatch-supported clocks
|
||||||
@available(SwiftStdlib 6.2, *)
|
enum DispatchClockID: CInt {
|
||||||
public enum DispatchClockID: CInt {
|
|
||||||
case suspending = 1
|
case suspending = 1
|
||||||
case continuous = 2
|
case continuous = 2
|
||||||
}
|
}
|
||||||
@@ -189,18 +188,7 @@ extension DispatchExecutor {
|
|||||||
|
|
||||||
func timestamp<C: Clock>(for instant: C.Instant, clock: C)
|
func timestamp<C: Clock>(for instant: C.Instant, clock: C)
|
||||||
-> (clockID: DispatchClockID, seconds: Int64, nanoseconds: Int64) {
|
-> (clockID: DispatchClockID, seconds: Int64, nanoseconds: Int64) {
|
||||||
let clockID = clock.dispatchClockID
|
if clock.traits.contains(.continuous) {
|
||||||
|
|
||||||
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:
|
|
||||||
let dispatchClock: ContinuousClock = .continuous
|
let dispatchClock: ContinuousClock = .continuous
|
||||||
let instant = dispatchClock.convert(instant: instant, from: clock)!
|
let instant = dispatchClock.convert(instant: instant, from: clock)!
|
||||||
let (seconds, attoseconds) = instant._value.components
|
let (seconds, attoseconds) = instant._value.components
|
||||||
@@ -208,6 +196,14 @@ extension DispatchExecutor {
|
|||||||
return (clockID: .continuous,
|
return (clockID: .continuous,
|
||||||
seconds: Int64(seconds),
|
seconds: Int64(seconds),
|
||||||
nanoseconds: Int64(nanoseconds))
|
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)
|
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
|
#if !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
|
||||||
/// Suspend task execution until a given deadline within a tolerance.
|
/// Suspend task execution until a given deadline within a tolerance.
|
||||||
/// If no tolerance is specified then the system may adjust the deadline
|
/// If no tolerance is specified then the system may adjust the deadline
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
import StdlibUnittest
|
import StdlibUnittest
|
||||||
|
|
||||||
|
@available(SwiftStdlib 6.2, *)
|
||||||
struct TickingClock: Clock {
|
struct TickingClock: Clock {
|
||||||
struct Duration: DurationProtocol {
|
struct Duration: DurationProtocol {
|
||||||
var ticks: Int
|
var ticks: Int
|
||||||
@@ -57,6 +58,7 @@ struct TickingClock: Clock {
|
|||||||
private var _now: Instant
|
private var _now: Instant
|
||||||
var now: Instant { return _now }
|
var now: Instant { return _now }
|
||||||
var minimumResolution: Duration { return Duration(ticks: 1) }
|
var minimumResolution: Duration { return Duration(ticks: 1) }
|
||||||
|
var traits: ClockTraits { [.monotonic] }
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
_now = Instant(ticksFromStart: 0)
|
_now = Instant(ticksFromStart: 0)
|
||||||
@@ -87,6 +89,7 @@ struct TickingClock: Clock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(SwiftStdlib 6.2, *)
|
||||||
struct TockingClock: Clock {
|
struct TockingClock: Clock {
|
||||||
struct Duration: DurationProtocol {
|
struct Duration: DurationProtocol {
|
||||||
var tocks: Int
|
var tocks: Int
|
||||||
@@ -133,6 +136,7 @@ struct TockingClock: Clock {
|
|||||||
private var _now: Instant
|
private var _now: Instant
|
||||||
var now: Instant { return _now }
|
var now: Instant { return _now }
|
||||||
var minimumResolution: Duration { return Duration(tocks: 1) }
|
var minimumResolution: Duration { return Duration(tocks: 1) }
|
||||||
|
var traits: ClockTraits { [.monotonic] }
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
_now = Instant(tocksFromStart: 1000)
|
_now = Instant(tocksFromStart: 1000)
|
||||||
|
|||||||
Reference in New Issue
Block a user