Browse Source

Add Linux support for core:time

In addition to sleep() and now(), it also defines nanosleep(), boot_time() and seconds_since_boot()
Jeroen van Rijn 6 years ago
parent
commit
1584260886
2 changed files with 103 additions and 20 deletions
  1. 59 20
      core/os/os_linux.odin
  2. 44 0
      core/time/time_linux.odin

+ 59 - 20
core/os/os_linux.odin

@@ -125,29 +125,49 @@ X_OK :: 1; // Test for execute permission
 W_OK :: 2; // Test for write permission
 R_OK :: 4; // Test for read permission
 
+TimeSpec :: struct {
+	tv_sec  : i64,  /* seconds */
+	tv_nsec : i64,  /* nanoseconds */
+};
+
+CLOCK_REALTIME           :: 0;
+CLOCK_MONOTONIC          :: 1;
+CLOCK_PROCESS_CPUTIME_ID :: 2;
+CLOCK_THREAD_CPUTIME_ID  :: 3;
+CLOCK_MONOTONIC_RAW      :: 4;
+CLOCK_REALTIME_COARSE    :: 5;
+CLOCK_MONOTONIC_COARSE   :: 6;
+CLOCK_BOOTTIME           :: 7;
+CLOCK_REALTIME_ALARM     :: 8;
+CLOCK_BOOTTIME_ALARM     :: 9;
+
 foreign libc {
-	@(link_name="open")    _unix_open    :: proc(path: cstring, mode: int) -> Handle ---;
-	@(link_name="close")   _unix_close   :: proc(fd: Handle) -> i32 ---;
-	@(link_name="read")    _unix_read    :: proc(fd: Handle, buf: rawptr, size: int) -> int ---;
-	@(link_name="write")   _unix_write   :: proc(fd: Handle, buf: rawptr, size: int) -> int ---;
-	@(link_name="lseek64") _unix_seek    :: proc(fd: Handle, offset: i64, whence: i32) -> i64 ---;
-	@(link_name="gettid")  _unix_gettid  :: proc() -> u64 ---;
-	@(link_name="stat")    _unix_stat    :: proc(path: cstring, stat: ^Stat) -> i32 ---;
-	@(link_name="access")  _unix_access  :: proc(path: cstring, mask: int) -> i32 ---;
-
-	@(link_name="malloc")  _unix_malloc  :: proc(size: int) -> rawptr ---;
-	@(link_name="calloc")  _unix_calloc  :: proc(num, size: int) -> rawptr ---;
-	@(link_name="free")    _unix_free    :: proc(ptr: rawptr) ---;
-	@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr ---;
-	@(link_name="getenv")  _unix_getenv  :: proc(cstring) -> cstring ---;
-
-	@(link_name="exit")    _unix_exit    :: proc(status: int) -> ! ---;
+	@(link_name="open")             _unix_open          :: proc(path: cstring, mode: int) -> Handle ---;
+	@(link_name="close")            _unix_close         :: proc(fd: Handle) -> i32 ---;
+	@(link_name="read")             _unix_read          :: proc(fd: Handle, buf: rawptr, size: int) -> int ---;
+	@(link_name="write")            _unix_write         :: proc(fd: Handle, buf: rawptr, size: int) -> int ---;
+	@(link_name="lseek64")          _unix_seek          :: proc(fd: Handle, offset: i64, whence: i32) -> i64 ---;
+	@(link_name="gettid")           _unix_gettid        :: proc() -> u64 ---;
+	@(link_name="stat")             _unix_stat          :: proc(path: cstring, stat: ^Stat) -> i32 ---;
+	@(link_name="access")           _unix_access        :: proc(path: cstring, mask: int) -> i32 ---;
+
+	@(link_name="malloc")           _unix_malloc        :: proc(size: int) -> rawptr ---;
+	@(link_name="calloc")           _unix_calloc        :: proc(num, size: int) -> rawptr ---;
+	@(link_name="free")             _unix_free          :: proc(ptr: rawptr) ---;
+	@(link_name="realloc")          _unix_realloc       :: proc(ptr: rawptr, size: int) -> rawptr ---;
+	@(link_name="getenv")           _unix_getenv        :: proc(cstring) -> cstring ---;
+
+	@(link_name="clock_gettime")    _unix_clock_gettime :: proc(clock_id: u64, timespec: ^TimeSpec) ---;
+	@(link_name="nanosleep")        _unix_nanosleep     :: proc(requested: ^TimeSpec, remaining: ^TimeSpec) -> int ---;
+	@(link_name="sleep")            _unix_sleep         :: proc(seconds: u64) -> int ---;
+
+	@(link_name="exit")             _unix_exit          :: proc(status: int) -> ! ---;
 }
 foreign dl {
-	@(link_name="dlopen")  _unix_dlopen  :: proc(filename: cstring, flags: int) -> rawptr ---;
-	@(link_name="dlsym")   _unix_dlsym   :: proc(handle: rawptr, symbol: cstring) -> rawptr ---;
-	@(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> int ---;
-	@(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---;
+	@(link_name="dlopen")           _unix_dlopen        :: proc(filename: cstring, flags: int) -> rawptr ---;
+	@(link_name="dlsym")            _unix_dlsym         :: proc(handle: rawptr, symbol: cstring) -> rawptr ---;
+	@(link_name="dlclose")          _unix_dlclose       :: proc(handle: rawptr) -> int ---;
+	@(link_name="dlerror")          _unix_dlerror       :: proc() -> cstring ---;
 }
 
 // TODO(zangent): Change this to just `open` when Bill fixes overloading.
@@ -245,6 +265,25 @@ exit :: proc(code: int) -> ! {
 	_unix_exit(code);
 }
 
+clock_gettime :: proc(clock_id: u64) -> TimeSpec {
+	ts : TimeSpec;
+	_unix_clock_gettime(clock_id, &ts);
+	return ts;
+}
+
+sleep :: proc(seconds: u64) -> int {
+
+	return _unix_sleep(seconds);
+}
+
+nanosleep :: proc(nanoseconds: i64) -> int {
+	assert(nanoseconds <= 999999999);
+	requested, remaining : TimeSpec;
+	requested = TimeSpec{tv_nsec = nanoseconds};
+
+	return _unix_nanosleep(&requested, &remaining);
+}
+
 current_thread_id :: proc "contextless" () -> int {
 	// return int(_unix_gettid());
 	return 0;

+ 44 - 0
core/time/time_linux.odin

@@ -0,0 +1,44 @@
+package time
+
+import "core:os";
+import "core:fmt";
+
+// NOTE(Jeroen): The times returned are in UTC
+
+now :: proc() -> Time {
+
+    time_spec_now := os.clock_gettime(os.CLOCK_REALTIME);
+    ns := time_spec_now.tv_sec * 1e9 + time_spec_now.tv_nsec;
+    return Time{_nsec=ns};
+}
+
+boot_time :: proc() -> Time {
+
+    ts_now := os.clock_gettime(os.CLOCK_REALTIME);
+    ts_boottime := os.clock_gettime(os.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 := os.clock_gettime(os.CLOCK_BOOTTIME);
+    return f64(ts_boottime.tv_sec) + f64(ts_boottime.tv_nsec) / 1e9;
+}
+
+sleep :: proc(d: Duration) {
+
+    ds := duration_seconds(d);
+    seconds := u64(ds);
+    nanoseconds := i64((ds - f64(seconds)) * 1e9);
+
+    if seconds > 0 do os.sleep(seconds);
+    if nanoseconds > 0 do os.nanosleep(nanoseconds);
+}
+
+nanosleep :: proc(d: Duration) {
+    // NOTE(Jeroen): os.nanosleep returns -1 on failure, 0 on success
+    // duration needs to be [0, 999999999] nanoseconds.
+    os.nanosleep(i64(d));
+}