1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192 |
- //+build linux, darwin, freebsd
- package time
- IS_SUPPORTED :: true; // NOTE: Times on Darwin are UTC.
- when ODIN_OS == "darwin" {
- foreign import libc "System.framework"
- } else {
- foreign import libc "system:c"
- }
- @(default_calling_convention="c")
- foreign libc {
- @(link_name="clock_gettime") _unix_clock_gettime :: proc(clock_id: u64, timespec: ^TimeSpec) -> i32 ---;
- @(link_name="sleep") _unix_sleep :: proc(seconds: u32) -> i32 ---;
- @(link_name="nanosleep") _unix_nanosleep :: proc(requested: ^TimeSpec, remaining: ^TimeSpec) -> i32 ---;
- }
- TimeSpec :: struct {
- tv_sec : i64, /* seconds */
- tv_nsec : i64, /* nanoseconds */
- };
- CLOCK_REALTIME :: 0; // NOTE(tetra): May jump in time, when user changes the system time.
- CLOCK_MONOTONIC :: 1; // NOTE(tetra): May stand still while system is asleep.
- CLOCK_PROCESS_CPUTIME_ID :: 2;
- CLOCK_THREAD_CPUTIME_ID :: 3;
- CLOCK_MONOTONIC_RAW :: 4; // NOTE(tetra): "RAW" means: Not adjusted by NTP.
- CLOCK_REALTIME_COARSE :: 5; // NOTE(tetra): "COARSE" clocks are apparently much faster, but not "fine-grained."
- CLOCK_MONOTONIC_COARSE :: 6;
- CLOCK_BOOTTIME :: 7; // NOTE(tetra): Same as MONOTONIC, except also including time system was asleep.
- CLOCK_REALTIME_ALARM :: 8;
- CLOCK_BOOTTIME_ALARM :: 9;
- // TODO(tetra, 2019-11-05): The original implementation of this package for Darwin used this constants.
- // I do not know if Darwin programmers are used to the existance of these constants or not, so
- // I'm leaving aliases to them for now.
- CLOCK_SYSTEM :: CLOCK_REALTIME;
- CLOCK_CALENDAR :: CLOCK_MONOTONIC;
- clock_gettime :: proc(clock_id: u64) -> TimeSpec {
- ts : TimeSpec; // NOTE(tetra): Do we need to initialize this?
- _unix_clock_gettime(clock_id, &ts);
- return ts;
- }
- now :: proc() -> Time {
- time_spec_now := clock_gettime(CLOCK_REALTIME);
- ns := time_spec_now.tv_sec * 1e9 + time_spec_now.tv_nsec;
- return Time{_nsec=ns};
- }
- boot_time :: proc() -> Time {
- ts_now := clock_gettime(CLOCK_REALTIME);
- ts_boottime := clock_gettime(CLOCK_BOOTTIME);
- ns := (ts_now.tv_sec - ts_boottime.tv_sec) * 1e9 + ts_now.tv_nsec - ts_boottime.tv_nsec;
- return Time{_nsec=ns};
- }
- seconds_since_boot :: proc() -> f64 {
- ts_boottime := clock_gettime(CLOCK_BOOTTIME);
- return f64(ts_boottime.tv_sec) + f64(ts_boottime.tv_nsec) / 1e9;
- }
- sleep :: proc(d: Duration) {
- ds := duration_seconds(d);
- seconds := u32(ds);
- nanoseconds := i64((ds - f64(seconds)) * 1e9);
- if seconds > 0 { _unix_sleep(seconds); }
- if nanoseconds > 0 { nanosleep(nanoseconds); }
- }
- nanosleep :: proc(nanoseconds: i64) -> int {
- // NOTE(tetra): Should we remove this assert? We are measuring nanoseconds after all...
- assert(nanoseconds <= 999999999);
- requested := TimeSpec{tv_nsec = nanoseconds};
- remaining: TimeSpec; // NOTE(tetra): Do we need to initialize this?
- return int(_unix_nanosleep(&requested, &remaining));
- }
- _tick_now :: proc() -> Tick {
- t := clock_gettime(CLOCK_MONOTONIC_RAW);
- _nsec := t.tv_sec*1e9 + t.tv_nsec;
- return Tick{_nsec = _nsec};
- }
|