build(zig-0.16): port windows backend to zig-0.16
This commit is contained in:
parent
5c863fbb4a
commit
69b705f8ea
2 changed files with 44 additions and 21 deletions
|
|
@ -13,6 +13,23 @@ pub const emits_subtree_created_on_movein = true;
|
||||||
|
|
||||||
const windows = std.os.windows;
|
const windows = std.os.windows;
|
||||||
|
|
||||||
|
// Types removed from std.os.windows in zig-0.16.
|
||||||
|
const OVERLAPPED = extern struct {
|
||||||
|
Internal: windows.ULONG_PTR = 0,
|
||||||
|
InternalHigh: windows.ULONG_PTR = 0,
|
||||||
|
Offset: windows.DWORD = 0,
|
||||||
|
OffsetHigh: windows.DWORD = 0,
|
||||||
|
hEvent: ?windows.HANDLE = null,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Constants removed from std.os.windows in zig-0.16.
|
||||||
|
const GENERIC_READ: windows.DWORD = 0x80000000;
|
||||||
|
const FILE_SHARE_READ: windows.DWORD = 0x00000001;
|
||||||
|
const FILE_SHARE_WRITE: windows.DWORD = 0x00000002;
|
||||||
|
const FILE_SHARE_DELETE: windows.DWORD = 0x00000004;
|
||||||
|
const OPEN_EXISTING: windows.DWORD = 3;
|
||||||
|
const INFINITE: windows.DWORD = 0xFFFFFFFF;
|
||||||
|
|
||||||
const win32 = struct {
|
const win32 = struct {
|
||||||
pub extern "kernel32" fn CloseHandle(hObject: windows.HANDLE) callconv(.winapi) windows.BOOL;
|
pub extern "kernel32" fn CloseHandle(hObject: windows.HANDLE) callconv(.winapi) windows.BOOL;
|
||||||
pub extern "kernel32" fn ReadDirectoryChangesW(
|
pub extern "kernel32" fn ReadDirectoryChangesW(
|
||||||
|
|
@ -22,14 +39,14 @@ const win32 = struct {
|
||||||
bWatchSubtree: windows.BOOL,
|
bWatchSubtree: windows.BOOL,
|
||||||
dwNotifyFilter: windows.DWORD,
|
dwNotifyFilter: windows.DWORD,
|
||||||
lpBytesReturned: ?*windows.DWORD,
|
lpBytesReturned: ?*windows.DWORD,
|
||||||
lpOverlapped: ?*windows.OVERLAPPED,
|
lpOverlapped: ?*OVERLAPPED,
|
||||||
lpCompletionRoutine: ?*anyopaque,
|
lpCompletionRoutine: ?*anyopaque,
|
||||||
) callconv(.winapi) windows.BOOL;
|
) callconv(.winapi) windows.BOOL;
|
||||||
pub extern "kernel32" fn GetQueuedCompletionStatus(
|
pub extern "kernel32" fn GetQueuedCompletionStatus(
|
||||||
CompletionPort: windows.HANDLE,
|
CompletionPort: windows.HANDLE,
|
||||||
lpNumberOfBytesTransferred: *windows.DWORD,
|
lpNumberOfBytesTransferred: *windows.DWORD,
|
||||||
lpCompletionKey: *windows.ULONG_PTR,
|
lpCompletionKey: *windows.ULONG_PTR,
|
||||||
lpOverlapped: *?*windows.OVERLAPPED,
|
lpOverlapped: *?*OVERLAPPED,
|
||||||
dwMilliseconds: windows.DWORD,
|
dwMilliseconds: windows.DWORD,
|
||||||
) callconv(.winapi) windows.BOOL;
|
) callconv(.winapi) windows.BOOL;
|
||||||
pub extern "kernel32" fn CreateFileW(
|
pub extern "kernel32" fn CreateFileW(
|
||||||
|
|
@ -45,9 +62,15 @@ const win32 = struct {
|
||||||
CompletionPort: windows.HANDLE,
|
CompletionPort: windows.HANDLE,
|
||||||
dwNumberOfBytesTransferred: windows.DWORD,
|
dwNumberOfBytesTransferred: windows.DWORD,
|
||||||
dwCompletionKey: windows.ULONG_PTR,
|
dwCompletionKey: windows.ULONG_PTR,
|
||||||
lpOverlapped: ?*windows.OVERLAPPED,
|
lpOverlapped: ?*OVERLAPPED,
|
||||||
) callconv(.winapi) windows.BOOL;
|
) callconv(.winapi) windows.BOOL;
|
||||||
pub extern "kernel32" fn GetFileAttributesW(lpFileName: [*:0]const windows.WCHAR) callconv(.winapi) windows.DWORD;
|
pub extern "kernel32" fn GetFileAttributesW(lpFileName: [*:0]const windows.WCHAR) callconv(.winapi) windows.DWORD;
|
||||||
|
pub extern "kernel32" fn CreateIoCompletionPort(
|
||||||
|
FileHandle: windows.HANDLE,
|
||||||
|
ExistingCompletionPort: ?windows.HANDLE,
|
||||||
|
CompletionKey: windows.ULONG_PTR,
|
||||||
|
NumberOfConcurrentThreads: windows.DWORD,
|
||||||
|
) callconv(.winapi) ?windows.HANDLE;
|
||||||
};
|
};
|
||||||
|
|
||||||
handler: *Handler,
|
handler: *Handler,
|
||||||
|
|
@ -64,7 +87,7 @@ const SHUTDOWN_KEY: windows.ULONG_PTR = 0;
|
||||||
const Watch = struct {
|
const Watch = struct {
|
||||||
handle: windows.HANDLE,
|
handle: windows.HANDLE,
|
||||||
buf: Buf,
|
buf: Buf,
|
||||||
overlapped: windows.OVERLAPPED,
|
overlapped: OVERLAPPED,
|
||||||
path: []u8, // owned
|
path: []u8, // owned
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -92,7 +115,7 @@ const notify_filter: windows.DWORD =
|
||||||
0x00000040; // FILE_NOTIFY_CHANGE_CREATION
|
0x00000040; // FILE_NOTIFY_CHANGE_CREATION
|
||||||
|
|
||||||
pub fn init(io: std.Io, handler: *Handler) !@This() {
|
pub fn init(io: std.Io, handler: *Handler) !@This() {
|
||||||
const iocp = try windows.CreateIoCompletionPort(windows.INVALID_HANDLE_VALUE, null, 0, 1);
|
const iocp = win32.CreateIoCompletionPort(windows.INVALID_HANDLE_VALUE, null, 0, 1) orelse return error.SystemResources;
|
||||||
return .{ .handler = handler, .io = io, .iocp = iocp, .thread = null, .watches = .empty, .watches_mutex = std.Io.Mutex.init, .path_types = .empty };
|
return .{ .handler = handler, .io = io, .iocp = iocp, .thread = null, .watches = .empty, .watches_mutex = std.Io.Mutex.init, .path_types = .empty };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -131,11 +154,11 @@ fn thread_fn(
|
||||||
) void {
|
) void {
|
||||||
var bytes: windows.DWORD = 0;
|
var bytes: windows.DWORD = 0;
|
||||||
var key: windows.ULONG_PTR = 0;
|
var key: windows.ULONG_PTR = 0;
|
||||||
var overlapped_ptr: ?*windows.OVERLAPPED = null;
|
var overlapped_ptr: ?*OVERLAPPED = null;
|
||||||
while (true) {
|
while (true) {
|
||||||
// Block indefinitely until IOCP has a completion or shutdown signal.
|
// Block indefinitely until IOCP has a completion or shutdown signal.
|
||||||
const ok = win32.GetQueuedCompletionStatus(iocp, &bytes, &key, &overlapped_ptr, windows.INFINITE);
|
const ok = win32.GetQueuedCompletionStatus(iocp, &bytes, &key, &overlapped_ptr, INFINITE);
|
||||||
if (ok == 0 or key == SHUTDOWN_KEY) return;
|
if (ok == .FALSE or key == SHUTDOWN_KEY) return;
|
||||||
const triggered_handle: windows.HANDLE = @ptrFromInt(key);
|
const triggered_handle: windows.HANDLE = @ptrFromInt(key);
|
||||||
watches_mutex.lockUncancelable(io);
|
watches_mutex.lockUncancelable(io);
|
||||||
var it = watches.iterator();
|
var it = watches.iterator();
|
||||||
|
|
@ -303,8 +326,8 @@ fn thread_fn(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Re-arm ReadDirectoryChangesW for the next batch.
|
// Re-arm ReadDirectoryChangesW for the next batch.
|
||||||
w.overlapped = std.mem.zeroes(windows.OVERLAPPED);
|
w.overlapped = std.mem.zeroes(OVERLAPPED);
|
||||||
if (win32.ReadDirectoryChangesW(w.handle, w.buf.ptr, buf_size, 1, notify_filter, null, &w.overlapped, null) == 0)
|
if (win32.ReadDirectoryChangesW(w.handle, w.buf.ptr, buf_size, .TRUE, notify_filter, null, &w.overlapped, null) == .FALSE)
|
||||||
std.log.err("nightwatch: ReadDirectoryChangesW re-arm failed for {s}, future events lost", .{entry.key_ptr.*});
|
std.log.err("nightwatch: ReadDirectoryChangesW re-arm failed for {s}, future events lost", .{entry.key_ptr.*});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -320,16 +343,16 @@ pub fn add_watch(self: *@This(), allocator: std.mem.Allocator, path: []const u8)
|
||||||
defer allocator.free(path_w);
|
defer allocator.free(path_w);
|
||||||
const handle = win32.CreateFileW(
|
const handle = win32.CreateFileW(
|
||||||
path_w,
|
path_w,
|
||||||
windows.GENERIC_READ,
|
GENERIC_READ,
|
||||||
windows.FILE_SHARE_READ | windows.FILE_SHARE_WRITE | windows.FILE_SHARE_DELETE,
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||||
null,
|
null,
|
||||||
windows.OPEN_EXISTING,
|
OPEN_EXISTING,
|
||||||
0x02000000 | 0x40000000, // FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED
|
0x02000000 | 0x40000000, // FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED
|
||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
if (handle == windows.INVALID_HANDLE_VALUE) return error.WatchFailed;
|
if (handle == windows.INVALID_HANDLE_VALUE) return error.WatchFailed;
|
||||||
errdefer _ = win32.CloseHandle(handle);
|
errdefer _ = win32.CloseHandle(handle);
|
||||||
_ = windows.CreateIoCompletionPort(handle, self.iocp, @intFromPtr(handle), 0) catch return error.WatchFailed;
|
_ = win32.CreateIoCompletionPort(handle, self.iocp, @intFromPtr(handle), 0) orelse return error.WatchFailed;
|
||||||
const buf = try allocator.alignedAlloc(u8, .fromByteUnits(4), buf_size);
|
const buf = try allocator.alignedAlloc(u8, .fromByteUnits(4), buf_size);
|
||||||
errdefer allocator.free(buf);
|
errdefer allocator.free(buf);
|
||||||
const owned_path = try allocator.dupe(u8, path);
|
const owned_path = try allocator.dupe(u8, path);
|
||||||
|
|
@ -338,8 +361,8 @@ pub fn add_watch(self: *@This(), allocator: std.mem.Allocator, path: []const u8)
|
||||||
// if the watches map is resized by a concurrent add_watch call.
|
// if the watches map is resized by a concurrent add_watch call.
|
||||||
const w = try allocator.create(Watch);
|
const w = try allocator.create(Watch);
|
||||||
errdefer allocator.destroy(w);
|
errdefer allocator.destroy(w);
|
||||||
w.* = .{ .handle = handle, .buf = buf, .overlapped = std.mem.zeroes(windows.OVERLAPPED), .path = owned_path };
|
w.* = .{ .handle = handle, .buf = buf, .overlapped = std.mem.zeroes(OVERLAPPED), .path = owned_path };
|
||||||
if (win32.ReadDirectoryChangesW(handle, buf.ptr, buf_size, 1, notify_filter, null, &w.overlapped, null) == 0)
|
if (win32.ReadDirectoryChangesW(handle, buf.ptr, buf_size, .TRUE, notify_filter, null, &w.overlapped, null) == .FALSE)
|
||||||
return error.WatchFailed;
|
return error.WatchFailed;
|
||||||
try self.watches.put(allocator, owned_path, w);
|
try self.watches.put(allocator, owned_path, w);
|
||||||
// Seed path_types with pre-existing entries so delete/rename events for
|
// Seed path_types with pre-existing entries so delete/rename events for
|
||||||
|
|
|
||||||
10
src/main.zig
10
src/main.zig
|
|
@ -133,19 +133,19 @@ var win_shutdown = std.atomic.Value(bool).init(false);
|
||||||
fn win_ctrl_handler(ctrl_type: std.os.windows.DWORD) callconv(.winapi) std.os.windows.BOOL {
|
fn win_ctrl_handler(ctrl_type: std.os.windows.DWORD) callconv(.winapi) std.os.windows.BOOL {
|
||||||
_ = ctrl_type;
|
_ = ctrl_type;
|
||||||
win_shutdown.store(true, .release);
|
win_shutdown.store(true, .release);
|
||||||
return std.os.windows.TRUE;
|
return .TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_windows() void {
|
fn run_windows(io: std.Io) void {
|
||||||
const SetConsoleCtrlHandler = struct {
|
const SetConsoleCtrlHandler = struct {
|
||||||
extern "kernel32" fn SetConsoleCtrlHandler(
|
extern "kernel32" fn SetConsoleCtrlHandler(
|
||||||
HandlerRoutine: ?*const fn (std.os.windows.DWORD) callconv(.winapi) std.os.windows.BOOL,
|
HandlerRoutine: ?*const fn (std.os.windows.DWORD) callconv(.winapi) std.os.windows.BOOL,
|
||||||
Add: std.os.windows.BOOL,
|
Add: std.os.windows.BOOL,
|
||||||
) callconv(.winapi) std.os.windows.BOOL;
|
) callconv(.winapi) std.os.windows.BOOL;
|
||||||
}.SetConsoleCtrlHandler;
|
}.SetConsoleCtrlHandler;
|
||||||
_ = SetConsoleCtrlHandler(win_ctrl_handler, std.os.windows.TRUE);
|
_ = SetConsoleCtrlHandler(win_ctrl_handler, .TRUE);
|
||||||
while (!win_shutdown.load(.acquire)) {
|
while (!win_shutdown.load(.acquire)) {
|
||||||
std.Thread.sleep(50 * std.time.ns_per_ms);
|
std.Io.sleep(io, std.Io.Duration.fromMilliseconds(50), .awake) catch {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -309,7 +309,7 @@ pub fn main(init: std.process.Init) !void {
|
||||||
if (Watcher.interface_type == .polling) {
|
if (Watcher.interface_type == .polling) {
|
||||||
try run_linux(&watcher);
|
try run_linux(&watcher);
|
||||||
} else if (builtin.os.tag == .windows) {
|
} else if (builtin.os.tag == .windows) {
|
||||||
run_windows();
|
run_windows(init.io);
|
||||||
} else if (is_posix) {
|
} else if (is_posix) {
|
||||||
run_posix();
|
run_posix();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue