Commit 53d011fa1a

Andrew Kelley <andrew@ziglang.org>
2020-05-25 02:06:56
(breaking) std.time fixups and API changes
Remove the constants that assume a base unit in favor of explicit x_per_y constants. nanosecond calendar timestamps now use i128 for the type. This affects fs.File.Stat, std.time.nanoTimestamp, and fs.File.updateTimes. calendar timestamps are now signed, because the value can be less than the epoch (the user can set their computer time to whatever they wish). implement std.os.clock_gettime for Windows when clock id is CLOCK_CALENDAR.
1 parent c6e7d0f
lib/std/event/batch.zig
@@ -122,7 +122,7 @@ test "std.event.Batch" {
 }
 
 fn sleepALittle(count: *usize) void {
-    std.time.sleep(1 * std.time.millisecond);
+    std.time.sleep(1 * std.time.ns_per_ms);
     _ = @atomicRmw(usize, count, .Add, 1, .SeqCst);
 }
 
lib/std/event/group.zig
@@ -145,7 +145,7 @@ fn testGroup(allocator: *Allocator) callconv(.Async) void {
     testing.expectError(error.ItBroke, another.wait());
 }
 fn sleepALittle(count: *usize) callconv(.Async) void {
-    std.time.sleep(1 * std.time.millisecond);
+    std.time.sleep(1 * std.time.ns_per_ms);
     _ = @atomicRmw(usize, count, .Add, 1, .SeqCst);
 }
 fn increaseByTen(count: *usize) callconv(.Async) void {
lib/std/event/loop.zig
@@ -457,7 +457,7 @@ pub const Loop = struct {
                         => {
                             // Even poll() didn't work. The best we can do now is sleep for a
                             // small duration and then hope that something changed.
-                            std.time.sleep(1 * std.time.millisecond);
+                            std.time.sleep(1 * std.time.ns_per_ms);
                         },
                     };
                     resume @frame();
lib/std/fs/file.zig
@@ -227,14 +227,12 @@ pub const File = struct {
         size: u64,
         mode: Mode,
 
-        /// access time in nanoseconds
-        atime: i64,
-
-        /// last modification time in nanoseconds
-        mtime: i64,
-
-        /// creation time in nanoseconds
-        ctime: i64,
+        /// Access time in nanoseconds, relative to UTC 1970-01-01.
+        atime: i128,
+        /// Last modification time in nanoseconds, relative to UTC 1970-01-01.
+        mtime: i128,
+        /// Creation time in nanoseconds, relative to UTC 1970-01-01.
+        ctime: i128,
     };
 
     pub const StatError = os.FStatError;
@@ -270,9 +268,9 @@ pub const File = struct {
             .inode = st.ino,
             .size = @bitCast(u64, st.size),
             .mode = st.mode,
-            .atime = @as(i64, atime.tv_sec) * std.time.ns_per_s + atime.tv_nsec,
-            .mtime = @as(i64, mtime.tv_sec) * std.time.ns_per_s + mtime.tv_nsec,
-            .ctime = @as(i64, ctime.tv_sec) * std.time.ns_per_s + ctime.tv_nsec,
+            .atime = @as(i128, atime.tv_sec) * std.time.ns_per_s + atime.tv_nsec,
+            .mtime = @as(i128, mtime.tv_sec) * std.time.ns_per_s + mtime.tv_nsec,
+            .ctime = @as(i128, ctime.tv_sec) * std.time.ns_per_s + ctime.tv_nsec,
         };
     }
 
