mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
std.Io: bring back Timestamp but also keep Clock.Timestamp
this feels better
This commit is contained in:
parent
89412fda77
commit
ebcc6f166c
@ -556,7 +556,7 @@ pub fn main() !void {
|
|||||||
try run.thread_pool.init(thread_pool_options);
|
try run.thread_pool.init(thread_pool_options);
|
||||||
defer run.thread_pool.deinit();
|
defer run.thread_pool.deinit();
|
||||||
|
|
||||||
const now = Io.Timestamp.now(io, .awake) catch |err| fatal("failed to collect timestamp: {t}", .{err});
|
const now = Io.Clock.Timestamp.now(io, .awake) catch |err| fatal("failed to collect timestamp: {t}", .{err});
|
||||||
|
|
||||||
run.web_server = if (webui_listen) |listen_address| ws: {
|
run.web_server = if (webui_listen) |listen_address| ws: {
|
||||||
if (builtin.single_threaded) unreachable; // `fatal` above
|
if (builtin.single_threaded) unreachable; // `fatal` above
|
||||||
|
|||||||
@ -21,7 +21,7 @@ io: Io,
|
|||||||
manifest_dir: fs.Dir,
|
manifest_dir: fs.Dir,
|
||||||
hash: HashHelper = .{},
|
hash: HashHelper = .{},
|
||||||
/// This value is accessed from multiple threads, protected by mutex.
|
/// This value is accessed from multiple threads, protected by mutex.
|
||||||
recent_problematic_timestamp: i128 = 0,
|
recent_problematic_timestamp: Io.Timestamp = .zero,
|
||||||
mutex: std.Thread.Mutex = .{},
|
mutex: std.Thread.Mutex = .{},
|
||||||
|
|
||||||
/// A set of strings such as the zig library directory or project source root, which
|
/// A set of strings such as the zig library directory or project source root, which
|
||||||
@ -155,7 +155,7 @@ pub const File = struct {
|
|||||||
pub const Stat = struct {
|
pub const Stat = struct {
|
||||||
inode: fs.File.INode,
|
inode: fs.File.INode,
|
||||||
size: u64,
|
size: u64,
|
||||||
mtime: i128,
|
mtime: Io.Timestamp,
|
||||||
|
|
||||||
pub fn fromFs(fs_stat: fs.File.Stat) Stat {
|
pub fn fromFs(fs_stat: fs.File.Stat) Stat {
|
||||||
return .{
|
return .{
|
||||||
@ -330,7 +330,7 @@ pub const Manifest = struct {
|
|||||||
diagnostic: Diagnostic = .none,
|
diagnostic: Diagnostic = .none,
|
||||||
/// Keeps track of the last time we performed a file system write to observe
|
/// Keeps track of the last time we performed a file system write to observe
|
||||||
/// what time the file system thinks it is, according to its own granularity.
|
/// what time the file system thinks it is, according to its own granularity.
|
||||||
recent_problematic_timestamp: i128 = 0,
|
recent_problematic_timestamp: Io.Timestamp = .zero,
|
||||||
|
|
||||||
pub const Diagnostic = union(enum) {
|
pub const Diagnostic = union(enum) {
|
||||||
none,
|
none,
|
||||||
@ -728,7 +728,7 @@ pub const Manifest = struct {
|
|||||||
file.stat = .{
|
file.stat = .{
|
||||||
.size = stat_size,
|
.size = stat_size,
|
||||||
.inode = stat_inode,
|
.inode = stat_inode,
|
||||||
.mtime = stat_mtime,
|
.mtime = .{ .nanoseconds = stat_mtime },
|
||||||
};
|
};
|
||||||
file.bin_digest = file_bin_digest;
|
file.bin_digest = file_bin_digest;
|
||||||
break :f file;
|
break :f file;
|
||||||
@ -747,7 +747,7 @@ pub const Manifest = struct {
|
|||||||
.stat = .{
|
.stat = .{
|
||||||
.size = stat_size,
|
.size = stat_size,
|
||||||
.inode = stat_inode,
|
.inode = stat_inode,
|
||||||
.mtime = stat_mtime,
|
.mtime = .{ .nanoseconds = stat_mtime },
|
||||||
},
|
},
|
||||||
.bin_digest = file_bin_digest,
|
.bin_digest = file_bin_digest,
|
||||||
};
|
};
|
||||||
@ -780,7 +780,7 @@ pub const Manifest = struct {
|
|||||||
return error.CacheCheckFailed;
|
return error.CacheCheckFailed;
|
||||||
};
|
};
|
||||||
const size_match = actual_stat.size == cache_hash_file.stat.size;
|
const size_match = actual_stat.size == cache_hash_file.stat.size;
|
||||||
const mtime_match = actual_stat.mtime == cache_hash_file.stat.mtime;
|
const mtime_match = actual_stat.mtime.nanoseconds == cache_hash_file.stat.mtime.nanoseconds;
|
||||||
const inode_match = actual_stat.inode == cache_hash_file.stat.inode;
|
const inode_match = actual_stat.inode == cache_hash_file.stat.inode;
|
||||||
|
|
||||||
if (!size_match or !mtime_match or !inode_match) {
|
if (!size_match or !mtime_match or !inode_match) {
|
||||||
@ -792,7 +792,7 @@ pub const Manifest = struct {
|
|||||||
|
|
||||||
if (self.isProblematicTimestamp(cache_hash_file.stat.mtime)) {
|
if (self.isProblematicTimestamp(cache_hash_file.stat.mtime)) {
|
||||||
// The actual file has an unreliable timestamp, force it to be hashed
|
// The actual file has an unreliable timestamp, force it to be hashed
|
||||||
cache_hash_file.stat.mtime = 0;
|
cache_hash_file.stat.mtime = .zero;
|
||||||
cache_hash_file.stat.inode = 0;
|
cache_hash_file.stat.inode = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -848,10 +848,10 @@ pub const Manifest = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn isProblematicTimestamp(man: *Manifest, file_time: i128) bool {
|
fn isProblematicTimestamp(man: *Manifest, timestamp: Io.Timestamp) bool {
|
||||||
// If the file_time is prior to the most recent problematic timestamp
|
// If the file_time is prior to the most recent problematic timestamp
|
||||||
// then we don't need to access the filesystem.
|
// then we don't need to access the filesystem.
|
||||||
if (file_time < man.recent_problematic_timestamp)
|
if (timestamp.nanoseconds < man.recent_problematic_timestamp.nanoseconds)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Next we will check the globally shared Cache timestamp, which is accessed
|
// Next we will check the globally shared Cache timestamp, which is accessed
|
||||||
@ -861,7 +861,7 @@ pub const Manifest = struct {
|
|||||||
|
|
||||||
// Save the global one to our local one to avoid locking next time.
|
// Save the global one to our local one to avoid locking next time.
|
||||||
man.recent_problematic_timestamp = man.cache.recent_problematic_timestamp;
|
man.recent_problematic_timestamp = man.cache.recent_problematic_timestamp;
|
||||||
if (file_time < man.recent_problematic_timestamp)
|
if (timestamp.nanoseconds < man.recent_problematic_timestamp.nanoseconds)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// This flag prevents multiple filesystem writes for the same hit() call.
|
// This flag prevents multiple filesystem writes for the same hit() call.
|
||||||
@ -879,7 +879,7 @@ pub const Manifest = struct {
|
|||||||
man.cache.recent_problematic_timestamp = man.recent_problematic_timestamp;
|
man.cache.recent_problematic_timestamp = man.recent_problematic_timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
return file_time >= man.recent_problematic_timestamp;
|
return timestamp.nanoseconds >= man.recent_problematic_timestamp.nanoseconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn populateFileHash(self: *Manifest, ch_file: *File) !void {
|
fn populateFileHash(self: *Manifest, ch_file: *File) !void {
|
||||||
@ -904,7 +904,7 @@ pub const Manifest = struct {
|
|||||||
|
|
||||||
if (self.isProblematicTimestamp(ch_file.stat.mtime)) {
|
if (self.isProblematicTimestamp(ch_file.stat.mtime)) {
|
||||||
// The actual file has an unreliable timestamp, force it to be hashed
|
// The actual file has an unreliable timestamp, force it to be hashed
|
||||||
ch_file.stat.mtime = 0;
|
ch_file.stat.mtime = .zero;
|
||||||
ch_file.stat.inode = 0;
|
ch_file.stat.inode = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1040,7 +1040,7 @@ pub const Manifest = struct {
|
|||||||
|
|
||||||
if (self.isProblematicTimestamp(new_file.stat.mtime)) {
|
if (self.isProblematicTimestamp(new_file.stat.mtime)) {
|
||||||
// The actual file has an unreliable timestamp, force it to be hashed
|
// The actual file has an unreliable timestamp, force it to be hashed
|
||||||
new_file.stat.mtime = 0;
|
new_file.stat.mtime = .zero;
|
||||||
new_file.stat.inode = 0;
|
new_file.stat.inode = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -11,7 +11,7 @@ tcp_server: ?net.Server,
|
|||||||
serve_thread: ?std.Thread,
|
serve_thread: ?std.Thread,
|
||||||
|
|
||||||
/// Uses `Io.Clock.awake`.
|
/// Uses `Io.Clock.awake`.
|
||||||
base_timestamp: i96,
|
base_timestamp: Io.Timestamp,
|
||||||
/// The "step name" data which trails `abi.Hello`, for the steps in `all_steps`.
|
/// The "step name" data which trails `abi.Hello`, for the steps in `all_steps`.
|
||||||
step_names_trailing: []u8,
|
step_names_trailing: []u8,
|
||||||
|
|
||||||
@ -43,6 +43,8 @@ runner_request: ?RunnerRequest,
|
|||||||
/// on a fixed interval of this many milliseconds.
|
/// on a fixed interval of this many milliseconds.
|
||||||
const default_update_interval_ms = 500;
|
const default_update_interval_ms = 500;
|
||||||
|
|
||||||
|
pub const base_clock: Io.Clock = .awake;
|
||||||
|
|
||||||
/// Thread-safe. Triggers updates to be sent to connected WebSocket clients; see `update_id`.
|
/// Thread-safe. Triggers updates to be sent to connected WebSocket clients; see `update_id`.
|
||||||
pub fn notifyUpdate(ws: *WebServer) void {
|
pub fn notifyUpdate(ws: *WebServer) void {
|
||||||
_ = ws.update_id.rmw(.Add, 1, .release);
|
_ = ws.update_id.rmw(.Add, 1, .release);
|
||||||
@ -58,13 +60,13 @@ pub const Options = struct {
|
|||||||
root_prog_node: std.Progress.Node,
|
root_prog_node: std.Progress.Node,
|
||||||
watch: bool,
|
watch: bool,
|
||||||
listen_address: net.IpAddress,
|
listen_address: net.IpAddress,
|
||||||
base_timestamp: Io.Timestamp,
|
base_timestamp: Io.Clock.Timestamp,
|
||||||
};
|
};
|
||||||
pub fn init(opts: Options) WebServer {
|
pub fn init(opts: Options) WebServer {
|
||||||
// The upcoming `Io` interface should allow us to use `Io.async` and `Io.concurrent`
|
// The upcoming `Io` interface should allow us to use `Io.async` and `Io.concurrent`
|
||||||
// instead of threads, so that the web server can function in single-threaded builds.
|
// instead of threads, so that the web server can function in single-threaded builds.
|
||||||
comptime assert(!builtin.single_threaded);
|
comptime assert(!builtin.single_threaded);
|
||||||
assert(opts.base_timestamp.clock == .awake);
|
assert(opts.base_timestamp.clock == base_clock);
|
||||||
|
|
||||||
const all_steps = opts.all_steps;
|
const all_steps = opts.all_steps;
|
||||||
|
|
||||||
@ -109,7 +111,7 @@ pub fn init(opts: Options) WebServer {
|
|||||||
.tcp_server = null,
|
.tcp_server = null,
|
||||||
.serve_thread = null,
|
.serve_thread = null,
|
||||||
|
|
||||||
.base_timestamp = opts.base_timestamp.nanoseconds,
|
.base_timestamp = opts.base_timestamp.raw,
|
||||||
.step_names_trailing = step_names_trailing,
|
.step_names_trailing = step_names_trailing,
|
||||||
|
|
||||||
.step_status_bits = step_status_bits,
|
.step_status_bits = step_status_bits,
|
||||||
@ -248,9 +250,8 @@ pub fn finishBuild(ws: *WebServer, opts: struct {
|
|||||||
|
|
||||||
pub fn now(s: *const WebServer) i64 {
|
pub fn now(s: *const WebServer) i64 {
|
||||||
const io = s.graph.io;
|
const io = s.graph.io;
|
||||||
const base: Io.Timestamp = .{ .nanoseconds = s.base_timestamp, .clock = .awake };
|
const ts = base_clock.now(io) catch s.base_timestamp;
|
||||||
const ts = Io.Timestamp.now(io, base.clock) catch base;
|
return @intCast(s.base_timestamp.durationTo(ts).toNanoseconds());
|
||||||
return @intCast(base.durationTo(ts).toNanoseconds());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accept(ws: *WebServer, stream: net.Stream) void {
|
fn accept(ws: *WebServer, stream: net.Stream) void {
|
||||||
@ -519,7 +520,7 @@ pub fn serveTarFile(ws: *WebServer, request: *http.Server.Request, paths: []cons
|
|||||||
if (cached_cwd_path == null) cached_cwd_path = try std.process.getCwdAlloc(gpa);
|
if (cached_cwd_path == null) cached_cwd_path = try std.process.getCwdAlloc(gpa);
|
||||||
break :cwd cached_cwd_path.?;
|
break :cwd cached_cwd_path.?;
|
||||||
};
|
};
|
||||||
try archiver.writeFile(path.sub_path, &file_reader, stat.mtime);
|
try archiver.writeFile(path.sub_path, &file_reader, @intCast(stat.mtime.toSeconds()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// intentionally not calling `archiver.finishPedantically`
|
// intentionally not calling `archiver.finishPedantically`
|
||||||
|
|||||||
149
lib/std/Io.zig
149
lib/std/Io.zig
@ -669,7 +669,7 @@ pub const VTable = struct {
|
|||||||
fileSeekBy: *const fn (?*anyopaque, file: File, offset: i64) File.SeekError!void,
|
fileSeekBy: *const fn (?*anyopaque, file: File, offset: i64) File.SeekError!void,
|
||||||
fileSeekTo: *const fn (?*anyopaque, file: File, offset: u64) File.SeekError!void,
|
fileSeekTo: *const fn (?*anyopaque, file: File, offset: u64) File.SeekError!void,
|
||||||
|
|
||||||
now: *const fn (?*anyopaque, Timestamp.Clock) Timestamp.Error!i96,
|
now: *const fn (?*anyopaque, Clock) Clock.Error!Timestamp,
|
||||||
sleep: *const fn (?*anyopaque, Timeout) SleepError!void,
|
sleep: *const fn (?*anyopaque, Timeout) SleepError!void,
|
||||||
|
|
||||||
listen: *const fn (?*anyopaque, address: net.IpAddress, options: net.IpAddress.ListenOptions) net.IpAddress.ListenError!net.Server,
|
listen: *const fn (?*anyopaque, address: net.IpAddress, options: net.IpAddress.ListenOptions) net.IpAddress.ListenError!net.Server,
|
||||||
@ -705,10 +705,6 @@ pub const UnexpectedError = error{
|
|||||||
pub const Dir = @import("Io/Dir.zig");
|
pub const Dir = @import("Io/Dir.zig");
|
||||||
pub const File = @import("Io/File.zig");
|
pub const File = @import("Io/File.zig");
|
||||||
|
|
||||||
pub const Timestamp = struct {
|
|
||||||
nanoseconds: i96,
|
|
||||||
clock: Clock,
|
|
||||||
|
|
||||||
pub const Clock = enum {
|
pub const Clock = enum {
|
||||||
/// A settable system-wide clock that measures real (i.e. wall-clock)
|
/// A settable system-wide clock that measures real (i.e. wall-clock)
|
||||||
/// time. This clock is affected by discontinuous jumps in the system
|
/// time. This clock is affected by discontinuous jumps in the system
|
||||||
@ -755,68 +751,132 @@ pub const Timestamp = struct {
|
|||||||
/// Tracks the amount of CPU in user or kernel mode used by the calling
|
/// Tracks the amount of CPU in user or kernel mode used by the calling
|
||||||
/// thread.
|
/// thread.
|
||||||
cpu_thread,
|
cpu_thread,
|
||||||
};
|
|
||||||
|
|
||||||
pub fn durationTo(from: Timestamp, to: Timestamp) Duration {
|
|
||||||
assert(from.clock == to.clock);
|
|
||||||
return .{ .nanoseconds = to.nanoseconds - from.nanoseconds };
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn addDuration(from: Timestamp, duration: Duration) Timestamp {
|
|
||||||
return .{
|
|
||||||
.nanoseconds = from.nanoseconds + duration.nanoseconds,
|
|
||||||
.clock = from.clock,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const Error = error{UnsupportedClock} || UnexpectedError;
|
pub const Error = error{UnsupportedClock} || UnexpectedError;
|
||||||
|
|
||||||
/// This function is not cancelable because first of all it does not block,
|
/// This function is not cancelable because first of all it does not block,
|
||||||
/// but more importantly, the cancelation logic itself may want to check
|
/// but more importantly, the cancelation logic itself may want to check
|
||||||
/// the time.
|
/// the time.
|
||||||
pub fn now(io: Io, clock: Clock) Error!Timestamp {
|
pub fn now(clock: Clock, io: Io) Error!Io.Timestamp {
|
||||||
|
return io.vtable.now(io.userdata, clock);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const Timestamp = struct {
|
||||||
|
raw: Io.Timestamp,
|
||||||
|
clock: Clock,
|
||||||
|
|
||||||
|
/// This function is not cancelable because first of all it does not block,
|
||||||
|
/// but more importantly, the cancelation logic itself may want to check
|
||||||
|
/// the time.
|
||||||
|
pub fn now(io: Io, clock: Clock) Error!Clock.Timestamp {
|
||||||
return .{
|
return .{
|
||||||
.nanoseconds = try io.vtable.now(io.userdata, clock),
|
.raw = try io.vtable.now(io.userdata, clock),
|
||||||
.clock = clock,
|
.clock = clock,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fromNow(io: Io, clock: Clock, duration: Duration) Error!Timestamp {
|
pub fn wait(t: Clock.Timestamp, io: Io) SleepError!void {
|
||||||
const now_ts = try now(io, clock);
|
return io.vtable.sleep(io.userdata, .{ .deadline = t });
|
||||||
return addDuration(now_ts, duration);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn untilNow(timestamp: Timestamp, io: Io) Error!Duration {
|
pub fn durationTo(from: Clock.Timestamp, to: Clock.Timestamp) Clock.Duration {
|
||||||
const now_ts = try Timestamp.now(io, timestamp.clock);
|
assert(from.clock == to.clock);
|
||||||
|
return .{
|
||||||
|
.raw = from.raw.durationTo(to.raw),
|
||||||
|
.clock = from.clock,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addDuration(from: Clock.Timestamp, duration: Clock.Duration) Clock.Timestamp {
|
||||||
|
assert(from.clock == duration.clock);
|
||||||
|
return .{
|
||||||
|
.raw = from.raw.addDuration(duration.raw),
|
||||||
|
.clock = from.clock,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fromNow(io: Io, duration: Clock.Duration) Error!Clock.Timestamp {
|
||||||
|
return .{
|
||||||
|
.clock = duration.clock,
|
||||||
|
.raw = (try duration.clock.now(io)).addDuration(duration.raw),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn untilNow(timestamp: Clock.Timestamp, io: Io) Error!Clock.Duration {
|
||||||
|
const now_ts = try Clock.Timestamp.now(io, timestamp.clock);
|
||||||
return timestamp.durationTo(now_ts);
|
return timestamp.durationTo(now_ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn durationFromNow(timestamp: Timestamp, io: Io) Error!Duration {
|
pub fn durationFromNow(timestamp: Clock.Timestamp, io: Io) Error!Clock.Duration {
|
||||||
const now_ts = try now(io, timestamp.clock);
|
const now_ts = try timestamp.clock.now(io);
|
||||||
return now_ts.durationTo(timestamp);
|
return .{
|
||||||
|
.clock = timestamp.clock,
|
||||||
|
.raw = now_ts.durationTo(timestamp.raw),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toClock(t: Timestamp, io: Io, clock: Clock) Error!Timestamp {
|
pub fn toClock(t: Clock.Timestamp, io: Io, clock: Clock) Error!Clock.Timestamp {
|
||||||
if (t.clock == clock) return t;
|
if (t.clock == clock) return t;
|
||||||
const now_old = try now(io, t.clock);
|
const now_old = try t.clock.now(io);
|
||||||
const now_new = try now(io, clock);
|
const now_new = try clock.now(io);
|
||||||
const duration = now_old.durationTo(t);
|
const duration = now_old.durationTo(t);
|
||||||
return now_new.addDuration(duration);
|
return .{
|
||||||
|
.clock = clock,
|
||||||
|
.raw = now_new.addDuration(duration),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compare(lhs: Timestamp, op: std.math.CompareOperator, rhs: Timestamp) bool {
|
pub fn compare(lhs: Clock.Timestamp, op: std.math.CompareOperator, rhs: Clock.Timestamp) bool {
|
||||||
assert(lhs.clock == rhs.clock);
|
assert(lhs.clock == rhs.clock);
|
||||||
return std.math.compare(lhs.nanoseconds, op, rhs.nanoseconds);
|
return std.math.compare(lhs.raw.nanoseconds, op, rhs.raw.nanoseconds);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Duration = struct {
|
||||||
|
raw: Io.Duration,
|
||||||
|
clock: Clock,
|
||||||
|
|
||||||
|
pub fn sleep(duration: Clock.Duration, io: Io) SleepError!void {
|
||||||
|
return io.vtable.sleep(io.userdata, .{ .duration = duration });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Timestamp = struct {
|
||||||
|
nanoseconds: i96,
|
||||||
|
|
||||||
|
pub const zero: Timestamp = .{ .nanoseconds = 0 };
|
||||||
|
|
||||||
|
pub fn durationTo(from: Timestamp, to: Timestamp) Duration {
|
||||||
|
return .{ .nanoseconds = to.nanoseconds - from.nanoseconds };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addDuration(from: Timestamp, duration: Duration) Timestamp {
|
||||||
|
return .{ .nanoseconds = from.nanoseconds + duration.nanoseconds };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn withClock(t: Timestamp, clock: Clock) Clock.Timestamp {
|
||||||
|
return .{ .nanoseconds = t.nanoseconds, .clock = clock };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toSeconds(t: Timestamp) i64 {
|
pub fn toSeconds(t: Timestamp) i64 {
|
||||||
return @intCast(@divTrunc(t.nanoseconds, std.time.ns_per_s));
|
return @intCast(@divTrunc(t.nanoseconds, std.time.ns_per_s));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn formatNumber(t: Timestamp, w: *std.Io.Writer, n: std.fmt.Number) std.Io.Writer.Error!void {
|
||||||
|
return w.printInt(t.nanoseconds, n.mode.base() orelse 10, n.case, .{
|
||||||
|
.precision = n.precision,
|
||||||
|
.width = n.width,
|
||||||
|
.alignment = n.alignment,
|
||||||
|
.fill = n.fill,
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Duration = struct {
|
pub const Duration = struct {
|
||||||
nanoseconds: i96,
|
nanoseconds: i96,
|
||||||
|
|
||||||
|
pub const zero: Duration = .{ .nanoseconds = 0 };
|
||||||
pub const max: Duration = .{ .nanoseconds = std.math.maxInt(i96) };
|
pub const max: Duration = .{ .nanoseconds = std.math.maxInt(i96) };
|
||||||
|
|
||||||
pub fn fromNanoseconds(x: i96) Duration {
|
pub fn fromNanoseconds(x: i96) Duration {
|
||||||
@ -842,38 +902,29 @@ pub const Duration = struct {
|
|||||||
pub fn toNanoseconds(d: Duration) i96 {
|
pub fn toNanoseconds(d: Duration) i96 {
|
||||||
return d.nanoseconds;
|
return d.nanoseconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sleep(duration: Duration, io: Io) SleepError!void {
|
|
||||||
return io.vtable.sleep(io.userdata, .{ .duration = .{ .duration = duration, .clock = .awake } });
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Declares under what conditions an operation should return `error.Timeout`.
|
/// Declares under what conditions an operation should return `error.Timeout`.
|
||||||
pub const Timeout = union(enum) {
|
pub const Timeout = union(enum) {
|
||||||
none,
|
none,
|
||||||
duration: ClockAndDuration,
|
duration: Clock.Duration,
|
||||||
deadline: Timestamp,
|
deadline: Clock.Timestamp,
|
||||||
|
|
||||||
pub const Error = error{ Timeout, UnsupportedClock };
|
pub const Error = error{ Timeout, UnsupportedClock };
|
||||||
|
|
||||||
pub const ClockAndDuration = struct {
|
pub fn toDeadline(t: Timeout, io: Io) Clock.Error!?Clock.Timestamp {
|
||||||
clock: Timestamp.Clock,
|
|
||||||
duration: Duration,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn toDeadline(t: Timeout, io: Io) Timestamp.Error!?Timestamp {
|
|
||||||
return switch (t) {
|
return switch (t) {
|
||||||
.none => null,
|
.none => null,
|
||||||
.duration => |d| try .fromNow(io, d.clock, d.duration),
|
.duration => |d| try .fromNow(io, d),
|
||||||
.deadline => |d| d,
|
.deadline => |d| d,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toDurationFromNow(t: Timeout, io: Io) Timestamp.Error!?ClockAndDuration {
|
pub fn toDurationFromNow(t: Timeout, io: Io) Clock.Error!?Clock.Duration {
|
||||||
return switch (t) {
|
return switch (t) {
|
||||||
.none => null,
|
.none => null,
|
||||||
.duration => |d| d,
|
.duration => |d| d,
|
||||||
.deadline => |d| .{ .clock = d.clock, .duration = try d.durationFromNow(io) },
|
.deadline => |d| try d.durationFromNow(io),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -85,7 +85,7 @@ pub fn updateFile(
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (src_stat.size == dest_stat.size and
|
if (src_stat.size == dest_stat.size and
|
||||||
src_stat.mtime == dest_stat.mtime and
|
src_stat.mtime.nanoseconds == dest_stat.mtime.nanoseconds and
|
||||||
actual_mode == dest_stat.mode)
|
actual_mode == dest_stat.mode)
|
||||||
{
|
{
|
||||||
return .fresh;
|
return .fresh;
|
||||||
|
|||||||
@ -45,16 +45,12 @@ pub const Stat = struct {
|
|||||||
/// This is available on POSIX systems and is always 0 otherwise.
|
/// This is available on POSIX systems and is always 0 otherwise.
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
kind: Kind,
|
kind: Kind,
|
||||||
|
|
||||||
/// Last access time in nanoseconds, relative to UTC 1970-01-01.
|
/// Last access time in nanoseconds, relative to UTC 1970-01-01.
|
||||||
/// TODO change this to Io.Timestamp except don't waste storage on clock
|
atime: Io.Timestamp,
|
||||||
atime: i128,
|
|
||||||
/// Last modification time in nanoseconds, relative to UTC 1970-01-01.
|
/// Last modification time in nanoseconds, relative to UTC 1970-01-01.
|
||||||
/// TODO change this to Io.Timestamp except don't waste storage on clock
|
mtime: Io.Timestamp,
|
||||||
mtime: i128,
|
|
||||||
/// Last status/metadata change time in nanoseconds, relative to UTC 1970-01-01.
|
/// Last status/metadata change time in nanoseconds, relative to UTC 1970-01-01.
|
||||||
/// TODO change this to Io.Timestamp except don't waste storage on clock
|
ctime: Io.Timestamp,
|
||||||
ctime: i128,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn stdout() File {
|
pub fn stdout() File {
|
||||||
|
|||||||
@ -1147,26 +1147,26 @@ fn pwrite(userdata: ?*anyopaque, file: Io.File, buffer: []const u8, offset: posi
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nowPosix(userdata: ?*anyopaque, clock: Io.Timestamp.Clock) Io.Timestamp.Error!i96 {
|
fn nowPosix(userdata: ?*anyopaque, clock: Io.Clock) Io.Clock.Error!Io.Timestamp {
|
||||||
const pool: *Pool = @ptrCast(@alignCast(userdata));
|
const pool: *Pool = @ptrCast(@alignCast(userdata));
|
||||||
_ = pool;
|
_ = pool;
|
||||||
const clock_id: posix.clockid_t = clockToPosix(clock);
|
const clock_id: posix.clockid_t = clockToPosix(clock);
|
||||||
var tp: posix.timespec = undefined;
|
var tp: posix.timespec = undefined;
|
||||||
switch (posix.errno(posix.system.clock_gettime(clock_id, &tp))) {
|
switch (posix.errno(posix.system.clock_gettime(clock_id, &tp))) {
|
||||||
.SUCCESS => return @intCast(@as(i128, tp.sec) * std.time.ns_per_s + tp.nsec),
|
.SUCCESS => return timestampFromPosix(&tp),
|
||||||
.INVAL => return error.UnsupportedClock,
|
.INVAL => return error.UnsupportedClock,
|
||||||
else => |err| return posix.unexpectedErrno(err),
|
else => |err| return posix.unexpectedErrno(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nowWindows(userdata: ?*anyopaque, clock: Io.Timestamp.Clock) Io.Timestamp.Error!i96 {
|
fn nowWindows(userdata: ?*anyopaque, clock: Io.Clock) Io.Clock.Error!Io.Timestamp {
|
||||||
const pool: *Pool = @ptrCast(@alignCast(userdata));
|
const pool: *Pool = @ptrCast(@alignCast(userdata));
|
||||||
_ = pool;
|
_ = pool;
|
||||||
switch (clock) {
|
switch (clock) {
|
||||||
.realtime => {
|
.realtime => {
|
||||||
// RtlGetSystemTimePrecise() has a granularity of 100 nanoseconds
|
// RtlGetSystemTimePrecise() has a granularity of 100 nanoseconds
|
||||||
// and uses the NTFS/Windows epoch, which is 1601-01-01.
|
// and uses the NTFS/Windows epoch, which is 1601-01-01.
|
||||||
return @as(i96, windows.ntdll.RtlGetSystemTimePrecise()) * 100;
|
return .{ .nanoseconds = @as(i96, windows.ntdll.RtlGetSystemTimePrecise()) * 100 };
|
||||||
},
|
},
|
||||||
.monotonic, .uptime => {
|
.monotonic, .uptime => {
|
||||||
// QPC on windows doesn't fail on >= XP/2000 and includes time suspended.
|
// 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
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nowWasi(userdata: ?*anyopaque, clock: Io.Timestamp.Clock) Io.Timestamp.Error!i96 {
|
fn nowWasi(userdata: ?*anyopaque, clock: Io.Clock) Io.Clock.Error!Io.Timestamp {
|
||||||
const pool: *Pool = @ptrCast(@alignCast(userdata));
|
const pool: *Pool = @ptrCast(@alignCast(userdata));
|
||||||
_ = pool;
|
_ = pool;
|
||||||
var ns: std.os.wasi.timestamp_t = undefined;
|
var ns: std.os.wasi.timestamp_t = undefined;
|
||||||
@ -1196,13 +1196,10 @@ fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
|
|||||||
});
|
});
|
||||||
const deadline_nanoseconds: i96 = switch (timeout) {
|
const deadline_nanoseconds: i96 = switch (timeout) {
|
||||||
.none => std.math.maxInt(i96),
|
.none => std.math.maxInt(i96),
|
||||||
.duration => |d| d.duration.nanoseconds,
|
.duration => |duration| duration.raw.nanoseconds,
|
||||||
.deadline => |deadline| deadline.nanoseconds,
|
.deadline => |deadline| deadline.raw.nanoseconds,
|
||||||
};
|
|
||||||
var timespec: posix.timespec = .{
|
|
||||||
.sec = @intCast(@divFloor(deadline_nanoseconds, std.time.ns_per_s)),
|
|
||||||
.nsec = @intCast(@mod(deadline_nanoseconds, std.time.ns_per_s)),
|
|
||||||
};
|
};
|
||||||
|
var timespec: posix.timespec = timestampToPosix(deadline_nanoseconds);
|
||||||
while (true) {
|
while (true) {
|
||||||
try pool.checkCancel();
|
try pool.checkCancel();
|
||||||
switch (std.os.linux.E.init(std.os.linux.clock_nanosleep(clock_id, .{ .ABSTIME = switch (timeout) {
|
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 {
|
|||||||
.sec = std.math.maxInt(sec_type),
|
.sec = std.math.maxInt(sec_type),
|
||||||
.nsec = std.math.maxInt(nsec_type),
|
.nsec = std.math.maxInt(nsec_type),
|
||||||
};
|
};
|
||||||
const ns = d.duration.nanoseconds;
|
break :t timestampToPosix(d.duration.nanoseconds);
|
||||||
break :t .{
|
|
||||||
.sec = @intCast(@divFloor(ns, std.time.ns_per_s)),
|
|
||||||
.nsec = @intCast(@mod(ns, std.time.ns_per_s)),
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
while (true) {
|
while (true) {
|
||||||
try pool.checkCancel();
|
try pool.checkCancel();
|
||||||
@ -1879,8 +1872,8 @@ fn netReceive(
|
|||||||
const max_poll_ms = std.math.maxInt(u31);
|
const max_poll_ms = std.math.maxInt(u31);
|
||||||
const timeout_ms: u31 = if (deadline) |d| t: {
|
const timeout_ms: u31 = if (deadline) |d| t: {
|
||||||
const duration = d.durationFromNow(pool.io()) catch |err| return .{ err, message_i };
|
const duration = d.durationFromNow(pool.io()) catch |err| return .{ err, message_i };
|
||||||
if (duration.nanoseconds <= 0) return .{ error.Timeout, message_i };
|
if (duration.raw.nanoseconds <= 0) return .{ error.Timeout, message_i };
|
||||||
break :t @intCast(@min(max_poll_ms, duration.toMilliseconds()));
|
break :t @intCast(@min(max_poll_ms, duration.raw.toMilliseconds()));
|
||||||
} else max_poll_ms;
|
} else max_poll_ms;
|
||||||
|
|
||||||
const poll_rc = posix.system.poll(&poll_fds, poll_fds.len, timeout_ms);
|
const poll_rc = posix.system.poll(&poll_fds, poll_fds.len, timeout_ms);
|
||||||
@ -2160,7 +2153,7 @@ fn recoverableOsBugDetected() void {
|
|||||||
if (builtin.mode == .Debug) unreachable;
|
if (builtin.mode == .Debug) unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clockToPosix(clock: Io.Timestamp.Clock) posix.clockid_t {
|
fn clockToPosix(clock: Io.Clock) posix.clockid_t {
|
||||||
return switch (clock) {
|
return switch (clock) {
|
||||||
.real => posix.CLOCK.REALTIME,
|
.real => posix.CLOCK.REALTIME,
|
||||||
.awake => switch (builtin.os.tag) {
|
.awake => switch (builtin.os.tag) {
|
||||||
@ -2176,7 +2169,7 @@ fn clockToPosix(clock: Io.Timestamp.Clock) posix.clockid_t {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clockToWasi(clock: Io.Timestamp.Clock) std.os.wasi.clockid_t {
|
fn clockToWasi(clock: Io.Clock) std.os.wasi.clockid_t {
|
||||||
return switch (clock) {
|
return switch (clock) {
|
||||||
.realtime => .REALTIME,
|
.realtime => .REALTIME,
|
||||||
.awake => .MONOTONIC,
|
.awake => .MONOTONIC,
|
||||||
@ -2204,9 +2197,9 @@ fn statFromLinux(stx: *const std.os.linux.Statx) Io.File.Stat {
|
|||||||
std.os.linux.S.IFSOCK => .unix_domain_socket,
|
std.os.linux.S.IFSOCK => .unix_domain_socket,
|
||||||
else => .unknown,
|
else => .unknown,
|
||||||
},
|
},
|
||||||
.atime = @as(i128, atime.sec) * std.time.ns_per_s + atime.nsec,
|
.atime = .{ .nanoseconds = @intCast(@as(i128, atime.sec) * std.time.ns_per_s + atime.nsec) },
|
||||||
.mtime = @as(i128, mtime.sec) * std.time.ns_per_s + mtime.nsec,
|
.mtime = .{ .nanoseconds = @intCast(@as(i128, mtime.sec) * std.time.ns_per_s + mtime.nsec) },
|
||||||
.ctime = @as(i128, ctime.sec) * std.time.ns_per_s + ctime.nsec,
|
.ctime = .{ .nanoseconds = @intCast(@as(i128, ctime.sec) * std.time.ns_per_s + ctime.nsec) },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2238,9 +2231,9 @@ fn statFromPosix(st: *const std.posix.Stat) Io.File.Stat {
|
|||||||
|
|
||||||
break :k .unknown;
|
break :k .unknown;
|
||||||
},
|
},
|
||||||
.atime = @as(i128, atime.sec) * std.time.ns_per_s + atime.nsec,
|
.atime = timestampFromPosix(&atime),
|
||||||
.mtime = @as(i128, mtime.sec) * std.time.ns_per_s + mtime.nsec,
|
.mtime = timestampFromPosix(&mtime),
|
||||||
.ctime = @as(i128, ctime.sec) * std.time.ns_per_s + ctime.nsec,
|
.ctime = timestampFromPosix(&ctime),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2263,3 +2256,14 @@ fn statFromWasi(st: *const std.os.wasi.filestat_t) Io.File.Stat {
|
|||||||
.ctime = st.ctim,
|
.ctime = st.ctim,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn timestampFromPosix(timespec: *const std.posix.timespec) Io.Timestamp {
|
||||||
|
return .{ .nanoseconds = @intCast(@as(i128, timespec.sec) * std.time.ns_per_s + timespec.nsec) };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn timestampToPosix(nanoseconds: i96) std.posix.timespec {
|
||||||
|
return .{
|
||||||
|
.sec = @intCast(@divFloor(nanoseconds, std.time.ns_per_s)),
|
||||||
|
.nsec = @intCast(@mod(nanoseconds, std.time.ns_per_s)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@ -79,7 +79,7 @@ pub const LookupError = error{
|
|||||||
NameServerFailure,
|
NameServerFailure,
|
||||||
/// Failed to open or read "/etc/hosts" or "/etc/resolv.conf".
|
/// Failed to open or read "/etc/hosts" or "/etc/resolv.conf".
|
||||||
DetectingNetworkConfigurationFailed,
|
DetectingNetworkConfigurationFailed,
|
||||||
} || Io.Timestamp.Error || IpAddress.BindError || Io.Cancelable;
|
} || Io.Clock.Error || IpAddress.BindError || Io.Cancelable;
|
||||||
|
|
||||||
pub const LookupResult = struct {
|
pub const LookupResult = struct {
|
||||||
/// How many `LookupOptions.addresses_buffer` elements are populated.
|
/// 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
|
|||||||
|
|
||||||
// boot clock is chosen because time the computer is suspended should count
|
// boot clock is chosen because time the computer is suspended should count
|
||||||
// against time spent waiting for external messages to arrive.
|
// against time spent waiting for external messages to arrive.
|
||||||
var now_ts = try Io.Timestamp.now(io, .boot);
|
const clock: Io.Clock = .boot;
|
||||||
|
var now_ts = try clock.now(io);
|
||||||
const final_ts = now_ts.addDuration(.fromSeconds(rc.timeout_seconds));
|
const final_ts = now_ts.addDuration(.fromSeconds(rc.timeout_seconds));
|
||||||
const attempt_duration: Io.Duration = .{
|
const attempt_duration: Io.Duration = .{
|
||||||
.nanoseconds = std.time.ns_per_s * @as(usize, rc.timeout_seconds) / rc.attempts,
|
.nanoseconds = std.time.ns_per_s * @as(usize, rc.timeout_seconds) / rc.attempts,
|
||||||
};
|
};
|
||||||
|
|
||||||
send: while (now_ts.compare(.lt, final_ts)) : (now_ts = try Io.Timestamp.now(io, .boot)) {
|
send: while (now_ts.nanoseconds < final_ts.nanoseconds) : (now_ts = try clock.now(io)) {
|
||||||
const max_messages = queries_buffer.len * ResolvConf.max_nameservers;
|
const max_messages = queries_buffer.len * ResolvConf.max_nameservers;
|
||||||
{
|
{
|
||||||
var message_buffer: [max_messages]Io.net.OutgoingMessage = undefined;
|
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
|
|||||||
_ = io.vtable.netSend(io.userdata, socket.handle, message_buffer[0..message_i], .{});
|
_ = io.vtable.netSend(io.userdata, socket.handle, message_buffer[0..message_i], .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
const timeout: Io.Timeout = .{ .deadline = now_ts.addDuration(attempt_duration) };
|
const timeout: Io.Timeout = .{ .deadline = .{
|
||||||
|
.raw = now_ts.addDuration(attempt_duration),
|
||||||
|
.clock = clock,
|
||||||
|
} };
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
var message_buffer: [max_messages]Io.net.IncomingMessage = undefined;
|
var message_buffer: [max_messages]Io.net.IncomingMessage = undefined;
|
||||||
|
|||||||
@ -637,23 +637,23 @@ pub const UpdateTimesError = posix.FutimensError || windows.SetFileTimeError;
|
|||||||
pub fn updateTimes(
|
pub fn updateTimes(
|
||||||
self: File,
|
self: File,
|
||||||
/// access timestamp in nanoseconds
|
/// access timestamp in nanoseconds
|
||||||
atime: i128,
|
atime: Io.Timestamp,
|
||||||
/// last modification timestamp in nanoseconds
|
/// last modification timestamp in nanoseconds
|
||||||
mtime: i128,
|
mtime: Io.Timestamp,
|
||||||
) UpdateTimesError!void {
|
) UpdateTimesError!void {
|
||||||
if (builtin.os.tag == .windows) {
|
if (builtin.os.tag == .windows) {
|
||||||
const atime_ft = windows.nanoSecondsToFileTime(atime);
|
const atime_ft = windows.nanoSecondsToFileTime(atime.nanoseconds);
|
||||||
const mtime_ft = windows.nanoSecondsToFileTime(mtime);
|
const mtime_ft = windows.nanoSecondsToFileTime(mtime.nanoseconds);
|
||||||
return windows.SetFileTime(self.handle, null, &atime_ft, &mtime_ft);
|
return windows.SetFileTime(self.handle, null, &atime_ft, &mtime_ft);
|
||||||
}
|
}
|
||||||
const times = [2]posix.timespec{
|
const times = [2]posix.timespec{
|
||||||
posix.timespec{
|
posix.timespec{
|
||||||
.sec = math.cast(isize, @divFloor(atime, std.time.ns_per_s)) orelse maxInt(isize),
|
.sec = math.cast(isize, @divFloor(atime.nanoseconds, std.time.ns_per_s)) orelse maxInt(isize),
|
||||||
.nsec = math.cast(isize, @mod(atime, std.time.ns_per_s)) orelse maxInt(isize),
|
.nsec = math.cast(isize, @mod(atime.nanoseconds, std.time.ns_per_s)) orelse maxInt(isize),
|
||||||
},
|
},
|
||||||
posix.timespec{
|
posix.timespec{
|
||||||
.sec = math.cast(isize, @divFloor(mtime, std.time.ns_per_s)) orelse maxInt(isize),
|
.sec = math.cast(isize, @divFloor(mtime.nanoseconds, std.time.ns_per_s)) orelse maxInt(isize),
|
||||||
.nsec = math.cast(isize, @mod(mtime, std.time.ns_per_s)) orelse maxInt(isize),
|
.nsec = math.cast(isize, @mod(mtime.nanoseconds, std.time.ns_per_s)) orelse maxInt(isize),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
try posix.futimens(self.handle, ×);
|
try posix.futimens(self.handle, ×);
|
||||||
|
|||||||
@ -320,7 +320,7 @@ pub const Connection = struct {
|
|||||||
const tls: *Tls = @ptrCast(base);
|
const tls: *Tls = @ptrCast(base);
|
||||||
var random_buffer: [176]u8 = undefined;
|
var random_buffer: [176]u8 = undefined;
|
||||||
std.crypto.random.bytes(&random_buffer);
|
std.crypto.random.bytes(&random_buffer);
|
||||||
const now_ts = if (Io.Timestamp.now(io, .real)) |ts| ts.toSeconds() else |_| return error.TlsInitializationFailed;
|
const now_ts = if (Io.Clock.real.now(io)) |ts| ts.toSeconds() else |_| return error.TlsInitializationFailed;
|
||||||
tls.* = .{
|
tls.* = .{
|
||||||
.connection = .{
|
.connection = .{
|
||||||
.client = client,
|
.client = client,
|
||||||
|
|||||||
@ -18,7 +18,6 @@ pub const Options = struct {
|
|||||||
|
|
||||||
underlying_writer: *Io.Writer,
|
underlying_writer: *Io.Writer,
|
||||||
prefix: []const u8 = "",
|
prefix: []const u8 = "",
|
||||||
mtime_now: u64 = 0,
|
|
||||||
|
|
||||||
const Error = error{
|
const Error = error{
|
||||||
WriteFailed,
|
WriteFailed,
|
||||||
@ -44,10 +43,12 @@ pub fn writeFile(
|
|||||||
w: *Writer,
|
w: *Writer,
|
||||||
sub_path: []const u8,
|
sub_path: []const u8,
|
||||||
file_reader: *Io.File.Reader,
|
file_reader: *Io.File.Reader,
|
||||||
stat_mtime: i128,
|
/// If you want to match the file format's expectations, it wants number of
|
||||||
|
/// seconds since POSIX epoch. Zero is also a great option here to make
|
||||||
|
/// generated tarballs more reproducible.
|
||||||
|
mtime: u64,
|
||||||
) WriteFileError!void {
|
) WriteFileError!void {
|
||||||
const size = try file_reader.getSize();
|
const size = try file_reader.getSize();
|
||||||
const mtime: u64 = @intCast(@divFloor(stat_mtime, std.time.ns_per_s));
|
|
||||||
|
|
||||||
var header: Header = .{};
|
var header: Header = .{};
|
||||||
try w.setPath(&header, sub_path);
|
try w.setPath(&header, sub_path);
|
||||||
@ -238,7 +239,6 @@ pub const Header = extern struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Integer number of seconds since January 1, 1970, 00:00 Coordinated Universal Time.
|
// Integer number of seconds since January 1, 1970, 00:00 Coordinated Universal Time.
|
||||||
// mtime == 0 will use current time
|
|
||||||
pub fn setMtime(w: *Header, mtime: u64) error{OctalOverflow}!void {
|
pub fn setMtime(w: *Header, mtime: u64) error{OctalOverflow}!void {
|
||||||
try octal(&w.mtime, mtime);
|
try octal(&w.mtime, mtime);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user