| author | |
| committer | |
| log | ebcc6f166c9c34d00b750f26687c9ee36b243cb0 |
| tree | 73ba685c9985284f2ebf5aee3b81fb30eaca9c86 |
| parent | 89412fda775aecdedf4047355f2c45b48334a285 |
this feels better11 files changed, 233 insertions(+), 177 deletions(-)
lib/compiler/build_runner.zig+1-1| ... | @@ -556,7 +556,7 @@ pub fn main() !void { | ... | @@ -556,7 +556,7 @@ pub fn main() !void { |
| 556 | try run.thread_pool.init(thread_pool_options); | 556 | try run.thread_pool.init(thread_pool_options); |
| 557 | defer run.thread_pool.deinit(); | 557 | defer run.thread_pool.deinit(); |
| 558 | 558 | ||
| 559 | const now = Io.Timestamp.now(io, .awake) catch |err| fatal("failed to collect timestamp: {t}", .{err}); | 559 | const now = Io.Clock.Timestamp.now(io, .awake) catch |err| fatal("failed to collect timestamp: {t}", .{err}); |
| 560 | 560 | ||
| 561 | run.web_server = if (webui_listen) |listen_address| ws: { | 561 | run.web_server = if (webui_listen) |listen_address| ws: { |
| 562 | if (builtin.single_threaded) unreachable; // `fatal` above | 562 | if (builtin.single_threaded) unreachable; // `fatal` above |
lib/std/Build/Cache.zig+13-13| ... | @@ -21,7 +21,7 @@ io: Io, | ... | @@ -21,7 +21,7 @@ io: Io, |
| 21 | manifest_dir: fs.Dir, | 21 | manifest_dir: fs.Dir, |
| 22 | hash: HashHelper = .{}, | 22 | hash: HashHelper = .{}, |
| 23 | /// This value is accessed from multiple threads, protected by mutex. | 23 | /// This value is accessed from multiple threads, protected by mutex. |
| 24 | recent_problematic_timestamp: i128 = 0, | 24 | recent_problematic_timestamp: Io.Timestamp = .zero, |
| 25 | mutex: std.Thread.Mutex = .{}, | 25 | mutex: std.Thread.Mutex = .{}, |
| 26 | 26 | ||
| 27 | /// A set of strings such as the zig library directory or project source root, which | 27 | /// A set of strings such as the zig library directory or project source root, which |
| ... | @@ -155,7 +155,7 @@ pub const File = struct { | ... | @@ -155,7 +155,7 @@ pub const File = struct { |
| 155 | pub const Stat = struct { | 155 | pub const Stat = struct { |
| 156 | inode: fs.File.INode, | 156 | inode: fs.File.INode, |
| 157 | size: u64, | 157 | size: u64, |
| 158 | mtime: i128, | 158 | mtime: Io.Timestamp, |
| 159 | 159 | ||
| 160 | pub fn fromFs(fs_stat: fs.File.Stat) Stat { | 160 | pub fn fromFs(fs_stat: fs.File.Stat) Stat { |
| 161 | return .{ | 161 | return .{ |
| ... | @@ -330,7 +330,7 @@ pub const Manifest = struct { | ... | @@ -330,7 +330,7 @@ pub const Manifest = struct { |
| 330 | diagnostic: Diagnostic = .none, | 330 | diagnostic: Diagnostic = .none, |
| 331 | /// Keeps track of the last time we performed a file system write to observe | 331 | /// Keeps track of the last time we performed a file system write to observe |
| 332 | /// what time the file system thinks it is, according to its own granularity. | 332 | /// what time the file system thinks it is, according to its own granularity. |
| 333 | recent_problematic_timestamp: i128 = 0, | 333 | recent_problematic_timestamp: Io.Timestamp = .zero, |
| 334 | 334 | ||
| 335 | pub const Diagnostic = union(enum) { | 335 | pub const Diagnostic = union(enum) { |
| 336 | none, | 336 | none, |
| ... | @@ -728,7 +728,7 @@ pub const Manifest = struct { | ... | @@ -728,7 +728,7 @@ pub const Manifest = struct { |
| 728 | file.stat = .{ | 728 | file.stat = .{ |
| 729 | .size = stat_size, | 729 | .size = stat_size, |
| 730 | .inode = stat_inode, | 730 | .inode = stat_inode, |
| 731 | .mtime = stat_mtime, | 731 | .mtime = .{ .nanoseconds = stat_mtime }, |
| 732 | }; | 732 | }; |
| 733 | file.bin_digest = file_bin_digest; | 733 | file.bin_digest = file_bin_digest; |
| 734 | break :f file; | 734 | break :f file; |
| ... | @@ -747,7 +747,7 @@ pub const Manifest = struct { | ... | @@ -747,7 +747,7 @@ pub const Manifest = struct { |
| 747 | .stat = .{ | 747 | .stat = .{ |
| 748 | .size = stat_size, | 748 | .size = stat_size, |
| 749 | .inode = stat_inode, | 749 | .inode = stat_inode, |
| 750 | .mtime = stat_mtime, | 750 | .mtime = .{ .nanoseconds = stat_mtime }, |
| 751 | }, | 751 | }, |
| 752 | .bin_digest = file_bin_digest, | 752 | .bin_digest = file_bin_digest, |
| 753 | }; | 753 | }; |
| ... | @@ -780,7 +780,7 @@ pub const Manifest = struct { | ... | @@ -780,7 +780,7 @@ pub const Manifest = struct { |
| 780 | return error.CacheCheckFailed; | 780 | return error.CacheCheckFailed; |
| 781 | }; | 781 | }; |
| 782 | const size_match = actual_stat.size == cache_hash_file.stat.size; | 782 | const size_match = actual_stat.size == cache_hash_file.stat.size; |
| 783 | const mtime_match = actual_stat.mtime == cache_hash_file.stat.mtime; | 783 | const mtime_match = actual_stat.mtime.nanoseconds == cache_hash_file.stat.mtime.nanoseconds; |
| 784 | const inode_match = actual_stat.inode == cache_hash_file.stat.inode; | 784 | const inode_match = actual_stat.inode == cache_hash_file.stat.inode; |
| 785 | 785 | ||
| 786 | if (!size_match or !mtime_match or !inode_match) { | 786 | if (!size_match or !mtime_match or !inode_match) { |
| ... | @@ -792,7 +792,7 @@ pub const Manifest = struct { | ... | @@ -792,7 +792,7 @@ pub const Manifest = struct { |
| 792 | 792 | ||
| 793 | if (self.isProblematicTimestamp(cache_hash_file.stat.mtime)) { | 793 | if (self.isProblematicTimestamp(cache_hash_file.stat.mtime)) { |
| 794 | // The actual file has an unreliable timestamp, force it to be hashed | 794 | // The actual file has an unreliable timestamp, force it to be hashed |
| 795 | cache_hash_file.stat.mtime = 0; | 795 | cache_hash_file.stat.mtime = .zero; |
| 796 | cache_hash_file.stat.inode = 0; | 796 | cache_hash_file.stat.inode = 0; |
| 797 | } | 797 | } |
| 798 | 798 | ||
| ... | @@ -848,10 +848,10 @@ pub const Manifest = struct { | ... | @@ -848,10 +848,10 @@ pub const Manifest = struct { |
| 848 | } | 848 | } |
| 849 | } | 849 | } |
| 850 | 850 | ||
| 851 | fn isProblematicTimestamp(man: *Manifest, file_time: i128) bool { | 851 | fn isProblematicTimestamp(man: *Manifest, timestamp: Io.Timestamp) bool { |
| 852 | // If the file_time is prior to the most recent problematic timestamp | 852 | // If the file_time is prior to the most recent problematic timestamp |
| 853 | // then we don't need to access the filesystem. | 853 | // then we don't need to access the filesystem. |
| 854 | if (file_time < man.recent_problematic_timestamp) | 854 | if (timestamp.nanoseconds < man.recent_problematic_timestamp.nanoseconds) |
| 855 | return false; | 855 | return false; |
| 856 | 856 | ||
| 857 | // Next we will check the globally shared Cache timestamp, which is accessed | 857 | // Next we will check the globally shared Cache timestamp, which is accessed |
| ... | @@ -861,7 +861,7 @@ pub const Manifest = struct { | ... | @@ -861,7 +861,7 @@ pub const Manifest = struct { |
| 861 | 861 | ||
| 862 | // Save the global one to our local one to avoid locking next time. | 862 | // Save the global one to our local one to avoid locking next time. |
| 863 | man.recent_problematic_timestamp = man.cache.recent_problematic_timestamp; | 863 | man.recent_problematic_timestamp = man.cache.recent_problematic_timestamp; |
| 864 | if (file_time < man.recent_problematic_timestamp) | 864 | if (timestamp.nanoseconds < man.recent_problematic_timestamp.nanoseconds) |
| 865 | return false; | 865 | return false; |
| 866 | 866 | ||
| 867 | // This flag prevents multiple filesystem writes for the same hit() call. | 867 | // This flag prevents multiple filesystem writes for the same hit() call. |
| ... | @@ -879,7 +879,7 @@ pub const Manifest = struct { | ... | @@ -879,7 +879,7 @@ pub const Manifest = struct { |
| 879 | man.cache.recent_problematic_timestamp = man.recent_problematic_timestamp; | 879 | man.cache.recent_problematic_timestamp = man.recent_problematic_timestamp; |
| 880 | } | 880 | } |
| 881 | 881 | ||
| 882 | return file_time >= man.recent_problematic_timestamp; | 882 | return timestamp.nanoseconds >= man.recent_problematic_timestamp.nanoseconds; |
| 883 | } | 883 | } |
| 884 | 884 | ||
| 885 | fn populateFileHash(self: *Manifest, ch_file: *File) !void { | 885 | fn populateFileHash(self: *Manifest, ch_file: *File) !void { |
| ... | @@ -904,7 +904,7 @@ pub const Manifest = struct { | ... | @@ -904,7 +904,7 @@ pub const Manifest = struct { |
| 904 | 904 | ||
| 905 | if (self.isProblematicTimestamp(ch_file.stat.mtime)) { | 905 | if (self.isProblematicTimestamp(ch_file.stat.mtime)) { |
| 906 | // The actual file has an unreliable timestamp, force it to be hashed | 906 | // The actual file has an unreliable timestamp, force it to be hashed |
| 907 | ch_file.stat.mtime = 0; | 907 | ch_file.stat.mtime = .zero; |
| 908 | ch_file.stat.inode = 0; | 908 | ch_file.stat.inode = 0; |
| 909 | } | 909 | } |
| 910 | 910 | ||
| ... | @@ -1040,7 +1040,7 @@ pub const Manifest = struct { | ... | @@ -1040,7 +1040,7 @@ pub const Manifest = struct { |
| 1040 | 1040 | ||
| 1041 | if (self.isProblematicTimestamp(new_file.stat.mtime)) { | 1041 | if (self.isProblematicTimestamp(new_file.stat.mtime)) { |
| 1042 | // The actual file has an unreliable timestamp, force it to be hashed | 1042 | // The actual file has an unreliable timestamp, force it to be hashed |
| 1043 | new_file.stat.mtime = 0; | 1043 | new_file.stat.mtime = .zero; |
| 1044 | new_file.stat.inode = 0; | 1044 | new_file.stat.inode = 0; |
| 1045 | } | 1045 | } |
| 1046 | 1046 |
lib/std/Build/WebServer.zig+9-8| ... | @@ -11,7 +11,7 @@ tcp_server: ?net.Server, | ... | @@ -11,7 +11,7 @@ tcp_server: ?net.Server, |
| 11 | serve_thread: ?std.Thread, | 11 | serve_thread: ?std.Thread, |
| 12 | 12 | ||
| 13 | /// Uses `Io.Clock.awake`. | 13 | /// Uses `Io.Clock.awake`. |
| 14 | base_timestamp: i96, | 14 | base_timestamp: Io.Timestamp, |
| 15 | /// The "step name" data which trails `abi.Hello`, for the steps in `all_steps`. | 15 | /// The "step name" data which trails `abi.Hello`, for the steps in `all_steps`. |
| 16 | step_names_trailing: []u8, | 16 | step_names_trailing: []u8, |
| 17 | 17 | ||
| ... | @@ -43,6 +43,8 @@ runner_request: ?RunnerRequest, | ... | @@ -43,6 +43,8 @@ runner_request: ?RunnerRequest, |
| 43 | /// on a fixed interval of this many milliseconds. | 43 | /// on a fixed interval of this many milliseconds. |
| 44 | const default_update_interval_ms = 500; | 44 | const default_update_interval_ms = 500; |
| 45 | 45 | ||
| 46 | pub const base_clock: Io.Clock = .awake; | ||
| 47 | |||
| 46 | /// Thread-safe. Triggers updates to be sent to connected WebSocket clients; see `update_id`. | 48 | /// Thread-safe. Triggers updates to be sent to connected WebSocket clients; see `update_id`. |
| 47 | pub fn notifyUpdate(ws: *WebServer) void { | 49 | pub fn notifyUpdate(ws: *WebServer) void { |
| 48 | _ = ws.update_id.rmw(.Add, 1, .release); | 50 | _ = ws.update_id.rmw(.Add, 1, .release); |
| ... | @@ -58,13 +60,13 @@ pub const Options = struct { | ... | @@ -58,13 +60,13 @@ pub const Options = struct { |
| 58 | root_prog_node: std.Progress.Node, | 60 | root_prog_node: std.Progress.Node, |
| 59 | watch: bool, | 61 | watch: bool, |
| 60 | listen_address: net.IpAddress, | 62 | listen_address: net.IpAddress, |
| 61 | base_timestamp: Io.Timestamp, | 63 | base_timestamp: Io.Clock.Timestamp, |
| 62 | }; | 64 | }; |
| 63 | pub fn init(opts: Options) WebServer { | 65 | pub fn init(opts: Options) WebServer { |
| 64 | // The upcoming `Io` interface should allow us to use `Io.async` and `Io.concurrent` | 66 | // The upcoming `Io` interface should allow us to use `Io.async` and `Io.concurrent` |
| 65 | // instead of threads, so that the web server can function in single-threaded builds. | 67 | // instead of threads, so that the web server can function in single-threaded builds. |
| 66 | comptime assert(!builtin.single_threaded); | 68 | comptime assert(!builtin.single_threaded); |
| 67 | assert(opts.base_timestamp.clock == .awake); | 69 | assert(opts.base_timestamp.clock == base_clock); |
| 68 | 70 | ||
| 69 | const all_steps = opts.all_steps; | 71 | const all_steps = opts.all_steps; |
| 70 | 72 | ||
| ... | @@ -109,7 +111,7 @@ pub fn init(opts: Options) WebServer { | ... | @@ -109,7 +111,7 @@ pub fn init(opts: Options) WebServer { |
| 109 | .tcp_server = null, | 111 | .tcp_server = null, |
| 110 | .serve_thread = null, | 112 | .serve_thread = null, |
| 111 | 113 | ||
| 112 | .base_timestamp = opts.base_timestamp.nanoseconds, | 114 | .base_timestamp = opts.base_timestamp.raw, |
| 113 | .step_names_trailing = step_names_trailing, | 115 | .step_names_trailing = step_names_trailing, |
| 114 | 116 | ||
| 115 | .step_status_bits = step_status_bits, | 117 | .step_status_bits = step_status_bits, |
| ... | @@ -248,9 +250,8 @@ pub fn finishBuild(ws: *WebServer, opts: struct { | ... | @@ -248,9 +250,8 @@ pub fn finishBuild(ws: *WebServer, opts: struct { |
| 248 | 250 | ||
| 249 | pub fn now(s: *const WebServer) i64 { | 251 | pub fn now(s: *const WebServer) i64 { |
| 250 | const io = s.graph.io; | 252 | const io = s.graph.io; |
| 251 | const base: Io.Timestamp = .{ .nanoseconds = s.base_timestamp, .clock = .awake }; | 253 | const ts = base_clock.now(io) catch s.base_timestamp; |
| 252 | const ts = Io.Timestamp.now(io, base.clock) catch base; | 254 | return @intCast(s.base_timestamp.durationTo(ts).toNanoseconds()); |
| 253 | return @intCast(base.durationTo(ts).toNanoseconds()); | ||
| 254 | } | 255 | } |
| 255 | 256 | ||
| 256 | fn accept(ws: *WebServer, stream: net.Stream) void { | 257 | fn accept(ws: *WebServer, stream: net.Stream) void { |
| ... | @@ -519,7 +520,7 @@ pub fn serveTarFile(ws: *WebServer, request: *http.Server.Request, paths: []cons | ... | @@ -519,7 +520,7 @@ pub fn serveTarFile(ws: *WebServer, request: *http.Server.Request, paths: []cons |
| 519 | if (cached_cwd_path == null) cached_cwd_path = try std.process.getCwdAlloc(gpa); | 520 | if (cached_cwd_path == null) cached_cwd_path = try std.process.getCwdAlloc(gpa); |
| 520 | break :cwd cached_cwd_path.?; | 521 | break :cwd cached_cwd_path.?; |
| 521 | }; | 522 | }; |
| 522 | try archiver.writeFile(path.sub_path, &file_reader, stat.mtime); | 523 | try archiver.writeFile(path.sub_path, &file_reader, @intCast(stat.mtime.toSeconds())); |
| 523 | } | 524 | } |
| 524 | 525 | ||
| 525 | // intentionally not calling `archiver.finishPedantically` | 526 | // intentionally not calling `archiver.finishPedantically` |
lib/std/Io.zig+155-104| ... | @@ -669,7 +669,7 @@ pub const VTable = struct { | ... | @@ -669,7 +669,7 @@ pub const VTable = struct { |
| 669 | fileSeekBy: *const fn (?*anyopaque, file: File, offset: i64) File.SeekError!void, | 669 | fileSeekBy: *const fn (?*anyopaque, file: File, offset: i64) File.SeekError!void, |
| 670 | fileSeekTo: *const fn (?*anyopaque, file: File, offset: u64) File.SeekError!void, | 670 | fileSeekTo: *const fn (?*anyopaque, file: File, offset: u64) File.SeekError!void, |
| 671 | 671 | ||
| 672 | now: *const fn (?*anyopaque, Timestamp.Clock) Timestamp.Error!i96, | 672 | now: *const fn (?*anyopaque, Clock) Clock.Error!Timestamp, |
| 673 | sleep: *const fn (?*anyopaque, Timeout) SleepError!void, | 673 | sleep: *const fn (?*anyopaque, Timeout) SleepError!void, |
| 674 | 674 | ||
| 675 | listen: *const fn (?*anyopaque, address: net.IpAddress, options: net.IpAddress.ListenOptions) net.IpAddress.ListenError!net.Server, | 675 | listen: *const fn (?*anyopaque, address: net.IpAddress, options: net.IpAddress.ListenOptions) net.IpAddress.ListenError!net.Server, |
| ... | @@ -705,118 +705,178 @@ pub const UnexpectedError = error{ | ... | @@ -705,118 +705,178 @@ pub const UnexpectedError = error{ |
| 705 | pub const Dir = @import("Io/Dir.zig"); | 705 | pub const Dir = @import("Io/Dir.zig"); |
| 706 | pub const File = @import("Io/File.zig"); | 706 | pub const File = @import("Io/File.zig"); |
| 707 | 707 | ||
| 708 | pub const Timestamp = struct { | 708 | pub const Clock = enum { |
| 709 | nanoseconds: i96, | 709 | /// A settable system-wide clock that measures real (i.e. wall-clock) |
| 710 | clock: Clock, | 710 | /// time. This clock is affected by discontinuous jumps in the system |
| 711 | 711 | /// time (e.g., if the system administrator manually changes the | |
| 712 | pub const Clock = enum { | 712 | /// clock), and by frequency adjust‐ ments performed by NTP and similar |
| 713 | /// A settable system-wide clock that measures real (i.e. wall-clock) | 713 | /// applications. |
| 714 | /// time. This clock is affected by discontinuous jumps in the system | 714 | /// |
| 715 | /// time (e.g., if the system administrator manually changes the | 715 | /// This clock normally counts the number of seconds since 1970-01-01 |
| 716 | /// clock), and by frequency adjust‐ ments performed by NTP and similar | 716 | /// 00:00:00 Coordinated Universal Time (UTC) except that it ignores |
| 717 | /// applications. | 717 | /// leap seconds; near a leap second it is typically adjusted by NTP to |
| 718 | /// | 718 | /// stay roughly in sync with UTC. |
| 719 | /// This clock normally counts the number of seconds since 1970-01-01 | 719 | /// |
| 720 | /// 00:00:00 Coordinated Universal Time (UTC) except that it ignores | 720 | /// The epoch is implementation-defined. For example NTFS/Windows uses |
| 721 | /// leap seconds; near a leap second it is typically adjusted by NTP to | 721 | /// 1601-01-01. |
| 722 | /// stay roughly in sync with UTC. | 722 | real, |
| 723 | /// | 723 | /// A nonsettable system-wide clock that represents time since some |
| 724 | /// The epoch is implementation-defined. For example NTFS/Windows uses | 724 | /// unspecified point in the past. |
| 725 | /// 1601-01-01. | 725 | /// |
| 726 | real, | 726 | /// Monotonic: Guarantees that the time returned by consecutive calls |
| 727 | /// A nonsettable system-wide clock that represents time since some | 727 | /// will not go backwards, but successive calls may return identical |
| 728 | /// unspecified point in the past. | 728 | /// (not-increased) time values. |
| 729 | /// | 729 | /// |
| 730 | /// Monotonic: Guarantees that the time returned by consecutive calls | 730 | /// Not affected by discontinuous jumps in the system time (e.g., if |
| 731 | /// will not go backwards, but successive calls may return identical | 731 | /// the system administrator manually changes the clock), but may be |
| 732 | /// (not-increased) time values. | 732 | /// affected by frequency adjustments. |
| 733 | /// | 733 | /// |
| 734 | /// Not affected by discontinuous jumps in the system time (e.g., if | 734 | /// This clock expresses intent to **exclude time that the system is |
| 735 | /// the system administrator manually changes the clock), but may be | 735 | /// suspended**. However, implementations may be unable to satisify |
| 736 | /// affected by frequency adjustments. | 736 | /// this, and may include that time. |
| 737 | /// | 737 | /// |
| 738 | /// This clock expresses intent to **exclude time that the system is | 738 | /// * On Linux, corresponds `CLOCK_MONOTONIC`. |
| 739 | /// suspended**. However, implementations may be unable to satisify | 739 | /// * On macOS, corresponds to `CLOCK_UPTIME_RAW`. |
| 740 | /// this, and may include that time. | 740 | awake, |
| 741 | /// | 741 | /// Identical to `awake` except it expresses intent to **include time |
| 742 | /// * On Linux, corresponds `CLOCK_MONOTONIC`. | 742 | /// that the system is suspended**, however, due to limitations it may |
| 743 | /// * On macOS, corresponds to `CLOCK_UPTIME_RAW`. | 743 | /// behave identically to `awake`. |
| 744 | awake, | 744 | /// |
| 745 | /// Identical to `awake` except it expresses intent to **include time | 745 | /// * On Linux, corresponds `CLOCK_BOOTTIME`. |
| 746 | /// that the system is suspended**, however, due to limitations it may | 746 | /// * On macOS, corresponds to `CLOCK_MONOTONIC_RAW`. |
| 747 | /// behave identically to `awake`. | 747 | boot, |
| 748 | /// | 748 | /// Tracks the amount of CPU in user or kernel mode used by the calling |
| 749 | /// * On Linux, corresponds `CLOCK_BOOTTIME`. | 749 | /// process. |
| 750 | /// * On macOS, corresponds to `CLOCK_MONOTONIC_RAW`. | 750 | cpu_process, |
| 751 | boot, | 751 | /// Tracks the amount of CPU in user or kernel mode used by the calling |
| 752 | /// Tracks the amount of CPU in user or kernel mode used by the calling | 752 | /// thread. |
| 753 | /// process. | 753 | cpu_thread, |
| 754 | cpu_process, | ||
| 755 | /// Tracks the amount of CPU in user or kernel mode used by the calling | ||
| 756 | /// thread. | ||
| 757 | cpu_thread, | ||
| 758 | }; | ||
| 759 | |||
| 760 | pub fn durationTo(from: Timestamp, to: Timestamp) Duration { | ||
| 761 | assert(from.clock == to.clock); | ||
| 762 | return .{ .nanoseconds = to.nanoseconds - from.nanoseconds }; | ||
| 763 | } | ||
| 764 | |||
| 765 | pub fn addDuration(from: Timestamp, duration: Duration) Timestamp { | ||
| 766 | return .{ | ||
| 767 | .nanoseconds = from.nanoseconds + duration.nanoseconds, | ||
| 768 | .clock = from.clock, | ||
| 769 | }; | ||
| 770 | } | ||
| 771 | 754 | ||
| 772 | pub const Error = error{UnsupportedClock} || UnexpectedError; | 755 | pub const Error = error{UnsupportedClock} || UnexpectedError; |
| 773 | 756 | ||
| 774 | /// This function is not cancelable because first of all it does not block, | 757 | /// This function is not cancelable because first of all it does not block, |
| 775 | /// but more importantly, the cancelation logic itself may want to check | 758 | /// but more importantly, the cancelation logic itself may want to check |
| 776 | /// the time. | 759 | /// the time. |
| 777 | pub fn now(io: Io, clock: Clock) Error!Timestamp { | 760 | pub fn now(clock: Clock, io: Io) Error!Io.Timestamp { |
| 778 | return .{ | 761 | return io.vtable.now(io.userdata, clock); |
| 779 | .nanoseconds = try io.vtable.now(io.userdata, clock), | ||
| 780 | .clock = clock, | ||
| 781 | }; | ||
| 782 | } | 762 | } |
| 783 | 763 | ||
| 784 | pub fn fromNow(io: Io, clock: Clock, duration: Duration) Error!Timestamp { | 764 | pub const Timestamp = struct { |
| 785 | const now_ts = try now(io, clock); | 765 | raw: Io.Timestamp, |
| 786 | return addDuration(now_ts, duration); | 766 | clock: Clock, |
| 787 | } | 767 | |
| 768 | /// This function is not cancelable because first of all it does not block, | ||
| 769 | /// but more importantly, the cancelation logic itself may want to check | ||
| 770 | /// the time. | ||
| 771 | pub fn now(io: Io, clock: Clock) Error!Clock.Timestamp { | ||
| 772 | return .{ | ||
| 773 | .raw = try io.vtable.now(io.userdata, clock), | ||
| 774 | .clock = clock, | ||
| 775 | }; | ||
| 776 | } | ||
| 788 | 777 | ||
| 789 | pub fn untilNow(timestamp: Timestamp, io: Io) Error!Duration { | 778 | pub fn wait(t: Clock.Timestamp, io: Io) SleepError!void { |
| 790 | const now_ts = try Timestamp.now(io, timestamp.clock); | 779 | return io.vtable.sleep(io.userdata, .{ .deadline = t }); |
| 791 | return timestamp.durationTo(now_ts); | 780 | } |
| 792 | } | 781 | |
| 782 | pub fn durationTo(from: Clock.Timestamp, to: Clock.Timestamp) Clock.Duration { | ||
| 783 | assert(from.clock == to.clock); | ||
| 784 | return .{ | ||
| 785 | .raw = from.raw.durationTo(to.raw), | ||
| 786 | .clock = from.clock, | ||
| 787 | }; | ||
| 788 | } | ||
| 793 | 789 | ||
| 794 | pub fn durationFromNow(timestamp: Timestamp, io: Io) Error!Duration { | 790 | pub fn addDuration(from: Clock.Timestamp, duration: Clock.Duration) Clock.Timestamp { |
| 795 | const now_ts = try now(io, timestamp.clock); | 791 | assert(from.clock == duration.clock); |
| 796 | return now_ts.durationTo(timestamp); | 792 | return .{ |
| 793 | .raw = from.raw.addDuration(duration.raw), | ||
| 794 | .clock = from.clock, | ||
| 795 | }; | ||
| 796 | } | ||
| 797 | |||
| 798 | pub fn fromNow(io: Io, duration: Clock.Duration) Error!Clock.Timestamp { | ||
| 799 | return .{ | ||
| 800 | .clock = duration.clock, | ||
| 801 | .raw = (try duration.clock.now(io)).addDuration(duration.raw), | ||
| 802 | }; | ||
| 803 | } | ||
| 804 | |||
| 805 | pub fn untilNow(timestamp: Clock.Timestamp, io: Io) Error!Clock.Duration { | ||
| 806 | const now_ts = try Clock.Timestamp.now(io, timestamp.clock); | ||
| 807 | return timestamp.durationTo(now_ts); | ||
| 808 | } | ||
| 809 | |||
| 810 | pub fn durationFromNow(timestamp: Clock.Timestamp, io: Io) Error!Clock.Duration { | ||
| 811 | const now_ts = try timestamp.clock.now(io); | ||
| 812 | return .{ | ||
| 813 | .clock = timestamp.clock, | ||
| 814 | .raw = now_ts.durationTo(timestamp.raw), | ||
| 815 | }; | ||
| 816 | } | ||
| 817 | |||
| 818 | pub fn toClock(t: Clock.Timestamp, io: Io, clock: Clock) Error!Clock.Timestamp { | ||
| 819 | if (t.clock == clock) return t; | ||
| 820 | const now_old = try t.clock.now(io); | ||
| 821 | const now_new = try clock.now(io); | ||
| 822 | const duration = now_old.durationTo(t); | ||
| 823 | return .{ | ||
| 824 | .clock = clock, | ||
| 825 | .raw = now_new.addDuration(duration), | ||
| 826 | }; | ||
| 827 | } | ||
| 828 | |||
| 829 | pub fn compare(lhs: Clock.Timestamp, op: std.math.CompareOperator, rhs: Clock.Timestamp) bool { | ||
| 830 | assert(lhs.clock == rhs.clock); | ||
| 831 | return std.math.compare(lhs.raw.nanoseconds, op, rhs.raw.nanoseconds); | ||
| 832 | } | ||
| 833 | }; | ||
| 834 | |||
| 835 | pub const Duration = struct { | ||
| 836 | raw: Io.Duration, | ||
| 837 | clock: Clock, | ||
| 838 | |||
| 839 | pub fn sleep(duration: Clock.Duration, io: Io) SleepError!void { | ||
| 840 | return io.vtable.sleep(io.userdata, .{ .duration = duration }); | ||
| 841 | } | ||
| 842 | }; | ||
| 843 | }; | ||
| 844 | |||
| 845 | pub const Timestamp = struct { | ||
| 846 | nanoseconds: i96, | ||
| 847 | |||
| 848 | pub const zero: Timestamp = .{ .nanoseconds = 0 }; | ||
| 849 | |||
| 850 | pub fn durationTo(from: Timestamp, to: Timestamp) Duration { | ||
| 851 | return .{ .nanoseconds = to.nanoseconds - from.nanoseconds }; | ||
| 797 | } | 852 | } |
| 798 | 853 | ||
| 799 | pub fn toClock(t: Timestamp, io: Io, clock: Clock) Error!Timestamp { | 854 | pub fn addDuration(from: Timestamp, duration: Duration) Timestamp { |
| 800 | if (t.clock == clock) return t; | 855 | return .{ .nanoseconds = from.nanoseconds + duration.nanoseconds }; |
| 801 | const now_old = try now(io, t.clock); | ||
| 802 | const now_new = try now(io, clock); | ||
| 803 | const duration = now_old.durationTo(t); | ||
| 804 | return now_new.addDuration(duration); | ||
| 805 | } | 856 | } |
| 806 | 857 | ||
| 807 | pub fn compare(lhs: Timestamp, op: std.math.CompareOperator, rhs: Timestamp) bool { | 858 | pub fn withClock(t: Timestamp, clock: Clock) Clock.Timestamp { |
| 808 | assert(lhs.clock == rhs.clock); | 859 | return .{ .nanoseconds = t.nanoseconds, .clock = clock }; |
| 809 | return std.math.compare(lhs.nanoseconds, op, rhs.nanoseconds); | ||
| 810 | } | 860 | } |
| 811 | 861 | ||
| 812 | pub fn toSeconds(t: Timestamp) i64 { | 862 | pub fn toSeconds(t: Timestamp) i64 { |
| 813 | return @intCast(@divTrunc(t.nanoseconds, std.time.ns_per_s)); | 863 | return @intCast(@divTrunc(t.nanoseconds, std.time.ns_per_s)); |
| 814 | } | 864 | } |
| 865 | |||
| 866 | pub fn formatNumber(t: Timestamp, w: *std.Io.Writer, n: std.fmt.Number) std.Io.Writer.Error!void { | ||
| 867 | return w.printInt(t.nanoseconds, n.mode.base() orelse 10, n.case, .{ | ||
| 868 | .precision = n.precision, | ||
| 869 | .width = n.width, | ||
| 870 | .alignment = n.alignment, | ||
| 871 | .fill = n.fill, | ||
| 872 | }); | ||
| 873 | } | ||
| 815 | }; | 874 | }; |
| 816 | 875 | ||
| 817 | pub const Duration = struct { | 876 | pub const Duration = struct { |
| 818 | nanoseconds: i96, | 877 | nanoseconds: i96, |
| 819 | 878 | ||
| 879 | pub const zero: Duration = .{ .nanoseconds = 0 }; | ||
| 820 | pub const max: Duration = .{ .nanoseconds = std.math.maxInt(i96) }; | 880 | pub const max: Duration = .{ .nanoseconds = std.math.maxInt(i96) }; |
| 821 | 881 | ||
| 822 | pub fn fromNanoseconds(x: i96) Duration { | 882 | pub fn fromNanoseconds(x: i96) Duration { |
| ... | @@ -842,38 +902,29 @@ pub const Duration = struct { | ... | @@ -842,38 +902,29 @@ pub const Duration = struct { |
| 842 | pub fn toNanoseconds(d: Duration) i96 { | 902 | pub fn toNanoseconds(d: Duration) i96 { |
| 843 | return d.nanoseconds; | 903 | return d.nanoseconds; |
| 844 | } | 904 | } |
| 845 | |||
| 846 | pub fn sleep(duration: Duration, io: Io) SleepError!void { | ||
| 847 | return io.vtable.sleep(io.userdata, .{ .duration = .{ .duration = duration, .clock = .awake } }); | ||
| 848 | } | ||
| 849 | }; | 905 | }; |
| 850 | 906 | ||
| 851 | /// Declares under what conditions an operation should return `error.Timeout`. | 907 | /// Declares under what conditions an operation should return `error.Timeout`. |
| 852 | pub const Timeout = union(enum) { | 908 | pub const Timeout = union(enum) { |
| 853 | none, | 909 | none, |
| 854 | duration: ClockAndDuration, | 910 | duration: Clock.Duration, |
| 855 | deadline: Timestamp, | 911 | deadline: Clock.Timestamp, |
| 856 | 912 | ||
| 857 | pub const Error = error{ Timeout, UnsupportedClock }; | 913 | pub const Error = error{ Timeout, UnsupportedClock }; |
| 858 | 914 | ||
| 859 | pub const ClockAndDuration = struct { | 915 | pub fn toDeadline(t: Timeout, io: Io) Clock.Error!?Clock.Timestamp { |
| 860 | clock: Timestamp.Clock, | ||
| 861 | duration: Duration, | ||
| 862 | }; | ||
| 863 | |||
| 864 | pub fn toDeadline(t: Timeout, io: Io) Timestamp.Error!?Timestamp { | ||
| 865 | return switch (t) { | 916 | return switch (t) { |
| 866 | .none => null, | 917 | .none => null, |
| 867 | .duration => |d| try .fromNow(io, d.clock, d.duration), | 918 | .duration => |d| try .fromNow(io, d), |
| 868 | .deadline => |d| d, | 919 | .deadline => |d| d, |
| 869 | }; | 920 | }; |
| 870 | } | 921 | } |
| 871 | 922 | ||
| 872 | pub fn toDurationFromNow(t: Timeout, io: Io) Timestamp.Error!?ClockAndDuration { | 923 | pub fn toDurationFromNow(t: Timeout, io: Io) Clock.Error!?Clock.Duration { |
| 873 | return switch (t) { | 924 | return switch (t) { |
| 874 | .none => null, | 925 | .none => null, |
| 875 | .duration => |d| d, | 926 | .duration => |d| d, |
| 876 | .deadline => |d| .{ .clock = d.clock, .duration = try d.durationFromNow(io) }, | 927 | .deadline => |d| try d.durationFromNow(io), |
| 877 | }; | 928 | }; |
| 878 | } | 929 | } |
| 879 | 930 |
lib/std/Io/Dir.zig+1-1| ... | @@ -85,7 +85,7 @@ pub fn updateFile( | ... | @@ -85,7 +85,7 @@ pub fn updateFile( |
| 85 | }; | 85 | }; |
| 86 | 86 | ||
| 87 | if (src_stat.size == dest_stat.size and | 87 | if (src_stat.size == dest_stat.size and |
| 88 | src_stat.mtime == dest_stat.mtime and | 88 | src_stat.mtime.nanoseconds == dest_stat.mtime.nanoseconds and |
| 89 | actual_mode == dest_stat.mode) | 89 | actual_mode == dest_stat.mode) |
| 90 | { | 90 | { |
| 91 | return .fresh; | 91 | return .fresh; |
lib/std/Io/File.zig+3-7| ... | @@ -45,16 +45,12 @@ pub const Stat = struct { | ... | @@ -45,16 +45,12 @@ pub const Stat = struct { |
| 45 | /// This is available on POSIX systems and is always 0 otherwise. | 45 | /// This is available on POSIX systems and is always 0 otherwise. |
| 46 | mode: Mode, | 46 | mode: Mode, |
| 47 | kind: Kind, | 47 | kind: Kind, |
| 48 | |||
| 49 | /// Last access time in nanoseconds, relative to UTC 1970-01-01. | 48 | /// Last access time in nanoseconds, relative to UTC 1970-01-01. |
| 50 | /// TODO change this to Io.Timestamp except don't waste storage on clock | 49 | atime: Io.Timestamp, |
| 51 | atime: i128, | ||
| 52 | /// Last modification time in nanoseconds, relative to UTC 1970-01-01. | 50 | /// Last modification time in nanoseconds, relative to UTC 1970-01-01. |
| 53 | /// TODO change this to Io.Timestamp except don't waste storage on clock | 51 | mtime: Io.Timestamp, |
| 54 | mtime: i128, | ||
| 55 | /// Last status/metadata change time in nanoseconds, relative to UTC 1970-01-01. | 52 | /// Last status/metadata change time in nanoseconds, relative to UTC 1970-01-01. |
| 56 | /// TODO change this to Io.Timestamp except don't waste storage on clock | 53 | ctime: Io.Timestamp, |
| 57 | ctime: i128, | ||
| 58 | }; | 54 | }; |
| 59 | 55 | ||
| 60 | pub fn stdout() File { | 56 | pub fn stdout() File { |
lib/std/Io/Threaded.zig+30-26| ... | @@ -1147,26 +1147,26 @@ fn pwrite(userdata: ?*anyopaque, file: Io.File, buffer: []const u8, offset: posi | ... | @@ -1147,26 +1147,26 @@ fn pwrite(userdata: ?*anyopaque, file: Io.File, buffer: []const u8, offset: posi |
| 1147 | }; | 1147 | }; |
| 1148 | } | 1148 | } |
| 1149 | 1149 | ||
| 1150 | fn nowPosix(userdata: ?*anyopaque, clock: Io.Timestamp.Clock) Io.Timestamp.Error!i96 { | 1150 | fn nowPosix(userdata: ?*anyopaque, clock: Io.Clock) Io.Clock.Error!Io.Timestamp { |
| 1151 | const pool: *Pool = @ptrCast(@alignCast(userdata)); | 1151 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 1152 | _ = pool; | 1152 | _ = pool; |
| 1153 | const clock_id: posix.clockid_t = clockToPosix(clock); | 1153 | const clock_id: posix.clockid_t = clockToPosix(clock); |
| 1154 | var tp: posix.timespec = undefined; | 1154 | var tp: posix.timespec = undefined; |
| 1155 | switch (posix.errno(posix.system.clock_gettime(clock_id, &tp))) { | 1155 | switch (posix.errno(posix.system.clock_gettime(clock_id, &tp))) { |
| 1156 | .SUCCESS => return @intCast(@as(i128, tp.sec) * std.time.ns_per_s + tp.nsec), | 1156 | .SUCCESS => return timestampFromPosix(&tp), |
| 1157 | .INVAL => return error.UnsupportedClock, | 1157 | .INVAL => return error.UnsupportedClock, |
| 1158 | else => |err| return posix.unexpectedErrno(err), | 1158 | else => |err| return posix.unexpectedErrno(err), |
| 1159 | } | 1159 | } |
| 1160 | } | 1160 | } |
| 1161 | 1161 | ||
| 1162 | fn nowWindows(userdata: ?*anyopaque, clock: Io.Timestamp.Clock) Io.Timestamp.Error!i96 { | 1162 | fn nowWindows(userdata: ?*anyopaque, clock: Io.Clock) Io.Clock.Error!Io.Timestamp { |
| 1163 | const pool: *Pool = @ptrCast(@alignCast(userdata)); | 1163 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 1164 | _ = pool; | 1164 | _ = pool; |
| 1165 | switch (clock) { | 1165 | switch (clock) { |
| 1166 | .realtime => { | 1166 | .realtime => { |
| 1167 | // RtlGetSystemTimePrecise() has a granularity of 100 nanoseconds | 1167 | // RtlGetSystemTimePrecise() has a granularity of 100 nanoseconds |
| 1168 | // and uses the NTFS/Windows epoch, which is 1601-01-01. | 1168 | // and uses the NTFS/Windows epoch, which is 1601-01-01. |
| 1169 | return @as(i96, windows.ntdll.RtlGetSystemTimePrecise()) * 100; | 1169 | return .{ .nanoseconds = @as(i96, windows.ntdll.RtlGetSystemTimePrecise()) * 100 }; |
| 1170 | }, | 1170 | }, |
| 1171 | .monotonic, .uptime => { | 1171 | .monotonic, .uptime => { |
| 1172 | // QPC on windows doesn't fail on >= XP/2000 and includes time suspended. | 1172 | // QPC on windows doesn't fail on >= XP/2000 and includes time suspended. |
| ... | @@ -1178,7 +1178,7 @@ fn nowWindows(userdata: ?*anyopaque, clock: Io.Timestamp.Clock) Io.Timestamp.Err | ... | @@ -1178,7 +1178,7 @@ fn nowWindows(userdata: ?*anyopaque, clock: Io.Timestamp.Clock) Io.Timestamp.Err |
| 1178 | } | 1178 | } |
| 1179 | } | 1179 | } |
| 1180 | 1180 | ||
| 1181 | fn nowWasi(userdata: ?*anyopaque, clock: Io.Timestamp.Clock) Io.Timestamp.Error!i96 { | 1181 | fn nowWasi(userdata: ?*anyopaque, clock: Io.Clock) Io.Clock.Error!Io.Timestamp { |
| 1182 | const pool: *Pool = @ptrCast(@alignCast(userdata)); | 1182 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 1183 | _ = pool; | 1183 | _ = pool; |
| 1184 | var ns: std.os.wasi.timestamp_t = undefined; | 1184 | var ns: std.os.wasi.timestamp_t = undefined; |
| ... | @@ -1196,13 +1196,10 @@ fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { | ... | @@ -1196,13 +1196,10 @@ fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { |
| 1196 | }); | 1196 | }); |
| 1197 | const deadline_nanoseconds: i96 = switch (timeout) { | 1197 | const deadline_nanoseconds: i96 = switch (timeout) { |
| 1198 | .none => std.math.maxInt(i96), | 1198 | .none => std.math.maxInt(i96), |
| 1199 | .duration => |d| d.duration.nanoseconds, | 1199 | .duration => |duration| duration.raw.nanoseconds, |
| 1200 | .deadline => |deadline| deadline.nanoseconds, | 1200 | .deadline => |deadline| deadline.raw.nanoseconds, |
| 1201 | }; | ||
| 1202 | var timespec: posix.timespec = .{ | ||
| 1203 | .sec = @intCast(@divFloor(deadline_nanoseconds, std.time.ns_per_s)), | ||
| 1204 | .nsec = @intCast(@mod(deadline_nanoseconds, std.time.ns_per_s)), | ||
| 1205 | }; | 1201 | }; |
| 1202 | var timespec: posix.timespec = timestampToPosix(deadline_nanoseconds); | ||
| 1206 | while (true) { | 1203 | while (true) { |
| 1207 | try pool.checkCancel(); | 1204 | try pool.checkCancel(); |
| 1208 | switch (std.os.linux.E.init(std.os.linux.clock_nanosleep(clock_id, .{ .ABSTIME = switch (timeout) { | 1205 | switch (std.os.linux.E.init(std.os.linux.clock_nanosleep(clock_id, .{ .ABSTIME = switch (timeout) { |
| ... | @@ -1267,11 +1264,7 @@ fn sleepPosix(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { | ... | @@ -1267,11 +1264,7 @@ fn sleepPosix(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { |
| 1267 | .sec = std.math.maxInt(sec_type), | 1264 | .sec = std.math.maxInt(sec_type), |
| 1268 | .nsec = std.math.maxInt(nsec_type), | 1265 | .nsec = std.math.maxInt(nsec_type), |
| 1269 | }; | 1266 | }; |
| 1270 | const ns = d.duration.nanoseconds; | 1267 | break :t timestampToPosix(d.duration.nanoseconds); |
| 1271 | break :t .{ | ||
| 1272 | .sec = @intCast(@divFloor(ns, std.time.ns_per_s)), | ||
| 1273 | .nsec = @intCast(@mod(ns, std.time.ns_per_s)), | ||
| 1274 | }; | ||
| 1275 | }; | 1268 | }; |
| 1276 | while (true) { | 1269 | while (true) { |
| 1277 | try pool.checkCancel(); | 1270 | try pool.checkCancel(); |
| ... | @@ -1879,8 +1872,8 @@ fn netReceive( | ... | @@ -1879,8 +1872,8 @@ fn netReceive( |
| 1879 | const max_poll_ms = std.math.maxInt(u31); | 1872 | const max_poll_ms = std.math.maxInt(u31); |
| 1880 | const timeout_ms: u31 = if (deadline) |d| t: { | 1873 | const timeout_ms: u31 = if (deadline) |d| t: { |
| 1881 | const duration = d.durationFromNow(pool.io()) catch |err| return .{ err, message_i }; | 1874 | const duration = d.durationFromNow(pool.io()) catch |err| return .{ err, message_i }; |
| 1882 | if (duration.nanoseconds <= 0) return .{ error.Timeout, message_i }; | 1875 | if (duration.raw.nanoseconds <= 0) return .{ error.Timeout, message_i }; |
| 1883 | break :t @intCast(@min(max_poll_ms, duration.toMilliseconds())); | 1876 | break :t @intCast(@min(max_poll_ms, duration.raw.toMilliseconds())); |
| 1884 | } else max_poll_ms; | 1877 | } else max_poll_ms; |
| 1885 | 1878 | ||
| 1886 | const poll_rc = posix.system.poll(&poll_fds, poll_fds.len, timeout_ms); | 1879 | const poll_rc = posix.system.poll(&poll_fds, poll_fds.len, timeout_ms); |
| ... | @@ -2160,7 +2153,7 @@ fn recoverableOsBugDetected() void { | ... | @@ -2160,7 +2153,7 @@ fn recoverableOsBugDetected() void { |
| 2160 | if (builtin.mode == .Debug) unreachable; | 2153 | if (builtin.mode == .Debug) unreachable; |
| 2161 | } | 2154 | } |
| 2162 | 2155 | ||
| 2163 | fn clockToPosix(clock: Io.Timestamp.Clock) posix.clockid_t { | 2156 | fn clockToPosix(clock: Io.Clock) posix.clockid_t { |
| 2164 | return switch (clock) { | 2157 | return switch (clock) { |
| 2165 | .real => posix.CLOCK.REALTIME, | 2158 | .real => posix.CLOCK.REALTIME, |
| 2166 | .awake => switch (builtin.os.tag) { | 2159 | .awake => switch (builtin.os.tag) { |
| ... | @@ -2176,7 +2169,7 @@ fn clockToPosix(clock: Io.Timestamp.Clock) posix.clockid_t { | ... | @@ -2176,7 +2169,7 @@ fn clockToPosix(clock: Io.Timestamp.Clock) posix.clockid_t { |
| 2176 | }; | 2169 | }; |
| 2177 | } | 2170 | } |
| 2178 | 2171 | ||
| 2179 | fn clockToWasi(clock: Io.Timestamp.Clock) std.os.wasi.clockid_t { | 2172 | fn clockToWasi(clock: Io.Clock) std.os.wasi.clockid_t { |
| 2180 | return switch (clock) { | 2173 | return switch (clock) { |
| 2181 | .realtime => .REALTIME, | 2174 | .realtime => .REALTIME, |
| 2182 | .awake => .MONOTONIC, | 2175 | .awake => .MONOTONIC, |
| ... | @@ -2204,9 +2197,9 @@ fn statFromLinux(stx: *const std.os.linux.Statx) Io.File.Stat { | ... | @@ -2204,9 +2197,9 @@ fn statFromLinux(stx: *const std.os.linux.Statx) Io.File.Stat { |
| 2204 | std.os.linux.S.IFSOCK => .unix_domain_socket, | 2197 | std.os.linux.S.IFSOCK => .unix_domain_socket, |
| 2205 | else => .unknown, | 2198 | else => .unknown, |
| 2206 | }, | 2199 | }, |
| 2207 | .atime = @as(i128, atime.sec) * std.time.ns_per_s + atime.nsec, | 2200 | .atime = .{ .nanoseconds = @intCast(@as(i128, atime.sec) * std.time.ns_per_s + atime.nsec) }, |
| 2208 | .mtime = @as(i128, mtime.sec) * std.time.ns_per_s + mtime.nsec, | 2201 | .mtime = .{ .nanoseconds = @intCast(@as(i128, mtime.sec) * std.time.ns_per_s + mtime.nsec) }, |
| 2209 | .ctime = @as(i128, ctime.sec) * std.time.ns_per_s + ctime.nsec, | 2202 | .ctime = .{ .nanoseconds = @intCast(@as(i128, ctime.sec) * std.time.ns_per_s + ctime.nsec) }, |
| 2210 | }; | 2203 | }; |
| 2211 | } | 2204 | } |
| 2212 | 2205 | ||
| ... | @@ -2238,9 +2231,9 @@ fn statFromPosix(st: *const std.posix.Stat) Io.File.Stat { | ... | @@ -2238,9 +2231,9 @@ fn statFromPosix(st: *const std.posix.Stat) Io.File.Stat { |
| 2238 | 2231 | ||
| 2239 | break :k .unknown; | 2232 | break :k .unknown; |
| 2240 | }, | 2233 | }, |
| 2241 | .atime = @as(i128, atime.sec) * std.time.ns_per_s + atime.nsec, | 2234 | .atime = timestampFromPosix(&atime), |
| 2242 | .mtime = @as(i128, mtime.sec) * std.time.ns_per_s + mtime.nsec, | 2235 | .mtime = timestampFromPosix(&mtime), |
| 2243 | .ctime = @as(i128, ctime.sec) * std.time.ns_per_s + ctime.nsec, | 2236 | .ctime = timestampFromPosix(&ctime), |
| 2244 | }; | 2237 | }; |
| 2245 | } | 2238 | } |
| 2246 | 2239 | ||
| ... | @@ -2263,3 +2256,14 @@ fn statFromWasi(st: *const std.os.wasi.filestat_t) Io.File.Stat { | ... | @@ -2263,3 +2256,14 @@ fn statFromWasi(st: *const std.os.wasi.filestat_t) Io.File.Stat { |
| 2263 | .ctime = st.ctim, | 2256 | .ctime = st.ctim, |
| 2264 | }; | 2257 | }; |
| 2265 | } | 2258 | } |
| 2259 | |||
| 2260 | fn timestampFromPosix(timespec: *const std.posix.timespec) Io.Timestamp { | ||
| 2261 | return .{ .nanoseconds = @intCast(@as(i128, timespec.sec) * std.time.ns_per_s + timespec.nsec) }; | ||
| 2262 | } | ||
| 2263 | |||
| 2264 | fn timestampToPosix(nanoseconds: i96) std.posix.timespec { | ||
| 2265 | return .{ | ||
| 2266 | .sec = @intCast(@divFloor(nanoseconds, std.time.ns_per_s)), | ||
| 2267 | .nsec = @intCast(@mod(nanoseconds, std.time.ns_per_s)), | ||
| 2268 | }; | ||
| 2269 | } |
lib/std/Io/net/HostName.zig+8-4| ... | @@ -79,7 +79,7 @@ pub const LookupError = error{ | ... | @@ -79,7 +79,7 @@ pub const LookupError = error{ |
| 79 | NameServerFailure, | 79 | NameServerFailure, |
| 80 | /// Failed to open or read "/etc/hosts" or "/etc/resolv.conf". | 80 | /// Failed to open or read "/etc/hosts" or "/etc/resolv.conf". |
| 81 | DetectingNetworkConfigurationFailed, | 81 | DetectingNetworkConfigurationFailed, |
| 82 | } || Io.Timestamp.Error || IpAddress.BindError || Io.Cancelable; | 82 | } || Io.Clock.Error || IpAddress.BindError || Io.Cancelable; |
| 83 | 83 | ||
| 84 | pub const LookupResult = struct { | 84 | pub const LookupResult = struct { |
| 85 | /// How many `LookupOptions.addresses_buffer` elements are populated. | 85 | /// How many `LookupOptions.addresses_buffer` elements are populated. |
| ... | @@ -294,13 +294,14 @@ fn lookupDns(io: Io, lookup_canon_name: []const u8, rc: *const ResolvConf, optio | ... | @@ -294,13 +294,14 @@ fn lookupDns(io: Io, lookup_canon_name: []const u8, rc: *const ResolvConf, optio |
| 294 | 294 | ||
| 295 | // boot clock is chosen because time the computer is suspended should count | 295 | // boot clock is chosen because time the computer is suspended should count |
| 296 | // against time spent waiting for external messages to arrive. | 296 | // against time spent waiting for external messages to arrive. |
| 297 | var now_ts = try Io.Timestamp.now(io, .boot); | 297 | const clock: Io.Clock = .boot; |
| 298 | var now_ts = try clock.now(io); | ||
| 298 | const final_ts = now_ts.addDuration(.fromSeconds(rc.timeout_seconds)); | 299 | const final_ts = now_ts.addDuration(.fromSeconds(rc.timeout_seconds)); |
| 299 | const attempt_duration: Io.Duration = .{ | 300 | const attempt_duration: Io.Duration = .{ |
| 300 | .nanoseconds = std.time.ns_per_s * @as(usize, rc.timeout_seconds) / rc.attempts, | 301 | .nanoseconds = std.time.ns_per_s * @as(usize, rc.timeout_seconds) / rc.attempts, |
| 301 | }; | 302 | }; |
| 302 | 303 | ||
| 303 | send: while (now_ts.compare(.lt, final_ts)) : (now_ts = try Io.Timestamp.now(io, .boot)) { | 304 | send: while (now_ts.nanoseconds < final_ts.nanoseconds) : (now_ts = try clock.now(io)) { |
| 304 | const max_messages = queries_buffer.len * ResolvConf.max_nameservers; | 305 | const max_messages = queries_buffer.len * ResolvConf.max_nameservers; |
| 305 | { | 306 | { |
| 306 | var message_buffer: [max_messages]Io.net.OutgoingMessage = undefined; | 307 | var message_buffer: [max_messages]Io.net.OutgoingMessage = undefined; |
| ... | @@ -319,7 +320,10 @@ fn lookupDns(io: Io, lookup_canon_name: []const u8, rc: *const ResolvConf, optio | ... | @@ -319,7 +320,10 @@ fn lookupDns(io: Io, lookup_canon_name: []const u8, rc: *const ResolvConf, optio |
| 319 | _ = io.vtable.netSend(io.userdata, socket.handle, message_buffer[0..message_i], .{}); | 320 | _ = io.vtable.netSend(io.userdata, socket.handle, message_buffer[0..message_i], .{}); |
| 320 | } | 321 | } |
| 321 | 322 | ||
| 322 | const timeout: Io.Timeout = .{ .deadline = now_ts.addDuration(attempt_duration) }; | 323 | const timeout: Io.Timeout = .{ .deadline = .{ |
| 324 | .raw = now_ts.addDuration(attempt_duration), | ||
| 325 | .clock = clock, | ||
| 326 | } }; | ||
| 323 | 327 | ||
| 324 | while (true) { | 328 | while (true) { |
| 325 | var message_buffer: [max_messages]Io.net.IncomingMessage = undefined; | 329 | var message_buffer: [max_messages]Io.net.IncomingMessage = undefined; |
lib/std/fs/File.zig+8-8| ... | @@ -637,23 +637,23 @@ pub const UpdateTimesError = posix.FutimensError || windows.SetFileTimeError; | ... | @@ -637,23 +637,23 @@ pub const UpdateTimesError = posix.FutimensError || windows.SetFileTimeError; |
| 637 | pub fn updateTimes( | 637 | pub fn updateTimes( |
| 638 | self: File, | 638 | self: File, |
| 639 | /// access timestamp in nanoseconds | 639 | /// access timestamp in nanoseconds |
| 640 | atime: i128, | 640 | atime: Io.Timestamp, |
| 641 | /// last modification timestamp in nanoseconds | 641 | /// last modification timestamp in nanoseconds |
| 642 | mtime: i128, | 642 | mtime: Io.Timestamp, |
| 643 | ) UpdateTimesError!void { | 643 | ) UpdateTimesError!void { |
| 644 | if (builtin.os.tag == .windows) { | 644 | if (builtin.os.tag == .windows) { |
| 645 | const atime_ft = windows.nanoSecondsToFileTime(atime); | 645 | const atime_ft = windows.nanoSecondsToFileTime(atime.nanoseconds); |
| 646 | const mtime_ft = windows.nanoSecondsToFileTime(mtime); | 646 | const mtime_ft = windows.nanoSecondsToFileTime(mtime.nanoseconds); |
| 647 | return windows.SetFileTime(self.handle, null, &atime_ft, &mtime_ft); | 647 | return windows.SetFileTime(self.handle, null, &atime_ft, &mtime_ft); |
| 648 | } | 648 | } |
| 649 | const times = [2]posix.timespec{ | 649 | const times = [2]posix.timespec{ |
| 650 | posix.timespec{ | 650 | posix.timespec{ |
| 651 | .sec = math.cast(isize, @divFloor(atime, std.time.ns_per_s)) orelse maxInt(isize), | 651 | .sec = math.cast(isize, @divFloor(atime.nanoseconds, std.time.ns_per_s)) orelse maxInt(isize), |
| 652 | .nsec = math.cast(isize, @mod(atime, std.time.ns_per_s)) orelse maxInt(isize), | 652 | .nsec = math.cast(isize, @mod(atime.nanoseconds, std.time.ns_per_s)) orelse maxInt(isize), |
| 653 | }, | 653 | }, |
| 654 | posix.timespec{ | 654 | posix.timespec{ |
| 655 | .sec = math.cast(isize, @divFloor(mtime, std.time.ns_per_s)) orelse maxInt(isize), | 655 | .sec = math.cast(isize, @divFloor(mtime.nanoseconds, std.time.ns_per_s)) orelse maxInt(isize), |
| 656 | .nsec = math.cast(isize, @mod(mtime, std.time.ns_per_s)) orelse maxInt(isize), | 656 | .nsec = math.cast(isize, @mod(mtime.nanoseconds, std.time.ns_per_s)) orelse maxInt(isize), |
| 657 | }, | 657 | }, |
| 658 | }; | 658 | }; |
| 659 | try posix.futimens(self.handle, &times); | 659 | try posix.futimens(self.handle, &times); |
lib/std/http/Client.zig+1-1| ... | @@ -320,7 +320,7 @@ pub const Connection = struct { | ... | @@ -320,7 +320,7 @@ pub const Connection = struct { |
| 320 | const tls: *Tls = @ptrCast(base); | 320 | const tls: *Tls = @ptrCast(base); |
| 321 | var random_buffer: [176]u8 = undefined; | 321 | var random_buffer: [176]u8 = undefined; |
| 322 | std.crypto.random.bytes(&random_buffer); | 322 | std.crypto.random.bytes(&random_buffer); |
| 323 | const now_ts = if (Io.Timestamp.now(io, .real)) |ts| ts.toSeconds() else |_| return error.TlsInitializationFailed; | 323 | const now_ts = if (Io.Clock.real.now(io)) |ts| ts.toSeconds() else |_| return error.TlsInitializationFailed; |
| 324 | tls.* = .{ | 324 | tls.* = .{ |
| 325 | .connection = .{ | 325 | .connection = .{ |
| 326 | .client = client, | 326 | .client = client, |
lib/std/tar/Writer.zig+4-4| ... | @@ -18,7 +18,6 @@ pub const Options = struct { | ... | @@ -18,7 +18,6 @@ pub const Options = struct { |
| 18 | 18 | ||
| 19 | underlying_writer: *Io.Writer, | 19 | underlying_writer: *Io.Writer, |
| 20 | prefix: []const u8 = "", | 20 | prefix: []const u8 = "", |
| 21 | mtime_now: u64 = 0, | ||
| 22 | 21 | ||
| 23 | const Error = error{ | 22 | const Error = error{ |
| 24 | WriteFailed, | 23 | WriteFailed, |
| ... | @@ -44,10 +43,12 @@ pub fn writeFile( | ... | @@ -44,10 +43,12 @@ pub fn writeFile( |
| 44 | w: *Writer, | 43 | w: *Writer, |
| 45 | sub_path: []const u8, | 44 | sub_path: []const u8, |
| 46 | file_reader: *Io.File.Reader, | 45 | file_reader: *Io.File.Reader, |
| 47 | stat_mtime: i128, | 46 | /// If you want to match the file format's expectations, it wants number of |
| 47 | /// seconds since POSIX epoch. Zero is also a great option here to make | ||
| 48 | /// generated tarballs more reproducible. | ||
| 49 | mtime: u64, | ||
| 48 | ) WriteFileError!void { | 50 | ) WriteFileError!void { |
| 49 | const size = try file_reader.getSize(); | 51 | const size = try file_reader.getSize(); |
| 50 | const mtime: u64 = @intCast(@divFloor(stat_mtime, std.time.ns_per_s)); | ||
| 51 | 52 | ||
| 52 | var header: Header = .{}; | 53 | var header: Header = .{}; |
| 53 | try w.setPath(&header, sub_path); | 54 | try w.setPath(&header, sub_path); |
| ... | @@ -238,7 +239,6 @@ pub const Header = extern struct { | ... | @@ -238,7 +239,6 @@ pub const Header = extern struct { |
| 238 | } | 239 | } |
| 239 | 240 | ||
| 240 | // Integer number of seconds since January 1, 1970, 00:00 Coordinated Universal Time. | 241 | // Integer number of seconds since January 1, 1970, 00:00 Coordinated Universal Time. |
| 241 | // mtime == 0 will use current time | ||
| 242 | pub fn setMtime(w: *Header, mtime: u64) error{OctalOverflow}!void { | 242 | pub fn setMtime(w: *Header, mtime: u64) error{OctalOverflow}!void { |
| 243 | try octal(&w.mtime, mtime); | 243 | try octal(&w.mtime, mtime); |
| 244 | } | 244 | } |