33//! for maximum parallelism — completely bypasses std.http.Client and std.Io.
44//! On Windows: uses std.http.Client per probe thread (Winsock API not fully wrapped in Zig 0.16).
55//! A background ticker thread provides real-time progress display.
6+ //!
7+ //! Cross-compilation note: native_os (builtin.os.tag) is a comptime constant, so
8+ //! `if (native_os == .windows) return;` guards prevent the dead POSIX branch from
9+ //! being type-checked on Windows, avoiding errors from unavailable libc symbols.
610
711const std = @import ("std" );
812const builtin = @import ("builtin" );
@@ -46,7 +50,10 @@ const TickerContext = struct {
4650};
4751
4852/// Background thread that refreshes the progress display at a fixed interval.
53+ /// POSIX-only: uses clock_gettime, nanosleep, and write(2).
4954fn tickerThread (ctx : * TickerContext ) void {
55+ if (native_os == .windows ) return ;
56+
5057 var latency_buf : [64 ]u8 = undefined ;
5158 var msg_buf : [256 ]u8 = undefined ;
5259 const req : std.c.timespec = .{ .sec = 0 , .nsec = 100_000_000 }; // 100ms
@@ -69,6 +76,12 @@ fn tickerThread(ctx: *TickerContext) void {
6976/// POSIX implementation — raw TCP connect
7077/// ============================================================
7178fn probeThreadMainPosix (ctx : * ProbeThreadContext ) void {
79+ if (native_os == .windows ) {
80+ // Never called on Windows (comptime switch in probeThreadMain),
81+ // but guard prevents body from being type-checked on Windows.
82+ _ = ctx .done .fetchAdd (1 , .monotonic );
83+ return ;
84+ }
7285 defer _ = ctx .done .fetchAdd (1 , .monotonic );
7386
7487 // Parse URL to extract host and port
@@ -270,19 +283,21 @@ pub fn probeAll(
270283 var done = std .atomic .Value (usize ).init (0 );
271284 var time_buf : [64 ]u8 = undefined ;
272285
273- // Capture start time
274- var start_ts : std.c.timespec = undefined ;
275- _ = std .c .clock_gettime (.MONOTONIC , & start_ts );
276- const start_ns : i96 = @as (i96 , start_ts .sec ) * 1_000_000_000 + start_ts .nsec ;
286+ // Capture start time (POSIX: clock_gettime, Windows: zero — ticker is skipped)
287+ const start_ns : i96 = if (native_os == .windows ) 0 else ns : {
288+ var ts : std.c.timespec = undefined ;
289+ _ = std .c .clock_gettime (.MONOTONIC , & ts );
290+ break :ns @as (i96 , ts .sec ) * 1_000_000_000 + ts .nsec ;
291+ };
277292
278- // Spawn background ticker thread for dynamic progress display
293+ // Spawn background ticker thread for dynamic progress display (POSIX only)
279294 var ticker_ctx : TickerContext = .{
280295 .total = total ,
281296 .done = & done ,
282297 .start_ns = start_ns ,
283298 .stop = std .atomic .Value (bool ).init (false ),
284299 };
285- const ticker = if (progress_writer != null )
300+ const ticker = if (progress_writer != null and native_os != .windows )
286301 std .Thread .spawn (.{}, tickerThread , .{& ticker_ctx }) catch null
287302 else
288303 null ;
@@ -346,12 +361,16 @@ pub fn probeAll(
346361 }
347362
348363 if (progress_writer ) | pw | {
349- var end_ts : std.c.timespec = undefined ;
350- _ = std .c .clock_gettime (.MONOTONIC , & end_ts );
351- const end_ns : i96 = @as (i96 , end_ts .sec ) * 1_000_000_000 + end_ts .nsec ;
352- const elapsed_ns : u64 = if (end_ns > start_ns ) @intCast (end_ns - start_ns ) else 0 ;
353- const elapsed_str = formatLatency (& time_buf , elapsed_ns );
354- try pw .print ("\x1b [2K\r Probing: done ({d} sources, {s})\n " , .{ total , elapsed_str });
364+ if (native_os == .windows ) {
365+ try pw .print ("\x1b [2K\r Probing: done ({d} sources)\n " , .{total });
366+ } else {
367+ var end_ts : std.c.timespec = undefined ;
368+ _ = std .c .clock_gettime (.MONOTONIC , & end_ts );
369+ const end_ns : i96 = @as (i96 , end_ts .sec ) * 1_000_000_000 + end_ts .nsec ;
370+ const elapsed_ns : u64 = if (end_ns > start_ns ) @intCast (end_ns - start_ns ) else 0 ;
371+ const elapsed_str = formatLatency (& time_buf , elapsed_ns );
372+ try pw .print ("\x1b [2K\r Probing: done ({d} sources, {s})\n " , .{ total , elapsed_str });
373+ }
355374 try pw .flush ();
356375 }
357376}
0 commit comments