Skip to content

Commit 58c00a8

Browse files
authored
std.posix: Use separate clock ID enums for clock_gettime() and timerfd_create() (#22627)
1 parent c44be99 commit 58c00a8

File tree

6 files changed

+63
-23
lines changed

6 files changed

+63
-23
lines changed

lib/std/Thread/Futex.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -543,7 +543,7 @@ const PosixImpl = struct {
543543
// This can be changed with pthread_condattr_setclock, but it's an extension and may not be available everywhere.
544544
var ts: c.timespec = undefined;
545545
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;
547547
ts.sec +|= @as(@TypeOf(ts.sec), @intCast(timeout_ns / std.time.ns_per_s));
548548
ts.nsec += @as(@TypeOf(ts.nsec), @intCast(timeout_ns % std.time.ns_per_s));
549549

lib/std/c.zig

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,23 @@ pub const ARCH = switch (native_os) {
213213
.linux => linux.ARCH,
214214
else => void,
215215
};
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.
223+
pub const TIMERFD_CLOCK = timerfd_clockid_t;
224+
pub 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+
216233
pub const CLOCK = clockid_t;
217234
pub const clockid_t = switch (native_os) {
218235
.linux, .emscripten => linux.clockid_t,
@@ -9256,7 +9273,7 @@ pub extern "c" fn epoll_pwait(
92569273
sigmask: *const sigset_t,
92579274
) c_int;
92589275

9259-
pub extern "c" fn timerfd_create(clockid: clockid_t, flags: c_int) c_int;
9276+
pub extern "c" fn timerfd_create(clockid: timerfd_clockid_t, flags: c_int) c_int;
92609277
pub extern "c" fn timerfd_settime(
92619278
fd: c_int,
92629279
flags: c_int,

lib/std/os/linux.zig

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2215,7 +2215,7 @@ pub fn eventfd(count: u32, flags: u32) usize {
22152215
return syscall2(.eventfd2, count, flags);
22162216
}
22172217

2218-
pub fn timerfd_create(clockid: clockid_t, flags: TFD) usize {
2218+
pub fn timerfd_create(clockid: timerfd_clockid_t, flags: TFD) usize {
22192219
return syscall2(
22202220
.timerfd_create,
22212221
@intFromEnum(clockid),
@@ -4696,8 +4696,32 @@ pub const clockid_t = enum(u32) {
46964696
BOOTTIME = 7,
46974697
REALTIME_ALARM = 8,
46984698
BOOTTIME_ALARM = 9,
4699-
SGI_CYCLE = 10,
4700-
TAI = 11,
4699+
// In the linux kernel header file (time.h) is the following note:
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.
4721+
pub const TIMERFD_CLOCK = timerfd_clockid_t;
4722+
pub const timerfd_clockid_t = enum(u32) {
4723+
REALTIME = 0,
4724+
MONOTONIC = 1,
47014725
_,
47024726
};
47034727

lib/std/os/linux/test.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ test "timer" {
4141
var err: linux.E = linux.E.init(epoll_fd);
4242
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, .{});
4545
try expect(linux.E.init(timer_fd) == .SUCCESS);
4646

4747
const time_interval = linux.timespec{

lib/std/posix.zig

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ pub const blkcnt_t = system.blkcnt_t;
121121
pub const blksize_t = system.blksize_t;
122122
pub const clock_t = system.clock_t;
123123
pub const clockid_t = system.clockid_t;
124+
pub const timerfd_clockid_t = system.timerfd_clockid_t;
124125
pub const cpu_set_t = system.cpu_set_t;
125126
pub const dev_t = system.dev_t;
126127
pub const dl_phdr_info = system.dl_phdr_info;
@@ -155,6 +156,7 @@ pub const socklen_t = system.socklen_t;
155156
pub const stack_t = system.stack_t;
156157
pub const time_t = system.time_t;
157158
pub const timespec = system.timespec;
159+
pub const timestamp_t = system.timestamp_t;
158160
pub const timeval = system.timeval;
159161
pub const timezone = system.timezone;
160162
pub const ucontext_t = system.ucontext_t;
@@ -5653,21 +5655,21 @@ pub fn dl_iterate_phdr(
56535655

56545656
pub const ClockGetTimeError = error{UnsupportedClock} || UnexpectedError;
56555657

5656-
/// TODO: change this to return the timespec as a return value
5657-
pub fn clock_gettime(clock_id: clockid_t, tp: *timespec) ClockGetTimeError!void {
5658+
pub fn clock_gettime(clock_id: clockid_t) ClockGetTimeError!timespec {
5659+
var tp: timespec = undefined;
56585660
if (native_os == .wasi and !builtin.link_libc) {
5659-
var ts: wasi.timestamp_t = undefined;
5661+
var ts: timestamp_t = undefined;
56605662
switch (system.clock_time_get(clock_id, 1, &ts)) {
56615663
.SUCCESS => {
5662-
tp.* = .{
5664+
tp = .{
56635665
.sec = @intCast(ts / std.time.ns_per_s),
56645666
.nsec = @intCast(ts % std.time.ns_per_s),
56655667
};
56665668
},
56675669
.INVAL => return error.UnsupportedClock,
56685670
else => |err| return unexpectedErrno(err),
56695671
}
5670-
return;
5672+
return tp;
56715673
}
56725674
if (native_os == .windows) {
56735675
if (clock_id == .REALTIME) {
@@ -5676,19 +5678,19 @@ pub fn clock_gettime(clock_id: clockid_t, tp: *timespec) ClockGetTimeError!void
56765678
// FileTime has a granularity of 100 nanoseconds and uses the NTFS/Windows epoch.
56775679
const ft64 = (@as(u64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
56785680
const ft_per_s = std.time.ns_per_s / 100;
5679-
tp.* = .{
5681+
tp = .{
56805682
.sec = @as(i64, @intCast(ft64 / ft_per_s)) + std.time.epoch.windows,
56815683
.nsec = @as(c_long, @intCast(ft64 % ft_per_s)) * 100,
56825684
};
5683-
return;
5685+
return tp;
56845686
} else {
56855687
// TODO POSIX implementation of CLOCK.MONOTONIC on Windows.
56865688
return error.UnsupportedClock;
56875689
}
56885690
}
56895691

5690-
switch (errno(system.clock_gettime(clock_id, tp))) {
5691-
.SUCCESS => return,
5692+
switch (errno(system.clock_gettime(clock_id, &tp))) {
5693+
.SUCCESS => return tp,
56925694
.FAULT => unreachable,
56935695
.INVAL => return error.UnsupportedClock,
56945696
else => |err| return unexpectedErrno(err),
@@ -5697,7 +5699,7 @@ pub fn clock_gettime(clock_id: clockid_t, tp: *timespec) ClockGetTimeError!void
56975699

56985700
pub fn clock_getres(clock_id: clockid_t, res: *timespec) ClockGetTimeError!void {
56995701
if (native_os == .wasi and !builtin.link_libc) {
5700-
var ts: wasi.timestamp_t = undefined;
5702+
var ts: timestamp_t = undefined;
57015703
switch (system.clock_res_get(@bitCast(clock_id), &ts)) {
57025704
.SUCCESS => res.* = .{
57035705
.sec = @intCast(ts / std.time.ns_per_s),
@@ -5910,8 +5912,7 @@ pub fn res_mkquery(
59105912
q[i + 3] = class;
59115913

59125914
// Make a reasonably unpredictable id
5913-
var ts: timespec = undefined;
5914-
clock_gettime(.REALTIME, &ts) catch {};
5915+
const ts = clock_gettime(.REALTIME) catch unreachable;
59155916
const UInt = std.meta.Int(.unsigned, @bitSizeOf(@TypeOf(ts.nsec)));
59165917
const unsec: UInt = @bitCast(ts.nsec);
59175918
const id: u32 = @truncate(unsec + unsec / 65536);
@@ -7293,7 +7294,7 @@ pub const TimerFdCreateError = error{
72937294
pub const TimerFdGetError = error{InvalidHandle} || UnexpectedError;
72947295
pub const TimerFdSetError = TimerFdGetError || error{Canceled};
72957296

7296-
pub fn timerfd_create(clock_id: clockid_t, flags: system.TFD) TimerFdCreateError!fd_t {
7297+
pub fn timerfd_create(clock_id: system.timerfd_clockid_t, flags: system.TFD) TimerFdCreateError!fd_t {
72977298
const rc = system.timerfd_create(clock_id, @bitCast(flags));
72987299
return switch (errno(rc)) {
72997300
.SUCCESS => @intCast(rc),

lib/std/time.zig

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,7 @@ pub fn nanoTimestamp() i128 {
6868
return value.toEpoch();
6969
},
7070
else => {
71-
var ts: posix.timespec = undefined;
72-
posix.clock_gettime(.REALTIME, &ts) catch |err| switch (err) {
71+
const ts = posix.clock_gettime(.REALTIME) catch |err| switch (err) {
7372
error.UnsupportedClock, error.Unexpected => return 0, // "Precision of timing depends on hardware and OS".
7473
};
7574
return (@as(i128, ts.sec) * ns_per_s) + ts.nsec;
@@ -171,8 +170,7 @@ pub const Instant = struct {
171170
else => posix.CLOCK.MONOTONIC,
172171
};
173172

174-
var ts: posix.timespec = undefined;
175-
posix.clock_gettime(clock_id, &ts) catch return error.Unsupported;
173+
const ts = posix.clock_gettime(clock_id) catch return error.Unsupported;
176174
return .{ .timestamp = ts };
177175
}
178176

0 commit comments

Comments
 (0)