| ... | @@ -13,44 +13,35 @@ const posix = std.os.posix; | ... | @@ -13,44 +13,35 @@ const posix = std.os.posix; |
| 13 | | 13 | |
| 14 | pub const epoch = @import("epoch.zig"); | 14 | pub const epoch = @import("epoch.zig"); |
| 15 | | 15 | |
| 16 | /// Sleep for the specified duration | 16 | /// Spurious wakeups are possible and no precision of timing is guaranteed. |
| 17 | pub fn sleep(nanoseconds: u64) void { | 17 | pub fn sleep(nanoseconds: u64) void { |
| 18 | switch (builtin.os) { | 18 | switch (builtin.os) { |
| 19 | Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => { | 19 | Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => { |
| 20 | const s = nanoseconds / ns_per_s; | 20 | const s = nanoseconds / ns_per_s; |
| 21 | const ns = nanoseconds % ns_per_s; | 21 | const ns = nanoseconds % ns_per_s; |
| 22 | posixSleep(@intCast(u63, s), @intCast(u63, ns)); | 22 | posixSleep(s, ns); |
| 23 | }, | 23 | }, |
| 24 | Os.windows => { | 24 | Os.windows => { |
| 25 | const ns_per_ms = ns_per_s / ms_per_s; | 25 | const ns_per_ms = ns_per_s / ms_per_s; |
| 26 | const milliseconds = nanoseconds / ns_per_ms; | 26 | const milliseconds = nanoseconds / ns_per_ms; |
| 27 | windows.Sleep(@intCast(windows.DWORD, milliseconds)); | 27 | const ms_that_will_fit = std.math.cast(windows.DWORD, milliseconds) catch std.math.maxInt(windows.DWORD); |
| | 28 | windows.Sleep(ms_that_will_fit); |
| 28 | }, | 29 | }, |
| 29 | else => @compileError("Unsupported OS"), | 30 | else => @compileError("Unsupported OS"), |
| 30 | } | 31 | } |
| 31 | } | 32 | } |
| 32 | | 33 | |
| 33 | pub fn posixSleep(seconds: u63, nanoseconds: u63) void { | 34 | /// Spurious wakeups are possible and no precision of timing is guaranteed. |
| 34 | var req: posix.timespec = undefined; | 35 | pub fn posixSleep(seconds: u64, nanoseconds: u64) void { |
| | 36 | var req = posix.timespec{ |
| | 37 | .tv_sec = std.math.cast(isize, seconds) catch std.math.maxInt(isize), |
| | 38 | .tv_nsec = std.math.cast(isize, nanoseconds) catch std.math.maxInt(isize), |
| | 39 | }; |
| 35 | var rem: posix.timespec = undefined; | 40 | var rem: posix.timespec = undefined; |
| 36 | | | |
| 37 | var req_sec = seconds; | | |
| 38 | var req_nsec = nanoseconds; | | |
| 39 | | | |
| 40 | while (true) { | 41 | while (true) { |
| 41 | req.tv_sec = math.min(math.maxInt(isize), req_sec); | | |
| 42 | req.tv_nsec = @intCast(isize, req_nsec); | | |
| 43 | | | |
| 44 | req_sec -= @intCast(u63, req.tv_sec); | | |
| 45 | req_nsec = 0; | | |
| 46 | | | |
| 47 | const ret_val = posix.nanosleep(&req, &rem); | 42 | const ret_val = posix.nanosleep(&req, &rem); |
| 48 | const err = posix.getErrno(ret_val); | 43 | const err = posix.getErrno(ret_val); |
| 49 | switch (err) { | 44 | switch (err) { |
| 50 | 0 => { | | |
| 51 | // If there's still time to wait keep running the loop | | |
| 52 | if (req_sec == 0 and req_nsec == 0) return; | | |
| 53 | }, | | |
| 54 | posix.EFAULT => unreachable, | 45 | posix.EFAULT => unreachable, |
| 55 | posix.EINVAL => { | 46 | posix.EINVAL => { |
| 56 | // Sometimes Darwin returns EINVAL for no reason. | 47 | // Sometimes Darwin returns EINVAL for no reason. |
| ... | @@ -58,10 +49,10 @@ pub fn posixSleep(seconds: u63, nanoseconds: u63) void { | ... | @@ -58,10 +49,10 @@ pub fn posixSleep(seconds: u63, nanoseconds: u63) void { |
| 58 | return; | 49 | return; |
| 59 | }, | 50 | }, |
| 60 | posix.EINTR => { | 51 | posix.EINTR => { |
| 61 | req_sec += @intCast(u63, rem.tv_sec); | 52 | req = rem; |
| 62 | req_nsec = @intCast(u63, rem.tv_nsec); | | |
| 63 | continue; | 53 | continue; |
| 64 | }, | 54 | }, |
| | 55 | // This prong handles success as well as unexpected errors. |
| 65 | else => return, | 56 | else => return, |
| 66 | } | 57 | } |
| 67 | } | 58 | } |