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