From d6fbbafcfd44409cf07ad2fa14380eac8848d360 Mon Sep 17 00:00:00 2001 From: xeon Date: Sat, 7 Feb 2026 11:39:07 +0300 Subject: [PATCH] chore(build!): update to zig 0.16.0-dev.2510+bcb5218a2 --- README.md | 2 +- build.zig.zon | 2 +- common/src/io/poll.zig | 75 +++++++++++++++++++++++++++-------- confsv/src/main.zig | 7 +--- envrc | 2 +- gamesv/src/Session/auth.zig | 2 +- gamesv/src/logic/Resource.zig | 5 +-- gamesv/src/main.zig | 7 +--- 8 files changed, 65 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 3f116bb..82f23d5 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ # Getting Started ## Requirements -- Zig 0.16.0-dev.2459: [Linux](https://ziglang.org/builds/zig-x86_64-linux-0.16.0-dev.2459+37d14a4f3.tar.xz)/[Windows](https://ziglang.org/builds/zig-x86_64-windows-0.16.0-dev.2459+37d14a4f3.zip) +- Zig 0.16.0-dev.2510: [Linux](https://ziglang.org/builds/zig-x86_64-linux-0.16.0-dev.2510+bcb5218a2.tar.xz)/[Windows](https://ziglang.org/builds/zig-x86_64-windows-0.16.0-dev.2510+bcb5218a2.zip) #### For additional help, you can join our [discord server](https://discord.xeondev.com) diff --git a/build.zig.zon b/build.zig.zon index c919d50..45e21b4 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -1,7 +1,7 @@ .{ .name = .LR_S, .version = "0.1.0", - .minimum_zig_version = "0.16.0-dev.2471+e9eadee00", + .minimum_zig_version = "0.16.0-dev.2510+bcb5218a2", .paths = .{""}, .fingerprint = 0x50ff8392fab61337, } diff --git a/common/src/io/poll.zig b/common/src/io/poll.zig index 500af64..d78c12a 100644 --- a/common/src/io/poll.zig +++ b/common/src/io/poll.zig @@ -20,6 +20,11 @@ const native_arch = builtin.cpu.arch; const iovlen_t = @FieldType(posix.msghdr_const, "iovlen"); +extern "kernel32" fn SetConsoleCtrlHandler( + HandlerRoutine: ?windows.HANDLER_ROUTINE, + Add: windows.BOOL, +) callconv(.winapi) windows.BOOL; + pub const IoOptions = struct { stack_size: usize = 1024 * 1024, // 1MB max_iovecs_len: usize = 8, @@ -298,7 +303,7 @@ pub fn Poll(comptime io_options: IoOptions) type { pub fn remainingTimeNanoseconds(sleeper: *const Sleeper) ?i96 { const until = sleeper.until orelse return null; - const ts = currentTime(until.clock) catch unreachable; + const ts = currentTime(until.clock); return until.raw.nanoseconds - ts.nanoseconds; } @@ -1200,16 +1205,17 @@ pub fn Poll(comptime io_options: IoOptions) type { group.token.raw = null; } - fn sleep(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { + fn sleep(userdata: ?*anyopaque, timeout: Io.Timeout) Io.Cancelable!void { if (timeout == .none) return; const p: *ThisPoll = @ptrCast(@alignCast(userdata)); + // TODO: eliminate this. EventLoop fiber should be statically allocated. p.ensureEventLoop() catch return error.Canceled; const sleeper = WaitScheduler.Sleeper.create( p.gpa, p.obtainCurrentRestorePoint(), - (try timeout.toDeadline(p.io())).?, + timeout.toTimestamp(p.io()), null, // futexless wait ) catch return error.Canceled; @@ -1219,11 +1225,42 @@ pub fn Poll(comptime io_options: IoOptions) type { try checkCancel(p); } - fn now(userdata: ?*anyopaque, clock: Io.Clock) Io.Clock.Error!Io.Timestamp { + fn now(userdata: ?*anyopaque, clock: Io.Clock) Io.Timestamp { _ = userdata; return currentTime(clock); } + fn clockResolution(userdata: ?*anyopaque, clock: Io.Clock) Io.Clock.ResolutionError!Io.Duration { + _ = userdata; + + return switch (native_os) { + .windows => switch (clock) { + .awake, .boot, .real => { + var qpf: windows.LARGE_INTEGER = undefined; + if (windows.ntdll.RtlQueryPerformanceFrequency(&qpf) != 0) { + return .zero; + } + const common_qpf = 10_000_000; + if (qpf == common_qpf) return .fromNanoseconds(std.time.ns_per_s / common_qpf); + + const scale = @as(u64, std.time.ns_per_s << 32) / @as(u32, @intCast(qpf)); + const result = scale >> 32; + return .fromNanoseconds(result); + }, + .cpu_process, .cpu_thread => return error.ClockUnavailable, + }, + else => { + const clock_id: posix.clockid_t = clockToPosix(clock) orelse return .zero; + var timespec: posix.timespec = undefined; + return switch (posix.errno(posix.system.clock_getres(clock_id, ×pec))) { + .SUCCESS => .fromNanoseconds(timespecToNs(×pec)), + .INVAL => return error.ClockUnavailable, + else => |err| return posix.unexpectedErrno(err), + }; + }, + }; + } + fn checkCancel(userdata: ?*anyopaque) Io.Cancelable!void { const p: *ThisPoll = @ptrCast(@alignCast(userdata)); if (p.interrupted) return error.Canceled; @@ -1363,7 +1400,7 @@ pub fn Poll(comptime io_options: IoOptions) type { _ = flags; if (message_buffer.len == 0) return .{ null, 0 }; - if (timeout != .none) return .{ error.UnsupportedClock, 0 }; // timeouts are not supported for now. + if (timeout != .none) return .{ error.Timeout, 0 }; // timeouts are not supported for now. const p: *ThisPoll = @ptrCast(@alignCast(userdata)); @@ -1561,7 +1598,7 @@ pub fn Poll(comptime io_options: IoOptions) type { timeout: Io.Timeout, ) Io.Cancelable!void { const p: *ThisPoll = @ptrCast(@alignCast(userdata)); - const wait_until = timeout.toDeadline(p.io()) catch null; + const wait_until = timeout.toTimestamp(p.io()); const sleeper = WaitScheduler.Sleeper.create( p.gpa, @@ -2275,7 +2312,7 @@ pub fn Poll(comptime io_options: IoOptions) type { fn setInterruptHandler(waker: Waker) void { if (native_os == .windows) { InterruptHandler.waker = waker; - windows.SetConsoleCtrlHandler(InterruptHandler.onInterruptWindows, true) catch {}; + _ = SetConsoleCtrlHandler(InterruptHandler.onInterruptWindows, windows.TRUE); } else { posix.sigaction(posix.SIG.INT, &.{ .handler = .{ .handler = InterruptHandler.onInterruptPosix }, @@ -2362,7 +2399,7 @@ pub fn Poll(comptime io_options: IoOptions) type { }; } -fn clockToPosix(clock: Io.Clock) Io.Clock.Error!posix.clockid_t { +fn clockToPosix(clock: Io.Clock) ?posix.clockid_t { return switch (clock) { .real => posix.CLOCK.REALTIME, .awake => switch (native_os) { @@ -2375,11 +2412,11 @@ fn clockToPosix(clock: Io.Clock) Io.Clock.Error!posix.clockid_t { .linux => posix.CLOCK.BOOTTIME, else => posix.CLOCK.MONOTONIC, }, - .cpu_thread, .cpu_process => return error.UnsupportedClock, + .cpu_thread, .cpu_process => null, }; } -fn currentTime(clock: Io.Clock) Io.Clock.Error!Io.Timestamp { +fn currentTime(clock: Io.Clock) Io.Timestamp { if (native_os == .windows) { switch (clock) { .real => { @@ -2396,17 +2433,17 @@ fn currentTime(clock: Io.Clock) Io.Clock.Error!Io.Timestamp { const result = (@as(u96, qpc) * scale) >> 32; return .{ .nanoseconds = @intCast(result) }; }, - else => return error.UnsupportedClock, + else => return .zero, } } else { // POSIX - const clock_id: posix.clockid_t = try clockToPosix(clock); + const clock_id = clockToPosix(clock) orelse return .zero; var tp: posix.timespec = undefined; - switch (posix.errno(posix.system.clock_gettime(clock_id, &tp))) { - .SUCCESS => return .{ .nanoseconds = @intCast(@as(i128, tp.sec) * std.time.ns_per_s + tp.nsec) }, - .INVAL => return error.UnsupportedClock, - else => |err| return posix.unexpectedErrno(err), - } + return switch (posix.errno(posix.system.clock_gettime(clock_id, &tp))) { + .SUCCESS => .{ .nanoseconds = @intCast(@as(i128, tp.sec) * std.time.ns_per_s + tp.nsec) }, + .INVAL => .zero, + else => .zero, + }; } } @@ -2496,6 +2533,10 @@ fn timespecToMs(timespec: posix.timespec) i64 { return @intCast((timespec.sec * 1000) + @divFloor(timespec.nsec, std.time.ns_per_ms)); } +fn timespecToNs(timespec: *const posix.timespec) i96 { + return @intCast(@as(i128, timespec.sec) * std.time.ns_per_s + timespec.nsec); +} + fn initWSA() void { const wsa_version: u16 = 0x0202; var data: ws2_32.WSADATA = undefined; diff --git a/confsv/src/main.zig b/confsv/src/main.zig index 9ac29b5..1380dd9 100644 --- a/confsv/src/main.zig +++ b/confsv/src/main.zig @@ -53,7 +53,7 @@ fn start(init: Init.Minimal, io: Io, gpa: Allocator) u8 { var http_processors: Io.Group = .init; defer http_processors.cancel(io); - var preferred_clock: Io.Clock = .awake; // Prefer monotonic clock by default. Fallback to realtime. + const preferred_clock: Io.Clock = if (Io.Clock.awake.resolution(io)) |_| .awake else |_| .real; var concurrency_availability: ConcurrencyAvailability = .undetermined; log.info("listening at {f}", .{listen_address}); @@ -67,11 +67,6 @@ fn start(init: Init.Minimal, io: Io, gpa: Allocator) u8 { while (true) { if (io.sleep(.fromSeconds(1), preferred_clock)) break else |sleep_err| switch (sleep_err) { error.Canceled => break :accept_loop, // Shutdown requested - error.UnsupportedClock => preferred_clock = if (preferred_clock == .awake) - .real - else - continue :accept_loop, // No clock available. - error.Unexpected => continue :accept_loop, // Sleep is unimportant then. } } diff --git a/envrc b/envrc index 0bee77c..c9074b5 100755 --- a/envrc +++ b/envrc @@ -1,7 +1,7 @@ #!/bin/sh # DEPENDS: curl, tar, xz, realpath -ZIG_VERSION="0.16.0-dev.2471+e9eadee00" +ZIG_VERSION="0.16.0-dev.2510+bcb5218a2" ZIG_PLATFORM="x86_64-linux" ZIG_DIST="zig-${ZIG_PLATFORM}-${ZIG_VERSION}" ZIG_DIR="./.direnv/${ZIG_DIST}/" diff --git a/gamesv/src/Session/auth.zig b/gamesv/src/Session/auth.zig index 5245cb6..48ad02e 100644 --- a/gamesv/src/Session/auth.zig +++ b/gamesv/src/Session/auth.zig @@ -39,7 +39,7 @@ pub fn processLoginRequest(io: Io, session: *Session, request: *const pb.CS_LOGI try session.send(pb.SC_LOGIN{ .uid = request.uid, - .server_time = @intCast((Io.Clock.real.now(io) catch Io.Timestamp.zero).toSeconds()), + .server_time = @intCast(Io.Clock.real.now(io).toSeconds()), .server_time_zone = 3, }); diff --git a/gamesv/src/logic/Resource.zig b/gamesv/src/logic/Resource.zig index 84074a6..24904f8 100644 --- a/gamesv/src/logic/Resource.zig +++ b/gamesv/src/logic/Resource.zig @@ -15,10 +15,7 @@ pub const PingTimer = struct { last_client_ts: u64 = 0, pub fn serverTime(pt: PingTimer) u64 { - return if (Io.Clock.real.now(pt.io)) |ts| - @intCast(ts.toMilliseconds()) - else |_| - pt.last_client_ts; + return @intCast(Io.Clock.real.now(pt.io).toMilliseconds()); } }; diff --git a/gamesv/src/main.zig b/gamesv/src/main.zig index c4928a3..a5cb0bf 100644 --- a/gamesv/src/main.zig +++ b/gamesv/src/main.zig @@ -63,7 +63,7 @@ fn start(init: Init.Minimal, io: Io, gpa: Allocator) u8 { var sessions: Io.Group = .init; defer sessions.cancel(io); - var preferred_clock: Io.Clock = .awake; + const preferred_clock: Io.Clock = if (Io.Clock.awake.resolution(io)) |_| .awake else |_| .real; var concurrency_availability: Session.ConcurrencyAvailability = .undetermined; log.info("listening at {f}", .{listen_address}); @@ -77,11 +77,6 @@ fn start(init: Init.Minimal, io: Io, gpa: Allocator) u8 { while (true) { if (io.sleep(.fromSeconds(1), preferred_clock)) break else |sleep_err| switch (sleep_err) { error.Canceled => break :accept_loop, // Shutdown requested - error.UnsupportedClock => preferred_clock = if (preferred_clock == .awake) - .real - else - continue :accept_loop, // No clock available. - error.Unexpected => continue :accept_loop, // Sleep is unimportant then. } }