Commit 7a4758ed78

Thiago Teodoro Pereira Silva <thiago@thiagotps.xyz>
2022-05-17 00:56:33
std.os: add timerfd_create, timerfd_settime and timerfd_gettime
1 parent 1de7b8d
Changed files (2)
lib
lib/std/os/test.zig
@@ -1000,3 +1000,23 @@ test "access smoke test" {
     file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
     try os.access(file_path, os.F_OK);
 }
+
+test "timerfd" {
+    if (native_os != .linux)
+        return error.SkipZigTest;
+
+    const linux = os.linux;
+    var tfd = try os.timerfd_create(linux.CLOCK.MONOTONIC, linux.TFD.CLOEXEC);
+    defer os.close(tfd);
+
+    var sit: linux.itimerspec = .{ .it_interval = .{ .tv_sec = 0, .tv_nsec = 0 }, .it_value = .{ .tv_sec = 0, .tv_nsec = 10 * (1000 * 1000) } };
+    try os.timerfd_settime(tfd, 0, &sit, null);
+
+    var fds: [1]os.pollfd = .{.{ .fd = tfd, .events = os.linux.POLL.IN, .revents = 0 }};
+    try expectEqual(try os.poll(&fds, -1), 1);
+    var git = try os.timerfd_gettime(tfd);
+    try expectEqual(git, .{ .it_interval = .{ .tv_sec = 0, .tv_nsec = 0 }, .it_value = .{ .tv_sec = 0, .tv_nsec = 0 } });
+
+    try os.timerfd_settime(tfd, 0, &sit, null);
+    try expectEqual(try os.poll(&fds, 5), 0);
+}
lib/std/os.zig
@@ -6926,3 +6926,52 @@ pub fn perf_event_open(
         else => |err| return unexpectedErrno(err),
     }
 }
+
+pub const TimerFdCreateError = error{
+    AccessDenied,
+    ProcessFdQuotaExceeded,
+    SystemFdQuotaExceeded,
+    NoDevice,
+    SystemResources,
+} || UnexpectedError;
+
+pub const TimerFdGetError = error{InvalidHandle} || UnexpectedError;
+pub const TimerFdSetError = TimerFdGetError || error{Canceled};
+
+pub fn timerfd_create(clokid: i32, flags: u32) TimerFdCreateError!fd_t {
+    var rc = linux.timerfd_create(clokid, flags);
+    return switch (errno(rc)) {
+        .SUCCESS => @intCast(fd_t, rc),
+        .INVAL => unreachable,
+        .MFILE => return error.ProcessFdQuotaExceeded,
+        .NFILE => return error.SystemFdQuotaExceeded,
+        .NODEV => return error.NoDevice,
+        .NOMEM => return error.SystemResources,
+        .PERM => return error.AccessDenied,
+        else => |err| return unexpectedErrno(err),
+    };
+}
+
+pub fn timerfd_settime(fd: i32, flags: u32, new_value: *const linux.itimerspec, old_value: ?*linux.itimerspec) TimerFdSetError!void {
+    var rc = linux.timerfd_settime(fd, flags, new_value, old_value);
+    return switch (errno(rc)) {
+        .SUCCESS => {},
+        .BADF => error.InvalidHandle,
+        .FAULT => unreachable,
+        .INVAL => unreachable,
+        .CANCELED => error.Canceled,
+        else => |err| return unexpectedErrno(err),
+    };
+}
+
+pub fn timerfd_gettime(fd: i32) TimerFdGetError!linux.itimerspec {
+    var curr_value: linux.itimerspec = undefined;
+    var rc = linux.timerfd_gettime(fd, &curr_value);
+    return switch (errno(rc)) {
+        .SUCCESS => return curr_value,
+        .BADF => error.InvalidHandle,
+        .FAULT => unreachable,
+        .INVAL => unreachable,
+        else => |err| return unexpectedErrno(err),
+    };
+}