Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions lib/std/c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1527,6 +1527,18 @@ pub usingnamespace switch (native_os) {
},
};

// clock_nanosleep() and TIMER_ABSTIME exist in the libc of only some Unix-like
// systems, but they are consistent everywhere they exist.
pub usingnamespace switch (native_os) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unlikely to get merged using usingnamespace, see #19214 for how to avoid using it.

.linux, .freebsd, .netbsd, .dragonfly => struct {
pub const TIMER = struct {
pub const ABSTIME = 0x01;
};
pub extern "c" fn clock_nanosleep(clk_id: c_int, flags: c_int, rqtp: *const c.timespec, rmtp: ?*c.timespec) c_int;
},
else => struct {},
};

pub const fstat = switch (native_os) {
.macos => switch (native_arch) {
.x86_64 => private.@"fstat$INODE64",
Expand Down
43 changes: 43 additions & 0 deletions lib/std/os.zig
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ pub const Stat = system.Stat;
pub const T = system.T;
pub const TCSA = system.TCSA;
pub const TCP = system.TCP;
pub const TIMER = system.TIMER;
pub const VDSO = system.VDSO;
pub const W = system.W;
pub const addrinfo = system.addrinfo;
Expand Down Expand Up @@ -5812,6 +5813,48 @@ pub fn nanosleep(seconds: u64, nanoseconds: u64) void {
}
}

pub const ClockNanosleepError = error{
InvalidArgument,
NotImplemented,
UnsupportedClock,
} || UnexpectedError;

// The interface choices here are a blend of the existing ones from nanosleep()
// and clock_gettime(), and EINTR is retried internally to mirror nanosleep()
// while handling TIMER.ABSTIME properly.
pub fn clock_nanosleep(clk_id: i32, flags: i32, seconds: u64, nanoseconds: u64) ClockNanosleepError!void {
// We could also potentially do a poor emulation via clock_gettime() +
// nanosleep() on systems that have those, but for now:
if (!@hasDecl(system, "clock_nanosleep"))
@compileError("Unsupported OS");

var req = timespec{
.tv_sec = std.math.cast(isize, seconds) orelse std.math.maxInt(isize),
.tv_nsec = std.math.cast(isize, nanoseconds) orelse std.math.maxInt(isize),
};
var rem: timespec = undefined;
while (true) {
// All the POSIX/libc versions of clock_nanosleep return *positive*
// errno numbers, which are unusual. The direct Linux syscall uses
// normal -errno stuff.
const rc = system.clock_nanosleep(clk_id, flags, &req, &rem);
const errval: E = if (use_libc) @enumFromInt(rc) else errno(rc);
switch (errval) {
.SUCCESS => return,
.INTR => {
if (flags != system.TIMER.ABSTIME)
req = rem;
continue;
},
.OPNOTSUPP => return error.UnsupportedClock,
.INVAL => return error.InvalidArgument,
.NOSYS => return error.NotImplemented, // NetBSD
.FAULT => unreachable,
else => |err| return unexpectedErrno(err),
}
}
}

pub fn dl_iterate_phdr(
context: anytype,
comptime Error: type,
Expand Down
8 changes: 8 additions & 0 deletions lib/std/os/linux.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1369,6 +1369,10 @@ pub fn clock_settime(clk_id: i32, tp: *const timespec) usize {
return syscall2(.clock_settime, @as(usize, @bitCast(@as(isize, clk_id))), @intFromPtr(tp));
}

pub fn clock_nanosleep(clk_id: i32, flags: i32, rqtp: *const timespec, rmtp: ?*timespec) usize {
return std.os.linux.syscall4(.clock_nanosleep, @as(usize, @bitCast(@as(isize, clk_id))), @as(usize, @bitCast(@as(isize, flags))), @intFromPtr(rqtp), @intFromPtr(rmtp));
}

pub fn gettimeofday(tv: ?*timeval, tz: ?*timezone) usize {
return syscall2(.gettimeofday, @intFromPtr(tv), @intFromPtr(tz));
}
Expand Down Expand Up @@ -3420,6 +3424,10 @@ pub const CLOCK = struct {
pub const TAI = 11;
};

pub const TIMER = struct {
pub const ABSTIME = 0x01;
};

pub const CSIGNAL = 0x000000ff;

pub const CLONE = struct {
Expand Down
7 changes: 7 additions & 0 deletions lib/std/os/test.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1284,3 +1284,10 @@ test "fchmodat smoke test" {
try expectMode(tmp.dir.fd, "symlink", 0o600);
try expectMode(tmp.dir.fd, "regfile", 0o640);
}

test "clock_nanosleep smoke test" {
if (!@hasDecl(os.system, "clock_nanosleep")) return error.SkipZigTest;
// Absolute sleep until CLOCK.REALTIME is >= 0,0. Should always be <= now,
// and therefore should immediately return without error.
try os.clock_nanosleep(os.CLOCK.REALTIME, os.TIMER.ABSTIME, 0, 0);
}