File: Clock.swift

package info (click to toggle)
swiftlang 6.2.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,856,264 kB
  • sloc: cpp: 9,995,718; ansic: 2,234,019; asm: 1,092,167; python: 313,940; objc: 82,726; f90: 80,126; lisp: 38,373; pascal: 25,580; sh: 20,378; ml: 5,058; perl: 4,751; makefile: 4,725; awk: 3,535; javascript: 3,018; xml: 918; fortran: 664; cs: 573; ruby: 396
file content (156 lines) | stat: -rw-r--r-- 5,319 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import SystemExtras

/// WASI wall clock interface based on WASI Preview 2 `wall-clock` interface.
///
/// See also https://github.com/WebAssembly/wasi-clocks/blob/v0.2.0/wit/wall-clock.wit
public protocol WallClock {
    /// An instant in time, in seconds and nanoseconds.
    typealias Duration = (
        seconds: UInt64,
        nanoseconds: UInt32
    )

    /// Read the current value of the clock.
    func now() throws -> Duration

    /// Query the resolution of the clock.
    ///
    /// The nanoseconds field of the output is always less than 1000000000.
    func resolution() throws -> Duration
}

/// WASI monotonic clock interface based on WASI Preview 2 `monotonic-clock` interface.
///
/// See also https://github.com/WebAssembly/wasi-clocks/blob/v0.2.0/wit/monotonic-clock.wit
public protocol MonotonicClock {
    /// An instant in time, in nanoseconds.
    typealias Instant = UInt64
    /// A duration of time, in nanoseconds.
    typealias Duration = UInt64

    /// Read the current value of the clock.
    func now() throws -> Instant

    /// Query the resolution of the clock. Returns the duration of time
    /// corresponding to a clock tick.
    func resolution() throws -> Duration
}

#if os(Windows)

    import WinSDK
    import SystemPackage

    // MARK: - Windows

    /// A monotonic clock that uses the system's monotonic clock.
    public struct SystemMonotonicClock: MonotonicClock {

        public init() {
        }

        public func now() throws -> MonotonicClock.Instant {
            var counter = LARGE_INTEGER()
            guard QueryPerformanceCounter(&counter) else {
                throw Errno(windowsError: GetLastError())
            }
            return UInt64(counter.QuadPart)
        }

        public func resolution() throws -> MonotonicClock.Duration {
            var frequency = LARGE_INTEGER()
            guard QueryPerformanceFrequency(&frequency) else {
                throw Errno(windowsError: GetLastError())
            }
            // frequency is in counts per second
            return UInt64(1_000_000_000 / frequency.QuadPart)
        }
    }

    /// A wall clock that uses the system's wall clock.
    public struct SystemWallClock: WallClock {
        public init() {}

        public func now() throws -> WallClock.Duration {
            var fileTime = FILETIME()
            GetSystemTimeAsFileTime(&fileTime)
            // > the number of 100-nanosecond intervals since January 1, 1601 (UTC).
            // https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
            let time = (UInt64(fileTime.dwLowDateTime) | UInt64(fileTime.dwHighDateTime) << 32) / 10
            return (seconds: time / 1_000_000_000, nanoseconds: UInt32(time % 1_000_000_000))
        }

        public func resolution() throws -> WallClock.Duration {
            return (seconds: 0, nanoseconds: 100)
        }
    }

#else

    // MARK: - Unix-like platforms

    /// A monotonic clock that uses the system's monotonic clock.
    public struct SystemMonotonicClock: MonotonicClock {
        private var underlying: SystemExtras.Clock {
            #if os(Linux) || os(Android)
                return .monotonic
            #elseif os(macOS) || os(iOS) || os(watchOS) || os(tvOS) || os(visionOS)
                return .rawUptime
            #elseif os(WASI)
                return .monotonic
            #elseif os(OpenBSD) || os(FreeBSD)
                return .uptime
            #else
                #error("Unsupported platform")
            #endif
        }

        public init() {}

        public func now() throws -> MonotonicClock.Instant {
            let timeSpec = try WASIAbi.Errno.translatingPlatformErrno {
                try underlying.currentTime()
            }
            return WASIAbi.Timestamp(platformTimeSpec: timeSpec)
        }

        public func resolution() throws -> MonotonicClock.Duration {
            let timeSpec = try WASIAbi.Errno.translatingPlatformErrno {
                try underlying.resolution()
            }
            return WASIAbi.Timestamp(platformTimeSpec: timeSpec)
        }
    }

    /// A wall clock that uses the system's wall clock.
    public struct SystemWallClock: WallClock {
        private var underlying: SystemExtras.Clock {
            #if os(Linux) || os(Android)
                return .boottime
            #elseif os(macOS) || os(iOS) || os(watchOS) || os(tvOS) || os(visionOS)
                return .rawMonotonic
            #elseif os(OpenBSD) || os(FreeBSD) || os(WASI)
                return .monotonic
            #else
                #error("Unsupported platform")
            #endif
        }

        public init() {}

        public func now() throws -> WallClock.Duration {
            let timeSpec = try WASIAbi.Errno.translatingPlatformErrno {
                try underlying.currentTime()
            }
            return (seconds: UInt64(timeSpec.seconds), nanoseconds: UInt32(timeSpec.nanoseconds))
        }

        public func resolution() throws -> WallClock.Duration {
            let timeSpec = try WASIAbi.Errno.translatingPlatformErrno {
                try underlying.resolution()
            }
            return (seconds: UInt64(timeSpec.seconds), nanoseconds: UInt32(timeSpec.nanoseconds))
        }
    }

#endif