@@ -286,9 +284,9 @@ pub const File = struct {
     pub fn updateTimes(
         self: File,
         /// access timestamp in nanoseconds
-        atime: i64,
+        atime: i128,
         /// last modification timestamp in nanoseconds
-        mtime: i64,
+        mtime: i128,
     ) UpdateTimesError!void {
         if (builtin.os.tag == .windows) {
             const atime_ft = windows.nanoSecondsToFileTime(atime);
lib/std/fs/test.zig
@@ -10,7 +10,7 @@ test "openSelfExe" {
     self_exe_file.close();
 }
 
-const FILE_LOCK_TEST_SLEEP_TIME = 5 * std.time.millisecond;
+const FILE_LOCK_TEST_SLEEP_TIME = 5 * std.time.ns_per_ms;
 
 test "open file with exclusive nonblocking lock twice" {
     if (builtin.os.tag == .wasi) return error.SkipZigTest;
@@ -142,8 +142,8 @@ const FileLockTestContext = struct {
 
     // Output variables
     err: ?(File.OpenError || std.os.ReadError) = null,
-    start_time: u64 = 0,
-    end_time: u64 = 0,
+    start_time: i64 = 0,
+    end_time: i64 = 0,
     bytes_read: ?usize = null,
 
     fn overlaps(self: *const @This(), other: *const @This()) bool {
lib/std/os/bits/darwin.zig
@@ -1456,3 +1456,12 @@ pub const POLLHUP = 0x010;
 pub const POLLNVAL = 0x020;
 
 pub const POLLSTANDARD = POLLIN | POLLPRI | POLLOUT | POLLRDNORM | POLLRDBAND | POLLWRBAND | POLLERR | POLLHUP | POLLNVAL;
+
+pub const CLOCK_REALTIME = 0;
+pub const CLOCK_MONOTONIC = 6;
+pub const CLOCK_MONOTONIC_RAW = 4;
+pub const CLOCK_MONOTONIC_RAW_APPROX = 5;
+pub const CLOCK_UPTIME_RAW = 8;
+pub const CLOCK_UPTIME_RAW_APPROX = 9;
+pub const CLOCK_PROCESS_CPUTIME_ID = 12;
+pub const CLOCK_THREAD_CPUTIME_ID = 16;
lib/std/os/windows.zig
@@ -1193,23 +1193,23 @@ pub fn peb() *PEB {
 /// Universal Time (UTC).
 /// This function returns the number of nanoseconds since the canonical epoch,
 /// which is the POSIX one (Jan 01, 1970 AD).
-pub fn fromSysTime(hns: i64) i64 {
-    const adjusted_epoch = hns + std.time.epoch.windows * (std.time.ns_per_s / 100);
+pub fn fromSysTime(hns: i64) i128 {
+    const adjusted_epoch = @as(i128, hns + std.time.epoch.windows) * (std.time.ns_per_s / 100);
     return adjusted_epoch * 100;
 }
 
-pub fn toSysTime(ns: i64) i64 {
+pub fn toSysTime(ns: i128) i64 {
     const hns = @divFloor(ns, 100);
-    return hns - std.time.epoch.windows * (std.time.ns_per_s / 100);
+    return @intCast(i64, hns) - std.time.epoch.windows * (std.time.ns_per_s / 100);
 }
 
-pub fn fileTimeToNanoSeconds(ft: FILETIME) i64 {
-    const hns = @bitCast(i64, (@as(u64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime);
+pub fn fileTimeToNanoSeconds(ft: FILETIME) i128 {
+    const hns = (@as(i64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
     return fromSysTime(hns);
 }
 
 /// Converts a number of nanoseconds since the POSIX epoch to a Windows FILETIME.
-pub fn nanoSecondsToFileTime(ns: i64) FILETIME {
+pub fn nanoSecondsToFileTime(ns: i128) FILETIME {
     const adjusted = @bitCast(u64, toSysTime(ns));
     return FILETIME{
         .dwHighDateTime = @truncate(u32, adjusted >> 32),
lib/std/time/epoch.zig
@@ -1,15 +1,26 @@
-/// Epoch reference times in terms of their difference from
-///   posix epoch in seconds.
-pub const posix = 0; //Jan 01, 1970 AD
-pub const dos = 315532800; //Jan 01, 1980 AD
-pub const ios = 978307200; //Jan 01, 2001 AD
-pub const openvms = -3506716800; //Nov 17, 1858 AD
-pub const zos = -2208988800; //Jan 01, 1900 AD
-pub const windows = -11644473600; //Jan 01, 1601 AD
-pub const amiga = 252460800; //Jan 01, 1978 AD
-pub const pickos = -63244800; //Dec 31, 1967 AD
-pub const gps = 315964800; //Jan 06, 1980 AD
-pub const clr = -62135769600; //Jan 01, 0001 AD
+//! Epoch reference times in terms of their difference from
+//! UTC 1970-01-01 in seconds.
+
+/// Jan 01, 1970 AD
+pub const posix = 0;
+/// Jan 01, 1980 AD
+pub const dos = 315532800;
+/// Jan 01, 2001 AD
+pub const ios = 978307200;
+/// Nov 17, 1858 AD
+pub const openvms = -3506716800;
+/// Jan 01, 1900 AD
+pub const zos = -2208988800;
+/// Jan 01, 1601 AD
+pub const windows = -11644473600;
+/// Jan 01, 1978 AD
+pub const amiga = 252460800;
+/// Dec 31, 1967 AD
+pub const pickos = -63244800;
+/// Jan 06, 1980 AD
+pub const gps = 315964800;
+/// Jan 01, 0001 AD
+pub const clr = -62135769600;
 
 pub const unix = posix;
 pub const android = posix;
lib/std/net.zig
@@ -1135,13 +1135,13 @@ fn resMSendRc(
     }};
     const retry_interval = timeout / attempts;
     var next: u32 = 0;
-    var t2: u64 = std.time.milliTimestamp();
+    var t2: u64 = @bitCast(u64, std.time.milliTimestamp());
     var t0 = t2;
     var t1 = t2 - retry_interval;
 
     var servfail_retry: usize = undefined;
 
-    outer: while (t2 - t0 < timeout) : (t2 = std.time.milliTimestamp()) {
+    outer: while (t2 - t0 < timeout) : (t2 = @bitCast(u64, std.time.milliTimestamp())) {
         if (t2 - t1 >= retry_interval) {
             // Query all configured nameservers in parallel
             var i: usize = 0;
lib/std/os.zig
@@ -3880,6 +3880,8 @@ pub fn dl_iterate_phdr(
 
 pub const ClockGetTimeError = error{UnsupportedClock} || UnexpectedError;
 
+/// TODO: change this to return the timespec as a return value
+/// TODO: look into making clk_id an enum
 pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void {
     if (std.Target.current.os.tag == .wasi) {
         var ts: timestamp_t = undefined;
@@ -3895,6 +3897,23 @@ pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void {
         }
         return;
     }
+    if (std.Target.current.os.tag == .windows) {
+        if (clk_id == CLOCK_REALTIME) {
+            var ft: windows.FILETIME = undefined;
+            windows.kernel32.GetSystemTimeAsFileTime(&ft);
+            // FileTime has a granularity of 100 nanoseconds and uses the NTFS/Windows epoch.
+            const ft64 = (@as(u64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
+            const ft_per_s = std.time.ns_per_s / 100;
+            tp.* = .{
+                .tv_sec = @intCast(i64, ft64 / ft_per_s) + std.time.epoch.windows,
+                .tv_nsec = @intCast(c_long, ft64 % ft_per_s) * 100,
+            };
+            return;
+        } else {
+            // TODO POSIX implementation of CLOCK_MONOTONIC on Windows.
+            return error.UnsupportedClock;
+        }
+    }
 
     switch (errno(system.clock_gettime(clk_id, tp))) {
         0 => return,
lib/std/progress.zig
@@ -31,10 +31,10 @@ pub const Progress = struct {
     output_buffer: [100]u8 = undefined,
 
     /// How many nanoseconds between writing updates to the terminal.
-    refresh_rate_ns: u64 = 50 * std.time.millisecond,
+    refresh_rate_ns: u64 = 50 * std.time.ns_per_ms,
 
     /// How many nanoseconds to keep the output hidden
-    initial_delay_ns: u64 = 500 * std.time.millisecond,
+    initial_delay_ns: u64 = 500 * std.time.ns_per_ms,
 
     done: bool = true,
 
@@ -282,24 +282,24 @@ test "basic functionality" {
         next_sub_task = (next_sub_task + 1) % sub_task_names.len;
 
         node.completeOne();
-        std.time.sleep(5 * std.time.millisecond);
+        std.time.sleep(5 * std.time.ns_per_ms);
         node.completeOne();
         node.completeOne();
-        std.time.sleep(5 * std.time.millisecond);
+        std.time.sleep(5 * std.time.ns_per_ms);
         node.completeOne();
         node.completeOne();
-        std.time.sleep(5 * std.time.millisecond);
+        std.time.sleep(5 * std.time.ns_per_ms);
 
         node.end();
 
-        std.time.sleep(5 * std.time.millisecond);
+        std.time.sleep(5 * std.time.ns_per_ms);
     }
     {
         var node = root_node.start("this is a really long name designed to activate the truncation code. let's find out if it works", null);
         node.activate();
-        std.time.sleep(10 * std.time.millisecond);
+        std.time.sleep(10 * std.time.ns_per_ms);
         progress.refresh();
-        std.time.sleep(10 * std.time.millisecond);
+        std.time.sleep(10 * std.time.ns_per_ms);
         node.end();
     }
 }
lib/std/reset_event.zig
@@ -152,15 +152,15 @@ const PosixEvent = struct {
             if (comptime std.Target.current.isDarwin()) {
                 var tv: os.darwin.timeval = undefined;
                 assert(os.darwin.gettimeofday(&tv, null) == 0);
-                timeout_abs += @intCast(u64, tv.tv_sec) * time.second;
-                timeout_abs += @intCast(u64, tv.tv_usec) * time.microsecond;
+                timeout_abs += @intCast(u64, tv.tv_sec) * time.ns_per_s;
+                timeout_abs += @intCast(u64, tv.tv_usec) * time.us_per_s;
             } else {
                 os.clock_gettime(os.CLOCK_REALTIME, &ts) catch unreachable;
-                timeout_abs += @intCast(u64, ts.tv_sec) * time.second;
+                timeout_abs += @intCast(u64, ts.tv_sec) * time.ns_per_s;
                 timeout_abs += @intCast(u64, ts.tv_nsec);
             }
-            ts.tv_sec = @intCast(@TypeOf(ts.tv_sec), @divFloor(timeout_abs, time.second));
-            ts.tv_nsec = @intCast(@TypeOf(ts.tv_nsec), @mod(timeout_abs, time.second));
+            ts.tv_sec = @intCast(@TypeOf(ts.tv_sec), @divFloor(timeout_abs, time.ns_per_s));
+            ts.tv_nsec = @intCast(@TypeOf(ts.tv_nsec), @mod(timeout_abs, time.ns_per_s));
         }
 
         while (!self.is_set) {
lib/std/time.zig
@@ -4,16 +4,14 @@ const assert = std.debug.assert;
 const testing = std.testing;
 const os = std.os;
 const math = std.math;
+const is_windows = std.Target.current.os.tag == .windows;
 
 pub const epoch = @import("time/epoch.zig");
 
-const is_windows = std.Target.current.os.tag == .windows;
-
 /// Spurious wakeups are possible and no precision of timing is guaranteed.
 /// TODO integrate with evented I/O
 pub fn sleep(nanoseconds: u64) void {
     if (is_windows) {
-        const ns_per_ms = ns_per_s / ms_per_s;
         const big_ms_from_ns = nanoseconds / ns_per_ms;
         const ms = math.cast(os.windows.DWORD, big_ms_from_ns) catch math.maxInt(os.windows.DWORD);
         os.windows.kernel32.Sleep(ms);
@@ -49,105 +47,78 @@ pub fn sleep(nanoseconds: u64) void {
     std.os.nanosleep(s, ns);
 }
 
-/// Get the posix timestamp, UTC, in seconds
-/// TODO audit this function. is it possible to return an error?
-pub fn timestamp() u64 {
-    return @divFloor(milliTimestamp(), ms_per_s);
+/// Get a calendar timestamp, in seconds, relative to UTC 1970-01-01.
+/// Precision of timing depends on the hardware and operating system.
+/// The return value is signed because it is possible to have a date that is
+/// before the epoch.
+/// See `std.os.clock_gettime` for a POSIX timestamp.
+pub fn timestamp() i64 {
+    return @divFloor(milliTimestamp(), ns_per_s);
 }
 
-/// Get the posix timestamp, UTC, in milliseconds
-/// TODO audit this function. is it possible to return an error?
-pub fn milliTimestamp() u64 {
-    return @divFloor(nanoTimestamp(), millisecond);
+/// Get a calendar timestamp, in milliseconds, relative to UTC 1970-01-01.
+/// Precision of timing depends on the hardware and operating system.
+/// The return value is signed because it is possible to have a date that is
+/// before the epoch.
+/// See `std.os.clock_gettime` for a POSIX timestamp.
+pub fn milliTimestamp() i64 {
+    return @intCast(i64, @divFloor(nanoTimestamp(), ns_per_ms));
 }
 
-const DarwinTimeStart = struct {
-    timebase: os.darwin.mach_timebase_info_data,
-    inittime: os.darwin.timespec,
-    initclock: u64,
-};
-
-var global_timestart: DarwinTimeStart = undefined;
-var init_global_timestart_once = std.once(init_global_timestart);
-
-pub fn init_global_timestart() void {
-    var micro: os.darwin.timeval = undefined;
-    var timestart: DarwinTimeStart = undefined;
-
-    os.darwin.mach_timebase_info(&timestart.timebase);
-
-    const err = os.darwin.gettimeofday(&micro, null);
-    assert(err == 0);
-
-    timestart.initclock = os.darwin.mach_absolute_time();
-    timestart.inittime.tv_sec = micro.tv_sec;
-    timestart.inittime.tv_nsec = micro.tv_usec * 1000;
-
-    global_timestart = timestart;
-}
-
-/// Get the posix timestamp, UTC, in nanoseconds
-///
-/// On windows this only has a granularity of 100 nanoseconds.
-///
-/// TODO audit this function. is it possible to return an error?
-pub fn nanoTimestamp() u64 {
+/// Get a calendar timestamp, in nanoseconds, relative to UTC 1970-01-01.
+/// Precision of timing depends on the hardware and operating system.
+/// On Windows this has a maximum granularity of 100 nanoseconds.
+/// The return value is signed because it is possible to have a date that is
+/// before the epoch.
+/// See `std.os.clock_gettime` for a POSIX timestamp.
+pub fn nanoTimestamp() i128 {
     if (is_windows) {
-        //FileTime has a granularity of 100 nanoseconds
-        //  and uses the NTFS/Windows epoch
+        // FileTime has a granularity of 100 nanoseconds and uses the NTFS/Windows epoch,
+        // which is 1601-01-01.
+        const epoch_adj = epoch.windows * (ns_per_s / 100);
         var ft: os.windows.FILETIME = undefined;
         os.windows.kernel32.GetSystemTimeAsFileTime(&ft);
-        const ns_per_hns = 100;
-        const epoch_adj = epoch.windows * ns_per_s;
-
         const ft64 = (@as(u64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
-        return (ft64 * ns_per_hns) - -epoch_adj;
+        return @as(i128, @bitCast(i64, ft64) + epoch_adj) * 100;
     }
     if (builtin.os.tag == .wasi and !builtin.link_libc) {
         var ns: os.wasi.timestamp_t = undefined;
-
-        // TODO: Verify that precision is ignored
         const err = os.wasi.clock_time_get(os.wasi.CLOCK_REALTIME, 1, &ns);
         assert(err == os.wasi.ESUCCESS);
-
         return ns;
     }
-    if (comptime std.Target.current.isDarwin()) {
-        // https://stackoverflow.com/a/21352348
-        init_global_timestart_once.call();
-
-        const clock: u64 = os.darwin.mach_absolute_time() - global_timestart.initclock;
-        const nano = @divFloor(clock * @as(u64, global_timestart.timebase.numer), @as(u64, global_timestart.timebase.denom));
-
-        const tv_sec_nsec = @intCast(u64, global_timestart.inittime.tv_sec) * ns_per_s;
-        const tv_nsec = @intCast(u64, global_timestart.inittime.tv_nsec);
-
-        return tv_sec_nsec + tv_nsec + nano;
-    }
     var ts: os.timespec = undefined;
-    //From what I can tell there's no reason clock_gettime
-    //  should ever fail for us with CLOCK_REALTIME,
-    //  seccomp aside.
-    os.clock_gettime(os.CLOCK_REALTIME, &ts) catch unreachable;
-    const sec_ns = @intCast(u64, ts.tv_sec) * ns_per_s;
-    return sec_ns + @intCast(u64, ts.tv_nsec);
+    os.clock_gettime(os.CLOCK_REALTIME, &ts) catch |err| switch (err) {
+        error.UnsupportedClock, error.Unexpected => return 0, // "Precision of timing depends on hardware and OS".
+    };
+    return (@as(i128, ts.tv_sec) * ns_per_s) + ts.tv_nsec;
 }
 
-/// Multiples of a base unit (nanoseconds)
-pub const nanosecond = 1;
-pub const microsecond = 1000 * nanosecond;
-pub const millisecond = 1000 * microsecond;
-pub const second = 1000 * millisecond;
-pub const minute = 60 * second;
-pub const hour = 60 * minute;
-
-/// Divisions of a second
-pub const ns_per_s = 1000000000;
-pub const us_per_s = 1000000;
+// Divisions of a nanosecond.
+pub const ns_per_us = 1000;
+pub const ns_per_ms = 1000 * ns_per_us;
+pub const ns_per_s = 1000 * ns_per_ms;
+pub const ns_per_min = 60 * ns_per_s;
+pub const ns_per_hour = 60 * ns_per_min;
+pub const ns_per_day = 24 * ns_per_hour;
+pub const ns_per_week = 7 * ns_per_day;
+
+// Divisions of a microsecond.
+pub const us_per_ms = 1000;
+pub const us_per_s = 1000 * us_per_ms;
+pub const us_per_min = 60 * us_per_s;
+pub const us_per_hour = 60 * us_per_min;
+pub const us_per_day = 24 * us_per_hour;
+pub const us_per_week = 7 * us_per_day;
+
+// Divisions of a millisecond.
 pub const ms_per_s = 1000;
-pub const cs_per_s = 100;
+pub const ms_per_min = 60 * ms_per_s;
+pub const ms_per_hour = 60 * ms_per_min;
+pub const ms_per_day = 24 * ms_per_hour;
+pub const ms_per_week = 7 * ms_per_day;
 
-/// Common time divisions
+// Divisions of a second.
 pub const s_per_min = 60;
 pub const s_per_hour = s_per_min * 60;
 pub const s_per_day = s_per_hour * 24;
@@ -155,12 +126,12 @@ pub const s_per_week = s_per_day * 7;
 
 /// A monotonic high-performance timer.
 /// Timer.start() must be called to initialize the struct, which captures
-///   the counter frequency on windows and darwin, records the resolution,
-///   and gives the user an opportunity to check for the existnece of
-///   monotonic clocks without forcing them to check for error on each read.
+/// the counter frequency on windows and darwin, records the resolution,
+/// and gives the user an opportunity to check for the existnece of
+/// monotonic clocks without forcing them to check for error on each read.
 /// .resolution is in nanoseconds on all platforms but .start_time's meaning
-///   depends on the OS. On Windows and Darwin it is a hardware counter
-///   value that requires calculation to convert to a meaninful unit.
+/// depends on the OS. On Windows and Darwin it is a hardware counter
+/// value that requires calculation to convert to a meaninful unit.
 pub const Timer = struct {
     ///if we used resolution's value when performing the
     ///  performance counter calc on windows/darwin, it would
@@ -173,43 +144,58 @@ pub const Timer = struct {
     resolution: u64,
     start_time: u64,
 
-    const Error = error{TimerUnsupported};
+    pub const Error = error{TimerUnsupported};
 
-    ///At some point we may change our minds on RAW, but for now we're
-    ///  sticking with posix standard MONOTONIC. For more information, see:
-    ///  https://github.com/ziglang/zig/pull/933
+    /// At some point we may change our minds on RAW, but for now we're
+    /// sticking with posix standard MONOTONIC. For more information, see:
+    /// https://github.com/ziglang/zig/pull/933
     const monotonic_clock_id = os.CLOCK_MONOTONIC;
+
     /// Initialize the timer structure.
-    //This gives us an opportunity to grab the counter frequency in windows.
-    //On Windows: QueryPerformanceCounter will succeed on anything >= XP/2000.
-    //On Posix: CLOCK_MONOTONIC will only fail if the monotonic counter is not
-    //  supported, or if the timespec pointer is out of bounds, which should be
-    //  impossible here barring cosmic rays or other such occurrences of
-    //  incredibly bad luck.
-    //On Darwin: This cannot fail, as far as I am able to tell.
+    /// Can only fail when running in a hostile environment that intentionally injects
+    /// error values into syscalls, such as using seccomp on Linux to intercept
+    /// `clock_gettime`.
     pub fn start() Error!Timer {
-        var self: Timer = undefined;
-
+        // This gives us an opportunity to grab the counter frequency in windows.
+        // On Windows: QueryPerformanceCounter will succeed on anything >= XP/2000.
+        // On Posix: CLOCK_MONOTONIC will only fail if the monotonic counter is not
+        // supported, or if the timespec pointer is out of bounds, which should be
+        // impossible here barring cosmic rays or other such occurrences of
+        // incredibly bad luck.
+        // On Darwin: This cannot fail, as far as I am able to tell.
         if (is_windows) {
-            self.frequency = os.windows.QueryPerformanceFrequency();
-            self.resolution = @divFloor(ns_per_s, self.frequency);
-            self.start_time = os.windows.QueryPerformanceCounter();
+            const freq = os.windows.QueryPerformanceFrequency();
+            return Timer{
+                .frequency = freq,
+                .resolution = @divFloor(ns_per_s, freq),
+                .start_time = os.windows.QueryPerformanceCounter(),
+            };
         } else if (comptime std.Target.current.isDarwin()) {
-            os.darwin.mach_timebase_info(&self.frequency);
-            self.resolution = @divFloor(self.frequency.numer, self.frequency.denom);
-            self.start_time = os.darwin.mach_absolute_time();
+            var freq: os.darwin.mach_timebase_info_data = undefined;
+            os.darwin.mach_timebase_info(&freq);
+
+            return Timer{
+                .frequency = freq,
+                .resolution = @divFloor(freq.numer, freq.denom),
+                .start_time = os.darwin.mach_absolute_time(),
+            };
         } else {
-            //On Linux, seccomp can do arbitrary things to our ability to call
-            //  syscalls, including return any errno value it wants and
-            //  inconsistently throwing errors. Since we can't account for
-            //  abuses of seccomp in a reasonable way, we'll assume that if
-            //  seccomp is going to block us it will at least do so consistently
-            var ts: os.timespec = undefined;
-            os.clock_getres(monotonic_clock_id, &ts) catch return error.TimerUnsupported;
-            self.resolution = @intCast(u64, ts.tv_sec) * @as(u64, ns_per_s) + @intCast(u64, ts.tv_nsec);
+            // On Linux, seccomp can do arbitrary things to our ability to call
+            // syscalls, including return any errno value it wants and
+            // inconsistently throwing errors. Since we can't account for
+            // abuses of seccomp in a reasonable way, we'll assume that if
+            // seccomp is going to block us it will at least do so consistently
+            var res: os.timespec = undefined;
+            os.clock_getres(monotonic_clock_id, &res) catch return error.TimerUnsupported;
 
+            var ts: os.timespec = undefined;
             os.clock_gettime(monotonic_clock_id, &ts) catch return error.TimerUnsupported;
-            self.start_time = @intCast(u64, ts.tv_sec) * @as(u64, ns_per_s) + @intCast(u64, ts.tv_nsec);
+
+            return Timer{
+                .resolution = @intCast(u64, res.tv_sec) * ns_per_s + @intCast(u64, res.tv_nsec),
+                .start_time = @intCast(u64, ts.tv_sec) * ns_per_s + @intCast(u64, ts.tv_nsec),
+                .frequency = {},
+            };
         }
 
         return self;
@@ -262,7 +248,6 @@ test "sleep" {
 }
 
 test "timestamp" {
-    const ns_per_ms = (ns_per_s / ms_per_s);
     const margin = ns_per_ms * 50;
 
     const time_0 = milliTimestamp();
@@ -273,7 +258,6 @@ test "timestamp" {
 }
 
 test "Timer" {
-    const ns_per_ms = (ns_per_s / ms_per_s);
     const margin = ns_per_ms * 150;
 
     var timer = try Timer.start();