std lib sleep APIs: add doc comments and no @intCast

The sleep APIs are now documented as having spurious wakeups and no
precision of timing guaranteed. They also cannot fail. This commit makes
the entire range of u64 legal values to pass to std.os.time.sleep and
std.os.time.posixSleep. Values that do not fit in the native system APIs
will cause a sleep for the longest possible duration and then be handled
as a spurious wakeup.
This commit is contained in:
Andrew Kelley 2019-05-04 15:16:39 -04:00
parent 70a9ee3dd6
commit 09cbcf8841
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9

View File

@ -13,44 +13,35 @@ const posix = std.os.posix;
pub const epoch = @import("epoch.zig");
/// Sleep for the specified duration
/// Spurious wakeups are possible and no precision of timing is guaranteed.
pub fn sleep(nanoseconds: u64) void {
switch (builtin.os) {
Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
const s = nanoseconds / ns_per_s;
const ns = nanoseconds % ns_per_s;
posixSleep(@intCast(u63, s), @intCast(u63, ns));
posixSleep(s, ns);
},
Os.windows => {
const ns_per_ms = ns_per_s / ms_per_s;
const milliseconds = nanoseconds / ns_per_ms;
windows.Sleep(@intCast(windows.DWORD, milliseconds));
const ms_that_will_fit = std.math.cast(windows.DWORD, milliseconds) catch std.math.maxInt(windows.DWORD);
windows.Sleep(ms_that_will_fit);
},
else => @compileError("Unsupported OS"),
}
}
pub fn posixSleep(seconds: u63, nanoseconds: u63) void {
var req: posix.timespec = undefined;
/// Spurious wakeups are possible and no precision of timing is guaranteed.
pub fn posixSleep(seconds: u64, nanoseconds: u64) void {
var req = posix.timespec{
.tv_sec = std.math.cast(isize, seconds) catch std.math.maxInt(isize),
.tv_nsec = std.math.cast(isize, nanoseconds) catch std.math.maxInt(isize),
};
var rem: posix.timespec = undefined;
var req_sec = seconds;
var req_nsec = nanoseconds;
while (true) {
req.tv_sec = math.min(math.maxInt(isize), req_sec);
req.tv_nsec = @intCast(isize, req_nsec);
req_sec -= @intCast(u63, req.tv_sec);
req_nsec = 0;
const ret_val = posix.nanosleep(&req, &rem);
const err = posix.getErrno(ret_val);
switch (err) {
0 => {
// If there's still time to wait keep running the loop
if (req_sec == 0 and req_nsec == 0) return;
},
posix.EFAULT => unreachable,
posix.EINVAL => {
// Sometimes Darwin returns EINVAL for no reason.
@ -58,10 +49,10 @@ pub fn posixSleep(seconds: u63, nanoseconds: u63) void {
return;
},
posix.EINTR => {
req_sec += @intCast(u63, rem.tv_sec);
req_nsec = @intCast(u63, rem.tv_nsec);
req = rem;
continue;
},
// This prong handles success as well as unexpected errors.
else => return,
}
}