more fixes for windows and wasi

master
Andrew Kelley 2019-05-27 01:35:58 -04:00
parent 6be79d79aa
commit 129714d077
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
12 changed files with 92 additions and 71 deletions

View File

@ -616,7 +616,6 @@ set(ZIG_STD_FILES
"os/bits/wasi.zig"
"os/bits/windows.zig"
"os/darwin.zig"
"os/epoch.zig"
"os/freebsd.zig"
"os/linux.zig"
"os/linux/arm64.zig"
@ -723,6 +722,7 @@ set(ZIG_STD_FILES
"testing.zig"
"thread.zig"
"time.zig"
"time/epoch.zig"
"unicode.zig"
"valgrind.zig"
"valgrind/callgrind.zig"

View File

@ -32,7 +32,7 @@ pub const Loop = struct {
overlapped: Overlapped,
pub const overlapped_init = switch (builtin.os) {
builtin.Os.windows => windows.OVERLAPPED{
.windows => windows.OVERLAPPED{
.Internal = 0,
.InternalHigh = 0,
.Offset = 0,
@ -50,13 +50,13 @@ pub const Loop = struct {
};
pub const EventFd = switch (builtin.os) {
builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => KEventFd,
builtin.Os.linux => struct {
.macosx, .freebsd, .netbsd => KEventFd,
.linux => struct {
base: ResumeNode,
epoll_op: u32,
eventfd: i32,
},
builtin.Os.windows => struct {
.windows => struct {
base: ResumeNode,
completion_key: usize,
},
@ -69,11 +69,11 @@ pub const Loop = struct {
};
pub const Basic = switch (builtin.os) {
builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => KEventBasic,
builtin.Os.linux => struct {
.macosx, .freebsd, .netbsd => KEventBasic,
.linux => struct {
base: ResumeNode,
},
builtin.Os.windows => struct {
.windows => struct {
base: ResumeNode,
},
else => @compileError("unsupported OS"),
@ -147,7 +147,7 @@ pub const Loop = struct {
fn initOsData(self: *Loop, extra_thread_count: usize) InitOsDataError!void {
switch (builtin.os) {
builtin.Os.linux => {
.linux => {
self.os_data.fs_queue = std.atomic.Queue(fs.Request).init();
self.os_data.fs_queue_item = 0;
// we need another thread for the file system because Linux does not have an async
@ -221,7 +221,7 @@ pub const Loop = struct {
self.extra_threads[extra_thread_index] = try Thread.spawn(self, workerRun);
}
},
builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
.macosx, .freebsd, .netbsd => {
self.os_data.kqfd = try os.bsdKQueue();
errdefer os.close(self.os_data.kqfd);
@ -325,14 +325,14 @@ pub const Loop = struct {
self.extra_threads[extra_thread_index] = try Thread.spawn(self, workerRun);
}
},
builtin.Os.windows => {
self.os_data.io_port = try os.windowsCreateIoCompletionPort(
.windows => {
self.os_data.io_port = try windows.CreateIoCompletionPort(
windows.INVALID_HANDLE_VALUE,
null,
undefined,
maxInt(windows.DWORD),
);
errdefer os.close(self.os_data.io_port);
errdefer windows.CloseHandle(self.os_data.io_port);
for (self.eventfd_resume_nodes) |*eventfd_node, i| {
eventfd_node.* = std.atomic.Stack(ResumeNode.EventFd).Node{
@ -361,7 +361,7 @@ pub const Loop = struct {
while (i < extra_thread_index) : (i += 1) {
while (true) {
const overlapped = &self.final_resume_node.overlapped;
os.windowsPostQueuedCompletionStatus(self.os_data.io_port, undefined, undefined, overlapped) catch continue;
windows.PostQueuedCompletionStatus(self.os_data.io_port, undefined, undefined, overlapped) catch continue;
break;
}
}
@ -380,18 +380,18 @@ pub const Loop = struct {
fn deinitOsData(self: *Loop) void {
switch (builtin.os) {
builtin.Os.linux => {
.linux => {
os.close(self.os_data.final_eventfd);
while (self.available_eventfd_resume_nodes.pop()) |node| os.close(node.data.eventfd);
os.close(self.os_data.epollfd);
self.allocator.free(self.eventfd_resume_nodes);
},
builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
.macosx, .freebsd, .netbsd => {
os.close(self.os_data.kqfd);
os.close(self.os_data.fs_kqfd);
},
builtin.Os.windows => {
os.close(self.os_data.io_port);
.windows => {
windows.CloseHandle(self.os_data.io_port);
},
else => {},
}
@ -501,7 +501,7 @@ pub const Loop = struct {
const eventfd_node = &resume_stack_node.data;
eventfd_node.base.handle = next_tick_node.data;
switch (builtin.os) {
builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
.macosx, .freebsd, .netbsd => {
const kevent_array = (*const [1]os.Kevent)(&eventfd_node.kevent);
const empty_kevs = ([*]os.Kevent)(undefined)[0..0];
_ = os.bsdKEvent(self.os_data.kqfd, kevent_array, empty_kevs, null) catch {
@ -510,7 +510,7 @@ pub const Loop = struct {
return;
};
},
builtin.Os.linux => {
.linux => {
// the pending count is already accounted for
const epoll_events = os.EPOLLONESHOT | os.linux.EPOLLIN | os.linux.EPOLLOUT |
os.linux.EPOLLET;
@ -525,8 +525,8 @@ pub const Loop = struct {
return;
};
},
builtin.Os.windows => {
os.windowsPostQueuedCompletionStatus(
.windows => {
windows.PostQueuedCompletionStatus(
self.os_data.io_port,
undefined,
undefined,
@ -623,13 +623,13 @@ pub const Loop = struct {
if (prev == 1) {
// cause all the threads to stop
switch (builtin.os) {
builtin.Os.linux => {
.linux => {
self.posixFsRequest(&self.os_data.fs_end_request);
// writing 8 bytes to an eventfd cannot fail
os.write(self.os_data.final_eventfd, wakeup_bytes) catch unreachable;
return;
},
builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
.macosx, .freebsd, .netbsd => {
self.posixFsRequest(&self.os_data.fs_end_request);
const final_kevent = (*const [1]os.Kevent)(&self.os_data.final_kevent);
const empty_kevs = ([*]os.Kevent)(undefined)[0..0];
@ -637,12 +637,12 @@ pub const Loop = struct {
_ = os.bsdKEvent(self.os_data.kqfd, final_kevent, empty_kevs, null) catch unreachable;
return;
},
builtin.Os.windows => {
.windows => {
var i: usize = 0;
while (i < self.extra_threads.len + 1) : (i += 1) {
while (true) {
const overlapped = &self.final_resume_node.overlapped;
os.windowsPostQueuedCompletionStatus(self.os_data.io_port, undefined, undefined, overlapped) catch continue;
windows.PostQueuedCompletionStatus(self.os_data.io_port, undefined, undefined, overlapped) catch continue;
break;
}
}
@ -663,7 +663,7 @@ pub const Loop = struct {
}
switch (builtin.os) {
builtin.Os.linux => {
.linux => {
// only process 1 event so we don't steal from other threads
var events: [1]os.linux.epoll_event = undefined;
const count = os.epoll_wait(self.os_data.epollfd, events[0..], -1);
@ -687,7 +687,7 @@ pub const Loop = struct {
}
}
},
builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
.macosx, .freebsd, .netbsd => {
var eventlist: [1]os.Kevent = undefined;
const empty_kevs = ([*]os.Kevent)(undefined)[0..0];
const count = os.bsdKEvent(self.os_data.kqfd, empty_kevs, eventlist[0..], null) catch unreachable;
@ -713,16 +713,16 @@ pub const Loop = struct {
}
}
},
builtin.Os.windows => {
.windows => {
var completion_key: usize = undefined;
const overlapped = while (true) {
var nbytes: windows.DWORD = undefined;
var overlapped: ?*windows.OVERLAPPED = undefined;
switch (os.windowsGetQueuedCompletionStatus(self.os_data.io_port, &nbytes, &completion_key, &overlapped, windows.INFINITE)) {
os.WindowsWaitResult.Aborted => return,
os.WindowsWaitResult.Normal => {},
os.WindowsWaitResult.EOF => {},
os.WindowsWaitResult.Cancelled => continue,
switch (windows.GetQueuedCompletionStatus(self.os_data.io_port, &nbytes, &completion_key, &overlapped, windows.INFINITE)) {
.Aborted => return,
.Normal => {},
.EOF => {},
.Cancelled => continue,
}
if (overlapped) |o| break o;
} else unreachable; // TODO else unreachable should not be necessary
@ -831,9 +831,9 @@ pub const Loop = struct {
}
const OsData = switch (builtin.os) {
builtin.Os.linux => LinuxOsData,
builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => KEventData,
builtin.Os.windows => struct {
.linux => LinuxOsData,
.macosx, .freebsd, .netbsd => KEventData,
.windows => struct {
io_port: windows.HANDLE,
extra_thread_count: usize,
},

View File

@ -23,7 +23,7 @@ pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataD
&dir_path_ptr,
)) {
os.windows.S_OK => {
defer os.windows.CoTaskMemFree(@ptrCast(*c_void, dir_path_ptr));
defer os.windows.ole32.CoTaskMemFree(@ptrCast(*c_void, dir_path_ptr));
const global_dir = unicode.utf16leToUtf8Alloc(allocator, utf16lePtrSlice(dir_path_ptr)) catch |err| switch (err) {
error.UnexpectedSecondSurrogateHalf => return error.AppDataDirUnavailable,
error.ExpectedSecondSurrogateHalf => return error.AppDataDirUnavailable,

View File

@ -261,7 +261,7 @@ pub const HeapAllocator = switch (builtin.os) {
pub fn deinit(self: *HeapAllocator) void {
if (self.heap_handle) |heap_handle| {
_ = os.windows.HeapDestroy(heap_handle);
os.windows.HeapDestroy(heap_handle);
}
}
@ -274,12 +274,12 @@ pub const HeapAllocator = switch (builtin.os) {
const optional_heap_handle = @atomicLoad(?HeapHandle, &self.heap_handle, builtin.AtomicOrder.SeqCst);
const heap_handle = optional_heap_handle orelse blk: {
const options = if (builtin.single_threaded) os.windows.HEAP_NO_SERIALIZE else 0;
const hh = os.windows.HeapCreate(options, amt, 0) orelse return error.OutOfMemory;
const hh = os.windows.kernel32.HeapCreate(options, amt, 0) orelse return error.OutOfMemory;
const other_hh = @cmpxchgStrong(?HeapHandle, &self.heap_handle, null, hh, builtin.AtomicOrder.SeqCst, builtin.AtomicOrder.SeqCst) orelse break :blk hh;
_ = os.windows.HeapDestroy(hh);
os.windows.HeapDestroy(hh);
break :blk other_hh.?; // can't be null because of the cmpxchg
};
const ptr = os.windows.HeapAlloc(heap_handle, 0, amt) orelse return error.OutOfMemory;
const ptr = os.windows.kernel32.HeapAlloc(heap_handle, 0, amt) orelse return error.OutOfMemory;
const root_addr = @ptrToInt(ptr);
const adjusted_addr = mem.alignForward(root_addr, alignment);
const record_addr = adjusted_addr + n;
@ -309,12 +309,12 @@ pub const HeapAllocator = switch (builtin.os) {
const old_ptr = @intToPtr(*c_void, root_addr);
if (new_size == 0) {
if (os.windows.HeapFree(self.heap_handle.?, 0, old_ptr) == 0) unreachable;
os.windows.HeapFree(self.heap_handle.?, 0, old_ptr);
return old_mem[0..0];
}
const amt = new_size + new_align + @sizeOf(usize);
const new_ptr = os.windows.HeapReAlloc(
const new_ptr = os.windows.kernel32.HeapReAlloc(
self.heap_handle.?,
0,
old_ptr,

View File

@ -944,7 +944,7 @@ pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) RenameError!void {
/// Assumes target is Windows.
pub fn renameW(old_path: [*]const u16, new_path: [*]const u16) RenameError!void {
const flags = windows.MOVEFILE_REPLACE_EXISTING | windows.MOVEFILE_WRITE_THROUGH;
return windows.MoveFileExW(old_path_w, new_path_w, flags);
return windows.MoveFileExW(old_path, new_path, flags);
}
pub const MakeDirError = error{
@ -959,6 +959,8 @@ pub const MakeDirError = error{
NoSpaceLeft,
NotDir,
ReadOnlyFileSystem,
InvalidUtf8,
BadPathName,
Unexpected,
};
@ -2227,6 +2229,9 @@ pub const RealPathError = error{
BadPathName,
DeviceBusy,
SharingViolation,
PipeBusy,
/// On Windows, file paths must be valid Unicode.
InvalidUtf8,
@ -2294,7 +2299,7 @@ pub fn realpathW(pathname: [*]const u16, out_buffer: *[MAX_PATH_BYTES]u8) RealPa
var wide_buf: [windows.PATH_MAX_WIDE]u16 = undefined;
const wide_len = try windows.GetFinalPathNameByHandleW(h_file, &wide_buf, wide_buf.len, windows.VOLUME_NAME_DOS);
assert(wide_len <= wide_buf.len);
const wide_slice = wide_len[0..wide_len];
const wide_slice = wide_buf[0..wide_len];
// Windows returns \\?\ prepended to the path.
// We strip it to make this function consistent across platforms.
@ -2311,13 +2316,13 @@ pub fn nanosleep(seconds: u64, nanoseconds: u64) void {
if (windows.is_the_target and !builtin.link_libc) {
// TODO https://github.com/ziglang/zig/issues/1284
const small_s = math.cast(windows.DWORD, seconds) catch math.maxInt(windows.DWORD);
const ms_from_s = math.mul(small_s, std.time.ms_per_s) catch math.maxInt(windows.DWORD);
const ms_from_s = math.mul(windows.DWORD, small_s, std.time.ms_per_s) catch math.maxInt(windows.DWORD);
const ns_per_ms = std.time.ns_per_s / std.time.ms_per_s;
const big_ms_from_ns = nanoseconds / ns_per_ms;
const ms_from_ns = math.cast(windows.DWORD, big_ms_from_ns) catch math.maxInt(windows.DWORD);
const ms = math.add(ms_from_s, ms_from_ns) catch math.maxInt(windows.DWORD);
const ms = math.add(windows.DWORD, ms_from_s, ms_from_ns) catch math.maxInt(windows.DWORD);
windows.kernel32.Sleep(ms);
return;
}

View File

@ -1,5 +1,3 @@
use @import("../bits.zig");
pub const STDIN_FILENO = 0;
pub const STDOUT_FILENO = 1;
pub const STDERR_FILENO = 2;
@ -12,8 +10,6 @@ pub const ADVICE_WILLNEED: advice_t = 3;
pub const ADVICE_DONTNEED: advice_t = 4;
pub const ADVICE_NOREUSE: advice_t = 5;
pub const ciovec_t = iovec_const;
pub const clockid_t = u32;
pub const CLOCK_REALTIME: clockid_t = 0;
pub const CLOCK_MONOTONIC: clockid_t = 1;
@ -182,8 +178,6 @@ pub const FILESTAT_SET_MTIM_NOW: fstflags_t = 0x0008;
pub const inode_t = u64;
pub const iovec_t = iovec;
pub const linkcount_t = u32;
pub const lookupflags_t = u32;

View File

@ -5,6 +5,13 @@ use @import("../windows/bits.zig");
pub const fd_t = HANDLE;
pub const pid_t = HANDLE;
pub const time_t = c_longlong;
pub const timespec = extern struct {
tv_sec: time_t,
tv_nsec: c_long,
};
pub const sig_atomic_t = c_int;
/// maximum signal number + 1
@ -153,3 +160,4 @@ pub const EWOULDBLOCK = 140;
pub const SIGKILL = @compileError("Windows libc does not have this");
pub const EDQUOT = @compileError("Windows libc does not have this");
pub const TIOCGWINSZ = @compileError("Windows libc does not have this");
pub const F_OK = 0;

View File

@ -5,7 +5,7 @@ const std = @import("std");
const assert = std.debug.assert;
pub const is_the_target = builtin.os == .wasi;
pub use @import("bits/wasi.zig");
pub use @import("bits.zig");
comptime {
assert(@alignOf(i8) == 1);
@ -18,6 +18,9 @@ comptime {
assert(@alignOf(u64) == 8);
}
pub const iovec_t = iovec;
pub const ciovec_t = iovec_const;
pub extern "wasi_unstable" fn args_get(argv: [*][*]u8, argv_buf: [*]u8) errno_t;
pub extern "wasi_unstable" fn args_sizes_get(argc: *usize, argv_buf_size: *usize) errno_t;

View File

@ -134,6 +134,9 @@ pub fn WaitForSingleObject(handle: HANDLE, milliseconds: DWORD) WaitForSingleObj
pub const FindFirstFileError = error{
FileNotFound,
InvalidUtf8,
BadPathName,
NameTooLong,
Unexpected,
};
@ -192,7 +195,7 @@ pub fn PostQueuedCompletionStatus(
) PostQueuedCompletionStatusError!void {
if (kernel32.PostQueuedCompletionStatus(completion_port, bytes_transferred_count, completion_key, lpOverlapped) == 0) {
switch (kernel32.GetLastError()) {
else => return unexpectedError(err),
else => |err| return unexpectedError(err),
}
}
}
@ -350,7 +353,7 @@ pub fn DeleteFile(filename: []const u8) DeleteFileError!void {
}
pub fn DeleteFileW(filename: [*]const u16) DeleteFileError!void {
if (kernel32.DeleteFileW(file_path) == 0) {
if (kernel32.DeleteFileW(filename) == 0) {
switch (kernel32.GetLastError()) {
ERROR.FILE_NOT_FOUND => return error.FileNotFound,
ERROR.ACCESS_DENIED => return error.AccessDenied,
@ -501,7 +504,7 @@ pub fn GetFinalPathNameByHandleW(
buf_len: DWORD,
flags: DWORD,
) GetFinalPathNameByHandleError!DWORD {
const rc = kernel32.GetFinalPathNameByHandleW(h_file, buf_ptr, buf.len, flags);
const rc = kernel32.GetFinalPathNameByHandleW(hFile, buf_ptr, buf_len, flags);
if (rc == 0) {
switch (kernel32.GetLastError()) {
ERROR.FILE_NOT_FOUND => return error.FileNotFound,
@ -539,7 +542,7 @@ pub fn GetFileAttributes(filename: []const u8) GetFileAttributesError!DWORD {
}
pub fn GetFileAttributesW(lpFileName: [*]const u16) GetFileAttributesError!DWORD {
const rc = kernel32.GetFileAttributesW(path);
const rc = kernel32.GetFileAttributesW(lpFileName);
if (rc == INVALID_FILE_ATTRIBUTES) {
switch (kernel32.GetLastError()) {
ERROR.FILE_NOT_FOUND => return error.FileNotFound,
@ -705,6 +708,14 @@ pub fn InitOnceExecuteOnce(InitOnce: *INIT_ONCE, InitFn: INIT_ONCE_FN, Parameter
assert(kernel32.InitOnceExecuteOnce(InitOnce, InitFn, Parameter, Context) != 0);
}
pub fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: *c_void) void {
assert(kernel32.HeapFree(hHeap, dwFlags, lpMem) != 0);
}
pub fn HeapDestroy(hHeap: HANDLE) void {
assert(kernel32.HeapDestroy(hHeap) != 0);
}
pub fn cStrToPrefixedFileW(s: [*]const u8) ![PATH_MAX_WIDE + 1]u16 {
return sliceToPrefixedFileW(mem.toSliceConst(u8, s));
}

View File

@ -57,7 +57,7 @@ pub const Thread = struct {
} else
return switch (builtin.os) {
.linux => os.linux.gettid(),
.windows => windows.GetCurrentThreadId(),
.windows => windows.kernel32.GetCurrentThreadId(),
else => @compileError("Unsupported OS"),
};
}
@ -99,9 +99,9 @@ pub const Thread = struct {
os.munmap(self.data.memory);
},
.windows => {
assert(windows.WaitForSingleObject(self.data.handle, windows.INFINITE) == windows.WAIT_OBJECT_0);
assert(windows.CloseHandle(self.data.handle) != 0);
assert(windows.HeapFree(self.data.heap_handle, 0, self.data.alloc_start) != 0);
windows.WaitForSingleObject(self.data.handle, windows.INFINITE) catch unreachable;
windows.CloseHandle(self.data.handle);
windows.HeapFree(self.data.heap_handle, 0, self.data.alloc_start);
},
else => @compileError("Unsupported OS"),
}
@ -171,10 +171,10 @@ pub const Thread = struct {
}
};
const heap_handle = windows.GetProcessHeap() orelse return error.OutOfMemory;
const heap_handle = windows.kernel32.GetProcessHeap() orelse return error.OutOfMemory;
const byte_count = @alignOf(WinThread.OuterContext) + @sizeOf(WinThread.OuterContext);
const bytes_ptr = windows.HeapAlloc(heap_handle, 0, byte_count) orelse return error.OutOfMemory;
errdefer assert(windows.HeapFree(heap_handle, 0, bytes_ptr) != 0);
const bytes_ptr = windows.kernel32.HeapAlloc(heap_handle, 0, byte_count) orelse return error.OutOfMemory;
errdefer assert(windows.kernel32.HeapFree(heap_handle, 0, bytes_ptr) != 0);
const bytes = @ptrCast([*]u8, bytes_ptr)[0..byte_count];
const outer_context = std.heap.FixedBufferAllocator.init(bytes).allocator.create(WinThread.OuterContext) catch unreachable;
outer_context.* = WinThread.OuterContext{
@ -189,9 +189,9 @@ pub const Thread = struct {
};
const parameter = if (@sizeOf(Context) == 0) null else @ptrCast(*c_void, &outer_context.inner);
outer_context.thread.data.handle = windows.CreateThread(null, default_stack_size, WinThread.threadMain, parameter, 0, null) orelse {
switch (windows.GetLastError()) {
else => |err| windows.unexpectedError(err),
outer_context.thread.data.handle = windows.kernel32.CreateThread(null, default_stack_size, WinThread.threadMain, parameter, 0, null) orelse {
switch (windows.kernel32.GetLastError()) {
else => |err| return windows.unexpectedError(err),
}
};
return &outer_context.thread;
@ -333,7 +333,7 @@ pub const Thread = struct {
}
if (os.windows.is_the_target) {
var system_info: windows.SYSTEM_INFO = undefined;
windows.GetSystemInfo(&system_info);
windows.kernel32.GetSystemInfo(&system_info);
return @intCast(usize, system_info.dwNumberOfProcessors);
}
var count: c_int = undefined;

View File

@ -4,7 +4,7 @@ const assert = std.debug.assert;
const testing = std.testing;
const os = std.os;
pub const epoch = @import("epoch.zig");
pub const epoch = @import("time/epoch.zig");
/// Spurious wakeups are possible and no precision of timing is guaranteed.
pub fn sleep(nanoseconds: u64) void {