time_unix.odin 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. //+build linux, darwin, freebsd, openbsd
  2. package time
  3. IS_SUPPORTED :: true // NOTE: Times on Darwin are UTC.
  4. when ODIN_OS == .Darwin {
  5. foreign import libc "System.framework"
  6. } else {
  7. foreign import libc "system:c"
  8. }
  9. @(default_calling_convention="c")
  10. foreign libc {
  11. @(link_name="clock_gettime") _unix_clock_gettime :: proc(clock_id: u64, timespec: ^TimeSpec) -> i32 ---
  12. @(link_name="sleep") _unix_sleep :: proc(seconds: u32) -> i32 ---
  13. @(link_name="nanosleep") _unix_nanosleep :: proc(requested: ^TimeSpec, remaining: ^TimeSpec) -> i32 ---
  14. }
  15. TimeSpec :: struct {
  16. tv_sec : i64, /* seconds */
  17. tv_nsec : i64, /* nanoseconds */
  18. }
  19. when ODIN_OS == .OpenBSD {
  20. CLOCK_REALTIME :: 0
  21. CLOCK_PROCESS_CPUTIME_ID :: 2
  22. CLOCK_MONOTONIC :: 3
  23. CLOCK_THREAD_CPUTIME_ID :: 4
  24. CLOCK_UPTIME :: 5
  25. CLOCK_BOOTTIME :: 6
  26. // CLOCK_MONOTONIC_RAW doesn't exist, use CLOCK_MONOTONIC
  27. CLOCK_MONOTONIC_RAW :: CLOCK_MONOTONIC
  28. } else {
  29. CLOCK_REALTIME :: 0 // NOTE(tetra): May jump in time, when user changes the system time.
  30. CLOCK_MONOTONIC :: 1 // NOTE(tetra): May stand still while system is asleep.
  31. CLOCK_PROCESS_CPUTIME_ID :: 2
  32. CLOCK_THREAD_CPUTIME_ID :: 3
  33. CLOCK_MONOTONIC_RAW :: 4 // NOTE(tetra): "RAW" means: Not adjusted by NTP.
  34. CLOCK_REALTIME_COARSE :: 5 // NOTE(tetra): "COARSE" clocks are apparently much faster, but not "fine-grained."
  35. CLOCK_MONOTONIC_COARSE :: 6
  36. CLOCK_BOOTTIME :: 7 // NOTE(tetra): Same as MONOTONIC, except also including time system was asleep.
  37. CLOCK_REALTIME_ALARM :: 8
  38. CLOCK_BOOTTIME_ALARM :: 9
  39. }
  40. // TODO(tetra, 2019-11-05): The original implementation of this package for Darwin used this constants.
  41. // I do not know if Darwin programmers are used to the existance of these constants or not, so
  42. // I'm leaving aliases to them for now.
  43. CLOCK_SYSTEM :: CLOCK_REALTIME
  44. CLOCK_CALENDAR :: CLOCK_MONOTONIC
  45. clock_gettime :: proc "contextless" (clock_id: u64) -> TimeSpec {
  46. ts : TimeSpec // NOTE(tetra): Do we need to initialize this?
  47. _unix_clock_gettime(clock_id, &ts)
  48. return ts
  49. }
  50. now :: proc() -> Time {
  51. time_spec_now := clock_gettime(CLOCK_REALTIME)
  52. ns := time_spec_now.tv_sec * 1e9 + time_spec_now.tv_nsec
  53. return Time{_nsec=ns}
  54. }
  55. boot_time :: proc() -> Time {
  56. ts_now := clock_gettime(CLOCK_REALTIME)
  57. ts_boottime := clock_gettime(CLOCK_BOOTTIME)
  58. ns := (ts_now.tv_sec - ts_boottime.tv_sec) * 1e9 + ts_now.tv_nsec - ts_boottime.tv_nsec
  59. return Time{_nsec=ns}
  60. }
  61. seconds_since_boot :: proc() -> f64 {
  62. ts_boottime := clock_gettime(CLOCK_BOOTTIME)
  63. return f64(ts_boottime.tv_sec) + f64(ts_boottime.tv_nsec) / 1e9
  64. }
  65. sleep :: proc(d: Duration) {
  66. ds := duration_seconds(d)
  67. seconds := u32(ds)
  68. nanoseconds := i64((ds - f64(seconds)) * 1e9)
  69. if seconds > 0 { _unix_sleep(seconds) }
  70. if nanoseconds > 0 { nanosleep(nanoseconds) }
  71. }
  72. nanosleep :: proc(nanoseconds: i64) -> int {
  73. // NOTE(tetra): Should we remove this assert? We are measuring nanoseconds after all...
  74. assert(nanoseconds <= 999999999)
  75. requested := TimeSpec{tv_nsec = nanoseconds}
  76. remaining: TimeSpec // NOTE(tetra): Do we need to initialize this?
  77. return int(_unix_nanosleep(&requested, &remaining))
  78. }
  79. _tick_now :: proc "contextless" () -> Tick {
  80. t := clock_gettime(CLOCK_MONOTONIC_RAW)
  81. _nsec := t.tv_sec*1e9 + t.tv_nsec
  82. return Tick{_nsec = _nsec}
  83. }