hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit 786bc69f83d902972b4b9dfb520679a746f1a544
parent 16079e6475f338574113eb1984ecdf3f5868e61d
Author: Mykyta Holubakha <hilobakho@gmail.com>
Date:   Thu, 18 Mar 2021 17:27:22 +0200

time::now: use vdso

Diffstat:
Mgen-stdlib | 5+++--
Mstdlib.mk | 10++++++----
Dtime/+linux.ha | 64----------------------------------------------------------------
Atime/+linux/+aarch64.ha | 2++
Atime/+linux/+x86_64.ha | 2++
Atime/+linux/functions.ha | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 111 insertions(+), 70 deletions(-)

diff --git a/gen-stdlib b/gen-stdlib @@ -477,9 +477,10 @@ strio() { time() { printf '# time\n' gen_srcs time \ - '$(PLATFORM).ha' \ + '$(PLATFORM)/functions.ha' \ + '$(PLATFORM)/$(ARCH).ha' \ types.ha - gen_ssa time + gen_ssa time linux::vdso } temp() { diff --git a/stdlib.mk b/stdlib.mk @@ -582,10 +582,11 @@ $(HARECACHE)/temp/temp.ssa: $(stdlib_temp_srcs) $(stdlib_rt) $(stdlib_crypto_ran # time stdlib_time_srcs= \ - $(STDLIB)/time/$(PLATFORM).ha \ + $(STDLIB)/time/$(PLATFORM)/functions.ha \ + $(STDLIB)/time/$(PLATFORM)/$(ARCH).ha \ $(STDLIB)/time/types.ha -$(HARECACHE)/time/time.ssa: $(stdlib_time_srcs) $(stdlib_rt) +$(HARECACHE)/time/time.ssa: $(stdlib_time_srcs) $(stdlib_rt) $(stdlib_linux_vdso) @printf 'HAREC \t$@\n' @mkdir -p $(HARECACHE)/time @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ntime \ @@ -1198,10 +1199,11 @@ $(TESTCACHE)/temp/temp.ssa: $(testlib_temp_srcs) $(testlib_rt) $(testlib_crypto_ # time testlib_time_srcs= \ - $(STDLIB)/time/$(PLATFORM).ha \ + $(STDLIB)/time/$(PLATFORM)/functions.ha \ + $(STDLIB)/time/$(PLATFORM)/$(ARCH).ha \ $(STDLIB)/time/types.ha -$(TESTCACHE)/time/time.ssa: $(testlib_time_srcs) $(testlib_rt) +$(TESTCACHE)/time/time.ssa: $(testlib_time_srcs) $(testlib_rt) $(testlib_linux_vdso) @printf 'HAREC \t$@\n' @mkdir -p $(TESTCACHE)/time @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ntime \ diff --git a/time/+linux.ha b/time/+linux.ha @@ -1,64 +0,0 @@ -use rt; - -fn duration_to_timespec(n: duration, ts: *rt::timespec) void = { - ts.tv_sec = n / SECOND; - ts.tv_nsec = n % SECOND; -}; - -fn time_to_timespec(t: time, ts: *rt::timespec) void = { - ts.tv_sec = t.sec; - ts.tv_nsec = t.nsec; -}; - -fn timespec_to_time(ts: rt::timespec) time = time { - sec = ts.tv_sec, - nsec = ts.tv_nsec, -}; - -// Yields the process to the kernel and returns after the requested duration. -export fn sleep(n: duration) void = { - let in = rt::timespec { ... }; - duration_to_timespec(n, &in); - let req = &in; - - for (true) { - let res = rt::timespec { ... }; - match (rt::nanosleep(req, &res)) { - void => return, - err: rt::errno => switch (err) { - rt::EINTR => { - req = &res; - }, - * => abort("Unexpected error from nanosleep"), - }, - }; - }; -}; - -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 = 0, - - // 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 = 1, - - // Measures CPU time consumed by the calling process. - PROCESS_CPU = 2, - - // Time since the system was booted. Increases monotonically and, - // unlike [MONOTONIC], continues to tick while the system is suspended. - BOOT = 7, -}; - -// Returns the current time for a given clock. -export fn now(clock: clock) time = { - let tp = rt::timespec { ... }; - return match (rt::clock_gettime(clock, &tp)) { - void => timespec_to_time(tp), - err: rt::errno => abort("Unexpected error from clock_gettime"), - }; -}; diff --git a/time/+linux/+aarch64.ha b/time/+linux/+aarch64.ha @@ -0,0 +1,2 @@ +export def VDSO_CGT_SYM: str = "__kernel_clock_gettime"; +export def VDSO_CGT_VER: str = "LINUX_2.6.39"; diff --git a/time/+linux/+x86_64.ha b/time/+linux/+x86_64.ha @@ -0,0 +1,2 @@ +export def VDSO_CGT_SYM: str = "__vdso_clock_gettime"; +export def VDSO_CGT_VER: str = "LINUX_2.6"; diff --git a/time/+linux/functions.ha b/time/+linux/functions.ha @@ -0,0 +1,98 @@ +use rt; +use linux::vdso; + + +fn duration_to_timespec(n: duration, ts: *rt::timespec) void = { + ts.tv_sec = n / SECOND; + ts.tv_nsec = n % SECOND; +}; + +fn time_to_timespec(t: time, ts: *rt::timespec) void = { + ts.tv_sec = t.sec; + ts.tv_nsec = t.nsec; +}; + +fn timespec_to_time(ts: rt::timespec) time = time { + sec = ts.tv_sec, + nsec = ts.tv_nsec, +}; + +// Yields the process to the kernel and returns after the requested duration. +export fn sleep(n: duration) void = { + let in = rt::timespec { ... }; + duration_to_timespec(n, &in); + let req = &in; + + for (true) { + let res = rt::timespec { ... }; + match (rt::nanosleep(req, &res)) { + void => return, + err: rt::errno => switch (err) { + rt::EINTR => { + req = &res; + }, + * => abort("Unexpected error from nanosleep"), + }, + }; + }; +}; + +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 = 0, + + // 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 = 1, + + // Measures CPU time consumed by the calling process. + PROCESS_CPU = 2, + + // Time since the system was booted. Increases monotonically and, + // unlike [MONOTONIC], continues to tick while the system is suspended. + BOOT = 7, +}; + +let cgt_vdso: nullable *fn(int, *rt::timespec) int = null; + +fn get_cgt_vdso() nullable *fn(int, *rt::timespec) int = { + static let vdso_checked: bool = false; + if (vdso_checked) + return cgt_vdso; + vdso_checked = true; + + cgt_vdso = vdso::get_vdso_sym(VDSO_CGT_SYM, VDSO_CGT_VER) + : nullable *fn(int, *rt::timespec) int; + return cgt_vdso; +}; + +fn now_vdso(clock: clock, tp: *rt::timespec) (void | rt::errno) = { + let vfn = match (get_cgt_vdso()) { + null => return rt::wrap_errno(rt::ENOSYS), + vfn: *fn(int, *rt::timespec) int => vfn, + }; + let ret = vfn(clock, tp); + if (ret == 0) { + return; + }; + return rt::wrap_errno(ret); +}; + +// Returns the current time for a given clock. +export fn now(clock: clock) time = { + let tp = rt::timespec { ... }; + let err = match (now_vdso(clock, &tp)) { + void => return timespec_to_time(tp), + err: rt::errno => err + }; + if (err != rt::wrap_errno(rt::ENOSYS)) { + abort("Unexpected error from clock_gettime"); + }; + return match (rt::clock_gettime(clock, &tp)) { + void => timespec_to_time(tp), + err: rt::errno => abort("Unexpected error from clock_gettime"), + }; +};