hare

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

functions.ha (3405B)


      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 = rt::CLOCK_REALTIME,
     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 = rt::CLOCK_MONOTONIC,
     70 
     71 	// The uptime clock. It is the time that has elapsed since the system
     72 	// booted. Begins at zero.
     73 	BOOT = rt::CLOCK_BOOTTIME,
     74 
     75 	// The runtime clock. It only advances while the system is not suspended
     76 	// and begins when the system is booted. Begins at zero.
     77 	UPTIME = rt::CLOCK_UPTIME,
     78 
     79 	// The process CPU clock. It begins at zero and is advanced while the
     80 	// calling process is running in user or kernel mode.
     81 	PROCESS_CPU = rt::CLOCK_PROCESS_CPUTIME_ID,
     82 
     83 	// The thread CPU clock. It begins at zero and is advanced while the
     84 	// calling thread is running in user or kernel mode.
     85 	THREAD_CPU = rt::CLOCK_THREAD_CPUTIME_ID,
     86 };
     87 
     88 // Returns the current time for a given clock.
     89 export fn now(clock: clock) instant = {
     90 	let ts = rt::timespec { ... };
     91 	match (rt::clock_gettime(clock, &ts)) {
     92 	case void =>
     93 		return timespec_to_instant(ts);
     94 	case let err: rt::errno =>
     95 		abort("Unexpected error from clock_gettime");
     96 	};
     97 };
     98 
     99 // Sets system clock to given time.
    100 export fn set(clock: clock, t: instant) (void | errors::noaccess) = {
    101 	let tp = instant_to_timespec(t);
    102 	let err = match (rt::clock_settime(clock, &tp)) {
    103 	case void => return;
    104 	case let err: rt::errno =>
    105 		yield err;
    106 	};
    107 	if (err == rt::EPERM) {
    108 		return errors::noaccess;
    109 	};
    110 	abort("Unexpected error from clock_settime");
    111 };