1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module time
#include <time.h>
#include <errno.h>
struct C.tm {
tm_sec int
tm_min int
tm_hour int
tm_mday int
tm_mon int
tm_year int
tm_wday int
tm_yday int
tm_isdst int
}
fn C.timegm(&C.tm) C.time_t
// fn C.gmtime_r(&tm, &gbuf)
fn C.localtime_r(t &time_t, tm &C.tm)
fn make_unix_time(t C.tm) int {
return int(C.timegm(&t))
}
// local returns t with the location set to local time.
pub fn (t Time) local() Time {
loc_tm := C.tm{}
C.localtime_r(voidptr(&t.unix), &loc_tm)
return convert_ctime(loc_tm, t.microsecond)
}
// in most systems, these are __quad_t, which is an i64
struct C.timespec {
mut:
tv_sec i64
tv_nsec i64
}
// the first arg is defined in include/bits/types.h as `__S32_TYPE`, which is `int`
fn C.clock_gettime(int, &C.timespec)
fn C.nanosleep(req &C.timespec, rem &C.timespec) int
// sys_mono_now returns a *monotonically increasing time*, NOT a time adjusted for daylight savings, location etc.
pub fn sys_mono_now() u64 {
$if macos {
return sys_mono_now_darwin()
} $else {
ts := C.timespec{}
C.clock_gettime(C.CLOCK_MONOTONIC, &ts)
return u64(ts.tv_sec) * 1000000000 + u64(ts.tv_nsec)
}
}
// NB: vpc_now is used by `v -profile` .
// It should NOT call *any other v function*, just C functions and casts.
[inline]
fn vpc_now() u64 {
ts := C.timespec{}
C.clock_gettime(C.CLOCK_MONOTONIC, &ts)
return u64(ts.tv_sec) * 1000000000 + u64(ts.tv_nsec)
}
// The linux_* functions are placed here, since they're used on Android as well
// TODO: should `$if linux {}` be parsed on Android as well? (Android runs under the Linux kernel)
// linux_now returns the local time with high precision for most os:es
// this should be implemented properly with support for leap seconds.
// It uses the realtime clock to get and converts it to local time
fn linux_now() Time {
// get the high precision time as UTC realtime clock
// and use the nanoseconds part
mut ts := C.timespec{}
C.clock_gettime(C.CLOCK_REALTIME, &ts)
loc_tm := C.tm{}
C.localtime_r(voidptr(&ts.tv_sec), &loc_tm)
return convert_ctime(loc_tm, int(ts.tv_nsec / 1000))
}
fn linux_utc() Time {
// get the high precision time as UTC realtime clock
// and use the nanoseconds part
mut ts := C.timespec{}
C.clock_gettime(C.CLOCK_REALTIME, &ts)
return unix2(i64(ts.tv_sec), int(ts.tv_nsec / 1000))
}
// dummy to compile with all compilers
pub fn win_now() Time {
return Time{}
}
// dummy to compile with all compilers
pub fn win_utc() Time {
return Time{}
}
// dummy to compile with all compilers
pub struct C.timeval {
tv_sec u64
tv_usec u64
}
// return absolute timespec for now()+d
pub fn (d Duration) timespec() C.timespec {
mut ts := C.timespec{}
C.clock_gettime(C.CLOCK_REALTIME, &ts)
d_sec := d / second
d_nsec := d % second
ts.tv_sec += d_sec
ts.tv_nsec += d_nsec
if ts.tv_nsec > i64(second) {
ts.tv_nsec -= i64(second)
ts.tv_sec++
}
return ts
}
// return timespec of 1970/1/1
pub fn zero_timespec() C.timespec {
ts := C.timespec{
tv_sec: 0
tv_nsec: 0
}
return ts
}
// sleep makes the calling thread sleep for a given duration (in nanoseconds).
pub fn sleep(duration Duration) {
mut req := C.timespec{duration / second, duration % second}
rem := C.timespec{}
for C.nanosleep(&req, &rem) < 0 {
if C.errno == C.EINTR {
// Interrupted by a signal handler
req = rem
} else {
break
}
}
}
// some *nix system functions (e.g. `C.poll()`, C.epoll_wait()) accept an `int`
// value as *timeout in milliseconds* with the special value `-1` meaning "infinite"
pub fn (d Duration) sys_milliseconds() int {
if d > C.INT32_MAX * millisecond { // treat 2147483647000001 .. C.INT64_MAX as "infinite"
return -1
} else if d <= 0 {
return 0 // treat negative timeouts as 0 - consistent with Unix behaviour
} else {
return int(d / millisecond)
}
}
|