From 12c810f85dc7a599cf1cde733eb974a2896d05a0 Mon Sep 17 00:00:00 2001 From: Mikkel Hjortshoej Date: Tue, 23 Oct 2018 20:39:56 +0200 Subject: [PATCH 1/6] Add a file-, console- and multi-logger --- .gitignore | 3 +- core/log/file_console_logger.odin | 121 ++++++++++++++++++++++++++++++ core/log/log.odin | 64 ++++++++++++++-- 3 files changed, 180 insertions(+), 8 deletions(-) create mode 100644 core/log/file_console_logger.odin diff --git a/.gitignore b/.gitignore index 0c3e8b65a..a56b4f1e2 100644 --- a/.gitignore +++ b/.gitignore @@ -18,7 +18,7 @@ bld/ [Bb]in/ [Oo]bj/ [Ll]og/ - +![Cc]ore/[Ll]og/ # Visual Studio 2015 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot @@ -264,7 +264,6 @@ bin/ odin odin.dSYM - # shared collection shared/ diff --git a/core/log/file_console_logger.odin b/core/log/file_console_logger.odin new file mode 100644 index 000000000..af748e2a6 --- /dev/null +++ b/core/log/file_console_logger.odin @@ -0,0 +1,121 @@ +package log + +import "core:fmt"; +import "core:os"; + +Level_Headers := []string{ + "[DEBUG] --- ", + "[INFO ] --- ", + "[WARN ] --- ", + "[ERROR] --- ", + "[FATAL] --- ", +}; + +Default_Console_Logger_Opts :: Options{ + Option.Level, + Option.Terminal_Color, + Option.Short_File_Path, + Option.Line, + Option.Procedure, +} | Full_Timestamp_Opts; + +Default_File_Logger_Opts :: Options{ + Option.Level, + Option.Short_File_Path, + Option.Line, + Option.Procedure, +} | Full_Timestamp_Opts; + + +File_Console_Logger_Data :: struct { + lowest_level: Level, + file_handle: os.Handle, +} + +file_logger :: proc(h: os.Handle, lowest := Level.Debug, opt := Default_File_Logger_Opts, ident := "") -> Logger { + data := new(File_Console_Logger_Data); + data.lowest_level = lowest; + data.file_handle = h; + return Logger{file_console_logger_proc, data, opt, ident}; +} + +console_logger :: proc(lowest := Level.Debug, opt := Default_Console_Logger_Opts, ident := "") -> Logger { + data := new(File_Console_Logger_Data); + data.lowest_level = lowest; + data.file_handle = os.INVALID_HANDLE; + return Logger{file_console_logger_proc, data, opt, ident}; +} + +file_console_logger_proc :: proc(logger_data: rawptr, level: Level, ident: string, text: string, options: Options, location := #caller_location) { + data := cast(^File_Console_Logger_Data)logger_data; + if level < data.lowest_level do return; + + h : os.Handle; + if(data.file_handle != os.INVALID_HANDLE) do h = data.file_handle; + else do h = level <= Level.Error ? os.stdout : os.stderr; + backing: [1024]byte; //NOTE(Hoej): 1024 might be too much for a header backing, unless somebody has really long paths. + buf := fmt.string_buffer_from_slice(backing[:]); + + do_level_header(options, level, &buf); + + + /*if Full_Timestamp_Opts & options != nil { + time := os.get_current_system_time(); + if Option.Date in options do fmt.sbprintf(&buf, "%d-%d-%d ", time.year, time.month, time.day); + if Option.Time in options do fmt.sbprintf(&buf, "%d:%d:%d ", time.hour, time.minute, time.second); + } +*/ + do_location_header(options, &buf, location); + + if ident != "" do fmt.sbprintf(&buf, "[%s] ", ident); + //TODO(Hoej): When we have better atomics and such, make this thread-safe + fmt.fprintf(h, "%s %s\n", fmt.to_string(buf), text); +} + +do_level_header :: proc(opts : Options, level : Level, buf : ^fmt.String_Buffer) { + + RESET :: "\x1b[0m"; + RED :: "\x1b[31m"; + YELLOW :: "\x1b[33m"; + DARK_GREY :: "\x1b[90m"; + + col := RESET; + switch level { + case Level.Debug : col = DARK_GREY; + case Level.Info : col = RESET; + case Level.Warning : col = YELLOW; + case Level.Error, Level.Fatal : col = RED; + } + + if Option.Level in opts { + if Option.Terminal_Color in opts do fmt.sbprint(buf, col); + fmt.sbprint(buf, Level_Headers[level]); + if Option.Terminal_Color in opts do fmt.sbprint(buf, RESET); + } +} + +do_location_header :: proc(opts : Options, buf : ^fmt.String_Buffer, location := #caller_location) { + if Location_Header_Opts & opts != nil do fmt.sbprint(buf, "["); else do return; + + file := location.file_path; + if Option.Short_File_Path in opts { + when os.OS == "windows" do delimiter := '\\'; else do delimiter := '/'; + last := 0; + for r, i in location.file_path do if r == delimiter do last = i+1; + file = location.file_path[last:]; + } + + if Location_File_Opts & opts != nil do fmt.sbprint(buf, file); + + if Option.Procedure in opts { + if Location_File_Opts & opts != nil do fmt.sbprint(buf, "."); + fmt.sbprintf(buf, "%s()", location.procedure); + } + + if Option.Line in opts { + if Location_File_Opts & opts != nil || Option.Procedure in opts do fmt.sbprint(buf, ":"); + fmt.sbprint(buf, location.line); + } + + fmt.sbprint(buf, "] "); +} \ No newline at end of file diff --git a/core/log/log.odin b/core/log/log.odin index fac2fbe5b..b72977789 100644 --- a/core/log/log.odin +++ b/core/log/log.odin @@ -1,5 +1,8 @@ package log +import "core:fmt"; +import "core:runtime"; + Level :: enum { Debug, Info, @@ -9,26 +12,75 @@ Level :: enum { } Option :: enum { - Level, - Time, - File, - Line, - Procedure, + Level, + Date, + Time, + Short_File_Path, + Long_File_Path, + Line, + Procedure, + Terminal_Color } + Options :: bit_set[Option]; +Full_Timestamp_Opts :: Options{ + Option.Date, + Option.Time +}; +Location_Header_Opts :: Options{ + Option.Short_File_Path, + Option.Long_File_Path, + Option.Line, + Option.Procedure, +}; +Location_File_Opts :: Options{ + Option.Short_File_Path, + Option.Long_File_Path +}; Logger_Proc :: #type proc(data: rawptr, level: Level, ident, text: string, options: Options, location := #caller_location); Logger :: struct { procedure: Logger_Proc, data: rawptr, + options: Options, + ident: string } +Multi_Logger_Data :: struct { + loggers : []Logger, +} + +multi_logger :: proc(logs: ..Logger) -> Logger { + data := new(Multi_Logger_Data); + data.loggers = make([]Logger, len(logs)); + for log, i in logs do data.loggers[i] = log; + return Logger{multi_logger_proc, data, nil, ""}; +} + +multi_logger_proc :: proc(logger_data: rawptr, level: Level, ident: string, text: string, + options: Options, location := #caller_location) { + data := cast(^Multi_Logger_Data)logger_data; + if data.loggers == nil || len(data.loggers) == 0 do return; + for log in data.loggers do log.procedure(log.data, level, log.ident, text, log.options, location); +} nil_logger_proc :: proc(data: rawptr, level: Level, ident, text: string, options: Options, location := #caller_location) { // Do nothing } nil_logger :: proc() -> Logger { - return Logger{nil_logger_proc, nil}; + return Logger{nil_logger_proc, nil, nil, ""}; } + +debug :: proc(fmt_str : string, args : ..any, location := #caller_location) do log(level=Level.Debug, fmt_str=fmt_str, args=args, location=location); +info :: proc(fmt_str : string, args : ..any, location := #caller_location) do log(level=Level.Info, fmt_str=fmt_str, args=args, location=location); +warn :: proc(fmt_str : string, args : ..any, location := #caller_location) do log(level=Level.Warning, fmt_str=fmt_str, args=args, location=location); +error :: proc(fmt_str : string, args : ..any, location := #caller_location) do log(level=Level.Error, fmt_str=fmt_str, args=args, location=location); +fatal :: proc(fmt_str : string, args : ..any, location := #caller_location) do log(level=Level.Fatal, fmt_str=fmt_str, args=args, location=location); + +log :: proc(level : Level, fmt_str : string, args : ..any, location := #caller_location) { + logger := context.logger; + str := fmt.tprintf(fmt_str, ..args); //NOTE(Hoej): While tprint isn't thread-safe, no logging is. + logger.procedure(logger.data, level, logger.ident, str, logger.options, location); +} \ No newline at end of file From 984fa1c6729574deb2c30e63786437b729314f4f Mon Sep 17 00:00:00 2001 From: Mikkel Hjortshoej Date: Wed, 31 Oct 2018 19:20:55 +0100 Subject: [PATCH 2/6] remove ident from logger struct --- core/log/file_console_logger.odin | 11 +++++++---- core/log/log.odin | 29 ++++++++++++++--------------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/core/log/file_console_logger.odin b/core/log/file_console_logger.odin index af748e2a6..1be89864f 100644 --- a/core/log/file_console_logger.odin +++ b/core/log/file_console_logger.odin @@ -30,23 +30,26 @@ Default_File_Logger_Opts :: Options{ File_Console_Logger_Data :: struct { lowest_level: Level, file_handle: os.Handle, + ident : string, } file_logger :: proc(h: os.Handle, lowest := Level.Debug, opt := Default_File_Logger_Opts, ident := "") -> Logger { data := new(File_Console_Logger_Data); data.lowest_level = lowest; data.file_handle = h; - return Logger{file_console_logger_proc, data, opt, ident}; + data.ident = ident; + return Logger{file_console_logger_proc, data, opt}; } console_logger :: proc(lowest := Level.Debug, opt := Default_Console_Logger_Opts, ident := "") -> Logger { data := new(File_Console_Logger_Data); data.lowest_level = lowest; data.file_handle = os.INVALID_HANDLE; - return Logger{file_console_logger_proc, data, opt, ident}; + data.ident = ident; + return Logger{file_console_logger_proc, data, opt}; } -file_console_logger_proc :: proc(logger_data: rawptr, level: Level, ident: string, text: string, options: Options, location := #caller_location) { +file_console_logger_proc :: proc(logger_data: rawptr, level: Level, text: string, options: Options, location := #caller_location) { data := cast(^File_Console_Logger_Data)logger_data; if level < data.lowest_level do return; @@ -67,7 +70,7 @@ file_console_logger_proc :: proc(logger_data: rawptr, level: Level, ident: strin */ do_location_header(options, &buf, location); - if ident != "" do fmt.sbprintf(&buf, "[%s] ", ident); + if data.ident != "" do fmt.sbprintf(&buf, "[%s] ", data.ident); //TODO(Hoej): When we have better atomics and such, make this thread-safe fmt.fprintf(h, "%s %s\n", fmt.to_string(buf), text); } diff --git a/core/log/log.odin b/core/log/log.odin index b72977789..267f9cc38 100644 --- a/core/log/log.odin +++ b/core/log/log.odin @@ -38,13 +38,12 @@ Location_File_Opts :: Options{ Option.Long_File_Path }; -Logger_Proc :: #type proc(data: rawptr, level: Level, ident, text: string, options: Options, location := #caller_location); +Logger_Proc :: #type proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location); Logger :: struct { procedure: Logger_Proc, data: rawptr, options: Options, - ident: string } Multi_Logger_Data :: struct { @@ -55,32 +54,32 @@ multi_logger :: proc(logs: ..Logger) -> Logger { data := new(Multi_Logger_Data); data.loggers = make([]Logger, len(logs)); for log, i in logs do data.loggers[i] = log; - return Logger{multi_logger_proc, data, nil, ""}; + return Logger{multi_logger_proc, data, nil}; } -multi_logger_proc :: proc(logger_data: rawptr, level: Level, ident: string, text: string, +multi_logger_proc :: proc(logger_data: rawptr, level: Level, text: string, options: Options, location := #caller_location) { data := cast(^Multi_Logger_Data)logger_data; if data.loggers == nil || len(data.loggers) == 0 do return; - for log in data.loggers do log.procedure(log.data, level, log.ident, text, log.options, location); + for log in data.loggers do log.procedure(log.data, level, text, log.options, location); } -nil_logger_proc :: proc(data: rawptr, level: Level, ident, text: string, options: Options, location := #caller_location) { +nil_logger_proc :: proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location) { // Do nothing } nil_logger :: proc() -> Logger { - return Logger{nil_logger_proc, nil, nil, ""}; + return Logger{nil_logger_proc, nil, nil}; } -debug :: proc(fmt_str : string, args : ..any, location := #caller_location) do log(level=Level.Debug, fmt_str=fmt_str, args=args, location=location); -info :: proc(fmt_str : string, args : ..any, location := #caller_location) do log(level=Level.Info, fmt_str=fmt_str, args=args, location=location); -warn :: proc(fmt_str : string, args : ..any, location := #caller_location) do log(level=Level.Warning, fmt_str=fmt_str, args=args, location=location); -error :: proc(fmt_str : string, args : ..any, location := #caller_location) do log(level=Level.Error, fmt_str=fmt_str, args=args, location=location); -fatal :: proc(fmt_str : string, args : ..any, location := #caller_location) do log(level=Level.Fatal, fmt_str=fmt_str, args=args, location=location); +debug :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Debug, fmt_str=fmt_str, args=args, location=location); +info :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Info, fmt_str=fmt_str, args=args, location=location); +warn :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Warning, fmt_str=fmt_str, args=args, location=location); +error :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Error, fmt_str=fmt_str, args=args, location=location); +fatal :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Fatal, fmt_str=fmt_str, args=args, location=location); -log :: proc(level : Level, fmt_str : string, args : ..any, location := #caller_location) { +logf :: proc(level : Level, fmt_str : string, args : ..any, location := #caller_location) { logger := context.logger; - str := fmt.tprintf(fmt_str, ..args); //NOTE(Hoej): While tprint isn't thread-safe, no logging is. - logger.procedure(logger.data, level, logger.ident, str, logger.options, location); + str := len(args) > 0 ? fmt.tprintf(fmt_str, ..args) : fmt.tprint(fmt_str); //NOTE(Hoej): While tprint isn't thread-safe, no logging is. + logger.procedure(logger.data, level, str, logger.options, location); } \ No newline at end of file From 411d1450b026cce495bb60b4093aff2042696cf5 Mon Sep 17 00:00:00 2001 From: Mikkel Hjortshoej Date: Sat, 8 Dec 2018 16:02:33 +0100 Subject: [PATCH 3/6] Add timestamp support using the new core:time --- core/log/file_console_logger.odin | 34 +++++++++++++++++++++++-------- core/log/log.odin | 7 ++++++- core/time/time_linux.odin | 3 +++ core/time/time_osx.odin | 3 +++ core/time/time_windows.odin | 4 +++- 5 files changed, 41 insertions(+), 10 deletions(-) create mode 100644 core/time/time_linux.odin create mode 100644 core/time/time_osx.odin diff --git a/core/log/file_console_logger.odin b/core/log/file_console_logger.odin index 1be89864f..1d598285e 100644 --- a/core/log/file_console_logger.odin +++ b/core/log/file_console_logger.odin @@ -2,6 +2,7 @@ package log import "core:fmt"; import "core:os"; +import "core:time"; Level_Headers := []string{ "[DEBUG] --- ", @@ -33,15 +34,22 @@ File_Console_Logger_Data :: struct { ident : string, } -file_logger :: proc(h: os.Handle, lowest := Level.Debug, opt := Default_File_Logger_Opts, ident := "") -> Logger { +create_file_logger :: proc(h: os.Handle, lowest := Level.Debug, opt := Default_File_Logger_Opts, ident := "") -> Logger { data := new(File_Console_Logger_Data); data.lowest_level = lowest; data.file_handle = h; data.ident = ident; return Logger{file_console_logger_proc, data, opt}; } + +destroy_file_logger ::proc(log : ^Logger) { + data := cast(^File_Console_Logger_Data)log.data; + if data.file_handle != os.INVALID_HANDLE do os.close(data.file_handle); + free(data); + log^ = nil_logger(); +} -console_logger :: proc(lowest := Level.Debug, opt := Default_Console_Logger_Opts, ident := "") -> Logger { +create_console_logger :: proc(lowest := Level.Debug, opt := Default_Console_Logger_Opts, ident := "") -> Logger { data := new(File_Console_Logger_Data); data.lowest_level = lowest; data.file_handle = os.INVALID_HANDLE; @@ -49,6 +57,11 @@ console_logger :: proc(lowest := Level.Debug, opt := Default_Console_Logger_Opts return Logger{file_console_logger_proc, data, opt}; } +destroy_console_logger ::proc(log : ^Logger) { + free(log.data); + log^ = nil_logger(); +} + file_console_logger_proc :: proc(logger_data: rawptr, level: Level, text: string, options: Options, location := #caller_location) { data := cast(^File_Console_Logger_Data)logger_data; if level < data.lowest_level do return; @@ -61,13 +74,18 @@ file_console_logger_proc :: proc(logger_data: rawptr, level: Level, text: string do_level_header(options, level, &buf); - - /*if Full_Timestamp_Opts & options != nil { - time := os.get_current_system_time(); - if Option.Date in options do fmt.sbprintf(&buf, "%d-%d-%d ", time.year, time.month, time.day); - if Option.Time in options do fmt.sbprintf(&buf, "%d:%d:%d ", time.hour, time.minute, time.second); + when time.IS_SUPPORTED { + if Full_Timestamp_Opts & options != nil { + fmt.sbprint(&buf, "["); + t := time.now(); + y, m, d := time.date(t); + h, min, s := time.clock(t); + if Option.Date in options do fmt.sbprintf(&buf, "%d-%02d-%02d ", y, m, d); + if Option.Time in options do fmt.sbprintf(&buf, "%02d:%02d:%02d", h, min, s); + fmt.sbprint(&buf, "] "); + } } -*/ + do_location_header(options, &buf, location); if data.ident != "" do fmt.sbprintf(&buf, "[%s] ", data.ident); diff --git a/core/log/log.odin b/core/log/log.odin index 267f9cc38..6e1f33342 100644 --- a/core/log/log.odin +++ b/core/log/log.odin @@ -50,13 +50,18 @@ Multi_Logger_Data :: struct { loggers : []Logger, } -multi_logger :: proc(logs: ..Logger) -> Logger { +create_multi_logger :: proc(logs: ..Logger) -> Logger { data := new(Multi_Logger_Data); data.loggers = make([]Logger, len(logs)); for log, i in logs do data.loggers[i] = log; return Logger{multi_logger_proc, data, nil}; } +destroy_multi_logger ::proc(log : ^Logger) { + free(log.data); + log^ = nil_logger(); +} + multi_logger_proc :: proc(logger_data: rawptr, level: Level, text: string, options: Options, location := #caller_location) { data := cast(^Multi_Logger_Data)logger_data; diff --git a/core/time/time_linux.odin b/core/time/time_linux.odin new file mode 100644 index 000000000..7d1a1441c --- /dev/null +++ b/core/time/time_linux.odin @@ -0,0 +1,3 @@ +package time + +IS_SUPPORTED :: false; \ No newline at end of file diff --git a/core/time/time_osx.odin b/core/time/time_osx.odin new file mode 100644 index 000000000..7d1a1441c --- /dev/null +++ b/core/time/time_osx.odin @@ -0,0 +1,3 @@ +package time + +IS_SUPPORTED :: false; \ No newline at end of file diff --git a/core/time/time_windows.odin b/core/time/time_windows.odin index 6789a59d1..31fbca769 100644 --- a/core/time/time_windows.odin +++ b/core/time/time_windows.odin @@ -2,6 +2,8 @@ package time import "core:sys/win32" +IS_SUPPORTED :: true; + now :: proc() -> Time { file_time: win32.Filetime; @@ -18,5 +20,5 @@ now :: proc() -> Time { sleep :: proc(d: Duration) { - win32.Sleep(u32(d/Millisecond)); + win32.sleep(i32(d/Millisecond)); } From a565d842daea7b1fd021a7323d8f0ca862699d85 Mon Sep 17 00:00:00 2001 From: Mikkel Hjortshoej Date: Sat, 8 Dec 2018 16:12:20 +0100 Subject: [PATCH 4/6] Copy instead of loop --- core/log/log.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/log/log.odin b/core/log/log.odin index 6e1f33342..4a3af3cd2 100644 --- a/core/log/log.odin +++ b/core/log/log.odin @@ -53,7 +53,7 @@ Multi_Logger_Data :: struct { create_multi_logger :: proc(logs: ..Logger) -> Logger { data := new(Multi_Logger_Data); data.loggers = make([]Logger, len(logs)); - for log, i in logs do data.loggers[i] = log; + copy(data.loggers, logs); return Logger{multi_logger_proc, data, nil}; } From 158426088689c914eeaa8f9b570492eeff3216d8 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 8 Dec 2018 20:34:16 +0100 Subject: [PATCH 5/6] Add Linux support for core:time In addition to sleep() and now(), it also defines nanosleep(), boot_time() and seconds_since_boot() --- core/os/os_linux.odin | 75 +++++++++++++++++++++++++++++---------- core/time/time_linux.odin | 44 +++++++++++++++++++++++ 2 files changed, 101 insertions(+), 18 deletions(-) create mode 100644 core/time/time_linux.odin diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index a8d241d65..1ca41ee77 100644 --- a/core/os/os_linux.odin +++ b/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="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="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="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; diff --git a/core/time/time_linux.odin b/core/time/time_linux.odin new file mode 100644 index 000000000..47eb515c2 --- /dev/null +++ b/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)); +} From 1a6b7f99454ba67fab0e69ddc46e20aff94c8320 Mon Sep 17 00:00:00 2001 From: Mikkel Hjortshoej Date: Sat, 8 Dec 2018 21:12:01 +0100 Subject: [PATCH 6/6] set time_linux IS_SUPPORTED to true --- core/time/time_linux.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/time/time_linux.odin b/core/time/time_linux.odin index d661ee1fc..af19d9706 100644 --- a/core/time/time_linux.odin +++ b/core/time/time_linux.odin @@ -4,7 +4,7 @@ import "core:os"; import "core:fmt"; // NOTE(Jeroen): The times returned are in UTC -IS_SUPPORTED :: false; +IS_SUPPORTED :: true; now :: proc() -> Time {