From 0c6ab61b228211398841cf11912c7252362009b7 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 26 May 2019 23:35:26 -0400 Subject: [PATCH] tests passing on linux --- build.zig | 6 +-- doc/langref.html.in | 4 +- example/cat/main.zig | 9 ++-- example/guess_number/main.zig | 3 +- example/hello_world/hello_libc.zig | 2 +- src-self-hosted/compilation.zig | 1 + src-self-hosted/libc_installation.zig | 6 +-- src-self-hosted/main.zig | 19 +++---- std/c.zig | 13 +++-- std/c/linux.zig | 22 +++++++-- std/child_process.zig | 18 +++---- std/cstr.zig | 2 +- std/dynamic_library.zig | 38 +++++--------- std/event/fs.zig | 14 +++--- std/event/loop.zig | 32 ++++++------ std/event/net.zig | 27 +++++----- std/fs.zig | 26 ++-------- std/fs/file.zig | 15 +++--- std/fs/path.zig | 15 +++--- std/heap.zig | 2 +- std/io/test.zig | 8 +-- std/os.zig | 71 +++++++++++++++------------ std/os/bits/darwin.zig | 16 +++--- std/os/bits/freebsd.zig | 28 +++++------ std/os/bits/linux.zig | 30 +++++------ std/os/bits/netbsd.zig | 26 ++++------ std/os/linux.zig | 2 +- std/os/linux/test.zig | 2 +- std/os/linux/vdso.zig | 2 +- std/os/test.zig | 35 ++++++------- std/os/windows.zig | 38 ++++++++++++++ std/os/zen.zig | 2 +- std/process.zig | 22 ++++++++- std/thread.zig | 56 +++++++++++++-------- std/time.zig | 24 +++------ test/compare_output.zig | 6 +-- test/standalone/empty_env/main.zig | 2 +- test/tests.zig | 2 +- 38 files changed, 348 insertions(+), 298 deletions(-) diff --git a/build.zig b/build.zig index bb23502d82b5..82949ad5bcff 100644 --- a/build.zig +++ b/build.zig @@ -166,10 +166,8 @@ fn dependOnLib(b: *Builder, lib_exe_obj: var, dep: LibraryDep) void { } fn fileExists(filename: []const u8) !bool { - fs.File.exists(filename) catch |err| switch (err) { - error.PermissionDenied, - error.FileNotFound, - => return false, + fs.File.access(filename) catch |err| switch (err) { + error.FileNotFound => return false, else => return err, }; return true; diff --git a/doc/langref.html.in b/doc/langref.html.in index 5b9beba64493..19839904b1ce 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -796,8 +796,8 @@ const assert = std.debug.assert; threadlocal var x: i32 = 1234; test "thread local storage" { - const thread1 = try std.os.spawnThread({}, testTls); - const thread2 = try std.os.spawnThread({}, testTls); + const thread1 = try std.Thread.spawn({}, testTls); + const thread2 = try std.Thread.spawn({}, testTls); testTls({}); thread1.wait(); thread2.wait(); diff --git a/example/cat/main.zig b/example/cat/main.zig index 725521783114..c57c1e4bcbff 100644 --- a/example/cat/main.zig +++ b/example/cat/main.zig @@ -1,12 +1,13 @@ const std = @import("std"); const io = std.io; +const process = std.process; +const File = std.fs.File; const mem = std.mem; -const os = std.os; const warn = std.debug.warn; const allocator = std.debug.global_allocator; pub fn main() !void { - var args_it = os.args(); + var args_it = process.args(); const exe = try unwrapArg(args_it.next(allocator).?); var catted_anything = false; var stdout_file = try io.getStdOut(); @@ -20,7 +21,7 @@ pub fn main() !void { } else if (arg[0] == '-') { return usage(exe); } else { - var file = os.File.openRead(arg) catch |err| { + var file = File.openRead(arg) catch |err| { warn("Unable to open file: {}\n", @errorName(err)); return err; }; @@ -41,7 +42,7 @@ fn usage(exe: []const u8) !void { return error.Invalid; } -fn cat_file(stdout: *os.File, file: *os.File) !void { +fn cat_file(stdout: *File, file: *File) !void { var buf: [1024 * 4]u8 = undefined; while (true) { diff --git a/example/guess_number/main.zig b/example/guess_number/main.zig index b4eb1c292a4f..b1e557fd20c5 100644 --- a/example/guess_number/main.zig +++ b/example/guess_number/main.zig @@ -2,7 +2,6 @@ const builtin = @import("builtin"); const std = @import("std"); const io = std.io; const fmt = std.fmt; -const os = std.os; pub fn main() !void { var stdout_file = try io.getStdOut(); @@ -11,7 +10,7 @@ pub fn main() !void { try stdout.print("Welcome to the Guess Number Game in Zig.\n"); var seed_bytes: [@sizeOf(u64)]u8 = undefined; - os.getRandomBytes(seed_bytes[0..]) catch |err| { + std.crypto.randomBytes(seed_bytes[0..]) catch |err| { std.debug.warn("unable to seed random number generator: {}", err); return err; }; diff --git a/example/hello_world/hello_libc.zig b/example/hello_world/hello_libc.zig index 3f077283dbce..d18b1c26b35b 100644 --- a/example/hello_world/hello_libc.zig +++ b/example/hello_world/hello_libc.zig @@ -5,6 +5,6 @@ const c = @cImport({ }); export fn main(argc: c_int, argv: [*]?[*]u8) c_int { - c.fprintf(c.stderr, c"Hello, world!\n"); + _ = c.fprintf(c.stderr, c"Hello, world!\n"); return 0; } diff --git a/src-self-hosted/compilation.zig b/src-self-hosted/compilation.zig index 720c26945d31..450fde721944 100644 --- a/src-self-hosted/compilation.zig +++ b/src-self-hosted/compilation.zig @@ -301,6 +301,7 @@ pub const Compilation = struct { InvalidUtf8, BadPathName, DeviceBusy, + CurrentWorkingDirectoryUnlinked, }; pub const Event = union(enum) { diff --git a/src-self-hosted/libc_installation.zig b/src-self-hosted/libc_installation.zig index 53790ec8f4da..7ca849d10c93 100644 --- a/src-self-hosted/libc_installation.zig +++ b/src-self-hosted/libc_installation.zig @@ -182,7 +182,7 @@ pub const LibCInstallation = struct { } async fn findNativeIncludeDirLinux(self: *LibCInstallation, loop: *event.Loop) !void { - const cc_exe = std.process.getEnvPosix("CC") orelse "cc"; + const cc_exe = std.os.getenv("CC") orelse "cc"; const argv = []const []const u8{ cc_exe, "-E", @@ -392,7 +392,7 @@ pub const LibCInstallation = struct { /// caller owns returned memory async fn ccPrintFileName(loop: *event.Loop, o_file: []const u8, want_dirname: bool) ![]u8 { - const cc_exe = std.process.getEnvPosix("CC") orelse "cc"; + const cc_exe = std.os.getenv("CC") orelse "cc"; const arg1 = try std.fmt.allocPrint(loop.allocator, "-print-file-name={}", o_file); defer loop.allocator.free(arg1); const argv = []const []const u8{ cc_exe, arg1 }; @@ -463,7 +463,7 @@ fn fileExists(path: []const u8) !bool { if (fs.File.access(path)) |_| { return true; } else |err| switch (err) { - error.FileNotFound, error.PermissionDenied => return false, + error.FileNotFound => return false, else => return error.FileSystem, } } diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig index 1d2ac4917b24..4095caa8c400 100644 --- a/src-self-hosted/main.zig +++ b/src-self-hosted/main.zig @@ -702,6 +702,7 @@ const FmtError = error{ ReadOnlyFileSystem, LinkQuotaExceeded, FileBusy, + CurrentWorkingDirectoryUnlinked, } || fs.File.OpenError; async fn asyncFmtMain( @@ -851,7 +852,7 @@ fn cmdTargets(allocator: *Allocator, args: []const []const u8) !void { } fn cmdVersion(allocator: *Allocator, args: []const []const u8) !void { - try stdout.print("{}\n", std.cstr.toSliceConst(c.ZIG_VERSION_STRING)); + try stdout.print("{}\n", std.mem.toSliceConst(u8, c.ZIG_VERSION_STRING)); } const args_test_spec = []Flag{Flag.Bool("--help")}; @@ -924,14 +925,14 @@ fn cmdInternalBuildInfo(allocator: *Allocator, args: []const []const u8) !void { \\ZIG_DIA_GUIDS_LIB {} \\ , - std.cstr.toSliceConst(c.ZIG_CMAKE_BINARY_DIR), - std.cstr.toSliceConst(c.ZIG_CXX_COMPILER), - std.cstr.toSliceConst(c.ZIG_LLVM_CONFIG_EXE), - std.cstr.toSliceConst(c.ZIG_LLD_INCLUDE_PATH), - std.cstr.toSliceConst(c.ZIG_LLD_LIBRARIES), - std.cstr.toSliceConst(c.ZIG_STD_FILES), - std.cstr.toSliceConst(c.ZIG_C_HEADER_FILES), - std.cstr.toSliceConst(c.ZIG_DIA_GUIDS_LIB), + std.mem.toSliceConst(u8, c.ZIG_CMAKE_BINARY_DIR), + std.mem.toSliceConst(u8, c.ZIG_CXX_COMPILER), + std.mem.toSliceConst(u8, c.ZIG_LLVM_CONFIG_EXE), + std.mem.toSliceConst(u8, c.ZIG_LLD_INCLUDE_PATH), + std.mem.toSliceConst(u8, c.ZIG_LLD_LIBRARIES), + std.mem.toSliceConst(u8, c.ZIG_STD_FILES), + std.mem.toSliceConst(u8, c.ZIG_C_HEADER_FILES), + std.mem.toSliceConst(u8, c.ZIG_DIA_GUIDS_LIB), ); } diff --git a/std/c.zig b/std/c.zig index 9171a99ec9a7..90d8f0056e82 100644 --- a/std/c.zig +++ b/std/c.zig @@ -39,8 +39,8 @@ pub extern "c" fn open(path: [*]const u8, oflag: c_uint, ...) c_int; pub extern "c" fn raise(sig: c_int) c_int; pub extern "c" fn read(fd: fd_t, buf: [*]u8, nbyte: usize) isize; pub extern "c" fn pread(fd: fd_t, buf: [*]u8, nbyte: usize, offset: u64) isize; -pub extern "c" fn preadv(fd: c_int, iov: [*]const iovec, iovcnt: c_int, offset: usize) isize; -pub extern "c" fn pwritev(fd: c_int, iov: [*]const iovec, iovcnt: c_int, offset: usize) isize; +pub extern "c" fn preadv(fd: c_int, iov: [*]const iovec, iovcnt: c_uint, offset: usize) isize; +pub extern "c" fn pwritev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint, offset: usize) isize; pub extern "c" fn stat(noalias path: [*]const u8, noalias buf: *Stat) c_int; pub extern "c" fn write(fd: fd_t, buf: [*]const u8, nbyte: usize) isize; pub extern "c" fn pwrite(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: u64) isize; @@ -49,7 +49,7 @@ pub extern "c" fn munmap(addr: *align(page_size) c_void, len: usize) c_int; pub extern "c" fn mprotect(addr: *align(page_size) c_void, len: usize, prot: c_uint) c_int; pub extern "c" fn unlink(path: [*]const u8) c_int; pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8; -pub extern "c" fn waitpid(pid: c_int, stat_loc: *c_int, options: c_int) c_int; +pub extern "c" fn waitpid(pid: c_int, stat_loc: *c_uint, options: c_uint) c_int; pub extern "c" fn fork() c_int; pub extern "c" fn access(path: [*]const u8, mode: c_uint) c_int; pub extern "c" fn pipe(fds: *[2]fd_t) c_int; @@ -76,7 +76,12 @@ pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usi pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int; pub extern "c" fn bind(socket: fd_t, address: ?*const sockaddr, address_len: socklen_t) c_int; -pub extern "c" fn socket(domain: c_int, sock_type: c_int, protocol: c_int) c_int; +pub extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int; +pub extern "c" fn listen(sockfd: fd_t, backlog: c_uint) c_int; +pub extern "c" fn getsockname(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int; +pub extern "c" fn connect(sockfd: fd_t, sock_addr: *const sockaddr, addrlen: socklen_t) c_int; +pub extern "c" fn accept4(sockfd: fd_t, addr: *sockaddr, addrlen: *socklen_t, flags: c_uint) c_int; +pub extern "c" fn getsockopt(sockfd: fd_t, level: c_int, optname: c_int, optval: *c_void, optlen: *socklen_t) c_int; pub extern "c" fn kill(pid: pid_t, sig: c_int) c_int; pub extern "c" fn getdirentries(fd: fd_t, buf_ptr: [*]u8, nbytes: usize, basep: *i64) isize; pub extern "c" fn openat(fd: c_int, path: [*]const u8, flags: c_int) c_int; diff --git a/std/c/linux.zig b/std/c/linux.zig index 00fc600dabaa..9e028728c756 100644 --- a/std/c/linux.zig +++ b/std/c/linux.zig @@ -1,13 +1,27 @@ const std = @import("../std.zig"); use std.c; -pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) c_int; -pub extern "c" fn sched_getaffinity(pid: c_int, size: usize, set: *cpu_set_t) c_int; extern "c" fn __errno_location() *c_int; pub const _errno = __errno_location; +pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) c_int; +pub extern "c" fn sched_getaffinity(pid: c_int, size: usize, set: *cpu_set_t) c_int; +pub extern "c" fn eventfd(initval: c_uint, flags: c_uint) c_int; +pub extern "c" fn epoll_ctl(epfd: fd_t, op: c_uint, fd: fd_t, event: *epoll_event) c_int; +pub extern "c" fn epoll_create1(flags: c_uint) c_int; +pub extern "c" fn epoll_wait(epfd: fd_t, events: [*]epoll_event, maxevents: c_uint, timeout: c_int) c_int; +pub extern "c" fn epoll_pwait( + epfd: fd_t, + events: [*]epoll_event, + maxevents: c_int, + timeout: c_int, + sigmask: *const sigset_t, +) c_int; +pub extern "c" fn inotify_init1(flags: c_uint) c_int; +pub extern "c" fn inotify_add_watch(fd: fd_t, pathname: [*]const u8, mask: u32) c_int; + /// See std.elf for constants for this -pub extern fn getauxval(__type: c_ulong) c_ulong; +pub extern "c" fn getauxval(__type: c_ulong) c_ulong; pub const dl_iterate_phdr_callback = extern fn (info: *dl_phdr_info, size: usize, data: ?*c_void) c_int; -pub extern fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*c_void) c_int; +pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*c_void) c_int; diff --git a/std/child_process.zig b/std/child_process.zig index f870f5e08390..2209b2acc391 100644 --- a/std/child_process.zig +++ b/std/child_process.zig @@ -54,10 +54,10 @@ pub const ChildProcess = struct { os.ChangeCurDirError || windows.CreateProcessError; pub const Term = union(enum) { - Exited: i32, - Signal: i32, - Stopped: i32, - Unknown: i32, + Exited: u32, + Signal: u32, + Stopped: u32, + Unknown: u32, }; pub const StdIo = enum { @@ -155,7 +155,7 @@ pub const ChildProcess = struct { } pub const ExecResult = struct { - term: os.ChildProcess.Term, + term: Term, stdout: []u8, stderr: []u8, }; @@ -224,7 +224,7 @@ pub const ChildProcess = struct { if (windows.GetExitCodeProcess(self.handle, &exit_code) == 0) { break :x Term{ .Unknown = 0 }; } else { - break :x Term{ .Exited = @bitCast(i32, exit_code) }; + break :x Term{ .Exited = exit_code }; } }); @@ -240,7 +240,7 @@ pub const ChildProcess = struct { self.handleWaitResult(status); } - fn handleWaitResult(self: *ChildProcess, status: i32) void { + fn handleWaitResult(self: *ChildProcess, status: u32) void { self.term = self.cleanupAfterWait(status); } @@ -259,7 +259,7 @@ pub const ChildProcess = struct { } } - fn cleanupAfterWait(self: *ChildProcess, status: i32) !Term { + fn cleanupAfterWait(self: *ChildProcess, status: u32) !Term { defer { os.close(self.err_pipe[0]); os.close(self.err_pipe[1]); @@ -281,7 +281,7 @@ pub const ChildProcess = struct { return statusToTerm(status); } - fn statusToTerm(status: i32) Term { + fn statusToTerm(status: u32) Term { return if (os.WIFEXITED(status)) Term{ .Exited = os.WEXITSTATUS(status) } else if (os.WIFSIGNALED(status)) diff --git a/std/cstr.zig b/std/cstr.zig index c8c3447921c9..dd28e5044936 100644 --- a/std/cstr.zig +++ b/std/cstr.zig @@ -28,7 +28,7 @@ test "cstr fns" { fn testCStrFnsImpl() void { testing.expect(cmp(c"aoeu", c"aoez") == -1); - testing.expect(len(c"123456789") == 9); + testing.expect(mem.len(u8, c"123456789") == 9); } /// Returns a mutable slice with 1 more byte of length which is a null byte. diff --git a/std/dynamic_library.zig b/std/dynamic_library.zig index ce721350eafd..3ae3b4c66abf 100644 --- a/std/dynamic_library.zig +++ b/std/dynamic_library.zig @@ -6,8 +6,7 @@ const os = std.os; const assert = std.debug.assert; const testing = std.testing; const elf = std.elf; -const windows = os.windows; -const win_util = @import("os/windows/util.zig"); +const windows = std.os.windows; const maxInt = std.math.maxInt; pub const DynLib = switch (builtin.os) { @@ -102,17 +101,16 @@ pub fn linkmap_iterator(phdrs: []elf.Phdr) !LinkMap.Iterator { pub const LinuxDynLib = struct { elf_lib: ElfLib, fd: i32, - map_addr: usize, - map_size: usize, + memory: []align(mem.page_size) u8, /// Trusts the file pub fn open(allocator: *mem.Allocator, path: []const u8) !DynLib { const fd = try os.open(path, 0, os.O_RDONLY | os.O_CLOEXEC); - errdefer std.os.close(fd); + errdefer os.close(fd); - const size = @intCast(usize, (try std.os.posixFStat(fd)).size); + const size = @intCast(usize, (try os.fstat(fd)).size); - const addr = os.mmap( + const bytes = try os.mmap( null, size, os.PROT_READ | os.PROT_EXEC, @@ -120,21 +118,18 @@ pub const LinuxDynLib = struct { fd, 0, ); - errdefer os.munmap(addr, size); - - const bytes = @intToPtr([*]align(mem.page_size) u8, addr)[0..size]; + errdefer os.munmap(bytes); return DynLib{ .elf_lib = try ElfLib.init(bytes), .fd = fd, - .map_addr = addr, - .map_size = size, + .memory = bytes, }; } pub fn close(self: *DynLib) void { - os.munmap(self.map_addr, self.map_size); - std.os.close(self.fd); + os.munmap(self.memory); + os.close(self.fd); self.* = undefined; } @@ -253,28 +248,21 @@ pub const WindowsDynLib = struct { dll: windows.HMODULE, pub fn open(allocator: *mem.Allocator, path: []const u8) !WindowsDynLib { - const wpath = try win_util.sliceToPrefixedFileW(path); + const wpath = try windows.sliceToPrefixedFileW(path); return WindowsDynLib{ .allocator = allocator, - .dll = windows.LoadLibraryW(&wpath) orelse { - switch (windows.GetLastError()) { - windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound, - windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound, - windows.ERROR.MOD_NOT_FOUND => return error.FileNotFound, - else => |err| return windows.unexpectedError(err), - } - }, + .dll = try windows.LoadLibraryW(&wpath), }; } pub fn close(self: *WindowsDynLib) void { - assert(windows.FreeLibrary(self.dll) != 0); + windows.FreeLibrary(self.dll); self.* = undefined; } pub fn lookup(self: *WindowsDynLib, name: []const u8) ?usize { - return @ptrToInt(windows.GetProcAddress(self.dll, name.ptr)); + return @ptrToInt(windows.kernel32.GetProcAddress(self.dll, name.ptr)); } }; diff --git a/std/event/fs.zig b/std/event/fs.zig index 221070a06232..81d180235ece 100644 --- a/std/event/fs.zig +++ b/std/event/fs.zig @@ -36,7 +36,7 @@ pub const Request = struct { offset: usize, result: Error!void, - pub const Error = os.PosixWriteError; + pub const Error = os.WriteError; }; pub const PReadV = struct { @@ -45,7 +45,7 @@ pub const Request = struct { offset: usize, result: Error!usize, - pub const Error = os.PosixReadError; + pub const Error = os.ReadError; }; pub const Open = struct { @@ -172,7 +172,7 @@ pub async fn pwritevPosix( fd: fd_t, iovecs: []const os.iovec_const, offset: usize, -) os.PosixWriteError!void { +) os.WriteError!void { // workaround for https://github.com/ziglang/zig/issues/1194 suspend { resume @handle(); @@ -320,7 +320,7 @@ pub async fn preadvPosix( fd: fd_t, iovecs: []const os.iovec, offset: usize, -) os.PosixReadError!usize { +) os.ReadError!usize { // workaround for https://github.com/ziglang/zig/issues/1194 suspend { resume @handle(); @@ -786,7 +786,7 @@ pub fn Watch(comptime V: type) type { switch (builtin.os) { builtin.Os.linux => { - const inotify_fd = try os.linuxINotifyInit1(os.linux.IN_NONBLOCK | os.linux.IN_CLOEXEC); + const inotify_fd = try os.inotify_init1(os.linux.IN_NONBLOCK | os.linux.IN_CLOEXEC); errdefer os.close(inotify_fd); var result: *Self = undefined; @@ -977,7 +977,7 @@ pub fn Watch(comptime V: type) type { var basename_with_null_consumed = false; defer if (!basename_with_null_consumed) self.channel.loop.allocator.free(basename_with_null); - const wd = try os.linuxINotifyAddWatchC( + const wd = try os.inotify_add_watchC( self.os_data.inotify_fd, dirname_with_null.ptr, os.linux.IN_CLOSE_WRITE | os.linux.IN_ONLYDIR | os.linux.IN_EXCL_UNLINK, @@ -1255,7 +1255,7 @@ pub fn Watch(comptime V: type) type { ev = @ptrCast(*os.linux.inotify_event, ptr); if (ev.mask & os.linux.IN_CLOSE_WRITE == os.linux.IN_CLOSE_WRITE) { const basename_ptr = ptr + @sizeOf(os.linux.inotify_event); - const basename_with_null = basename_ptr[0 .. std.cstr.len(basename_ptr) + 1]; + const basename_with_null = basename_ptr[0 .. std.mem.len(u8, basename_ptr) + 1]; const user_value = blk: { const held = await (async watch.os_data.table_lock.acquire() catch unreachable); defer held.release(); diff --git a/std/event/loop.zig b/std/event/loop.zig index e1848684c7d2..ae19ebb0f872 100644 --- a/std/event/loop.zig +++ b/std/event/loop.zig @@ -99,7 +99,7 @@ pub const Loop = struct { /// have the correct pointer value. pub fn initMultiThreaded(self: *Loop, allocator: *mem.Allocator) !void { if (builtin.single_threaded) @compileError("initMultiThreaded unavailable when building in single-threaded mode"); - const core_count = try os.cpuCount(allocator); + const core_count = try Thread.cpuCount(); return self.initInternal(allocator, core_count); } @@ -139,9 +139,9 @@ pub const Loop = struct { self.allocator.free(self.extra_threads); } - const InitOsDataError = os.LinuxEpollCreateError || mem.Allocator.Error || os.LinuxEventFdError || - os.SpawnThreadError || os.LinuxEpollCtlError || os.BsdKEventError || - os.WindowsCreateIoCompletionPortError; + const InitOsDataError = os.EpollCreateError || mem.Allocator.Error || os.EventFdError || + Thread.SpawnError || os.EpollCtlError || os.KEventError || + windows.CreateIoCompletionPortError; const wakeup_bytes = []u8{0x1} ** 8; @@ -172,7 +172,7 @@ pub const Loop = struct { .handle = undefined, .overlapped = ResumeNode.overlapped_init, }, - .eventfd = try os.linuxEventFd(1, os.EFD_CLOEXEC | os.EFD_NONBLOCK), + .eventfd = try os.eventfd(1, os.EFD_CLOEXEC | os.EFD_NONBLOCK), .epoll_op = os.EPOLL_CTL_ADD, }, .next = undefined, @@ -180,17 +180,17 @@ pub const Loop = struct { self.available_eventfd_resume_nodes.push(eventfd_node); } - self.os_data.epollfd = try os.linuxEpollCreate(os.EPOLL_CLOEXEC); + self.os_data.epollfd = try os.epoll_create1(os.EPOLL_CLOEXEC); errdefer os.close(self.os_data.epollfd); - self.os_data.final_eventfd = try os.linuxEventFd(0, os.EFD_CLOEXEC | os.EFD_NONBLOCK); + self.os_data.final_eventfd = try os.eventfd(0, os.EFD_CLOEXEC | os.EFD_NONBLOCK); errdefer os.close(self.os_data.final_eventfd); self.os_data.final_eventfd_event = os.epoll_event{ .events = os.EPOLLIN, .data = os.epoll_data{ .ptr = @ptrToInt(&self.final_resume_node) }, }; - try os.linuxEpollCtl( + try os.epoll_ctl( self.os_data.epollfd, os.EPOLL_CTL_ADD, self.os_data.final_eventfd, @@ -211,7 +211,7 @@ pub const Loop = struct { var extra_thread_index: usize = 0; errdefer { // writing 8 bytes to an eventfd cannot fail - os.posixWrite(self.os_data.final_eventfd, wakeup_bytes) catch unreachable; + os.write(self.os_data.final_eventfd, wakeup_bytes) catch unreachable; while (extra_thread_index != 0) { extra_thread_index -= 1; self.extra_threads[extra_thread_index].wait(); @@ -417,11 +417,11 @@ pub const Loop = struct { .events = flags, .data = os.linux.epoll_data{ .ptr = @ptrToInt(resume_node) }, }; - try os.linuxEpollCtl(self.os_data.epollfd, op, fd, &ev); + try os.epoll_ctl(self.os_data.epollfd, op, fd, &ev); } pub fn linuxRemoveFd(self: *Loop, fd: i32) void { - os.linuxEpollCtl(self.os_data.epollfd, os.linux.EPOLL_CTL_DEL, fd, undefined) catch {}; + os.epoll_ctl(self.os_data.epollfd, os.linux.EPOLL_CTL_DEL, fd, undefined) catch {}; self.finishOneEvent(); } @@ -626,7 +626,7 @@ pub const Loop = struct { builtin.Os.linux => { self.posixFsRequest(&self.os_data.fs_end_request); // writing 8 bytes to an eventfd cannot fail - os.posixWrite(self.os_data.final_eventfd, wakeup_bytes) catch unreachable; + os.write(self.os_data.final_eventfd, wakeup_bytes) catch unreachable; return; }, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => { @@ -666,7 +666,7 @@ pub const Loop = struct { builtin.Os.linux => { // only process 1 event so we don't steal from other threads var events: [1]os.linux.epoll_event = undefined; - const count = os.linuxEpollWait(self.os_data.epollfd, events[0..], -1); + const count = os.epoll_wait(self.os_data.epollfd, events[0..], -1); for (events[0..count]) |ev| { const resume_node = @intToPtr(*ResumeNode, ev.data.ptr); const handle = resume_node.handle; @@ -783,10 +783,10 @@ pub const Loop = struct { switch (node.data.msg) { @TagType(fs.Request.Msg).End => return, @TagType(fs.Request.Msg).PWriteV => |*msg| { - msg.result = os.posix_pwritev(msg.fd, msg.iov.ptr, msg.iov.len, msg.offset); + msg.result = os.pwritev(msg.fd, msg.iov, msg.offset); }, @TagType(fs.Request.Msg).PReadV => |*msg| { - msg.result = os.posix_preadv(msg.fd, msg.iov.ptr, msg.iov.len, msg.offset); + msg.result = os.preadv(msg.fd, msg.iov, msg.offset); }, @TagType(fs.Request.Msg).Open => |*msg| { msg.result = os.openC(msg.path.ptr, msg.flags, msg.mode); @@ -800,7 +800,7 @@ pub const Loop = struct { break :blk; }; defer os.close(fd); - msg.result = os.posixWrite(fd, msg.contents); + msg.result = os.write(fd, msg.contents); }, } switch (node.data.finish) { diff --git a/std/event/net.zig b/std/event/net.zig index 2346b1eb23fe..f4398196e334 100644 --- a/std/event/net.zig +++ b/std/event/net.zig @@ -45,13 +45,13 @@ pub const Server = struct { ) !void { self.handleRequestFn = handleRequestFn; - const sockfd = try os.posixSocket(os.AF_INET, os.SOCK_STREAM | os.SOCK_CLOEXEC | os.SOCK_NONBLOCK, os.PROTO_tcp); + const sockfd = try os.socket(os.AF_INET, os.SOCK_STREAM | os.SOCK_CLOEXEC | os.SOCK_NONBLOCK, os.PROTO_tcp); errdefer os.close(sockfd); self.sockfd = sockfd; - try os.posixBind(sockfd, &address.os_addr); - try os.posixListen(sockfd, os.SOMAXCONN); - self.listen_address = std.net.Address.initPosix(try os.posixGetSockName(sockfd)); + try os.bind(sockfd, &address.os_addr); + try os.listen(sockfd, os.SOMAXCONN); + self.listen_address = std.net.Address.initPosix(try os.getsockname(sockfd)); self.accept_coro = try async Server.handler(self); errdefer cancel self.accept_coro.?; @@ -64,7 +64,10 @@ pub const Server = struct { /// Stop listening pub fn close(self: *Server) void { self.loop.linuxRemoveFd(self.sockfd.?); - os.close(self.sockfd.?); + if (self.sockfd) |fd| { + os.close(fd); + self.sockfd = null; + } } pub fn deinit(self: *Server) void { @@ -76,7 +79,7 @@ pub const Server = struct { while (true) { var accepted_addr: std.net.Address = undefined; // TODO just inline the following function here and don't expose it as posixAsyncAccept - if (os.posixAsyncAccept(self.sockfd.?, &accepted_addr.os_addr, os.SOCK_NONBLOCK | os.SOCK_CLOEXEC)) |accepted_fd| { + if (os.accept4_async(self.sockfd.?, &accepted_addr.os_addr, os.SOCK_NONBLOCK | os.SOCK_CLOEXEC)) |accepted_fd| { if (accepted_fd == -1) { // would block suspend; // we will get resumed by epoll_wait in the event loop @@ -105,7 +108,7 @@ pub const Server = struct { }; pub async fn connectUnixSocket(loop: *Loop, path: []const u8) !i32 { - const sockfd = try os.posixSocket( + const sockfd = try os.socket( os.AF_UNIX, os.SOCK_STREAM | os.SOCK_CLOEXEC | os.SOCK_NONBLOCK, 0, @@ -120,9 +123,9 @@ pub async fn connectUnixSocket(loop: *Loop, path: []const u8) !i32 { if (path.len > @typeOf(sock_addr.path).len) return error.NameTooLong; mem.copy(u8, sock_addr.path[0..], path); const size = @intCast(u32, @sizeOf(os.sa_family_t) + path.len); - try os.posixConnectAsync(sockfd, &sock_addr, size); + try os.connect_async(sockfd, &sock_addr, size); try await try async loop.linuxWaitFd(sockfd, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET); - try os.posixGetSockOptConnectError(sockfd); + try os.getsockoptError(sockfd); return sockfd; } @@ -249,12 +252,12 @@ pub async fn readv(loop: *Loop, fd: fd_t, data: []const []u8) !usize { pub async fn connect(loop: *Loop, _address: *const std.net.Address) !File { var address = _address.*; // TODO https://github.com/ziglang/zig/issues/1592 - const sockfd = try os.posixSocket(os.AF_INET, os.SOCK_STREAM | os.SOCK_CLOEXEC | os.SOCK_NONBLOCK, os.PROTO_tcp); + const sockfd = try os.socket(os.AF_INET, os.SOCK_STREAM | os.SOCK_CLOEXEC | os.SOCK_NONBLOCK, os.PROTO_tcp); errdefer os.close(sockfd); - try os.posixConnectAsync(sockfd, &address.os_addr, @sizeOf(os.sockaddr_in)); + try os.connect_async(sockfd, &address.os_addr, @sizeOf(os.sockaddr_in)); try await try async loop.linuxWaitFd(sockfd, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET); - try os.posixGetSockOptConnectError(sockfd); + try os.getsockoptError(sockfd); return File.openHandle(sockfd); } diff --git a/std/fs.zig b/std/fs.zig index 229f3099c217..5c0db7143500 100644 --- a/std/fs.zig +++ b/std/fs.zig @@ -38,24 +38,6 @@ pub const MAX_PATH_BYTES = switch (builtin.os) { else => @compileError("Unsupported OS"), }; -/// The result is a slice of `out_buffer`, from index `0`. -pub fn getCwd(out_buffer: *[MAX_PATH_BYTES]u8) ![]u8 { - return os.getcwd(out_buffer); -} - -/// Caller must free the returned memory. -pub fn getCwdAlloc(allocator: *Allocator) ![]u8 { - var buf: [MAX_PATH_BYTES]u8 = undefined; - return mem.dupe(allocator, u8, try os.getcwd(&buf)); -} - -test "getCwdAlloc" { - // at least call it so it gets compiled - var buf: [1000]u8 = undefined; - const allocator = &std.heap.FixedBufferAllocator.init(&buf).allocator; - _ = getCwdAlloc(allocator) catch {}; -} - // here we replace the standard +/ with -_ so that it can be used in a file name const b64_fs_encoder = base64.Base64Encoder.init("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", base64.standard_pad_char); @@ -260,17 +242,17 @@ pub fn makePath(allocator: *Allocator, full_path: []const u8) !void { /// Returns `error.DirNotEmpty` if the directory is not empty. /// To delete a directory recursively, see `deleteTree`. -pub fn deleteDir(dir_path: []const u8) DeleteDirError!void { +pub fn deleteDir(dir_path: []const u8) !void { return os.rmdir(dir_path); } /// Same as `deleteDir` except the parameter is a null-terminated UTF8-encoded string. -pub fn deleteDirC(dir_path: [*]const u8) DeleteDirError!void { +pub fn deleteDirC(dir_path: [*]const u8) !void { return os.rmdirC(dir_path); } /// Same as `deleteDir` except the parameter is a null-terminated UTF16LE-encoded string. -pub fn deleteDirW(dir_path: [*]const u16) DeleteDirError!void { +pub fn deleteDirW(dir_path: [*]const u16) !void { return os.rmdirW(dir_path); } @@ -362,7 +344,7 @@ pub fn deleteTree(allocator: *Allocator, full_path: []const u8) DeleteTreeError! }; defer dir.close(); - var full_entry_buf = ArrayList(u8).init(allocator); + var full_entry_buf = std.ArrayList(u8).init(allocator); defer full_entry_buf.deinit(); while (try dir.next()) |entry| { diff --git a/std/fs/file.zig b/std/fs/file.zig index 915dae331f92..7cb722292c88 100644 --- a/std/fs/file.zig +++ b/std/fs/file.zig @@ -137,24 +137,27 @@ pub const File = struct { /// Test for the existence of `path`. /// `path` is UTF8-encoded. - pub fn exists(path: []const u8) !void { + /// In general it is recommended to avoid this function. For example, + /// instead of testing if a file exists and then opening it, just + /// open it and handle the error for file not found. + pub fn access(path: []const u8) !void { return os.access(path, os.F_OK); } - /// Same as `exists` except the parameter is null-terminated. - pub fn existsC(path: [*]const u8) !void { + /// Same as `access` except the parameter is null-terminated. + pub fn accessC(path: [*]const u8) !void { return os.accessC(path, os.F_OK); } - /// Same as `exists` except the parameter is null-terminated UTF16LE-encoded. - pub fn existsW(path: [*]const u16) !void { + /// Same as `access` except the parameter is null-terminated UTF16LE-encoded. + pub fn accessW(path: [*]const u16) !void { return os.accessW(path, os.F_OK); } /// Upon success, the stream is in an uninitialized state. To continue using it, /// you must use the open() function. pub fn close(self: File) void { - os.close(self.handle); + return os.close(self.handle); } /// Test whether the file refers to a terminal. diff --git a/std/fs/path.zig b/std/fs/path.zig index 217bb44327da..7b95a3e4d22f 100644 --- a/std/fs/path.zig +++ b/std/fs/path.zig @@ -9,6 +9,7 @@ const Allocator = mem.Allocator; const math = std.math; const windows = std.os.windows; const fs = std.fs; +const process = std.process; pub const sep_windows = '\\'; pub const sep_posix = '/'; @@ -390,7 +391,7 @@ pub fn resolve(allocator: *Allocator, paths: []const []const u8) ![]u8 { pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { if (paths.len == 0) { assert(windows.is_the_target); // resolveWindows called on non windows can't use getCwd - return fs.getCwdAlloc(allocator); + return process.getCwdAlloc(allocator); } // determine which disk designator we will result with, if any @@ -485,7 +486,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { }, WindowsPath.Kind.None => { assert(windows.is_the_target); // resolveWindows called on non windows can't use getCwd - const cwd = try fs.getCwdAlloc(allocator); + const cwd = try process.getCwdAlloc(allocator); defer allocator.free(cwd); const parsed_cwd = windowsParsePath(cwd); result = try allocator.alloc(u8, max_size + parsed_cwd.disk_designator.len + 1); @@ -501,7 +502,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { } else { assert(windows.is_the_target); // resolveWindows called on non windows can't use getCwd // TODO call get cwd for the result_disk_designator instead of the global one - const cwd = try fs.getCwdAlloc(allocator); + const cwd = try process.getCwdAlloc(allocator); defer allocator.free(cwd); result = try allocator.alloc(u8, max_size + cwd.len + 1); @@ -571,7 +572,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { if (paths.len == 0) { assert(!windows.is_the_target); // resolvePosix called on windows can't use getCwd - return fs.getCwdAlloc(allocator); + return process.getCwdAlloc(allocator); } var first_index: usize = 0; @@ -593,7 +594,7 @@ pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { result = try allocator.alloc(u8, max_size); } else { assert(!windows.is_the_target); // resolvePosix called on windows can't use getCwd - const cwd = try fs.getCwdAlloc(allocator); + const cwd = try process.getCwdAlloc(allocator); defer allocator.free(cwd); result = try allocator.alloc(u8, max_size + cwd.len + 1); mem.copy(u8, result, cwd); @@ -632,7 +633,7 @@ pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { } test "resolve" { - const cwd = try fs.getCwdAlloc(debug.global_allocator); + const cwd = try process.getCwdAlloc(debug.global_allocator); if (windows.is_the_target) { if (windowsParsePath(cwd).kind == WindowsPath.Kind.Drive) { cwd[0] = asciiUpper(cwd[0]); @@ -646,7 +647,7 @@ test "resolve" { test "resolveWindows" { if (windows.is_the_target) { - const cwd = try fs.getCwdAlloc(debug.global_allocator); + const cwd = try process.getCwdAlloc(debug.global_allocator); const parsed_cwd = windowsParsePath(cwd); { const result = testResolveWindows([][]const u8{ "/usr/local", "lib\\zig\\std\\array_list.zig" }); diff --git a/std/heap.zig b/std/heap.zig index 198eb2d07348..6c6a97d037a1 100644 --- a/std/heap.zig +++ b/std/heap.zig @@ -112,7 +112,7 @@ pub const DirectAllocator = struct { -1, 0, ) catch return error.OutOfMemory; - if (alloc_size == n) return slice; + if (alloc_size == n) return slice[0..n]; const aligned_addr = mem.alignForward(@ptrToInt(slice.ptr), alignment); diff --git a/std/io/test.zig b/std/io/test.zig index 7928baa5979e..fc3b0f89025f 100644 --- a/std/io/test.zig +++ b/std/io/test.zig @@ -7,7 +7,7 @@ const DefaultPrng = std.rand.DefaultPrng; const expect = std.testing.expect; const expectError = std.testing.expectError; const mem = std.mem; -const os = std.os; +const fs = std.fs; const File = std.fs.File; test "write a file, read it, then delete it" { @@ -58,7 +58,7 @@ test "write a file, read it, then delete it" { expect(mem.eql(u8, contents["begin".len .. contents.len - "end".len], data)); expect(mem.eql(u8, contents[contents.len - "end".len ..], "end")); } - try os.deleteFile(tmp_file_name); + try fs.deleteFile(tmp_file_name); } test "BufferOutStream" { @@ -316,7 +316,7 @@ test "BitStreams with File Stream" { expectError(error.EndOfStream, bit_stream.readBitsNoEof(u1, 1)); } - try os.deleteFile(tmp_file_name); + try fs.deleteFile(tmp_file_name); } fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime packing: io.Packing) !void { @@ -596,7 +596,7 @@ test "c out stream" { const filename = c"tmp_io_test_file.txt"; const out_file = std.c.fopen(filename, c"w") orelse return error.UnableToOpenTestFile; - defer std.os.deleteFileC(filename) catch {}; + defer fs.deleteFileC(filename) catch {}; const out_stream = &io.COutStream.init(out_file).stream; try out_stream.print("hi: {}\n", i32(123)); diff --git a/std/os.zig b/std/os.zig index 1debb1623451..087d5e12a5d3 100644 --- a/std/os.zig +++ b/std/os.zig @@ -284,7 +284,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize { /// Number of bytes read is returned. Upon reading end-of-file, zero is returned. /// This function is for blocking file descriptors only. For non-blocking, see /// `preadvAsync`. -pub fn preadv(fd: fd_t, iov: [*]const iovec, count: usize, offset: u64) ReadError!usize { +pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) ReadError!usize { if (darwin.is_the_target) { // Darwin does not have preadv but it does have pread. var off: usize = 0; @@ -301,7 +301,7 @@ pub fn preadv(fd: fd_t, iov: [*]const iovec, count: usize, offset: u64) ReadErro if (inner_off == v.iov_len) { iov_i += 1; inner_off = 0; - if (iov_i == count) { + if (iov_i == iov.len) { return off; } } @@ -323,9 +323,10 @@ pub fn preadv(fd: fd_t, iov: [*]const iovec, count: usize, offset: u64) ReadErro } } while (true) { - const rc = system.preadv(fd, iov, count, offset); + // TODO handle the case when iov_len is too large and get rid of this @intCast + const rc = system.preadv(fd, iov.ptr, @intCast(u32, iov.len), offset); switch (errno(rc)) { - 0 => return rc, + 0 => return @bitCast(usize, rc), EINTR => continue, EINVAL => unreachable, EFAULT => unreachable, @@ -407,7 +408,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!void { /// Write multiple buffers to a file descriptor. Keeps trying if it gets interrupted. /// This function is for blocking file descriptors only. For non-blocking, see /// `pwritevAsync`. -pub fn pwritev(fd: fd_t, iov: [*]const iovec_const, count: usize, offset: u64) WriteError!void { +pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) WriteError!void { if (darwin.is_the_target) { // Darwin does not have pwritev but it does have pwrite. var off: usize = 0; @@ -424,7 +425,7 @@ pub fn pwritev(fd: fd_t, iov: [*]const iovec_const, count: usize, offset: u64) W if (inner_off == v.iov_len) { iov_i += 1; inner_off = 0; - if (iov_i == count) { + if (iov_i == iov.len) { return; } } @@ -449,7 +450,8 @@ pub fn pwritev(fd: fd_t, iov: [*]const iovec_const, count: usize, offset: u64) W } while (true) { - const rc = system.pwritev(fd, iov, count, offset); + // TODO handle the case when iov_len is too large and get rid of this @intCast + const rc = system.pwritev(fd, iov.ptr, @intCast(u32, iov.len), offset); switch (errno(rc)) { 0 => return, EINTR => continue, @@ -724,7 +726,7 @@ pub fn getcwd(out_buffer: []u8) GetCwdError![]u8 { EINVAL => unreachable, ENOENT => return error.CurrentWorkingDirectoryUnlinked, ERANGE => return error.NameTooLong, - else => return unexpectedErrno(err), + else => return unexpectedErrno(@intCast(usize, err)), } } @@ -1121,7 +1123,7 @@ pub fn readlinkC(file_path: [*]const u8, out_buffer: []u8) ReadLinkError![]u8 { } const rc = system.readlink(file_path, out_buffer.ptr, out_buffer.len); switch (errno(rc)) { - 0 => return out_buffer[0..rc], + 0 => return out_buffer[0..@bitCast(usize, rc)], EACCES => return error.AccessDenied, EFAULT => unreachable, EINVAL => unreachable, @@ -1307,7 +1309,7 @@ pub const BindError = error{ /// addr is `*const T` where T is one of the sockaddr pub fn bind(fd: i32, addr: *const sockaddr) BindError!void { - const rc = system.bind(fd, system, @sizeOf(sockaddr)); + const rc = system.bind(fd, addr, @sizeOf(sockaddr)); switch (errno(rc)) { 0 => return, EACCES => return error.AccessDenied, @@ -1521,7 +1523,7 @@ pub fn epoll_wait(epfd: i32, events: []epoll_event, timeout: i32) usize { // TODO get rid of the @intCast const rc = system.epoll_wait(epfd, events.ptr, @intCast(u32, events.len), timeout); switch (errno(rc)) { - 0 => return rc, + 0 => return @intCast(usize, rc), EINTR => continue, EBADF => unreachable, EFAULT => unreachable, @@ -1613,12 +1615,10 @@ pub const ConnectError = error{ /// Initiate a connection on a socket. /// This is for blocking file descriptors only. /// For non-blocking, see `connect_async`. -pub fn connect(sockfd: i32, sockaddr: *const sockaddr) ConnectError!void { +pub fn connect(sockfd: i32, sock_addr: *sockaddr, len: socklen_t) ConnectError!void { while (true) { - switch (errno(system.connect(sockfd, sockaddr, @sizeOf(sockaddr)))) { + switch (errno(system.connect(sockfd, sock_addr, @sizeOf(sockaddr)))) { 0 => return, - else => |err| return unexpectedErrno(err), - EACCES => return error.PermissionDenied, EPERM => return error.PermissionDenied, EADDRINUSE => return error.AddressInUse, @@ -1636,19 +1636,18 @@ pub fn connect(sockfd: i32, sockaddr: *const sockaddr) ConnectError!void { ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket. EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol. ETIMEDOUT => return error.ConnectionTimedOut, + else => |err| return unexpectedErrno(err), } } } /// Same as `connect` except it is for blocking socket file descriptors. /// It expects to receive EINPROGRESS`. -pub fn connect_async(sockfd: i32, sockaddr: *const c_void, len: u32) ConnectError!void { +pub fn connect_async(sockfd: i32, sock_addr: *sockaddr, len: socklen_t) ConnectError!void { while (true) { - switch (errno(system.connect(sockfd, sockaddr, len))) { - 0, EINPROGRESS => return, + switch (errno(system.connect(sockfd, sock_addr, @sizeOf(sockaddr)))) { EINTR => continue, - else => |err| return unexpectedErrno(err), - + 0, EINPROGRESS => return, EACCES => return error.PermissionDenied, EPERM => return error.PermissionDenied, EADDRINUSE => return error.AddressInUse, @@ -1664,13 +1663,14 @@ pub fn connect_async(sockfd: i32, sockaddr: *const c_void, len: u32) ConnectErro ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket. EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol. ETIMEDOUT => return error.ConnectionTimedOut, + else => |err| return unexpectedErrno(err), } } } pub fn getsockoptError(sockfd: i32) ConnectError!void { - var err_code: i32 = undefined; - var size: u32 = @sizeOf(i32); + var err_code: u32 = undefined; + var size: u32 = @sizeOf(u32); const rc = system.getsockopt(sockfd, SOL_SOCKET, SO_ERROR, @ptrCast([*]u8, &err_code), &size); assert(size == 4); switch (errno(rc)) { @@ -1702,11 +1702,13 @@ pub fn getsockoptError(sockfd: i32) ConnectError!void { } } -pub fn waitpid(pid: i32, flags: u32) i32 { - var status: i32 = undefined; +pub fn waitpid(pid: i32, flags: u32) u32 { + // TODO allow implicit pointer cast from *u32 to *c_uint ? + const Status = if (builtin.link_libc) c_uint else u32; + var status: Status = undefined; while (true) { switch (errno(system.waitpid(pid, &status, flags))) { - 0 => return status, + 0 => return @bitCast(u32, status), EINTR => continue, ECHILD => unreachable, // The process specified does not exist. It would be a race condition to handle this error. EINVAL => unreachable, // The options argument was invalid @@ -1892,11 +1894,19 @@ pub fn fork() ForkError!pid_t { } pub const MMapError = error{ + /// The underlying filesystem of the specified file does not support memory mapping. + MemoryMappingNotSupported, + + /// A file descriptor refers to a non-regular file. Or a file mapping was requested, + /// but the file descriptor is not open for reading. Or `MAP_SHARED` was requested + /// and `PROT_WRITE` is set, but the file descriptor is not open in `O_RDWR` mode. + /// Or `PROT_WRITE` is set, but the file is append-only. AccessDenied, + + /// The `prot` argument asks for `PROT_EXEC` but the mapped area belongs to a file on + /// a filesystem that was mounted no-exec. PermissionDenied, LockedMemoryLimitExceeded, - SystemFdQuotaExceeded, - MemoryMappingNotSupported, OutOfMemory, Unexpected, }; @@ -1932,7 +1942,6 @@ pub fn mmap( EAGAIN => return error.LockedMemoryLimitExceeded, EBADF => unreachable, // Always a race condition. EOVERFLOW => unreachable, // The number of pages used for length + offset would overflow. - ENFILE => return error.SystemFdQuotaExceeded, ENODEV => return error.MemoryMappingNotSupported, EINVAL => unreachable, // Invalid parameters to mmap() ENOMEM => return error.OutOfMemory, @@ -2265,7 +2274,7 @@ pub fn realpathC(pathname: [*]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPat ENAMETOOLONG => return error.NameTooLong, ELOOP => return error.SymLinkLoop, EIO => return error.InputOutput, - else => |err| return unexpectedErrno(err), + else => |err| return unexpectedErrno(@intCast(usize, err)), }; return mem.toSlice(u8, result_path); } @@ -2349,7 +2358,7 @@ pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void { } pub fn clock_getres(clk_id: i32, res: *timespec) ClockGetTimeError!void { - switch (errno(system.clock_getres(clk_id, tp))) { + switch (errno(system.clock_getres(clk_id, res))) { 0 => return, EFAULT => unreachable, EINVAL => return error.UnsupportedClock, @@ -2364,7 +2373,7 @@ pub const SchedGetAffinityError = error{ pub fn sched_getaffinity(pid: pid_t) SchedGetAffinityError!cpu_set_t { var set: cpu_set_t = undefined; - switch (errno(system.sched_getaffinity(pid, &set))) { + switch (errno(system.sched_getaffinity(pid, @sizeOf(cpu_set_t), &set))) { 0 => return set, EFAULT => unreachable, EINVAL => unreachable, diff --git a/std/os/bits/darwin.zig b/std/os/bits/darwin.zig index ed64a6426a82..6c578bc57e25 100644 --- a/std/os/bits/darwin.zig +++ b/std/os/bits/darwin.zig @@ -219,7 +219,7 @@ pub const MAP_NOCACHE = 0x0400; /// don't reserve needed swap area pub const MAP_NORESERVE = 0x0040; -pub const MAP_FAILED = maxInt(usize); +pub const MAP_FAILED = @intToPtr(*c_void, maxInt(usize)); /// [XSI] no hang in wait/no child to reap pub const WNOHANG = 0x00000001; @@ -749,26 +749,26 @@ pub const IPPROTO_UDP = 17; pub const IPPROTO_IP = 0; pub const IPPROTO_IPV6 = 41; -fn wstatus(x: i32) i32 { +fn wstatus(x: u32) u32 { return x & 0o177; } const wstopped = 0o177; -pub fn WEXITSTATUS(x: i32) i32 { +pub fn WEXITSTATUS(x: u32) u32 { return x >> 8; } -pub fn WTERMSIG(x: i32) i32 { +pub fn WTERMSIG(x: u32) u32 { return wstatus(x); } -pub fn WSTOPSIG(x: i32) i32 { +pub fn WSTOPSIG(x: u32) u32 { return x >> 8; } -pub fn WIFEXITED(x: i32) bool { +pub fn WIFEXITED(x: u32) bool { return wstatus(x) == 0; } -pub fn WIFSTOPPED(x: i32) bool { +pub fn WIFSTOPPED(x: u32) bool { return wstatus(x) == wstopped and WSTOPSIG(x) != 0x13; } -pub fn WIFSIGNALED(x: i32) bool { +pub fn WIFSIGNALED(x: u32) bool { return wstatus(x) != wstopped and wstatus(x) != 0; } diff --git a/std/os/bits/freebsd.zig b/std/os/bits/freebsd.zig index 941181f221f8..d4f49033e176 100644 --- a/std/os/bits/freebsd.zig +++ b/std/os/bits/freebsd.zig @@ -161,7 +161,7 @@ pub const CLOCK_SECOND = 13; pub const CLOCK_THREAD_CPUTIME_ID = 14; pub const CLOCK_PROCESS_CPUTIME_ID = 15; -pub const MAP_FAILED = maxInt(usize); +pub const MAP_FAILED = @intToPtr(*c_void, maxInt(usize)); pub const MAP_SHARED = 0x0001; pub const MAP_PRIVATE = 0x0002; pub const MAP_FIXED = 0x0010; @@ -644,29 +644,23 @@ pub const TIOCGPKT = 0x80045438; pub const TIOCGPTLCK = 0x80045439; pub const TIOCGEXCL = 0x80045440; -fn unsigned(s: i32) u32 { - return @bitCast(u32, s); +pub fn WEXITSTATUS(s: u32) u32 { + return (s & 0xff00) >> 8; } -fn signed(s: u32) i32 { - return @bitCast(i32, s); +pub fn WTERMSIG(s: u32) u32 { + return s & 0x7f; } -pub fn WEXITSTATUS(s: i32) i32 { - return signed((unsigned(s) & 0xff00) >> 8); -} -pub fn WTERMSIG(s: i32) i32 { - return signed(unsigned(s) & 0x7f); -} -pub fn WSTOPSIG(s: i32) i32 { +pub fn WSTOPSIG(s: u32) u32 { return WEXITSTATUS(s); } -pub fn WIFEXITED(s: i32) bool { +pub fn WIFEXITED(s: u32) bool { return WTERMSIG(s) == 0; } -pub fn WIFSTOPPED(s: i32) bool { - return @intCast(u16, (((unsigned(s) & 0xffff) *% 0x10001) >> 8)) > 0x7f00; +pub fn WIFSTOPPED(s: u32) bool { + return @intCast(u16, (((s & 0xffff) *% 0x10001) >> 8)) > 0x7f00; } -pub fn WIFSIGNALED(s: i32) bool { - return (unsigned(s) & 0xffff) -% 1 < 0xff; +pub fn WIFSIGNALED(s: u32) bool { + return (s & 0xffff) -% 1 < 0xff; } pub const winsize = extern struct { diff --git a/std/os/bits/linux.zig b/std/os/bits/linux.zig index 5473299488eb..6532e7236280 100644 --- a/std/os/bits/linux.zig +++ b/std/os/bits/linux.zig @@ -1,5 +1,7 @@ +const builtin = @import("builtin"); const std = @import("../../std.zig"); const maxInt = std.math.maxInt; +use @import("../bits.zig"); pub use @import("linux/errno.zig"); pub use switch (builtin.arch) { @@ -661,29 +663,23 @@ pub const TFD_CLOEXEC = O_CLOEXEC; pub const TFD_TIMER_ABSTIME = 1; pub const TFD_TIMER_CANCEL_ON_SET = (1 << 1); -fn unsigned(s: i32) u32 { - return @bitCast(u32, s); +pub fn WEXITSTATUS(s: u32) u32 { + return (s & 0xff00) >> 8; } -fn signed(s: u32) i32 { - return @bitCast(i32, s); +pub fn WTERMSIG(s: u32) u32 { + return s & 0x7f; } -pub fn WEXITSTATUS(s: i32) i32 { - return signed((unsigned(s) & 0xff00) >> 8); -} -pub fn WTERMSIG(s: i32) i32 { - return signed(unsigned(s) & 0x7f); -} -pub fn WSTOPSIG(s: i32) i32 { +pub fn WSTOPSIG(s: u32) u32 { return WEXITSTATUS(s); } -pub fn WIFEXITED(s: i32) bool { +pub fn WIFEXITED(s: u32) bool { return WTERMSIG(s) == 0; } -pub fn WIFSTOPPED(s: i32) bool { - return @intCast(u16, ((unsigned(s) & 0xffff) *% 0x10001) >> 8) > 0x7f00; +pub fn WIFSTOPPED(s: u32) bool { + return @intCast(u16, ((s & 0xffff) *% 0x10001) >> 8) > 0x7f00; } -pub fn WIFSIGNALED(s: i32) bool { - return (unsigned(s) & 0xffff) -% 1 < 0xff; +pub fn WIFSIGNALED(s: u32) bool { + return (s & 0xffff) -% 1 < 0xff; } pub const winsize = extern struct { @@ -902,7 +898,7 @@ pub const dirent64 = extern struct { pub const dl_phdr_info = extern struct { dlpi_addr: usize, dlpi_name: ?[*]const u8, - dlpi_phdr: [*]elf.Phdr, + dlpi_phdr: [*]std.elf.Phdr, dlpi_phnum: u16, }; diff --git a/std/os/bits/netbsd.zig b/std/os/bits/netbsd.zig index 4a9cf0391c3b..fc4c2904e027 100644 --- a/std/os/bits/netbsd.zig +++ b/std/os/bits/netbsd.zig @@ -152,7 +152,7 @@ pub const CLOCK_MONOTONIC = 3; pub const CLOCK_THREAD_CPUTIME_ID = 0x20000000; pub const CLOCK_PROCESS_CPUTIME_ID = 0x40000000; -pub const MAP_FAILED = maxInt(usize); +pub const MAP_FAILED = @intToPtr(*c_void, maxInt(usize)); pub const MAP_SHARED = 0x0001; pub const MAP_PRIVATE = 0x0002; pub const MAP_REMAPDUP = 0x0004; @@ -516,34 +516,28 @@ pub const TIOCSWINSZ = 0x80087467; pub const TIOCUCNTL = 0x80047466; pub const TIOCXMTFRAME = 0x80087444; -fn unsigned(s: i32) u32 { - return @bitCast(u32, s); +pub fn WEXITSTATUS(s: u32) u32 { + return (s >> 8) & 0xff; } -fn signed(s: u32) i32 { - return @bitCast(i32, s); +pub fn WTERMSIG(s: u32) u32 { + return s & 0x7f; } -pub fn WEXITSTATUS(s: i32) i32 { - return signed((unsigned(s) >> 8) & 0xff); -} -pub fn WTERMSIG(s: i32) i32 { - return signed(unsigned(s) & 0x7f); -} -pub fn WSTOPSIG(s: i32) i32 { +pub fn WSTOPSIG(s: u32) u32 { return WEXITSTATUS(s); } -pub fn WIFEXITED(s: i32) bool { +pub fn WIFEXITED(s: u32) bool { return WTERMSIG(s) == 0; } -pub fn WIFCONTINUED(s: i32) bool { +pub fn WIFCONTINUED(s: u32) bool { return ((s & 0x7f) == 0xffff); } -pub fn WIFSTOPPED(s: i32) bool { +pub fn WIFSTOPPED(s: u32) bool { return ((s & 0x7f != 0x7f) and !WIFCONTINUED(s)); } -pub fn WIFSIGNALED(s: i32) bool { +pub fn WIFSIGNALED(s: u32) bool { return !WIFSTOPPED(s) and !WIFCONTINUED(s) and !WIFEXITED(s); } diff --git a/std/os/linux.zig b/std/os/linux.zig index 4b3739907928..282aa19bf13c 100644 --- a/std/os/linux.zig +++ b/std/os/linux.zig @@ -382,7 +382,7 @@ pub fn unlinkat(dirfd: i32, path: [*]const u8, flags: u32) usize { return syscall3(SYS_unlinkat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), flags); } -pub fn waitpid(pid: i32, status: *i32, flags: u32) usize { +pub fn waitpid(pid: i32, status: *u32, flags: u32) usize { return syscall4(SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), flags, 0); } diff --git a/std/os/linux/test.zig b/std/os/linux/test.zig index 1949d0029864..c78b071c746b 100644 --- a/std/os/linux/test.zig +++ b/std/os/linux/test.zig @@ -11,7 +11,7 @@ test "getpid" { test "timer" { const epoll_fd = linux.epoll_create(); - var err = linux.getErrno(epoll_fd); + var err: usize = linux.getErrno(epoll_fd); expect(err == 0); const timer_fd = linux.timerfd_create(linux.CLOCK_MONOTONIC, 0); diff --git a/std/os/linux/vdso.zig b/std/os/linux/vdso.zig index 44cd0271cdce..86d54bfbf888 100644 --- a/std/os/linux/vdso.zig +++ b/std/os/linux/vdso.zig @@ -5,7 +5,7 @@ const mem = std.mem; const maxInt = std.math.maxInt; pub fn lookup(vername: []const u8, name: []const u8) usize { - const vdso_addr = std.os.linuxGetAuxVal(std.elf.AT_SYSINFO_EHDR); + const vdso_addr = std.os.system.getauxval(std.elf.AT_SYSINFO_EHDR); if (vdso_addr == 0) return 0; const eh = @intToPtr(*elf.Ehdr, vdso_addr); diff --git a/std/os/test.zig b/std/os/test.zig index f7d40e1f03e3..d4d662e97fbd 100644 --- a/std/os/test.zig +++ b/std/os/test.zig @@ -15,11 +15,11 @@ const AtomicRmwOp = builtin.AtomicRmwOp; const AtomicOrder = builtin.AtomicOrder; test "makePath, put some files in it, deleteTree" { - try os.makePath(a, "os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c"); + try fs.makePath(a, "os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c"); try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c" ++ fs.path.sep_str ++ "file.txt", "nonsense"); try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "file2.txt", "blah"); - try os.deleteTree(a, "os_test_tmp"); - if (os.Dir.open(a, "os_test_tmp")) |dir| { + try fs.deleteTree(a, "os_test_tmp"); + if (fs.Dir.open(a, "os_test_tmp")) |dir| { @panic("expected error"); } else |err| { expect(err == error.FileNotFound); @@ -27,7 +27,7 @@ test "makePath, put some files in it, deleteTree" { } test "access file" { - try os.makePath(a, "os_test_tmp"); + try fs.makePath(a, "os_test_tmp"); if (File.access("os_test_tmp" ++ fs.path.sep_str ++ "file.txt")) |ok| { @panic("expected error"); } else |err| { @@ -35,8 +35,8 @@ test "access file" { } try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "file.txt", ""); - try File.access("os_test_tmp" ++ fs.path.sep_str ++ "file.txt"); - try os.deleteTree(a, "os_test_tmp"); + try os.access("os_test_tmp" ++ fs.path.sep_str ++ "file.txt", os.F_OK); + try fs.deleteTree(a, "os_test_tmp"); } fn testThreadIdFn(thread_id: *Thread.Id) void { @@ -52,15 +52,12 @@ test "std.Thread.getCurrentId" { thread.wait(); if (Thread.use_pthreads) { expect(thread_current_id == thread_id); + } else if (os.windows.is_the_target) { + expect(Thread.getCurrentId() != thread_current_id); } else { - switch (builtin.os) { - builtin.Os.windows => expect(Thread.getCurrentId() != thread_current_id), - else => { - // If the thread completes very quickly, then thread_id can be 0. See the - // documentation comments for `std.Thread.handle`. - expect(thread_id == 0 or thread_current_id == thread_id); - }, - } + // If the thread completes very quickly, then thread_id can be 0. See the + // documentation comments for `std.Thread.handle`. + expect(thread_id == 0 or thread_current_id == thread_id); } } @@ -92,7 +89,7 @@ fn start2(ctx: *i32) u8 { } test "cpu count" { - const cpu_count = try std.os.cpuCount(a); + const cpu_count = try Thread.cpuCount(); expect(cpu_count >= 1); } @@ -105,7 +102,7 @@ test "AtomicFile" { \\ this is a test file ; { - var af = try os.AtomicFile.init(test_out_file, File.default_mode); + var af = try fs.AtomicFile.init(test_out_file, File.default_mode); defer af.deinit(); try af.file.write(test_content); try af.finish(); @@ -113,7 +110,7 @@ test "AtomicFile" { const content = try io.readFileAlloc(allocator, test_out_file); expect(mem.eql(u8, content, test_content)); - try os.deleteFile(test_out_file); + try fs.deleteFile(test_out_file); } test "thread local storage" { @@ -145,10 +142,10 @@ test "getrandom" { test "getcwd" { // at least call it so it gets compiled var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; - _ = os.getcwd(&buf) catch {}; + _ = os.getcwd(&buf) catch undefined; } test "realpath" { var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; - testing.expectError(error.FileNotFound, os.realpath("definitely_bogus_does_not_exist1234", &buf)); + testing.expectError(error.FileNotFound, fs.realpath("definitely_bogus_does_not_exist1234", &buf)); } diff --git a/std/os/windows.zig b/std/os/windows.zig index 9bfeee9fe1de..acad139955bd 100644 --- a/std/os/windows.zig +++ b/std/os/windows.zig @@ -1180,6 +1180,44 @@ pub fn CreateProcessW( } } +pub const LoadLibraryError = error{ + FileNotFound, + Unexpected, +}; + +pub fn LoadLibraryW(lpLibFileName: [*]const u16) LoadLibraryError!HMODULE { + return kernel32.LoadLibraryW(lpLibFileName) orelse { + switch (kernel32.GetLastError()) { + ERROR.FILE_NOT_FOUND => return error.FileNotFound, + ERROR.PATH_NOT_FOUND => return error.FileNotFound, + ERROR.MOD_NOT_FOUND => return error.FileNotFound, + else => |err| return unexpectedError(err), + } + }; +} + +pub fn FreeLibrary(hModule: HMODULE) void { + assert(kernel32.FreeLibrary(hModule) != 0); +} + +pub fn QueryPerformanceFrequency() u64 { + // "On systems that run Windows XP or later, the function will always succeed" + // https://docs.microsoft.com/en-us/windows/desktop/api/profileapi/nf-profileapi-queryperformancefrequency + var result: LARGE_INTEGER = undefined; + assert(kernel32.QueryPerformanceFrequency(&result) != 0); + // The kernel treats this integer as unsigned. + return @bitCast(u64, result); +} + +pub fn QueryPerformanceCounter() u64 { + // "On systems that run Windows XP or later, the function will always succeed" + // https://docs.microsoft.com/en-us/windows/desktop/api/profileapi/nf-profileapi-queryperformancecounter + var result: LARGE_INTEGER = undefined; + assert(kernel32.QueryPerformanceCounter(&result) != 0); + // The kernel treats this integer as unsigned. + return @bitCast(u64, result); +} + pub fn cStrToPrefixedFileW(s: [*]const u8) ![PATH_MAX_WIDE + 1]u16 { return sliceToPrefixedFileW(mem.toSliceConst(u8, s)); } diff --git a/std/os/zen.zig b/std/os/zen.zig index 6931b07f7852..8d2f9634863b 100644 --- a/std/os/zen.zig +++ b/std/os/zen.zig @@ -80,7 +80,7 @@ pub const STDOUT_FILENO = 1; pub const STDERR_FILENO = 2; // FIXME: let's borrow Linux's error numbers for now. -use @import("../bits/linux/errno.zig"); +use @import("bits/linux/errno.zig"); // Get the errno from a syscall return value, or 0 for no error. pub fn getErrno(r: usize) usize { const signed_r = @bitCast(isize, r); diff --git a/std/process.zig b/std/process.zig index baccbccb105c..b45074d67c82 100644 --- a/std/process.zig +++ b/std/process.zig @@ -1,7 +1,9 @@ const builtin = @import("builtin"); const std = @import("std.zig"); const os = std.os; +const fs = std.fs; const BufMap = std.BufMap; +const Buffer = std.Buffer; const mem = std.mem; const math = std.math; const Allocator = mem.Allocator; @@ -13,6 +15,24 @@ pub const exit = os.exit; pub const changeCurDir = os.chdir; pub const changeCurDirC = os.chdirC; +/// The result is a slice of `out_buffer`, from index `0`. +pub fn getCwd(out_buffer: *[fs.MAX_PATH_BYTES]u8) ![]u8 { + return os.getcwd(out_buffer); +} + +/// Caller must free the returned memory. +pub fn getCwdAlloc(allocator: *Allocator) ![]u8 { + var buf: [fs.MAX_PATH_BYTES]u8 = undefined; + return mem.dupe(allocator, u8, try os.getcwd(&buf)); +} + +test "getCwdAlloc" { + // at least call it so it gets compiled + var buf: [1000]u8 = undefined; + const allocator = &std.heap.FixedBufferAllocator.init(&buf).allocator; + _ = getCwdAlloc(allocator) catch undefined; +} + /// Caller must free result when done. /// TODO make this go through libc when we have it pub fn getEnvMap(allocator: *Allocator) !BufMap { @@ -402,7 +422,7 @@ pub fn argsAlloc(allocator: *mem.Allocator) ![]const []u8 { var contents = try Buffer.initSize(allocator, 0); defer contents.deinit(); - var slice_list = ArrayList(usize).init(allocator); + var slice_list = std.ArrayList(usize).init(allocator); defer slice_list.deinit(); while (it.next(allocator)) |arg_or_err| { diff --git a/std/thread.zig b/std/thread.zig index 53f42e555f8c..53be5a8c2d68 100644 --- a/std/thread.zig +++ b/std/thread.zig @@ -1,8 +1,10 @@ const builtin = @import("builtin"); const std = @import("std.zig"); const os = std.os; +const mem = std.mem; const windows = std.os.windows; const c = std.c; +const assert = std.debug.assert; pub const Thread = struct { data: Data, @@ -31,14 +33,12 @@ pub const Thread = struct { pub const Data = if (use_pthreads) struct { handle: Thread.Handle, - mmap_addr: usize, - mmap_len: usize, + memory: []align(mem.page_size) u8, } else switch (builtin.os) { .linux => struct { handle: Thread.Handle, - mmap_addr: usize, - mmap_len: usize, + memory: []align(mem.page_size) u8, }, .windows => struct { handle: Thread.Handle, @@ -56,7 +56,7 @@ pub const Thread = struct { return c.pthread_self(); } else return switch (builtin.os) { - .linux => linux.gettid(), + .linux => os.linux.gettid(), .windows => windows.GetCurrentThreadId(), else => @compileError("Unsupported OS"), }; @@ -82,21 +82,21 @@ pub const Thread = struct { os.EDEADLK => unreachable, else => unreachable, } - os.munmap(self.data.mmap_addr, self.data.mmap_len); + os.munmap(self.data.memory); } else switch (builtin.os) { .linux => { while (true) { const pid_value = @atomicLoad(i32, &self.data.handle, .SeqCst); if (pid_value == 0) break; - const rc = linux.futex_wait(&self.data.handle, linux.FUTEX_WAIT, pid_value, null); - switch (linux.getErrno(rc)) { + const rc = os.linux.futex_wait(&self.data.handle, os.linux.FUTEX_WAIT, pid_value, null); + switch (os.linux.getErrno(rc)) { 0 => continue, os.EINTR => continue, os.EAGAIN => continue, else => unreachable, } } - os.munmap(self.data.mmap_addr, self.data.mmap_len); + os.munmap(self.data.memory); }, .windows => { assert(windows.WaitForSingleObject(self.data.handle, windows.INFINITE) == windows.WAIT_OBJECT_0); @@ -130,6 +130,10 @@ pub const Thread = struct { /// Not enough userland memory to spawn the thread. OutOfMemory, + /// `mlockall` is enabled, and the memory needed to spawn the thread + /// would exceed the limit. + LockedMemoryLimitExceeded, + Unexpected, }; @@ -219,7 +223,7 @@ pub const Thread = struct { } }; - const MAP_GROWSDOWN = if (builtin.os == .linux) linux.MAP_GROWSDOWN else 0; + const MAP_GROWSDOWN = if (os.linux.is_the_target) os.linux.MAP_GROWSDOWN else 0; var stack_end_offset: usize = undefined; var thread_start_offset: usize = undefined; @@ -241,7 +245,7 @@ pub const Thread = struct { } // Finally, the Thread Local Storage, if any. if (!Thread.use_pthreads) { - if (linux.tls.tls_image) |tls_img| { + if (os.linux.tls.tls_image) |tls_img| { l = mem.alignForward(l, @alignOf(usize)); tls_start_offset = l; l += tls_img.alloc_size; @@ -249,12 +253,24 @@ pub const Thread = struct { } break :blk l; }; - const mmap_addr = try os.mmap(null, mmap_len, os.PROT_READ | os.PROT_WRITE, os.MAP_PRIVATE | os.MAP_ANONYMOUS | MAP_GROWSDOWN, -1, 0); - errdefer os.munmap(mmap_addr, mmap_len); + const mmap_slice = os.mmap( + null, + mem.alignForward(mmap_len, mem.page_size), + os.PROT_READ | os.PROT_WRITE, + os.MAP_PRIVATE | os.MAP_ANONYMOUS | MAP_GROWSDOWN, + -1, + 0, + ) catch |err| switch (err) { + error.MemoryMappingNotSupported => unreachable, // no file descriptor + error.AccessDenied => unreachable, // no file descriptor + error.PermissionDenied => unreachable, // no file descriptor + else => |e| return e, + }; + errdefer os.munmap(mmap_slice); + const mmap_addr = @ptrToInt(mmap_slice.ptr); const thread_ptr = @alignCast(@alignOf(Thread), @intToPtr(*Thread, mmap_addr + thread_start_offset)); - thread_ptr.data.mmap_addr = mmap_addr; - thread_ptr.data.mmap_len = mmap_len; + thread_ptr.data.memory = mmap_slice; var arg: usize = undefined; if (@sizeOf(Context) != 0) { @@ -269,7 +285,7 @@ pub const Thread = struct { if (c.pthread_attr_init(&attr) != 0) return error.SystemResources; defer assert(c.pthread_attr_destroy(&attr) == 0); - assert(c.pthread_attr_setstack(&attr, @intToPtr(*c_void, mmap_addr), stack_end_offset) == 0); + assert(c.pthread_attr_setstack(&attr, mmap_slice.ptr, stack_end_offset) == 0); const err = c.pthread_create(&thread_ptr.data.handle, &attr, MainFuncs.posixThreadMain, @intToPtr(*c_void, arg)); switch (err) { @@ -279,13 +295,13 @@ pub const Thread = struct { os.EINVAL => unreachable, else => return os.unexpectedErrno(@intCast(usize, err)), } - } else if (builtin.os == .linux) { + } else if (os.linux.is_the_target) { var flags: u32 = os.CLONE_VM | os.CLONE_FS | os.CLONE_FILES | os.CLONE_SIGHAND | os.CLONE_THREAD | os.CLONE_SYSVSEM | os.CLONE_PARENT_SETTID | os.CLONE_CHILD_CLEARTID | os.CLONE_DETACHED; var newtls: usize = undefined; - if (linux.tls.tls_image) |tls_img| { - newtls = linux.tls.copyTLS(mmap_addr + tls_start_offset); + if (os.linux.tls.tls_image) |tls_img| { + newtls = os.linux.tls.copyTLS(mmap_addr + tls_start_offset); flags |= os.CLONE_SETTLS; } const rc = os.linux.clone(MainFuncs.linuxThreadMain, mmap_addr + stack_end_offset, flags, arg, &thread_ptr.data.handle, newtls, &thread_ptr.data.handle); @@ -313,7 +329,7 @@ pub const Thread = struct { pub fn cpuCount() CpuCountError!usize { if (os.linux.is_the_target) { const cpu_set = try os.sched_getaffinity(0); - return os.CPU_COUNT(cpu_set); + return usize(os.CPU_COUNT(cpu_set)); // TODO should not need this usize cast } if (os.windows.is_the_target) { var system_info: windows.SYSTEM_INFO = undefined; diff --git a/std/time.zig b/std/time.zig index 1483a0a13295..d4a349880e24 100644 --- a/std/time.zig +++ b/std/time.zig @@ -95,7 +95,7 @@ pub const Timer = struct { /// be less precise frequency: switch (builtin.os) { .windows => u64, - .macosx, .ios, .tvos, .watchos => darwin.mach_timebase_info_data, + .macosx, .ios, .tvos, .watchos => os.darwin.mach_timebase_info_data, else => void, }, resolution: u64, @@ -119,20 +119,13 @@ pub const Timer = struct { var self: Timer = undefined; if (os.windows.is_the_target) { - var freq: i64 = undefined; - var err = windows.QueryPerformanceFrequency(&freq); - if (err == windows.FALSE) return error.TimerUnsupported; - self.frequency = @intCast(u64, freq); + self.frequency = os.windows.QueryPerformanceFrequency(); self.resolution = @divFloor(ns_per_s, self.frequency); - - var start_time: i64 = undefined; - err = windows.QueryPerformanceCounter(&start_time); - assert(err != windows.FALSE); - self.start_time = @intCast(u64, start_time); + self.start_time = os.windows.QueryPerformanceCounter(); } else if (os.darwin.is_the_target) { - darwin.mach_timebase_info(&self.frequency); + os.darwin.mach_timebase_info(&self.frequency); self.resolution = @divFloor(self.frequency.numer, self.frequency.denom); - self.start_time = darwin.mach_absolute_time(); + self.start_time = os.darwin.mach_absolute_time(); } else { //On Linux, seccomp can do arbitrary things to our ability to call // syscalls, including return any errno value it wants and @@ -177,13 +170,10 @@ pub const Timer = struct { fn clockNative() u64 { if (os.windows.is_the_target) { - var result: i64 = undefined; - var err = windows.QueryPerformanceCounter(&result); - assert(err != windows.FALSE); - return @intCast(u64, result); + return os.windows.QueryPerformanceCounter(); } if (os.darwin.is_the_target) { - return darwin.mach_absolute_time(); + return os.darwin.mach_absolute_time(); } var ts: os.timespec = undefined; os.clock_gettime(monotonic_clock_id, &ts) catch unreachable; diff --git a/test/compare_output.zig b/test/compare_output.zig index 72f4e223aaba..ee84e7caa7cb 100644 --- a/test/compare_output.zig +++ b/test/compare_output.zig @@ -377,7 +377,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { \\ stdout.print("before\n") catch unreachable; \\ defer stdout.print("defer1\n") catch unreachable; \\ defer stdout.print("defer2\n") catch unreachable; - \\ var args_it = @import("std").os.args(); + \\ var args_it = @import("std").process.args(); \\ if (args_it.skip() and !args_it.skip()) return; \\ defer stdout.print("defer3\n") catch unreachable; \\ stdout.print("after\n") catch unreachable; @@ -444,7 +444,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { \\const allocator = std.debug.global_allocator; \\ \\pub fn main() !void { - \\ var args_it = os.args(); + \\ var args_it = std.process.args(); \\ var stdout_file = try io.getStdOut(); \\ var stdout_adapter = stdout_file.outStream(); \\ const stdout = &stdout_adapter.stream; @@ -485,7 +485,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { \\const allocator = std.debug.global_allocator; \\ \\pub fn main() !void { - \\ var args_it = os.args(); + \\ var args_it = std.process.args(); \\ var stdout_file = try io.getStdOut(); \\ var stdout_adapter = stdout_file.outStream(); \\ const stdout = &stdout_adapter.stream; diff --git a/test/standalone/empty_env/main.zig b/test/standalone/empty_env/main.zig index 20b45c31378e..d6d5ecb5af7b 100644 --- a/test/standalone/empty_env/main.zig +++ b/test/standalone/empty_env/main.zig @@ -1,6 +1,6 @@ const std = @import("std"); pub fn main() void { - const env_map = std.os.getEnvMap(std.debug.global_allocator) catch @panic("unable to get env map"); + const env_map = std.process.getEnvMap(std.debug.global_allocator) catch @panic("unable to get env map"); std.testing.expect(env_map.count() == 0); } diff --git a/test/tests.zig b/test/tests.zig index 9bd9292b841d..030864aee064 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -393,7 +393,7 @@ pub const CompareOutputContext = struct { debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err)); }; - const expected_exit_code: i32 = 126; + const expected_exit_code: u32 = 126; switch (term) { .Exited => |code| { if (code != expected_exit_code) {