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 };