authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-04-22 13:24:25-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-04-22 13:24:25-04:00
log0dcadc61b4ce8fb3ffb75b8f266bff2c6ae149b6
tree5dcf2b82a30084f092f30033f0e23a0ca9160def
parent98b88bb52f6385cb5dbbd6bc2238939d8f45e47e
parentca4053ba49d8bd171e592783c6024795c4794fda

Merge branch 'std.os.time' of https://github.com/tgschultz/zig into tgschultz-std.os.time


12 files changed, 403 insertions(+), 54 deletions(-)

CMakeLists.txt+2
...@@ -510,6 +510,8 @@ set(ZIG_STD_FILES...@@ -510,6 +510,8 @@ set(ZIG_STD_FILES
510 "os/linux/index.zig"510 "os/linux/index.zig"
511 "os/linux/x86_64.zig"511 "os/linux/x86_64.zig"
512 "os/path.zig"512 "os/path.zig"
513 "os/time.zig"
514 "os/epoch.zig"
513 "os/windows/error.zig"515 "os/windows/error.zig"
514 "os/windows/index.zig"516 "os/windows/index.zig"
515 "os/windows/util.zig"517 "os/windows/util.zig"
std/c/darwin.zig+18
...@@ -3,10 +3,28 @@ pub extern "c" fn _NSGetExecutablePath(buf: &u8, bufsize: &u32) c_int;...@@ -3,10 +3,28 @@ pub extern "c" fn _NSGetExecutablePath(buf: &u8, bufsize: &u32) c_int;
33
4pub extern "c" fn __getdirentries64(fd: c_int, buf_ptr: &u8, buf_len: usize, basep: &i64) usize;4pub extern "c" fn __getdirentries64(fd: c_int, buf_ptr: &u8, buf_len: usize, basep: &i64) usize;
55
6pub extern "c" fn mach_absolute_time() u64;
7pub extern "c" fn mach_timebase_info(tinfo: ?&mach_timebase_info_data) void;
8
6pub use @import("../os/darwin_errno.zig");9pub use @import("../os/darwin_errno.zig");
710
8pub const _errno = __error;11pub const _errno = __error;
912
13pub const timeval = extern struct {
14 tv_sec: isize,
15 tv_usec: isize,
16};
17
18pub const timezone = extern struct {
19 tz_minuteswest: i32,
20 tz_dsttime: i32,
21};
22
23pub const mach_timebase_info_data = struct {
24 numer: u32,
25 denom: u32,
26};
27
10/// Renamed to Stat to not conflict with the stat function.28/// Renamed to Stat to not conflict with the stat function.
11pub const Stat = extern struct {29pub const Stat = extern struct {
12 dev: i32,30 dev: i32,
std/c/index.zig+1
...@@ -41,6 +41,7 @@ pub extern "c" fn dup2(old_fd: c_int, new_fd: c_int) c_int;...@@ -41,6 +41,7 @@ pub extern "c" fn dup2(old_fd: c_int, new_fd: c_int) c_int;
41pub extern "c" fn readlink(noalias path: &const u8, noalias buf: &u8, bufsize: usize) isize;41pub extern "c" fn readlink(noalias path: &const u8, noalias buf: &u8, bufsize: usize) isize;
42pub extern "c" fn realpath(noalias file_name: &const u8, noalias resolved_name: &u8) ?&u8;42pub extern "c" fn realpath(noalias file_name: &const u8, noalias resolved_name: &u8) ?&u8;
43pub extern "c" fn sigprocmask(how: c_int, noalias set: &const sigset_t, noalias oset: ?&sigset_t) c_int;43pub extern "c" fn sigprocmask(how: c_int, noalias set: &const sigset_t, noalias oset: ?&sigset_t) c_int;
44pub extern "c" fn gettimeofday(tv: ?&timeval, tz: ?&timezone) c_int;
44pub extern "c" fn sigaction(sig: c_int, noalias act: &const Sigaction, noalias oact: ?&Sigaction) c_int;45pub extern "c" fn sigaction(sig: c_int, noalias act: &const Sigaction, noalias oact: ?&Sigaction) c_int;
45pub extern "c" fn nanosleep(rqtp: &const timespec, rmtp: ?&timespec) c_int;46pub extern "c" fn nanosleep(rqtp: &const timespec, rmtp: ?&timespec) c_int;
46pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;47pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;
std/fmt/index.zig+2-1
...@@ -86,7 +86,8 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),...@@ -86,7 +86,8 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
86 },86 },
87 's' => {87 's' => {
88 state = State.Buf;88 state = State.Buf;
89 },'.' => {89 },
90 '.' => {
90 state = State.Float;91 state = State.Float;
91 },92 },
92 else => @compileError("Unknown format character: " ++ []u8{c}),93 else => @compileError("Unknown format character: " ++ []u8{c}),
std/os/darwin.zig+12
...@@ -260,6 +260,10 @@ pub fn readlink(noalias path: &const u8, noalias buf_ptr: &u8, buf_len: usize) u...@@ -260,6 +260,10 @@ pub fn readlink(noalias path: &const u8, noalias buf_ptr: &u8, buf_len: usize) u
260 return errnoWrap(c.readlink(path, buf_ptr, buf_len));260 return errnoWrap(c.readlink(path, buf_ptr, buf_len));
261}261}
262262
263pub fn gettimeofday(tv: ?&timeval, tz: ?&timezone) usize {
264 return errnoWrap(c.gettimeofday(tv, tz));
265}
266
263pub fn nanosleep(req: &const timespec, rem: ?&timespec) usize {267pub fn nanosleep(req: &const timespec, rem: ?&timespec) usize {
264 return errnoWrap(c.nanosleep(req, rem));268 return errnoWrap(c.nanosleep(req, rem));
265}269}
...@@ -330,3 +334,11 @@ pub fn sigaddset(set: &sigset_t, signo: u5) void {...@@ -330,3 +334,11 @@ pub fn sigaddset(set: &sigset_t, signo: u5) void {
330fn errnoWrap(value: isize) usize {334fn errnoWrap(value: isize) usize {
331 return @bitCast(usize, if (value == -1) -isize(*c._errno()) else value);335 return @bitCast(usize, if (value == -1) -isize(*c._errno()) else value);
332}336}
337
338
339pub const timezone = c.timezone;
340pub const timeval = c.timeval;
341pub const mach_timebase_info_data = c.mach_timebase_info_data;
342
343pub const mach_absolute_time = c.mach_absolute_time;
344pub const mach_timebase_info = c.mach_timebase_info;
\ No newline at end of file
std/os/epoch.zig created+26
...@@ -0,0 +1,26 @@
1/// Epoch reference times in terms of their difference from
2/// posix epoch in seconds.
3pub const posix = 0; //Jan 01, 1970 AD
4pub const dos = 315532800; //Jan 01, 1980 AD
5pub const ios = 978307200; //Jan 01, 2001 AD
6pub const openvms = -3506716800; //Nov 17, 1858 AD
7pub const zos = -2208988800; //Jan 01, 1900 AD
8pub const windows = -11644473600; //Jan 01, 1601 AD
9pub const amiga = 252460800; //Jan 01, 1978 AD
10pub const pickos = -63244800; //Dec 31, 1967 AD
11pub const gps = 315964800; //Jan 06, 1980 AD
12pub const clr = -62135769600; //Jan 01, 0001 AD
13
14pub const unix = posix;
15pub const android = posix;
16pub const os2 = dos;
17pub const bios = dos;
18pub const vfat = dos;
19pub const ntfs = windows;
20pub const ntp = zos;
21pub const jbase = pickos;
22pub const aros = amiga;
23pub const morphos = amiga;
24pub const brew = gps;
25pub const atsc = gps;
26pub const go = clr;
\ No newline at end of file
std/os/index.zig+4-47
...@@ -4,16 +4,16 @@ const Os = builtin.Os;...@@ -4,16 +4,16 @@ const Os = builtin.Os;
4const is_windows = builtin.os == Os.windows;4const is_windows = builtin.os == Os.windows;
5const os = this;5const os = this;
66
7test "std.os" {7comptime {
8 if (!builtin.is_test) return;
8 _ = @import("child_process.zig");9 _ = @import("child_process.zig");
9 _ = @import("darwin.zig");10 _ = @import("darwin.zig");
10 _ = @import("darwin_errno.zig");11 _ = @import("darwin_errno.zig");
11 _ = @import("get_user_id.zig");12 _ = @import("get_user_id.zig");
12 _ = @import("linux/errno.zig");
13 _ = @import("linux/index.zig");13 _ = @import("linux/index.zig");
14 _ = @import("linux/x86_64.zig");
15 _ = @import("path.zig");14 _ = @import("path.zig");
16 _ = @import("test.zig");15 _ = @import("test.zig");
16 _ = @import("time.zig");
17 _ = @import("windows/index.zig");17 _ = @import("windows/index.zig");
18}18}
1919
...@@ -32,6 +32,7 @@ pub const net = @import("net.zig");...@@ -32,6 +32,7 @@ pub const net = @import("net.zig");
32pub const ChildProcess = @import("child_process.zig").ChildProcess;32pub const ChildProcess = @import("child_process.zig").ChildProcess;
33pub const path = @import("path.zig");33pub const path = @import("path.zig");
34pub const File = @import("file.zig").File;34pub const File = @import("file.zig").File;
35pub const time = @import("time.zig");
3536
36pub const FileMode = switch (builtin.os) {37pub const FileMode = switch (builtin.os) {
37 Os.windows => void,38 Os.windows => void,
...@@ -1379,50 +1380,6 @@ pub fn readLink(allocator: &Allocator, pathname: []const u8) ![]u8 {...@@ -1379,50 +1380,6 @@ pub fn readLink(allocator: &Allocator, pathname: []const u8) ![]u8 {
1379 }1380 }
1380}1381}
13811382
1382pub fn sleep(seconds: usize, nanoseconds: usize) void {
1383 switch(builtin.os) {
1384 Os.linux, Os.macosx, Os.ios => {
1385 posixSleep(u63(seconds), u63(nanoseconds));
1386 },
1387 Os.windows => {
1388 const milliseconds = seconds * 1000 + nanoseconds / 1000000;
1389 windows.Sleep(windows.DWORD(milliseconds));
1390 },
1391 else => @compileError("Unsupported OS"),
1392 }
1393}
1394
1395const u63 = @IntType(false, 63);
1396pub fn posixSleep(seconds: u63, nanoseconds: u63) void {
1397 var req = posix.timespec {
1398 .tv_sec = seconds,
1399 .tv_nsec = nanoseconds,
1400 };
1401 var rem: posix.timespec = undefined;
1402 while (true) {
1403 const ret_val = posix.nanosleep(&req, &rem);
1404 const err = posix.getErrno(ret_val);
1405 if (err == 0) return;
1406 switch (err) {
1407 posix.EFAULT => unreachable,
1408 posix.EINVAL => {
1409 // Sometimes Darwin returns EINVAL for no reason.
1410 // We treat it as a spurious wakeup.
1411 return;
1412 },
1413 posix.EINTR => {
1414 req = rem;
1415 continue;
1416 },
1417 else => return,
1418 }
1419 }
1420}
1421
1422test "os.sleep" {
1423 sleep(0, 1);
1424}
1425
1426pub fn posix_setuid(uid: u32) !void {1383pub fn posix_setuid(uid: u32) !void {
1427 const err = posix.getErrno(posix.setuid(uid));1384 const err = posix.getErrno(posix.setuid(uid));
1428 if (err == 0) return;1385 if (err == 0) return;
std/os/linux/index.zig+23-6
...@@ -805,6 +805,26 @@ pub fn waitpid(pid: i32, status: &i32, options: i32) usize {...@@ -805,6 +805,26 @@ pub fn waitpid(pid: i32, status: &i32, options: i32) usize {
805 return syscall4(SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0);805 return syscall4(SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0);
806}806}
807807
808pub fn clock_gettime(clk_id: i32, tp: &timespec) usize {
809 return syscall2(SYS_clock_gettime, @bitCast(usize, isize(clk_id)), @ptrToInt(tp));
810}
811
812pub fn clock_getres(clk_id: i32, tp: &timespec) usize {
813 return syscall2(SYS_clock_getres, @bitCast(usize, isize(clk_id)), @ptrToInt(tp));
814}
815
816pub fn clock_settime(clk_id: i32, tp: &const timespec) usize {
817 return syscall2(SYS_clock_settime, @bitCast(usize, isize(clk_id)), @ptrToInt(tp));
818}
819
820pub fn gettimeofday(tv: &timeval, tz: &timezone) usize {
821 return syscall2(SYS_gettimeofday, @ptrToInt(tv), @ptrToInt(tz));
822}
823
824pub fn settimeofday(tv: &const timeval, tz: &const timezone) usize {
825 return syscall2(SYS_settimeofday, @ptrToInt(tv), @ptrToInt(tz));
826}
827
808pub fn nanosleep(req: &const timespec, rem: ?&timespec) usize {828pub fn nanosleep(req: &const timespec, rem: ?&timespec) usize {
809 return syscall2(SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem));829 return syscall2(SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem));
810}830}
...@@ -1289,10 +1309,7 @@ pub fn capset(hdrp: &cap_user_header_t, datap: &const cap_user_data_t) usize {...@@ -1289,10 +1309,7 @@ pub fn capset(hdrp: &cap_user_header_t, datap: &const cap_user_data_t) usize {
1289 return syscall2(SYS_capset, @ptrToInt(hdrp), @ptrToInt(datap));1309 return syscall2(SYS_capset, @ptrToInt(hdrp), @ptrToInt(datap));
1290}1310}
12911311
1292test "import linux test" {1312comptime {
1293 // TODO lazy analysis should prevent this test from being compiled on windows, but1313 if (!builtin.is_test) return;
1294 // it is still compiled on windows1314 _ = @import("test.zig");
1295 if (builtin.os == builtin.Os.linux) {
1296 _ = @import("test.zig");
1297 }
1298}1315}
std/os/linux/test.zig+3
...@@ -1,8 +1,11 @@...@@ -1,8 +1,11 @@
1const std = @import("../../index.zig");1const std = @import("../../index.zig");
2const builtin = @import("builtin");
2const linux = std.os.linux;3const linux = std.os.linux;
3const assert = std.debug.assert;4const assert = std.debug.assert;
45
5test "timer" {6test "timer" {
7 if (builtin.os != builtin.Os.linux) return;
8
6 const epoll_fd = linux.epoll_create();9 const epoll_fd = linux.epoll_create();
7 var err = linux.getErrno(epoll_fd);10 var err = linux.getErrno(epoll_fd);
8 assert(err == 0);11 assert(err == 0);
std/os/linux/x86_64.zig+10
...@@ -492,6 +492,16 @@ pub const timespec = extern struct {...@@ -492,6 +492,16 @@ pub const timespec = extern struct {
492 tv_nsec: isize,492 tv_nsec: isize,
493};493};
494494
495pub const timeval = extern struct {
496 tv_sec: isize,
497 tv_usec: isize,
498};
499
500pub const timezone = extern struct {
501 tz_minuteswest: i32,
502 tz_dsttime: i32,
503};
504
495pub const dirent = extern struct {505pub const dirent = extern struct {
496 d_ino: usize,506 d_ino: usize,
497 d_off: usize,507 d_off: usize,
std/os/time.zig created+288
...@@ -0,0 +1,288 @@
1const std = @import("../index.zig");
2const builtin = @import("builtin");
3const Os = builtin.Os;
4const debug = std.debug;
5
6const windows = std.os.windows;
7const linux = std.os.linux;
8const darwin = std.os.darwin;
9const posix = std.os.posix;
10
11pub const epoch = @import("epoch.zig");
12
13/// Sleep for the specified duration
14pub fn sleep(seconds: usize, nanoseconds: usize) void {
15 switch (builtin.os) {
16 Os.linux, Os.macosx, Os.ios => {
17 posixSleep(u63(seconds), u63(nanoseconds));
18 },
19 Os.windows => {
20 const ns_per_ms = ns_per_s / ms_per_s;
21 const milliseconds = seconds * ms_per_s + nanoseconds / ns_per_ms;
22 windows.Sleep(windows.DWORD(milliseconds));
23 },
24 else => @compileError("Unsupported OS"),
25 }
26}
27
28const u63 = @IntType(false, 63);
29pub fn posixSleep(seconds: u63, nanoseconds: u63) void {
30 var req = posix.timespec {
31 .tv_sec = seconds,
32 .tv_nsec = nanoseconds,
33 };
34 var rem: posix.timespec = undefined;
35 while (true) {
36 const ret_val = posix.nanosleep(&req, &rem);
37 const err = posix.getErrno(ret_val);
38 if (err == 0) return;
39 switch (err) {
40 posix.EFAULT => unreachable,
41 posix.EINVAL => {
42 // Sometimes Darwin returns EINVAL for no reason.
43 // We treat it as a spurious wakeup.
44 return;
45 },
46 posix.EINTR => {
47 req = rem;
48 continue;
49 },
50 else => return,
51 }
52 }
53}
54
55/// Get the posix timestamp, UTC, in seconds
56pub fn timestamp() u64 {
57 return @divFloor(milliTimestamp(), ms_per_s);
58}
59
60/// Get the posix timestamp, UTC, in milliseconds
61pub const milliTimestamp = switch (builtin.os) {
62 Os.windows => milliTimestampWindows,
63 Os.linux => milliTimestampPosix,
64 Os.macosx, Os.ios => milliTimestampDarwin,
65 else => @compileError("Unsupported OS"),
66};
67
68fn milliTimestampWindows() u64 {
69 //FileTime has a granularity of 100 nanoseconds
70 // and uses the NTFS/Windows epoch
71 var ft: i64 = undefined;
72 windows.GetSystemTimeAsFileTime(&ft);
73 const hns_per_ms = (ns_per_s / 100) / ms_per_s;
74 const epoch_adj = epoch.windows * ms_per_s;
75 return u64(@divFloor(ft, hns_per_ms) + epoch_adj);
76}
77
78fn milliTimestampDarwin() u64 {
79 //Sources suggest MacOS 10.12 has support for
80 // posix clock_gettime.
81 var tv: darwin.timeval = undefined;
82 var err = darwin.gettimeofday(&tv, null);
83 debug.assert(err == 0);
84 const sec_ms = u64(tv.tv_sec) * ms_per_s;
85 const usec_ms = @divFloor(u64(tv.tv_usec), us_per_s / ms_per_s);
86 return u64(sec_ms) + u64(usec_ms);
87}
88
89fn milliTimestampPosix() u64 {
90 //From what I can tell there's no reason clock_gettime
91 // should ever fail for us with CLOCK_REALTIME,
92 // seccomp aside.
93 var ts: posix.timespec = undefined;
94 const err = posix.clock_gettime(posix.CLOCK_REALTIME, &ts);
95 debug.assert(err == 0);
96 const sec_ms = u64(ts.tv_sec) * ms_per_s;
97 const nsec_ms = @divFloor(u64(ts.tv_nsec), ns_per_s / ms_per_s);
98 return sec_ms + nsec_ms;
99}
100
101/// Divisions of a second
102pub const ns_per_s = 1000000000;
103pub const us_per_s = 1000000;
104pub const ms_per_s = 1000;
105pub const cs_per_s = 100;
106
107/// Common time divisions
108pub const s_per_min = 60;
109pub const s_per_hour = s_per_min * 60;
110pub const s_per_day = s_per_hour * 24;
111pub const s_per_week = s_per_day * 7;
112
113
114/// A monotonic high-performance timer.
115/// Timer.start() must be called to initialize the struct, which captures
116/// the counter frequency on windows and darwin, records the resolution,
117/// and gives the user an oportunity to check for the existnece of
118/// monotonic clocks without forcing them to check for error on each read.
119/// .resolution is in nanoseconds on all platforms but .start_time's meaning
120/// depends on the OS. On Windows and Darwin it is a hardware counter
121/// value that requires calculation to convert to a meaninful unit.
122pub const Timer = struct {
123
124 //if we used resolution's value when performing the
125 // performance counter calc on windows/darwin, it would
126 // be less precise
127 frequency: switch (builtin.os) {
128 Os.windows => u64,
129 Os.macosx, Os.ios => darwin.mach_timebase_info_data,
130 else => void,
131 },
132 resolution: u64,
133 start_time: u64,
134
135
136 //At some point we may change our minds on RAW, but for now we're
137 // sticking with posix standard MONOTONIC. For more information, see:
138 // https://github.com/zig-lang/zig/pull/933
139 //
140 //const monotonic_clock_id = switch(builtin.os) {
141 // Os.linux => linux.CLOCK_MONOTONIC_RAW,
142 // else => posix.CLOCK_MONOTONIC,
143 //};
144 const monotonic_clock_id = posix.CLOCK_MONOTONIC;
145
146
147 /// Initialize the timer structure.
148 //This gives us an oportunity to grab the counter frequency in windows.
149 //On Windows: QueryPerformanceCounter will succeed on anything >= XP/2000.
150 //On Posix: CLOCK_MONOTONIC will only fail if the monotonic counter is not
151 // supported, or if the timespec pointer is out of bounds, which should be
152 // impossible here barring cosmic rays or other such occurances of
153 // incredibly bad luck.
154 //On Darwin: This cannot fail, as far as I am able to tell.
155 const TimerError = error{TimerUnsupported, Unexpected};
156 pub fn start() TimerError!Timer {
157 var self: Timer = undefined;
158
159 switch (builtin.os) {
160 Os.windows => {
161 var freq: i64 = undefined;
162 var err = windows.QueryPerformanceFrequency(&freq);
163 if (err == 0) return error.TimerUnsupported;
164 self.frequency = u64(freq);
165 self.resolution = @divFloor(ns_per_s, self.frequency);
166
167 var start_time: i64 = undefined;
168 err = windows.QueryPerformanceCounter(&start_time);
169 debug.assert(err != 0);
170 self.start_time = u64(start_time);
171 },
172 Os.linux => {
173 //On Linux, seccomp can do arbitrary things to our ability to call
174 // syscalls, including return any errno value it wants and
175 // inconsistently throwing errors. Since we can't account for
176 // abuses of seccomp in a reasonable way, we'll assume that if
177 // seccomp is going to block us it will at least do so consistently
178 var ts: posix.timespec = undefined;
179 var result = posix.clock_getres(monotonic_clock_id, &ts);
180 var errno = posix.getErrno(result);
181 switch (errno) {
182 0 => {},
183 posix.EINVAL => return error.TimerUnsupported,
184 else => return std.os.unexpectedErrorPosix(errno),
185 }
186 self.resolution = u64(ts.tv_sec) * u64(ns_per_s) + u64(ts.tv_nsec);
187
188 result = posix.clock_gettime(monotonic_clock_id, &ts);
189 errno = posix.getErrno(result);
190 if (errno != 0) return std.os.unexpectedErrorPosix(errno);
191 self.start_time = u64(ts.tv_sec) * u64(ns_per_s) + u64(ts.tv_nsec);
192 },
193 Os.macosx, Os.ios => {
194 darwin.mach_timebase_info(&self.frequency);
195 self.resolution = @divFloor(self.frequency.numer, self.frequency.denom);
196 self.start_time = darwin.mach_absolute_time();
197 },
198 else => @compileError("Unsupported OS"),
199 }
200 return self;
201 }
202
203 /// Reads the timer value since start or the last reset in nanoseconds
204 pub fn read(self: &Timer) u64 {
205 var clock = clockNative() - self.start_time;
206 return switch (builtin.os) {
207 Os.windows => @divFloor(clock * ns_per_s, self.frequency),
208 Os.linux => clock,
209 Os.macosx, Os.ios => @divFloor(clock * self.frequency.numer, self.frequency.denom),
210 else => @compileError("Unsupported OS"),
211 };
212 }
213
214 /// Resets the timer value to 0/now.
215 pub fn reset(self: &Timer) void
216 {
217 self.start_time = clockNative();
218 }
219
220 /// Returns the current value of the timer in nanoseconds, then resets it
221 pub fn lap(self: &Timer) u64 {
222 var now = clockNative();
223 var lap_time = self.read();
224 self.start_time = now;
225 return lap_time;
226 }
227
228
229 const clockNative = switch (builtin.os) {
230 Os.windows => clockWindows,
231 Os.linux => clockLinux,
232 Os.macosx, Os.ios => clockDarwin,
233 else => @compileError("Unsupported OS"),
234 };
235
236 fn clockWindows() u64 {
237 var result: i64 = undefined;
238 var err = windows.QueryPerformanceCounter(&result);
239 debug.assert(err != 0);
240 return u64(result);
241 }
242
243 fn clockDarwin() u64 {
244 return darwin.mach_absolute_time();
245 }
246
247 fn clockLinux() u64 {
248 var ts: posix.timespec = undefined;
249 var result = posix.clock_gettime(monotonic_clock_id, &ts);
250 debug.assert(posix.getErrno(result) == 0);
251 return u64(ts.tv_sec) * u64(ns_per_s) + u64(ts.tv_nsec);
252 }
253};
254
255
256
257
258
259test "os.time.sleep" {
260 sleep(0, 1);
261}
262
263test "os.time.timestamp" {
264 const ns_per_ms = (ns_per_s / ms_per_s);
265 const margin = 50;
266
267 const time_0 = milliTimestamp();
268 sleep(0, ns_per_ms);
269 const time_1 = milliTimestamp();
270 const interval = time_1 - time_0;
271 debug.assert(interval > 0 and interval < margin);
272}
273
274test "os.time.Timer" {
275 const ns_per_ms = (ns_per_s / ms_per_s);
276 const margin = ns_per_ms * 50;
277
278 var timer = try Timer.start();
279 sleep(0, 10 * ns_per_ms);
280 const time_0 = timer.read();
281 debug.assert(time_0 > 0 and time_0 < margin);
282
283 const time_1 = timer.lap();
284 debug.assert(time_1 > time_0);
285
286 timer.reset();
287 debug.assert(timer.read() < time_1);
288}
\ No newline at end of file
std/os/windows/index.zig+14
...@@ -1,3 +1,10 @@...@@ -1,3 +1,10 @@
1const builtin = @import("builtin");
2comptime {
3 if (!builtin.is_test) return;
4 _ = @import("util.zig");
5}
6
7
1pub const ERROR = @import("error.zig");8pub const ERROR = @import("error.zig");
29
3pub extern "advapi32" stdcallcc fn CryptAcquireContextA(phProv: &HCRYPTPROV, pszContainer: ?LPCSTR,10pub extern "advapi32" stdcallcc fn CryptAcquireContextA(phProv: &HCRYPTPROV, pszContainer: ?LPCSTR,
...@@ -61,6 +68,8 @@ pub extern "kernel32" stdcallcc fn GetFinalPathNameByHandleA(hFile: HANDLE, lpsz...@@ -61,6 +68,8 @@ pub extern "kernel32" stdcallcc fn GetFinalPathNameByHandleA(hFile: HANDLE, lpsz
6168
62pub extern "kernel32" stdcallcc fn GetProcessHeap() ?HANDLE;69pub extern "kernel32" stdcallcc fn GetProcessHeap() ?HANDLE;
6370
71pub extern "kernel32" stdcallcc fn GetSystemTimeAsFileTime(?&FILETIME) void;
72
64pub extern "kernel32" stdcallcc fn HeapCreate(flOptions: DWORD, dwInitialSize: SIZE_T, dwMaximumSize: SIZE_T) ?HANDLE;73pub extern "kernel32" stdcallcc fn HeapCreate(flOptions: DWORD, dwInitialSize: SIZE_T, dwMaximumSize: SIZE_T) ?HANDLE;
65pub extern "kernel32" stdcallcc fn HeapDestroy(hHeap: HANDLE) BOOL;74pub extern "kernel32" stdcallcc fn HeapDestroy(hHeap: HANDLE) BOOL;
66pub extern "kernel32" stdcallcc fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: &c_void, dwBytes: SIZE_T) ?&c_void;75pub extern "kernel32" stdcallcc fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: &c_void, dwBytes: SIZE_T) ?&c_void;
...@@ -77,6 +86,10 @@ pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem...@@ -77,6 +86,10 @@ pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem
7786
78pub extern "kernel32" stdcallcc fn MoveFileExA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR,87pub extern "kernel32" stdcallcc fn MoveFileExA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR,
79 dwFlags: DWORD) BOOL;88 dwFlags: DWORD) BOOL;
89
90pub extern "kernel32" stdcallcc fn QueryPerformanceCounter(lpPerformanceCount: &LARGE_INTEGER) BOOL;
91
92pub extern "kernel32" stdcallcc fn QueryPerformanceFrequency(lpFrequency: &LARGE_INTEGER) BOOL;
8093
81pub extern "kernel32" stdcallcc fn PathFileExists(pszPath: ?LPCTSTR) BOOL;94pub extern "kernel32" stdcallcc fn PathFileExists(pszPath: ?LPCTSTR) BOOL;
8295
...@@ -139,6 +152,7 @@ pub const UNICODE = false;...@@ -139,6 +152,7 @@ pub const UNICODE = false;
139pub const WCHAR = u16;152pub const WCHAR = u16;
140pub const WORD = u16;153pub const WORD = u16;
141pub const LARGE_INTEGER = i64;154pub const LARGE_INTEGER = i64;
155pub const FILETIME = i64;
142156
143pub const TRUE = 1;157pub const TRUE = 1;
144pub const FALSE = 0;158pub const FALSE = 0;