authorgravatar for 48591413+chrboesch@users.noreply.github.comChris Boesch <48591413+chrboesch@users.noreply.github.com> 2025-02-01 07:53:57+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-02-01 06:53:57+00:00
log58c00a829e8acf438b91e9f7e1729ce79be722fa
tree21a7941f28fe1aea30c2591d116ad09334b34c8d
parentc44be99f1abff2ab67d69964efecca380b96219e
signaturebadge-check Signed by PGP key B5690EEEBB952194

std.posix: Use separate clock ID enums for clock_gettime() and timerfd_create() (#22627)


6 files changed, 63 insertions(+), 23 deletions(-)

lib/std/Thread/Futex.zig+1-1
...@@ -543,7 +543,7 @@ const PosixImpl = struct {...@@ -543,7 +543,7 @@ const PosixImpl = struct {
543 // This can be changed with pthread_condattr_setclock, but it's an extension and may not be available everywhere.543 // This can be changed with pthread_condattr_setclock, but it's an extension and may not be available everywhere.
544 var ts: c.timespec = undefined;544 var ts: c.timespec = undefined;
545 if (timeout) |timeout_ns| {545 if (timeout) |timeout_ns| {
546 std.posix.clock_gettime(c.CLOCK.REALTIME, &ts) catch unreachable;546 ts = std.posix.clock_gettime(c.CLOCK.REALTIME) catch unreachable;
547 ts.sec +|= @as(@TypeOf(ts.sec), @intCast(timeout_ns / std.time.ns_per_s));547 ts.sec +|= @as(@TypeOf(ts.sec), @intCast(timeout_ns / std.time.ns_per_s));
548 ts.nsec += @as(@TypeOf(ts.nsec), @intCast(timeout_ns % std.time.ns_per_s));548 ts.nsec += @as(@TypeOf(ts.nsec), @intCast(timeout_ns % std.time.ns_per_s));
549549
lib/std/c.zig+18-1
...@@ -213,6 +213,23 @@ pub const ARCH = switch (native_os) {...@@ -213,6 +213,23 @@ pub const ARCH = switch (native_os) {
213 .linux => linux.ARCH,213 .linux => linux.ARCH,
214 else => void,214 else => void,
215};215};
216
217// For use with posix.timerfd_create()
218// Actually, the parameter for the timerfd_create() function is an integer,
219// which means that the developer has to figure out which value is appropriate.
220// To make this easier and, above all, safer, because an incorrect value leads
221// to a panic, an enum is introduced which only allows the values
222// that actually work.
223pub const TIMERFD_CLOCK = timerfd_clockid_t;
224pub const timerfd_clockid_t = switch (native_os) {
225 .linux, .freebsd => enum(u32) {
226 REALTIME = 0,
227 MONOTONIC = 1,
228 _,
229 },
230 else => clockid_t,
231};
232
216pub const CLOCK = clockid_t;233pub const CLOCK = clockid_t;
217pub const clockid_t = switch (native_os) {234pub const clockid_t = switch (native_os) {
218 .linux, .emscripten => linux.clockid_t,235 .linux, .emscripten => linux.clockid_t,
...@@ -9256,7 +9273,7 @@ pub extern "c" fn epoll_pwait(...@@ -9256,7 +9273,7 @@ pub extern "c" fn epoll_pwait(
9256 sigmask: *const sigset_t,9273 sigmask: *const sigset_t,
9257) c_int;9274) c_int;
92589275
9259pub extern "c" fn timerfd_create(clockid: clockid_t, flags: c_int) c_int;9276pub extern "c" fn timerfd_create(clockid: timerfd_clockid_t, flags: c_int) c_int;
9260pub extern "c" fn timerfd_settime(9277pub extern "c" fn timerfd_settime(
9261 fd: c_int,9278 fd: c_int,
9262 flags: c_int,9279 flags: c_int,
lib/std/os/linux.zig+27-3
...@@ -2215,7 +2215,7 @@ pub fn eventfd(count: u32, flags: u32) usize {...@@ -2215,7 +2215,7 @@ pub fn eventfd(count: u32, flags: u32) usize {
2215 return syscall2(.eventfd2, count, flags);2215 return syscall2(.eventfd2, count, flags);
2216}2216}
22172217
2218pub fn timerfd_create(clockid: clockid_t, flags: TFD) usize {2218pub fn timerfd_create(clockid: timerfd_clockid_t, flags: TFD) usize {
2219 return syscall2(2219 return syscall2(
2220 .timerfd_create,2220 .timerfd_create,
2221 @intFromEnum(clockid),2221 @intFromEnum(clockid),
...@@ -4696,8 +4696,32 @@ pub const clockid_t = enum(u32) {...@@ -4696,8 +4696,32 @@ pub const clockid_t = enum(u32) {
4696 BOOTTIME = 7,4696 BOOTTIME = 7,
4697 REALTIME_ALARM = 8,4697 REALTIME_ALARM = 8,
4698 BOOTTIME_ALARM = 9,4698 BOOTTIME_ALARM = 9,
4699 SGI_CYCLE = 10,4699 // In the linux kernel header file (time.h) is the following note:
4700 TAI = 11,4700 // * The driver implementing this got removed. The clock ID is kept as a
4701 // * place holder. Do not reuse!
4702 // Therefore, calling clock_gettime() with these IDs will result in an error.
4703 //
4704 // Some backgrond:
4705 // - SGI_CYCLE was for Silicon Graphics (SGI) workstations,
4706 // which are probably no longer in use, so it makes sense to disable
4707 // - TAI_CLOCK was designed as CLOCK_REALTIME(UTC) + tai_offset,
4708 // but tai_offset was always 0 in the kernel.
4709 // So there is no point in using this clock.
4710 // SGI_CYCLE = 10,
4711 // TAI = 11,
4712 _,
4713};
4714
4715// For use with posix.timerfd_create()
4716// Actually, the parameter for the timerfd_create() function is in integer,
4717// which means that the developer has to figure out which value is appropriate.
4718// To make this easier and, above all, safer, because an incorrect value leads
4719// to a panic, an enum is introduced which only allows the values
4720// that actually work.
4721pub const TIMERFD_CLOCK = timerfd_clockid_t;
4722pub const timerfd_clockid_t = enum(u32) {
4723 REALTIME = 0,
4724 MONOTONIC = 1,
4701 _,4725 _,
4702};4726};
47034727
lib/std/os/linux/test.zig+1-1
...@@ -41,7 +41,7 @@ test "timer" {...@@ -41,7 +41,7 @@ test "timer" {
41 var err: linux.E = linux.E.init(epoll_fd);41 var err: linux.E = linux.E.init(epoll_fd);
42 try expect(err == .SUCCESS);42 try expect(err == .SUCCESS);
4343
44 const timer_fd = linux.timerfd_create(linux.CLOCK.MONOTONIC, .{});44 const timer_fd = linux.timerfd_create(linux.TIMERFD_CLOCK.MONOTONIC, .{});
45 try expect(linux.E.init(timer_fd) == .SUCCESS);45 try expect(linux.E.init(timer_fd) == .SUCCESS);
4646
47 const time_interval = linux.timespec{47 const time_interval = linux.timespec{
lib/std/posix.zig+14-13
...@@ -121,6 +121,7 @@ pub const blkcnt_t = system.blkcnt_t;...@@ -121,6 +121,7 @@ pub const blkcnt_t = system.blkcnt_t;
121pub const blksize_t = system.blksize_t;121pub const blksize_t = system.blksize_t;
122pub const clock_t = system.clock_t;122pub const clock_t = system.clock_t;
123pub const clockid_t = system.clockid_t;123pub const clockid_t = system.clockid_t;
124pub const timerfd_clockid_t = system.timerfd_clockid_t;
124pub const cpu_set_t = system.cpu_set_t;125pub const cpu_set_t = system.cpu_set_t;
125pub const dev_t = system.dev_t;126pub const dev_t = system.dev_t;
126pub const dl_phdr_info = system.dl_phdr_info;127pub const dl_phdr_info = system.dl_phdr_info;
...@@ -155,6 +156,7 @@ pub const socklen_t = system.socklen_t;...@@ -155,6 +156,7 @@ pub const socklen_t = system.socklen_t;
155pub const stack_t = system.stack_t;156pub const stack_t = system.stack_t;
156pub const time_t = system.time_t;157pub const time_t = system.time_t;
157pub const timespec = system.timespec;158pub const timespec = system.timespec;
159pub const timestamp_t = system.timestamp_t;
158pub const timeval = system.timeval;160pub const timeval = system.timeval;
159pub const timezone = system.timezone;161pub const timezone = system.timezone;
160pub const ucontext_t = system.ucontext_t;162pub const ucontext_t = system.ucontext_t;
...@@ -5653,13 +5655,13 @@ pub fn dl_iterate_phdr(...@@ -5653,13 +5655,13 @@ pub fn dl_iterate_phdr(
56535655
5654pub const ClockGetTimeError = error{UnsupportedClock} || UnexpectedError;5656pub const ClockGetTimeError = error{UnsupportedClock} || UnexpectedError;
56555657
5656/// TODO: change this to return the timespec as a return value5658pub fn clock_gettime(clock_id: clockid_t) ClockGetTimeError!timespec {
5657pub fn clock_gettime(clock_id: clockid_t, tp: *timespec) ClockGetTimeError!void {5659 var tp: timespec = undefined;
5658 if (native_os == .wasi and !builtin.link_libc) {5660 if (native_os == .wasi and !builtin.link_libc) {
5659 var ts: wasi.timestamp_t = undefined;5661 var ts: timestamp_t = undefined;
5660 switch (system.clock_time_get(clock_id, 1, &ts)) {5662 switch (system.clock_time_get(clock_id, 1, &ts)) {
5661 .SUCCESS => {5663 .SUCCESS => {
5662 tp.* = .{5664 tp = .{
5663 .sec = @intCast(ts / std.time.ns_per_s),5665 .sec = @intCast(ts / std.time.ns_per_s),
5664 .nsec = @intCast(ts % std.time.ns_per_s),5666 .nsec = @intCast(ts % std.time.ns_per_s),
5665 };5667 };
...@@ -5667,7 +5669,7 @@ pub fn clock_gettime(clock_id: clockid_t, tp: *timespec) ClockGetTimeError!void...@@ -5667,7 +5669,7 @@ pub fn clock_gettime(clock_id: clockid_t, tp: *timespec) ClockGetTimeError!void
5667 .INVAL => return error.UnsupportedClock,5669 .INVAL => return error.UnsupportedClock,
5668 else => |err| return unexpectedErrno(err),5670 else => |err| return unexpectedErrno(err),
5669 }5671 }
5670 return;5672 return tp;
5671 }5673 }
5672 if (native_os == .windows) {5674 if (native_os == .windows) {
5673 if (clock_id == .REALTIME) {5675 if (clock_id == .REALTIME) {
...@@ -5676,19 +5678,19 @@ pub fn clock_gettime(clock_id: clockid_t, tp: *timespec) ClockGetTimeError!void...@@ -5676,19 +5678,19 @@ pub fn clock_gettime(clock_id: clockid_t, tp: *timespec) ClockGetTimeError!void
5676 // FileTime has a granularity of 100 nanoseconds and uses the NTFS/Windows epoch.5678 // FileTime has a granularity of 100 nanoseconds and uses the NTFS/Windows epoch.
5677 const ft64 = (@as(u64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime;5679 const ft64 = (@as(u64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
5678 const ft_per_s = std.time.ns_per_s / 100;5680 const ft_per_s = std.time.ns_per_s / 100;
5679 tp.* = .{5681 tp = .{
5680 .sec = @as(i64, @intCast(ft64 / ft_per_s)) + std.time.epoch.windows,5682 .sec = @as(i64, @intCast(ft64 / ft_per_s)) + std.time.epoch.windows,
5681 .nsec = @as(c_long, @intCast(ft64 % ft_per_s)) * 100,5683 .nsec = @as(c_long, @intCast(ft64 % ft_per_s)) * 100,
5682 };5684 };
5683 return;5685 return tp;
5684 } else {5686 } else {
5685 // TODO POSIX implementation of CLOCK.MONOTONIC on Windows.5687 // TODO POSIX implementation of CLOCK.MONOTONIC on Windows.
5686 return error.UnsupportedClock;5688 return error.UnsupportedClock;
5687 }5689 }
5688 }5690 }
56895691
5690 switch (errno(system.clock_gettime(clock_id, tp))) {5692 switch (errno(system.clock_gettime(clock_id, &tp))) {
5691 .SUCCESS => return,5693 .SUCCESS => return tp,
5692 .FAULT => unreachable,5694 .FAULT => unreachable,
5693 .INVAL => return error.UnsupportedClock,5695 .INVAL => return error.UnsupportedClock,
5694 else => |err| return unexpectedErrno(err),5696 else => |err| return unexpectedErrno(err),
...@@ -5697,7 +5699,7 @@ pub fn clock_gettime(clock_id: clockid_t, tp: *timespec) ClockGetTimeError!void...@@ -5697,7 +5699,7 @@ pub fn clock_gettime(clock_id: clockid_t, tp: *timespec) ClockGetTimeError!void
56975699
5698pub fn clock_getres(clock_id: clockid_t, res: *timespec) ClockGetTimeError!void {5700pub fn clock_getres(clock_id: clockid_t, res: *timespec) ClockGetTimeError!void {
5699 if (native_os == .wasi and !builtin.link_libc) {5701 if (native_os == .wasi and !builtin.link_libc) {
5700 var ts: wasi.timestamp_t = undefined;5702 var ts: timestamp_t = undefined;
5701 switch (system.clock_res_get(@bitCast(clock_id), &ts)) {5703 switch (system.clock_res_get(@bitCast(clock_id), &ts)) {
5702 .SUCCESS => res.* = .{5704 .SUCCESS => res.* = .{
5703 .sec = @intCast(ts / std.time.ns_per_s),5705 .sec = @intCast(ts / std.time.ns_per_s),
...@@ -5910,8 +5912,7 @@ pub fn res_mkquery(...@@ -5910,8 +5912,7 @@ pub fn res_mkquery(
5910 q[i + 3] = class;5912 q[i + 3] = class;
59115913
5912 // Make a reasonably unpredictable id5914 // Make a reasonably unpredictable id
5913 var ts: timespec = undefined;5915 const ts = clock_gettime(.REALTIME) catch unreachable;
5914 clock_gettime(.REALTIME, &ts) catch {};
5915 const UInt = std.meta.Int(.unsigned, @bitSizeOf(@TypeOf(ts.nsec)));5916 const UInt = std.meta.Int(.unsigned, @bitSizeOf(@TypeOf(ts.nsec)));
5916 const unsec: UInt = @bitCast(ts.nsec);5917 const unsec: UInt = @bitCast(ts.nsec);
5917 const id: u32 = @truncate(unsec + unsec / 65536);5918 const id: u32 = @truncate(unsec + unsec / 65536);
...@@ -7293,7 +7294,7 @@ pub const TimerFdCreateError = error{...@@ -7293,7 +7294,7 @@ pub const TimerFdCreateError = error{
7293pub const TimerFdGetError = error{InvalidHandle} || UnexpectedError;7294pub const TimerFdGetError = error{InvalidHandle} || UnexpectedError;
7294pub const TimerFdSetError = TimerFdGetError || error{Canceled};7295pub const TimerFdSetError = TimerFdGetError || error{Canceled};
72957296
7296pub fn timerfd_create(clock_id: clockid_t, flags: system.TFD) TimerFdCreateError!fd_t {7297pub fn timerfd_create(clock_id: system.timerfd_clockid_t, flags: system.TFD) TimerFdCreateError!fd_t {
7297 const rc = system.timerfd_create(clock_id, @bitCast(flags));7298 const rc = system.timerfd_create(clock_id, @bitCast(flags));
7298 return switch (errno(rc)) {7299 return switch (errno(rc)) {
7299 .SUCCESS => @intCast(rc),7300 .SUCCESS => @intCast(rc),
lib/std/time.zig+2-4
...@@ -68,8 +68,7 @@ pub fn nanoTimestamp() i128 {...@@ -68,8 +68,7 @@ pub fn nanoTimestamp() i128 {
68 return value.toEpoch();68 return value.toEpoch();
69 },69 },
70 else => {70 else => {
71 var ts: posix.timespec = undefined;71 const ts = posix.clock_gettime(.REALTIME) catch |err| switch (err) {
72 posix.clock_gettime(.REALTIME, &ts) catch |err| switch (err) {
73 error.UnsupportedClock, error.Unexpected => return 0, // "Precision of timing depends on hardware and OS".72 error.UnsupportedClock, error.Unexpected => return 0, // "Precision of timing depends on hardware and OS".
74 };73 };
75 return (@as(i128, ts.sec) * ns_per_s) + ts.nsec;74 return (@as(i128, ts.sec) * ns_per_s) + ts.nsec;
...@@ -171,8 +170,7 @@ pub const Instant = struct {...@@ -171,8 +170,7 @@ pub const Instant = struct {
171 else => posix.CLOCK.MONOTONIC,170 else => posix.CLOCK.MONOTONIC,
172 };171 };
173172
174 var ts: posix.timespec = undefined;173 const ts = posix.clock_gettime(clock_id) catch return error.Unsupported;
175 posix.clock_gettime(clock_id, &ts) catch return error.Unsupported;
176 return .{ .timestamp = ts };174 return .{ .timestamp = ts };
177 }175 }
178176