@@ -7,6 +7,23 @@ const builtin = @import("builtin");
77// Time utilities (std.time.milliTimestamp removed in 0.16)
88// ============================================================
99
10+ /// Get clock_gettime result as seconds and nanoseconds.
11+ fn getRealtimeClock () struct { sec : i64 , nsec : i64 } {
12+ if (comptime builtin .os .tag == .linux or builtin .os .tag == .macos or
13+ builtin .os .tag == .ios or builtin .os .tag == .tvos or
14+ builtin .os .tag == .watchos or builtin .os .tag == .visionos or
15+ builtin .os .tag == .freebsd or builtin .os .tag == .netbsd or
16+ builtin .os .tag == .openbsd or builtin .os .tag == .dragonfly )
17+ {
18+ var ts : std.c.timespec = .{ .sec = 0 , .nsec = 0 };
19+ const rc = std .c .clock_gettime (std .c .CLOCK .REALTIME , & ts );
20+ if (rc == 0 ) {
21+ return .{ .sec = ts .sec , .nsec = ts .nsec };
22+ }
23+ }
24+ return .{ .sec = 0 , .nsec = 0 };
25+ }
26+
1027/// Get current wall-clock time in nanoseconds since Unix epoch.
1128/// Replaces std.time.nanoTimestamp() which was removed in Zig 0.16.
1229pub fn nanoTimestamp () i128 {
@@ -16,26 +33,22 @@ pub fn nanoTimestamp() i128 {
1633 const intervals : i128 = @as (i128 , @as (u64 , ft .dwHighDateTime ) << 32 | @as (u64 , ft .dwLowDateTime ));
1734 return intervals * 100 - EPOCH_DIFF ;
1835 } else {
19- const ts = std . posix . clock_gettime ( .REALTIME ) catch return 0 ;
20- return @as (i128 , ts .sec ) * 1_000_000_000 + @as (i128 , ts .nsec );
36+ const clock = getRealtimeClock () ;
37+ return @as (i128 , clock .sec ) * 1_000_000_000 + @as (i128 , clock .nsec );
2138 }
2239}
2340
2441/// Get current wall-clock time in milliseconds since Unix epoch.
2542/// Replaces std.time.milliTimestamp() which was removed in Zig 0.16.
2643pub fn milliTimestamp () i64 {
2744 if (comptime builtin .os .tag == .windows ) {
28- // On Windows, use the Win32 API
2945 const ft = std .os .windows .GetSystemTimeAsFileTime ();
30- // Convert from Windows FILETIME (100ns intervals since 1601-01-01)
31- // to Unix timestamp in milliseconds
32- const EPOCH_DIFF : i64 = 11644473600000 ; // ms between 1601 and 1970
46+ const EPOCH_DIFF : i64 = 11644473600000 ;
3347 const intervals : i64 = @bitCast (@as (u64 , ft .dwHighDateTime ) << 32 | @as (u64 , ft .dwLowDateTime ));
3448 return @divFloor (intervals , 10000 ) - EPOCH_DIFF ;
3549 } else {
36- // POSIX: use clock_gettime with REALTIME clock
37- const ts = std .posix .clock_gettime (.REALTIME ) catch return 0 ;
38- return @as (i64 , ts .sec ) * 1000 + @divFloor (@as (i64 , ts .nsec ), 1_000_000 );
50+ const clock = getRealtimeClock ();
51+ return @as (i64 , clock .sec ) * 1000 + @divFloor (@as (i64 , clock .nsec ), 1_000_000 );
3952 }
4053}
4154
@@ -48,22 +61,50 @@ pub fn milliTimestamp() i64 {
4861pub fn sleep (ns : u64 ) void {
4962 const s : isize = @intCast (ns / std .time .ns_per_s );
5063 const remaining_ns : isize = @intCast (ns % std .time .ns_per_s );
51- var ts = std.posix .timespec { .sec = s , .nsec = remaining_ns };
64+ var ts : std.c .timespec = . { .sec = s , .nsec = remaining_ns };
5265 while (true ) {
5366 const rc = std .c .nanosleep (& ts , & ts );
54- switch (std .c .errno (rc )) {
55- .SUCCESS = > break ,
56- .INTR = > continue ,
57- else = > break ,
58- }
67+ if (rc == 0 ) break ;
68+ // On EINTR, retry with remaining time
69+ continue ;
5970 }
6071}
6172
6273// ============================================================
63- // Mutex (std.Thread.Mutex still exists in 0.16 but may move)
74+ // Mutex (std.Thread.Mutex removed in 0.16-dev.2736+)
75+ // Uses simple spinlock via atomics since std.Io.Mutex needs Io.
6476// ============================================================
6577
66- pub const Mutex = std .Thread .Mutex ;
78+ /// Simple spinlock mutex for use without Io.
79+ /// Replaces std.Thread.Mutex which was removed in Zig 0.16.
80+ pub const Mutex = struct {
81+ state : std .atomic .Value (u32 ) = std .atomic .Value (u32 ).init (0 ),
82+
83+ pub fn lock (self : * Mutex ) void {
84+ while (self .state .cmpxchgWeak (0 , 1 , .acquire , .monotonic ) != null ) {
85+ // Spin
86+ std .atomic .spinLoopHint ();
87+ }
88+ }
89+
90+ pub fn unlock (self : * Mutex ) void {
91+ self .state .store (0 , .release );
92+ }
93+
94+ pub fn tryLock (self : * Mutex ) bool {
95+ return self .state .cmpxchgStrong (0 , 1 , .acquire , .monotonic ) == null ;
96+ }
97+ };
98+
99+ // ============================================================
100+ // File descriptor close wrapper
101+ // ============================================================
102+
103+ /// Close a file descriptor using libc.
104+ /// Replaces std.posix.close() which was removed in Zig 0.16.
105+ fn closeFd (fd : std.posix.fd_t ) void {
106+ _ = std .c .close (fd );
107+ }
67108
68109// ============================================================
69110// File I/O helpers (std.fs.cwd() removed, needs std.Io now)
@@ -79,7 +120,7 @@ pub fn readFileAlloc(allocator: std.mem.Allocator, path: []const u8) ![]const u8
79120 if (err == error .FileNotFound ) return error .FileNotFound ;
80121 return err ;
81122 };
82- defer std . posix . close (fd );
123+ defer closeFd (fd );
83124
84125 // Read file in chunks
85126 var result = std .ArrayList (u8 ).empty ;
@@ -106,7 +147,7 @@ pub fn writeFile(allocator: std.mem.Allocator, path: []const u8, content: []cons
106147 .CREAT = true ,
107148 .TRUNC = true ,
108149 }, 0o644 ) catch | err | return err ;
109- defer std . posix . close (fd );
150+ defer closeFd (fd );
110151
111152 var remaining = content ;
112153 while (remaining .len > 0 ) {
@@ -274,7 +315,7 @@ pub fn spawnAndWait(
274315 const dev_null : [* :0 ]const u8 = "/dev/null" ;
275316 const null_fd = std .posix .openatZ (std .posix .AT .FDCWD , dev_null , .{ .ACCMODE = .WRONLY }, 0 ) catch std .process .exit (127 );
276317 if (std .c .dup2 (null_fd , 1 ) < 0 ) std .process .exit (127 );
277- std . posix . close (null_fd );
318+ closeFd (null_fd );
278319 },
279320 else = > {},
280321 }
@@ -285,7 +326,7 @@ pub fn spawnAndWait(
285326 const dev_null : [* :0 ]const u8 = "/dev/null" ;
286327 const null_fd = std .posix .openatZ (std .posix .AT .FDCWD , dev_null , .{ .ACCMODE = .WRONLY }, 0 ) catch std .process .exit (127 );
287328 if (std .c .dup2 (null_fd , 2 ) < 0 ) std .process .exit (127 );
288- std . posix . close (null_fd );
329+ closeFd (null_fd );
289330 },
290331 else = > {},
291332 }
0 commit comments