sleep
Owner: IIIlllIIIllI URL: git@github.com:nyangkosense/sleep.git
sleep.zig
// sleep.zig
const syscall = struct {
pub const write = 1;
pub const nanosleep = 35;
pub const exit = 60;
};
const EINTR = 4;
const MAX_SECONDS = 2147483647; // INT_MAX
fn writeSyscall(fd: u32, buf: [*]const u8, count: usize) usize {
var result: usize = undefined;
asm volatile (
\\ mov %[syscall_num], %%rax
\\ mov %[fd], %%rdi
\\ mov %[buf], %%rsi
\\ mov %[count], %%rdx
\\ syscall
: [result] "={rax}" (result)
: [syscall_num] "r" (@as(usize, syscall.write)),
[fd] "r" (@as(usize, fd)),
[buf] "r" (@intFromPtr(buf)),
[count] "r" (count)
: "rax", "rdi", "rsi", "rdx", "rcx", "r11", "memory"
);
return result;
}
fn nanosleepSyscall(req: *const Timespec, rem: ?*Timespec) isize {
var result: isize = undefined;
asm volatile (
\\ mov %[syscall_num], %%rax
\\ mov %[req], %%rdi
\\ mov %[rem], %%rsi
\\ syscall
: [result] "={rax}" (result)
: [syscall_num] "r" (@as(usize, syscall.nanosleep)),
[req] "r" (@intFromPtr(req)),
[rem] "r" (if (rem) |r| @intFromPtr(r) else @as(usize, 0))
: "rax", "rdi", "rsi", "rcx", "r11", "memory"
);
return result;
}
fn exitSyscall(code: u8) noreturn {
asm volatile (
\\ mov %[syscall_num], %%rax
\\ mov %[code], %%rdi
\\ syscall
:
: [syscall_num] "r" (@as(usize, syscall.exit)),
[code] "r" (@as(usize, code))
: "rax", "rdi", "memory"
);
unreachable;
}
const Timespec = extern struct {
tv_sec: u64,
tv_nsec: u64,
};
const ParseResult = struct {
seconds: u64,
nanos: u64,
};
fn parseTime(str: [*:0]const u8) ?ParseResult {
var seconds: u64 = 0;
var nanos: u64 = 0;
var i: usize = 0;
var saw_dot = false;
var decimal_places: u32 = 0;
if (str[0] == 0) return null;
while (str[i] != 0) : (i += 1) {
const c = str[i];
if (c == '.') {
if (saw_dot) return null; // Multiple dots
saw_dot = true;
continue;
}
if (c < '0' or c > '9') return null;
const digit = c - '0';
if (!saw_dot) {
const new_seconds = seconds * 10 + digit;
if (new_seconds < seconds or new_seconds > MAX_SECONDS) return null;
seconds = new_seconds;
} else {
if (decimal_places >= 9) continue;
nanos = nanos * 10 + digit;
decimal_places += 1;
}
}
while (decimal_places < 9) : (decimal_places += 1) {
nanos *= 10;
}
return ParseResult{ .seconds = seconds, .nanos = nanos };
}
fn writeNumber(n: u64) void {
if (n == 0) {
_ = writeSyscall(1, "0", 1);
return;
}
var buf: [20]u8 = undefined; // u64 max is 20 digits
var i: usize = 0;
var num = n;
while (num > 0) : (i += 1) {
buf[i] = @as(u8, @intCast(num % 10)) + '0';
num /= 10;
}
var j: usize = 0;
while (j < i) : (j += 1) {
const c = buf[i - 1 - j];
_ = writeSyscall(1, &c, 1);
}
}
fn start(stack_ptr: [*]usize) noreturn {
const argc = stack_ptr[0];
const argv: [*][*:0]u8 = @ptrCast(stack_ptr + 1);
if (argc != 2) {
const usage_msg = "Usage: sleep NUMBER[.FRACTION]\n";
_ = writeSyscall(2, usage_msg, usage_msg.len);
exitSyscall(1);
}
const parsed = parseTime(argv[1]) orelse {
const error_msg = "sleep: invalid time interval\n";
_ = writeSyscall(2, error_msg, error_msg.len);
exitSyscall(1);
};
var req = Timespec{
.tv_sec = parsed.seconds,
.tv_nsec = parsed.nanos,
};
var rem = Timespec{
.tv_sec = 0,
.tv_nsec = 0,
};
while (true) {
const result = nanosleepSyscall(&req, &rem);
if (result == 0) break;
const err = @as(usize, @bitCast(-result));
if (err != EINTR) break;
req = rem;
}
exitSyscall(0);
}
pub export fn _start() callconv(.Naked) noreturn {
@setRuntimeSafety(false);
asm volatile (
\\ xor %edi, %edi
\\ mov %rsp, %rsi
\\ jmp *%[start_fn]
:
: [start_fn] "r" (&start)
: "rdi", "rsi", "memory"
);
unreachable;
}