Skip to content

Instantly share code, notes, and snippets.

@lithdew
Last active July 19, 2020 21:16
Show Gist options
  • Save lithdew/79717cd161490bc1895a6df3f610a565 to your computer and use it in GitHub Desktop.
Save lithdew/79717cd161490bc1895a6df3f610a565 to your computer and use it in GitHub Desktop.
zig: listen for SIGINT (linux)
const std = @import("std");
const print = std.debug.print;
const assert = std.debug.assert;
pub const signalfd_siginfo = extern struct {
signo: u32,
errno: i32,
code: i32,
pid: u32,
uid: u32,
fd: i32,
tid: u32,
band: u32,
overrun: u32,
trapno: u32,
status: i32,
int: i32,
ptr: u64,
utime: u64,
stime: u64,
addr: u64,
addr_lsb: u16,
__pad2: u16,
syscall: i32,
call_addr: u64,
arch: u32,
__pad: [28]u8,
};
pub fn signalfd(fd: std.os.fd_t, mask: *const std.os.sigset_t, flags: i32) !std.os.fd_t {
const rc = signalfd4(fd, mask, flags);
switch (std.os.errno(rc)) {
0 => return @intCast(std.os.fd_t, rc),
std.os.EBADF, std.os.EINVAL => unreachable,
std.os.ENFILE => return error.SystemFdQuotaExceeded,
std.os.ENOMEM => return error.SystemResources,
std.os.EMFILE => return error.ProcessResources,
std.os.ENODEV => return error.InodeMountFail,
std.os.ENOSYS => return error.SystemOutdated,
else => |err| return std.os.unexpectedErrno(err),
}
}
pub fn signalfd4(fd: std.os.fd_t, mask: *const std.os.sigset_t, flags: i32) usize {
return std.os.linux.syscall4(
.signalfd4,
@bitCast(usize, @as(isize, fd)),
@ptrToInt(mask),
@bitCast(usize, @as(usize, std.os.NSIG / 8)),
@intCast(usize, flags),
);
}
pub fn sigaddset(set: *std.os.sigset_t, sig: u6) void {
const s = sig - 1;
const shift = @intCast(u5, s & (usize.bit_count - 1));
const val = @intCast(u32, 1) << shift;
(set.*)[@intCast(usize, s) / usize.bit_count] |= val;
}
pub fn main() !void {
const allocator = std.heap.page_allocator;
var mask: std.os.sigset_t = std.mem.zeroes(std.os.sigset_t);
sigaddset(&mask, std.os.SIGTERM);
sigaddset(&mask, std.os.SIGINT);
assert(std.os.linux.sigprocmask(std.os.SIG_BLOCK, &mask, null) == 0);
const signal_fd = try signalfd(-1, &mask, 0);
defer std.os.close(signal_fd);
print("Opened Signal FD: {}\n", .{signal_fd});
var list = std.ArrayList(std.os.pollfd).init(allocator);
defer list.deinit();
try list.append(.{ .fd = signal_fd, .events = std.os.POLLIN, .revents = 0 });
var counter: usize = 3;
Loop: while (true) {
const count = try std.os.poll(list.items, -1);
if (count == 0) {
print("Timed out; retrying...\n", .{});
continue;
}
for (list.items) |poll| {
assert(poll.fd == signal_fd);
var buf: [@sizeOf(signalfd_siginfo)]u8 align(8) = undefined;
assert((try std.os.read(signal_fd, &buf)) == buf.len);
var info = @ptrCast(*signalfd_siginfo, &buf);
assert(info.signo == std.os.SIGINT);
print("Hit Ctrl+C {} more time(s).\n", .{counter});
counter -= 1;
if (counter == 0) {
break :Loop;
}
}
}
print("Good bye.\n", .{});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment