diff --git a/ci/azure/linux_script b/ci/azure/linux_script index fb608d48e1..2a5d2ef1a8 100755 --- a/ci/azure/linux_script +++ b/ci/azure/linux_script @@ -14,7 +14,7 @@ sudo apt-get remove -y llvm-* sudo rm -rf /usr/local/* sudo apt-get install -y libxml2-dev libclang-10-dev llvm-10 llvm-10-dev liblld-10-dev cmake s3cmd gcc-7 g++-7 -QEMUBASE="qemu-linux-x86_64-5.0.0" +QEMUBASE="qemu-linux-x86_64-5.0.0-z2" wget https://ziglang.org/deps/$QEMUBASE.tar.xz tar xf $QEMUBASE.tar.xz PATH=$PWD/$QEMUBASE/bin:$PATH diff --git a/lib/std/c/netbsd.zig b/lib/std/c/netbsd.zig index f3c34b5cad..20960b3f77 100644 --- a/lib/std/c/netbsd.zig +++ b/lib/std/c/netbsd.zig @@ -9,6 +9,7 @@ pub const _errno = __errno; pub const dl_iterate_phdr_callback = extern fn (info: *dl_phdr_info, size: usize, data: ?*c_void) c_int; pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*c_void) c_int; +pub extern "c" fn arc4random_buf(buf: [*]u8, len: usize) void; pub extern "c" fn __fstat50(fd: fd_t, buf: *Stat) c_int; pub extern "c" fn __stat50(path: [*:0]const u8, buf: *Stat) c_int; pub extern "c" fn __clock_gettime50(clk_id: c_int, tp: *timespec) c_int; diff --git a/lib/std/event/loop.zig b/lib/std/event/loop.zig index 6337911cb6..6fa65f90dd 100644 --- a/lib/std/event/loop.zig +++ b/lib/std/event/loop.zig @@ -467,18 +467,43 @@ pub const Loop = struct { } pub fn waitUntilFdReadable(self: *Loop, fd: os.fd_t) void { - return self.linuxWaitFd(fd, os.EPOLLET | os.EPOLLONESHOT | os.EPOLLIN); + switch (builtin.os.tag) { + .linux => { + self.linuxWaitFd(fd, os.EPOLLET | os.EPOLLONESHOT | os.EPOLLIN); + }, + .macosx, .freebsd, .netbsd, .dragonfly => { + self.bsdWaitKev(@intCast(usize, fd), os.EVFILT_READ, os.EV_ONESHOT); + }, + else => @compileError("Unsupported OS"), + } } pub fn waitUntilFdWritable(self: *Loop, fd: os.fd_t) void { - return self.linuxWaitFd(fd, os.EPOLLET | os.EPOLLONESHOT | os.EPOLLOUT); + switch (builtin.os.tag) { + .linux => { + self.linuxWaitFd(fd, os.EPOLLET | os.EPOLLONESHOT | os.EPOLLOUT); + }, + .macosx, .freebsd, .netbsd, .dragonfly => { + self.bsdWaitKev(@intCast(usize, fd), os.EVFILT_WRITE, os.EV_ONESHOT); + }, + else => @compileError("Unsupported OS"), + } } pub fn waitUntilFdWritableOrReadable(self: *Loop, fd: os.fd_t) void { - return self.linuxWaitFd(fd, os.EPOLLET | os.EPOLLONESHOT | os.EPOLLOUT | os.EPOLLIN); + switch (builtin.os.tag) { + .linux => { + self.linuxWaitFd(@intCast(usize, fd), os.EPOLLET | os.EPOLLONESHOT | os.EPOLLOUT | os.EPOLLIN); + }, + .macosx, .freebsd, .netbsd, .dragonfly => { + self.bsdWaitKev(@intCast(usize, fd), os.EVFILT_READ, os.EV_ONESHOT); + self.bsdWaitKev(@intCast(usize, fd), os.EVFILT_WRITE, os.EV_ONESHOT); + }, + else => @compileError("Unsupported OS"), + } } - pub async fn bsdWaitKev(self: *Loop, ident: usize, filter: i16, fflags: u32) !os.Kevent { + pub async fn bsdWaitKev(self: *Loop, ident: usize, filter: i16, fflags: u32) void { var resume_node = ResumeNode.Basic{ .base = ResumeNode{ .id = ResumeNode.Id.Basic, @@ -489,40 +514,37 @@ pub const Loop = struct { }; defer self.bsdRemoveKev(ident, filter); suspend { - try self.bsdAddKev(&resume_node, ident, filter, fflags); + self.bsdAddKev(&resume_node, ident, filter, fflags) catch unreachable; } - return resume_node.kev; } /// resume_node must live longer than the anyframe that it holds a reference to. pub fn bsdAddKev(self: *Loop, resume_node: *ResumeNode.Basic, ident: usize, filter: i16, fflags: u32) !void { self.beginOneEvent(); errdefer self.finishOneEvent(); - var kev = os.Kevent{ + var kev = [1]os.Kevent{os.Kevent{ .ident = ident, .filter = filter, .flags = os.EV_ADD | os.EV_ENABLE | os.EV_CLEAR, .fflags = fflags, .data = 0, .udata = @ptrToInt(&resume_node.base), - }; - const kevent_array = (*const [1]os.Kevent)(&kev); - const empty_kevs = ([*]os.Kevent)(undefined)[0..0]; - _ = try os.kevent(self.os_data.kqfd, kevent_array, empty_kevs, null); + }}; + const empty_kevs = &[0]os.Kevent{}; + _ = try os.kevent(self.os_data.kqfd, &kev, empty_kevs, null); } pub fn bsdRemoveKev(self: *Loop, ident: usize, filter: i16) void { - var kev = os.Kevent{ + var kev = [1]os.Kevent{os.Kevent{ .ident = ident, .filter = filter, .flags = os.EV_DELETE, .fflags = 0, .data = 0, .udata = 0, - }; - const kevent_array = (*const [1]os.Kevent)(&kev); - const empty_kevs = ([*]os.Kevent)(undefined)[0..0]; - _ = os.kevent(self.os_data.kqfd, kevent_array, empty_kevs, null) catch undefined; + }}; + const empty_kevs = &[0]os.Kevent{}; + _ = os.kevent(self.os_data.kqfd, &kev, empty_kevs, null) catch undefined; self.finishOneEvent(); } @@ -679,7 +701,7 @@ pub const Loop = struct { } /// Performs an async `os.open` using a separate thread. - pub fn openZ(self: *Loop, file_path: [*:0]const u8, flags: u32, mode: usize) os.OpenError!os.fd_t { + pub fn openZ(self: *Loop, file_path: [*:0]const u8, flags: u32, mode: os.mode_t) os.OpenError!os.fd_t { var req_node = Request.Node{ .data = .{ .msg = .{ @@ -700,7 +722,7 @@ pub const Loop = struct { } /// Performs an async `os.opent` using a separate thread. - pub fn openatZ(self: *Loop, fd: os.fd_t, file_path: [*:0]const u8, flags: u32, mode: usize) os.OpenError!os.fd_t { + pub fn openatZ(self: *Loop, fd: os.fd_t, file_path: [*:0]const u8, flags: u32, mode: os.mode_t) os.OpenError!os.fd_t { var req_node = Request.Node{ .data = .{ .msg = .{ diff --git a/lib/std/fs.zig b/lib/std/fs.zig index f34ac5baa0..063b2f3fdc 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -1449,7 +1449,7 @@ pub fn createFileAbsoluteW(absolute_path_w: [*:0]const u16, flags: File.CreateFl /// Asserts that the path is absolute. See `Dir.deleteFile` for a function that /// operates on both absolute and relative paths. /// Asserts that the path parameter has no null bytes. -pub fn deleteFileAbsolute(absolute_path: []const u8) DeleteFileError!void { +pub fn deleteFileAbsolute(absolute_path: []const u8) Dir.DeleteFileError!void { assert(path.isAbsolute(absolute_path)); return cwd().deleteFile(absolute_path); } @@ -1457,13 +1457,13 @@ pub fn deleteFileAbsolute(absolute_path: []const u8) DeleteFileError!void { pub const deleteFileAbsoluteC = @compileError("deprecated: renamed to deleteFileAbsoluteZ"); /// Same as `deleteFileAbsolute` except the parameter is null-terminated. -pub fn deleteFileAbsoluteZ(absolute_path_c: [*:0]const u8) DeleteFileError!void { +pub fn deleteFileAbsoluteZ(absolute_path_c: [*:0]const u8) Dir.DeleteFileError!void { assert(path.isAbsoluteZ(absolute_path_c)); return cwd().deleteFileZ(absolute_path_c); } /// Same as `deleteFileAbsolute` except the parameter is WTF-16 encoded. -pub fn deleteFileAbsoluteW(absolute_path_w: [*:0]const u16) DeleteFileError!void { +pub fn deleteFileAbsoluteW(absolute_path_w: [*:0]const u16) Dir.DeleteFileError!void { assert(path.isAbsoluteWindowsW(absolute_path_w)); return cwd().deleteFileW(absolute_path_w); } diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig index 77c4018a6a..7d238c7e92 100644 --- a/lib/std/fs/test.zig +++ b/lib/std/fs/test.zig @@ -110,6 +110,22 @@ test "create file, lock and read from multiple process at once" { }; } +test "open file with exclusive nonblocking lock twice (absolute paths)" { + const allocator = std.testing.allocator; + + const file_paths: [1][]const u8 = .{"zig-test-absolute-paths.txt"}; + const filename = try fs.path.resolve(allocator, &file_paths); + defer allocator.free(filename); + + const file1 = try fs.createFileAbsolute(filename, .{ .lock = .Exclusive, .lock_nonblocking = true }); + + const file2 = fs.createFileAbsolute(filename, .{ .lock = .Exclusive, .lock_nonblocking = true }); + file1.close(); + std.testing.expectError(error.WouldBlock, file2); + + try fs.deleteFileAbsolute(filename); +} + const FileLockTestContext = struct { filename: []const u8, pid: if (builtin.os.tag == .windows) ?void else ?std.os.pid_t = null, diff --git a/lib/std/os.zig b/lib/std/os.zig index d605c0eed3..90c74738b8 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -153,6 +153,10 @@ pub fn getrandom(buffer: []u8) GetRandomError!void { } return; } + if (builtin.os.tag == .netbsd) { + netbsd.arc4random_buf(buffer.ptr, buffer.len); + return; + } if (builtin.os.tag == .wasi) { switch (wasi.random_get(buffer.ptr, buffer.len)) { 0 => return, @@ -854,7 +858,7 @@ pub const OpenError = error{ /// Open and possibly create a file. Keeps trying if it gets interrupted. /// See also `openC`. -pub fn open(file_path: []const u8, flags: u32, perm: usize) OpenError!fd_t { +pub fn open(file_path: []const u8, flags: u32, perm: mode_t) OpenError!fd_t { if (std.Target.current.os.tag == .windows) { const file_path_w = try windows.sliceToPrefixedFileW(file_path); return openW(file_path_w.span(), flags, perm); @@ -867,7 +871,7 @@ pub const openC = @compileError("deprecated: renamed to openZ"); /// Open and possibly create a file. Keeps trying if it gets interrupted. /// See also `open`. -pub fn openZ(file_path: [*:0]const u8, flags: u32, perm: usize) OpenError!fd_t { +pub fn openZ(file_path: [*:0]const u8, flags: u32, perm: mode_t) OpenError!fd_t { if (std.Target.current.os.tag == .windows) { const file_path_w = try windows.cStrToPrefixedFileW(file_path); return openW(file_path_w.span(), flags, perm); diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 5631a90ef9..15f9bf9b62 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -492,7 +492,7 @@ pub fn renameat2(oldfd: i32, oldpath: [*:0]const u8, newfd: i32, newpath: [*:0]c ); } -pub fn open(path: [*:0]const u8, flags: u32, perm: usize) usize { +pub fn open(path: [*:0]const u8, flags: u32, perm: mode_t) usize { if (@hasField(SYS, "open")) { return syscall3(.open, @ptrToInt(path), flags, perm); } else { @@ -506,11 +506,11 @@ pub fn open(path: [*:0]const u8, flags: u32, perm: usize) usize { } } -pub fn create(path: [*:0]const u8, perm: usize) usize { +pub fn create(path: [*:0]const u8, perm: mode_t) usize { return syscall2(.creat, @ptrToInt(path), perm); } -pub fn openat(dirfd: i32, path: [*:0]const u8, flags: u32, mode: usize) usize { +pub fn openat(dirfd: i32, path: [*:0]const u8, flags: u32, mode: mode_t) usize { // dirfd could be negative, for example AT_FDCWD is -100 return syscall4(.openat, @bitCast(usize, @as(isize, dirfd)), @ptrToInt(path), flags, mode); } diff --git a/src/os.cpp b/src/os.cpp index 16d6847d4e..26ed0dc4e1 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -1462,6 +1462,14 @@ static void init_rand() { unsigned seed; memcpy(&seed, ptr_random, sizeof(seed)); srand(seed); +#elif defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD) + unsigned seed; + size_t len = sizeof(seed); + int mib[2] = { CTL_KERN, KERN_ARND }; + if (sysctl(mib, 2, &seed, &len, NULL, 0) != 0) { + zig_panic("unable to query random data from sysctl"); + } + srand(seed); #else int fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC); if (fd == -1) {