hare

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

functions.ha (3000B)


      1 // SPDX-License-Identifier: MPL-2.0
      2 // (c) Hare authors <https://harelang.org>
      3 
      4 use errors;
      5 use rt;
      6 
      7 // Converts a [[duration]] to an [[rt::timespec]]. This function is
      8 // non-portable.
      9 export fn duration_to_timespec(n: duration) rt::timespec = rt::timespec {
     10 	tv_sec = n / SECOND,
     11 	tv_nsec = n % SECOND,
     12 };
     13 
     14 // Converts a [[duration]] to an [[rt::timeval]]. This function is
     15 // non-portable.
     16 export fn duration_to_timeval(d: duration) rt::timeval = rt::timeval {
     17 	tv_sec = d / SECOND,
     18 	tv_usec = d % SECOND / 1000,
     19 };
     20 
     21 // Converts an [[instant]] to an [[rt::timespec]]. This function is
     22 // non-portable.
     23 export fn instant_to_timespec(t: instant) rt::timespec = rt::timespec {
     24 	tv_sec = t.sec,
     25 	tv_nsec = t.nsec,
     26 };
     27 
     28 // Converts a [[rt::timespec]] to an [[instant]]. This function is
     29 // non-portable.
     30 export fn timespec_to_instant(ts: rt::timespec) instant = instant {
     31 	sec = ts.tv_sec,
     32 	nsec = ts.tv_nsec,
     33 };
     34 
     35 // Yields the process to the kernel and returns after the requested duration.
     36 export fn sleep(d: duration) void = {
     37 	let req = duration_to_timespec(d);
     38 
     39 	for (true) {
     40 		let res = rt::timespec { ... };
     41 		match (rt::nanosleep(&req, &res)) {
     42 		case void =>
     43 			return;
     44 		case let err: rt::errno =>
     45 			switch (err) {
     46 			case rt::EINTR =>
     47 				req = res;
     48 			case =>
     49 				abort("Unexpected error from nanosleep");
     50 			};
     51 		};
     52 	};
     53 };
     54 
     55 // An enumeration of clocks available on this system. Different clocks represent
     56 // times from different epochs, and have different characteristics with regards
     57 // to leap seconds, NTP adjustments, and so on. All systems provide the REALTIME
     58 // and MONOTONIC clocks at least; use of other clocks is not guaranteed to be
     59 // portable.
     60 export type clock = enum {
     61 	// The current wall-clock time. This may jump forwards or backwards in
     62 	// time to account for leap seconds, NTP adjustments, etc.
     63 	REALTIME = 0,
     64 
     65 	// The current monotonic time. This clock measures from some undefined
     66 	// epoch and is not affected by leap seconds, NTP adjustments, and
     67 	// changes to the system time: it always increases by one second per
     68 	// second.
     69 	MONOTONIC = 4,
     70 
     71 	// TODO: Document these
     72 	VIRTUAL = 1,
     73 	PROF = 2,
     74 	UPTIME = 5,
     75 	UPTIME_PRECISE = 7,
     76 	UPTIME_FAST = 8,
     77 	REALTIME_PRECISE = 9,
     78 	REALTIME_FAST = 10,
     79 	MONOTONIC_PRECISE = 11,
     80 	MONOTONIC_FAST = 12,
     81 	SECOND = 13,
     82 	THREAD_CPUTIME_ID = 14,
     83 	PROCESS_CPUTIME_ID = 15,
     84 };
     85 
     86 // Returns the current time for a given clock.
     87 export fn now(clock: clock) instant = {
     88 	let tp = rt::timespec { ... };
     89 	match (rt::clock_gettime(clock, &tp)) {
     90 	case void =>
     91 		return timespec_to_instant(tp);
     92 	case let err: rt::errno =>
     93 		abort("Unexpected error from clock_gettime");
     94 	};
     95 };
     96 
     97 // Sets system clock to given time.
     98 export fn set(clock: clock, t: instant) (void | errors::noaccess) = {
     99 	let tp = instant_to_timespec(t);
    100 	let err = match (rt::clock_settime(clock, &tp)) {
    101 	case void => return;
    102 	case let err: rt::errno =>
    103 		yield err;
    104 	};
    105 	if (err == rt::EPERM) {
    106 		return errors::noaccess;
    107 	};
    108 	abort("Unexpected error from clock_settime");
    109 };