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
|
// SPDX-License-Identifier: MPL-2.0
// (c) Hare authors <https://harelang.org>
use errors;
use rt;
// Converts a [[duration]] to an [[rt::timespec]]. This function is
// non-portable.
export fn duration_to_timespec(n: duration) rt::timespec = rt::timespec {
tv_sec = n / SECOND,
tv_nsec = n % SECOND,
};
// Converts a [[rt::timespec]] to a [[duration]]. This function is non-portable.
export fn timespec_to_duration(spec: rt::timespec) duration = {
return (spec.tv_sec: i64 * SECOND) + spec.tv_nsec: i64;
};
// Converts a [[duration]] to an [[rt::timeval]]. This function is
// non-portable.
export fn duration_to_timeval(d: duration) rt::timeval = rt::timeval {
tv_sec = d / SECOND,
tv_usec = d % SECOND / 1000,
};
// Converts an [[instant]] to an [[rt::timespec]]. This function is
// non-portable.
export fn instant_to_timespec(t: instant) rt::timespec = rt::timespec {
tv_sec = t.sec,
tv_nsec = t.nsec,
};
// Converts a [[rt::timespec]] to an [[instant]]. This function is
// non-portable.
export fn timespec_to_instant(ts: rt::timespec) instant = instant {
sec = ts.tv_sec,
nsec = ts.tv_nsec,
};
// Yields the process to the kernel and returns after the requested duration.
export fn sleep(d: duration) void = {
let req = duration_to_timespec(d);
for (true) {
let res = rt::timespec { ... };
match (rt::nanosleep(&req, &res)) {
case void =>
return;
case let err: rt::errno =>
switch (err) {
case rt::EINTR =>
req = res;
case =>
abort("Unexpected error from nanosleep");
};
};
};
};
// Yields the process to the kernel and returns when [[clock]] c reaches
// [[instant]] i. WARNING: In openbsd, this function has a flaw, which
// occasionally causes it to sleep for much longer than intended. This is
// unavoidable because openbsd is missing clock_nanosleep() and TIMER_ABSTIME.
// This is a temporary version until this function is implemented in openbsd.
export fn sleep_until(i: instant, c: clock = clock::MONOTONIC) void =
sleep(diff(now(c), i));
// An enumeration of clocks available on this system. Different clocks represent
// times from different epochs, and have different characteristics with regards
// to leap seconds, NTP adjustments, and so on. All systems provide the REALTIME
// and MONOTONIC clocks at least; use of other clocks is not guaranteed to be
// portable.
export type clock = enum {
// The current wall-clock time. This may jump forwards or backwards in
// time to account for leap seconds, NTP adjustments, etc.
REALTIME = rt::CLOCK_REALTIME,
// The current monotonic time. This clock measures from some undefined
// epoch and is not affected by leap seconds, NTP adjustments, and
// changes to the system time: it always increases by one second per
// second.
MONOTONIC = rt::CLOCK_MONOTONIC,
// The uptime clock. It is the time that has elapsed since the system
// booted. Begins at zero.
BOOT = rt::CLOCK_BOOTTIME,
// The runtime clock. It only advances while the system is not suspended
// and begins when the system is booted. Begins at zero.
UPTIME = rt::CLOCK_UPTIME,
// The process CPU clock. It begins at zero and is advanced while the
// calling process is running in user or kernel mode.
PROCESS_CPU = rt::CLOCK_PROCESS_CPUTIME_ID,
// The thread CPU clock. It begins at zero and is advanced while the
// calling thread is running in user or kernel mode.
THREAD_CPU = rt::CLOCK_THREAD_CPUTIME_ID,
};
// Returns the current time for a given clock.
export fn now(clock: clock) instant = {
let ts = rt::timespec { ... };
match (rt::clock_gettime(clock, &ts)) {
case void =>
return timespec_to_instant(ts);
case let err: rt::errno =>
abort("Unexpected error from clock_gettime");
};
};
// Sets system clock to given time.
export fn set(clock: clock, t: instant) (void | errors::noaccess) = {
let tp = instant_to_timespec(t);
let err = match (rt::clock_settime(clock, &tp)) {
case void => return;
case let err: rt::errno =>
yield err;
};
if (err == rt::EPERM) {
return errors::noaccess;
};
abort("Unexpected error from clock_settime");
};
|