diff options
| author | gingerBill <gingerBill@users.noreply.github.com> | 2023-02-28 12:15:54 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-02-28 12:15:54 +0000 |
| commit | 9afd9f9beae310d2a3bea98cd713b22d2f167cf9 (patch) | |
| tree | 1f5ed60d50eeb282ae4dd451dfe75fab73e32052 /core | |
| parent | eb60ec3899922b6b98a5ee1a00766d5d9b9917e1 (diff) | |
| parent | c8d3a9121bbed1cff1fee45d6ecf0fa4748f4d21 (diff) | |
Merge branch 'master' into new-temp-allocator
Diffstat (limited to 'core')
| -rw-r--r-- | core/crypto/rand_linux.odin | 2 | ||||
| -rw-r--r-- | core/intrinsics/intrinsics.odin | 4 | ||||
| -rw-r--r-- | core/os/os_darwin.odin | 72 | ||||
| -rw-r--r-- | core/os/os_linux.odin | 227 | ||||
| -rw-r--r-- | core/prof/spall/spall.odin | 208 | ||||
| -rw-r--r-- | core/runtime/core.odin | 7 | ||||
| -rw-r--r-- | core/runtime/default_temporary_allocator.odin | 5 | ||||
| -rw-r--r-- | core/runtime/internal.odin | 21 | ||||
| -rw-r--r-- | core/runtime/print.odin | 39 | ||||
| -rw-r--r-- | core/sync/primitives.odin | 2 | ||||
| -rw-r--r-- | core/sys/darwin/xnu_system_call_numbers.odin | 2 | ||||
| -rw-r--r-- | core/sys/darwin/xnu_system_call_wrappers.odin | 96 | ||||
| -rw-r--r-- | core/sys/unix/syscalls_linux.odin | 192 | ||||
| -rw-r--r-- | core/sys/windows/kernel32.odin | 7 | ||||
| -rw-r--r-- | core/time/perf.odin | 51 | ||||
| -rw-r--r-- | core/time/tsc_darwin.odin | 21 | ||||
| -rw-r--r-- | core/time/tsc_freebsd.odin | 21 | ||||
| -rw-r--r-- | core/time/tsc_linux.odin | 35 | ||||
| -rw-r--r-- | core/time/tsc_openbsd.odin | 7 | ||||
| -rw-r--r-- | core/time/tsc_windows.odin | 7 |
20 files changed, 737 insertions, 289 deletions
diff --git a/core/crypto/rand_linux.odin b/core/crypto/rand_linux.odin index 4d1183757..e5c194220 100644 --- a/core/crypto/rand_linux.odin +++ b/core/crypto/rand_linux.odin @@ -12,7 +12,7 @@ _rand_bytes :: proc (dst: []byte) { for l > 0 { to_read := min(l, _MAX_PER_CALL_BYTES) - ret := unix.sys_getrandom(raw_data(dst), to_read, 0) + ret := unix.sys_getrandom(raw_data(dst), uint(to_read), 0) if ret < 0 { switch os.Errno(-ret) { case os.EINTR: diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index 38542d2fc..890a6881d 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -283,7 +283,7 @@ wasm_memory_atomic_wait32 :: proc(ptr: ^u32, expected: u32, timeout_ns: i64) - wasm_memory_atomic_notify32 :: proc(ptr: ^u32, waiters: u32) -> (waiters_woken_up: u32) --- // x86 Targets (i386, amd64) -x86_cpuid :: proc(ax, cx: u32) -> (eax, ebc, ecx, edx: u32) --- +x86_cpuid :: proc(ax, cx: u32) -> (eax, ebx, ecx, edx: u32) --- x86_xgetbv :: proc(cx: u32) -> (eax, edx: u32) --- @@ -305,4 +305,4 @@ valgrind_client_request :: proc(default: uintptr, request: uintptr, a0, a1, a2, // Internal compiler use only -__entry_point :: proc() ---
\ No newline at end of file +__entry_point :: proc() --- diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index 838882404..c16cf737e 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -277,8 +277,10 @@ foreign libc { @(link_name="open") _unix_open :: proc(path: cstring, flags: i32, mode: u16) -> Handle --- @(link_name="close") _unix_close :: proc(handle: Handle) -> c.int --- - @(link_name="read") _unix_read :: proc(handle: Handle, buffer: rawptr, count: int) -> int --- - @(link_name="write") _unix_write :: proc(handle: Handle, buffer: rawptr, count: int) -> int --- + @(link_name="read") _unix_read :: proc(handle: Handle, buffer: rawptr, count: c.size_t) -> int --- + @(link_name="write") _unix_write :: proc(handle: Handle, buffer: rawptr, count: c.size_t) -> int --- + @(link_name="pread") _unix_pread :: proc(handle: Handle, buffer: rawptr, count: c.size_t, offset: i64) -> int --- + @(link_name="pwrite") _unix_pwrite :: proc(handle: Handle, buffer: rawptr, count: c.size_t, offset: i64) -> int --- @(link_name="lseek") _unix_lseek :: proc(fs: Handle, offset: int, whence: int) -> int --- @(link_name="gettid") _unix_gettid :: proc() -> u64 --- @(link_name="getpagesize") _unix_getpagesize :: proc() -> i32 --- @@ -386,45 +388,51 @@ close :: proc(fd: Handle) -> bool { @(private) MAX_RW :: 0x7fffffff // The limit on Darwin is max(i32), trying to read/write more than that fails. -write :: proc(fd: Handle, data: []u8) -> (int, Errno) { - assert(fd != -1) - - bytes_total := len(data) - bytes_written_total := 0 - - for bytes_written_total < bytes_total { - bytes_to_write := min(bytes_total - bytes_written_total, MAX_RW) - slice := data[bytes_written_total:bytes_written_total + bytes_to_write] - bytes_written := _unix_write(fd, raw_data(slice), bytes_to_write) - if bytes_written == -1 { - return bytes_written_total, 1 - } - bytes_written_total += bytes_written +write :: proc(fd: Handle, data: []byte) -> (int, Errno) { + if len(data) == 0 { + return 0, ERROR_NONE } - return bytes_written_total, 0 + bytes_written := _unix_write(fd, raw_data(data), c.size_t(len(data))) + if bytes_written < 0 { + return -1, Errno(get_last_error()) + } + return bytes_written, ERROR_NONE } read :: proc(fd: Handle, data: []u8) -> (int, Errno) { - assert(fd != -1) + if len(data) == 0 { + return 0, ERROR_NONE + } + + bytes_read := _unix_read(fd, raw_data(data), c.size_t(len(data))) + if bytes_read < 0 { + return -1, Errno(get_last_error()) + } + return bytes_read, ERROR_NONE +} +read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { + if len(data) == 0 { + return 0, ERROR_NONE + } - bytes_total := len(data) - bytes_read_total := 0 + bytes_read := _unix_pread(fd, raw_data(data), c.size_t(len(data)), offset) + if bytes_read < 0 { + return -1, Errno(get_last_error()) + } + return bytes_read, ERROR_NONE +} - for bytes_read_total < bytes_total { - bytes_to_read := min(bytes_total - bytes_read_total, MAX_RW) - slice := data[bytes_read_total:bytes_read_total + bytes_to_read] - bytes_read := _unix_read(fd, raw_data(slice), bytes_to_read) - if bytes_read == -1 { - return bytes_read_total, 1 - } - if bytes_read == 0 { - break - } - bytes_read_total += bytes_read +write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { + if len(data) == 0 { + return 0, ERROR_NONE } - return bytes_read_total, 0 + bytes_written := _unix_pwrite(fd, raw_data(data), c.size_t(len(data)), offset) + if bytes_written < 0 { + return -1, Errno(get_last_error()) + } + return bytes_written, ERROR_NONE } seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index 796298377..237e3495c 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -270,136 +270,6 @@ AT_FDCWD :: ~uintptr(99) /* -100 */ AT_REMOVEDIR :: uintptr(0x200) AT_SYMLINK_NOFOLLOW :: uintptr(0x100) -_unix_personality :: proc(persona: u64) -> int { - return int(intrinsics.syscall(unix.SYS_personality, uintptr(persona))) -} - -_unix_fork :: proc() -> Pid { - when ODIN_ARCH != .arm64 { - res := int(intrinsics.syscall(unix.SYS_fork)) - } else { - res := int(intrinsics.syscall(unix.SYS_clone, unix.SIGCHLD)) - } - return -1 if res < 0 else Pid(res) -} - -_unix_open :: proc(path: cstring, flags: int, mode: int = 0o000) -> Handle { - when ODIN_ARCH != .arm64 { - res := int(intrinsics.syscall(unix.SYS_open, uintptr(rawptr(path)), uintptr(flags), uintptr(mode))) - } else { // NOTE: arm64 does not have open - res := int(intrinsics.syscall(unix.SYS_openat, AT_FDCWD, uintptr(rawptr(path)), uintptr(flags), uintptr(mode))) - } - return -1 if res < 0 else Handle(res) -} - -_unix_close :: proc(fd: Handle) -> int { - return int(intrinsics.syscall(unix.SYS_close, uintptr(fd))) -} - -_unix_read :: proc(fd: Handle, buf: rawptr, size: uint) -> int { - return int(intrinsics.syscall(unix.SYS_read, uintptr(fd), uintptr(buf), uintptr(size))) -} - -_unix_write :: proc(fd: Handle, buf: rawptr, size: uint) -> int { - return int(intrinsics.syscall(unix.SYS_write, uintptr(fd), uintptr(buf), uintptr(size))) -} - -_unix_seek :: proc(fd: Handle, offset: i64, whence: int) -> i64 { - when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { - return i64(intrinsics.syscall(unix.SYS_lseek, uintptr(fd), uintptr(offset), uintptr(whence))) - } else { - low := uintptr(offset & 0xFFFFFFFF) - high := uintptr(offset >> 32) - result: i64 - res := i64(intrinsics.syscall(unix.SYS__llseek, uintptr(fd), high, low, uintptr(&result), uintptr(whence))) - return -1 if res < 0 else result - } -} - -_unix_stat :: proc(path: cstring, stat: ^OS_Stat) -> int { - when ODIN_ARCH == .amd64 { - return int(intrinsics.syscall(unix.SYS_stat, uintptr(rawptr(path)), uintptr(stat))) - } else when ODIN_ARCH != .arm64 { - return int(intrinsics.syscall(unix.SYS_stat64, uintptr(rawptr(path)), uintptr(stat))) - } else { // NOTE: arm64 does not have stat - return int(intrinsics.syscall(unix.SYS_fstatat, AT_FDCWD, uintptr(rawptr(path)), uintptr(stat), 0)) - } -} - -_unix_fstat :: proc(fd: Handle, stat: ^OS_Stat) -> int { - when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { - return int(intrinsics.syscall(unix.SYS_fstat, uintptr(fd), uintptr(stat))) - } else { - return int(intrinsics.syscall(unix.SYS_fstat64, uintptr(fd), uintptr(stat))) - } -} - -_unix_lstat :: proc(path: cstring, stat: ^OS_Stat) -> int { - when ODIN_ARCH == .amd64 { - return int(intrinsics.syscall(unix.SYS_lstat, uintptr(rawptr(path)), uintptr(stat))) - } else when ODIN_ARCH != .arm64 { - return int(intrinsics.syscall(unix.SYS_lstat64, uintptr(rawptr(path)), uintptr(stat))) - } else { // NOTE: arm64 does not have any lstat - return int(intrinsics.syscall(unix.SYS_fstatat, AT_FDCWD, uintptr(rawptr(path)), uintptr(stat), AT_SYMLINK_NOFOLLOW)) - } -} - -_unix_readlink :: proc(path: cstring, buf: rawptr, bufsiz: uint) -> int { - when ODIN_ARCH != .arm64 { - return int(intrinsics.syscall(unix.SYS_readlink, uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz))) - } else { // NOTE: arm64 does not have readlink - return int(intrinsics.syscall(unix.SYS_readlinkat, AT_FDCWD, uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz))) - } -} - -_unix_access :: proc(path: cstring, mask: int) -> int { - when ODIN_ARCH != .arm64 { - return int(intrinsics.syscall(unix.SYS_access, uintptr(rawptr(path)), uintptr(mask))) - } else { // NOTE: arm64 does not have access - return int(intrinsics.syscall(unix.SYS_faccessat, AT_FDCWD, uintptr(rawptr(path)), uintptr(mask))) - } -} - -_unix_getcwd :: proc(buf: rawptr, size: uint) -> int { - return int(intrinsics.syscall(unix.SYS_getcwd, uintptr(buf), uintptr(size))) -} - -_unix_chdir :: proc(path: cstring) -> int { - return int(intrinsics.syscall(unix.SYS_chdir, uintptr(rawptr(path)))) -} - -_unix_rename :: proc(old, new: cstring) -> int { - when ODIN_ARCH != .arm64 { - return int(intrinsics.syscall(unix.SYS_rename, uintptr(rawptr(old)), uintptr(rawptr(new)))) - } else { // NOTE: arm64 does not have rename - return int(intrinsics.syscall(unix.SYS_renameat, AT_FDCWD, uintptr(rawptr(old)), uintptr(rawptr(new)))) - } -} - -_unix_unlink :: proc(path: cstring) -> int { - when ODIN_ARCH != .arm64 { - return int(intrinsics.syscall(unix.SYS_unlink, uintptr(rawptr(path)))) - } else { // NOTE: arm64 does not have unlink - return int(intrinsics.syscall(unix.SYS_unlinkat, AT_FDCWD, uintptr(rawptr(path)), 0)) - } -} - -_unix_rmdir :: proc(path: cstring) -> int { - when ODIN_ARCH != .arm64 { - return int(intrinsics.syscall(unix.SYS_rmdir, uintptr(rawptr(path)))) - } else { // NOTE: arm64 does not have rmdir - return int(intrinsics.syscall(unix.SYS_unlinkat, AT_FDCWD, uintptr(rawptr(path)), AT_REMOVEDIR)) - } -} - -_unix_mkdir :: proc(path: cstring, mode: u32) -> int { - when ODIN_ARCH != .arm64 { - return int(intrinsics.syscall(unix.SYS_mkdir, uintptr(rawptr(path)), uintptr(mode))) - } else { // NOTE: arm64 does not have mkdir - return int(intrinsics.syscall(unix.SYS_mkdirat, AT_FDCWD, uintptr(rawptr(path)), uintptr(mode))) - } -} - foreign libc { @(link_name="__errno_location") __errno_location :: proc() -> ^int --- @@ -415,6 +285,7 @@ foreign libc { @(link_name="free") _unix_free :: proc(ptr: rawptr) --- @(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr --- + @(link_name="execvp") _unix_execvp :: proc(path: cstring, argv: [^]cstring) -> int --- @(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring --- @(link_name="putenv") _unix_putenv :: proc(cstring) -> c.int --- @(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr --- @@ -447,7 +318,7 @@ get_last_error :: proc "contextless" () -> int { } personality :: proc(persona: u64) -> (Errno) { - res := _unix_personality(persona) + res := unix.sys_personality(persona) if res == -1 { return _get_errno(res) } @@ -455,29 +326,47 @@ personality :: proc(persona: u64) -> (Errno) { } fork :: proc() -> (Pid, Errno) { - pid := _unix_fork() + pid := unix.sys_fork() if pid == -1 { - return -1, _get_errno(int(pid)) + return -1, _get_errno(pid) } - return pid, ERROR_NONE + return Pid(pid), ERROR_NONE } -open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { +execvp :: proc(path: string, args: []string) -> Errno { + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) + + args_cstrs := make([]cstring, len(args) + 2, context.temp_allocator) + args_cstrs[0] = strings.clone_to_cstring(path, context.temp_allocator) + for i := 0; i < len(args); i += 1 { + args_cstrs[i+1] = strings.clone_to_cstring(args[i], context.temp_allocator) + } + + _unix_execvp(path_cstr, raw_data(args_cstrs)) + return Errno(get_last_error()) +} + + +open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0o000) -> (Handle, Errno) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) - handle := _unix_open(cstr, flags, mode) + handle := unix.sys_open(cstr, flags, uint(mode)) if handle < 0 { - return INVALID_HANDLE, _get_errno(int(handle)) + return INVALID_HANDLE, _get_errno(handle) } - return handle, ERROR_NONE + return Handle(handle), ERROR_NONE } close :: proc(fd: Handle) -> Errno { - return _get_errno(_unix_close(fd)) + return _get_errno(unix.sys_close(int(fd))) } read :: proc(fd: Handle, data: []byte) -> (int, Errno) { - bytes_read := _unix_read(fd, &data[0], c.size_t(len(data))) + if len(data) == 0 { + return 0, ERROR_NONE + } + + bytes_read := unix.sys_read(int(fd), raw_data(data), len(data)) if bytes_read < 0 { return -1, _get_errno(bytes_read) } @@ -488,25 +377,49 @@ write :: proc(fd: Handle, data: []byte) -> (int, Errno) { if len(data) == 0 { return 0, ERROR_NONE } - bytes_written := _unix_write(fd, &data[0], uint(len(data))) + + bytes_written := unix.sys_write(int(fd), raw_data(data), len(data)) + if bytes_written < 0 { + return -1, _get_errno(bytes_written) + } + return bytes_written, ERROR_NONE +} +read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { + if len(data) == 0 { + return 0, ERROR_NONE + } + + bytes_read := unix.sys_pread(int(fd), raw_data(data), len(data), offset) + if bytes_read < 0 { + return -1, _get_errno(bytes_read) + } + return bytes_read, ERROR_NONE +} + +write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { + if len(data) == 0 { + return 0, ERROR_NONE + } + + bytes_written := unix.sys_pwrite(int(fd), raw_data(data), uint(len(data)), offset) if bytes_written < 0 { return -1, _get_errno(bytes_written) } - return int(bytes_written), ERROR_NONE + return bytes_written, ERROR_NONE } seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { - res := _unix_seek(fd, offset, whence) + res := unix.sys_lseek(int(fd), offset, whence) if res < 0 { return -1, _get_errno(int(res)) } - return res, ERROR_NONE + return i64(res), ERROR_NONE } file_size :: proc(fd: Handle) -> (i64, Errno) { // deliberately uninitialized; the syscall fills this buffer for us s: OS_Stat = --- - result := _unix_fstat(fd, &s) + result := unix.sys_fstat(int(fd), rawptr(&s)) if result < 0 { return 0, _get_errno(result) } @@ -517,25 +430,25 @@ rename :: proc(old_path, new_path: string) -> Errno { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() old_path_cstr := strings.clone_to_cstring(old_path, context.temp_allocator) new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator) - return _get_errno(_unix_rename(old_path_cstr, new_path_cstr)) + return _get_errno(unix.sys_rename(old_path_cstr, new_path_cstr)) } remove :: proc(path: string) -> Errno { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) - return _get_errno(_unix_unlink(path_cstr)) + return _get_errno(unix.sys_unlink(path_cstr)) } make_directory :: proc(path: string, mode: u32 = 0o775) -> Errno { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) - return _get_errno(_unix_mkdir(path_cstr, mode)) + return _get_errno(unix.sys_mkdir(path_cstr, uint(mode))) } remove_directory :: proc(path: string) -> Errno { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) - return _get_errno(_unix_rmdir(path_cstr)) + return _get_errno(unix.sys_rmdir(path_cstr)) } is_file_handle :: proc(fd: Handle) -> bool { @@ -589,7 +502,7 @@ is_dir :: proc {is_dir_path, is_dir_handle} exists :: proc(path: string) -> bool { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cpath := strings.clone_to_cstring(path, context.temp_allocator) - res := _unix_access(cpath, O_RDONLY) + res := unix.sys_access(cpath, O_RDONLY) return res == 0 } @@ -628,7 +541,7 @@ _stat :: proc(path: string) -> (OS_Stat, Errno) { // deliberately uninitialized; the syscall fills this buffer for us s: OS_Stat = --- - result := _unix_stat(cstr, &s) + result := unix.sys_stat(cstr, &s) if result < 0 { return s, _get_errno(result) } @@ -642,7 +555,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Errno) { // deliberately uninitialized; the syscall fills this buffer for us s: OS_Stat = --- - result := _unix_lstat(cstr, &s) + result := unix.sys_lstat(cstr, &s) if result < 0 { return s, _get_errno(result) } @@ -653,7 +566,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Errno) { _fstat :: proc(fd: Handle) -> (OS_Stat, Errno) { // deliberately uninitialized; the syscall fills this buffer for us s: OS_Stat = --- - result := _unix_fstat(fd, &s) + result := unix.sys_fstat(int(fd), rawptr(&s)) if result < 0 { return s, _get_errno(result) } @@ -711,7 +624,7 @@ _readlink :: proc(path: string) -> (string, Errno) { bufsz : uint = 256 buf := make([]byte, bufsz) for { - rc := _unix_readlink(path_cstr, &(buf[0]), bufsz) + rc := unix.sys_readlink(path_cstr, &(buf[0]), bufsz) if rc < 0 { delete(buf) return "", _get_errno(rc) @@ -760,7 +673,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { access :: proc(path: string, mask: int) -> (bool, Errno) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) - result := _unix_access(cstr, mask) + result := unix.sys_access(cstr, mask) if result < 0 { return false, _get_errno(result) } @@ -831,7 +744,7 @@ get_current_directory :: proc() -> string { page_size := get_page_size() buf := make([dynamic]u8, page_size) for { - #no_bounds_check res := _unix_getcwd(&buf[0], uint(len(buf))) + #no_bounds_check res := unix.sys_getcwd(&buf[0], uint(len(buf))) if res >= 0 { return strings.string_from_nul_terminated_ptr(&buf[0], len(buf)) @@ -848,7 +761,7 @@ get_current_directory :: proc() -> string { set_current_directory :: proc(path: string) -> (err: Errno) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) - res := _unix_chdir(cstr) + res := unix.sys_chdir(cstr) if res < 0 { return _get_errno(res) } diff --git a/core/prof/spall/spall.odin b/core/prof/spall/spall.odin new file mode 100644 index 000000000..ff8c69222 --- /dev/null +++ b/core/prof/spall/spall.odin @@ -0,0 +1,208 @@ +package prof_spall + +import "core:os" +import "core:time" +import "core:intrinsics" +import "core:mem" + +// File Format + +MANUAL_MAGIC :: u64le(0x0BADF00D) + +Manual_Header :: struct #packed { + magic: u64le, + version: u64le, + timestamp_scale: f64le, + reserved: u64le, +} + +Manual_Event_Type :: enum u8 { + Invalid = 0, + + Begin = 3, + End = 4, + Instant = 5, + + Pad_Skip = 7, +} + +Begin_Event :: struct #packed { + type: Manual_Event_Type, + category: u8, + pid: u32le, + tid: u32le, + ts: f64le, + name_len: u8, + args_len: u8, +} +BEGIN_EVENT_MAX :: size_of(Begin_Event) + 255 + 255 + +End_Event :: struct #packed { + type: Manual_Event_Type, + pid: u32le, + tid: u32le, + ts: f64le, +} + +Pad_Skip :: struct #packed { + type: Manual_Event_Type, + size: u32le, +} + +// User Interface + +Context :: struct { + precise_time: bool, + timestamp_scale: f64, + fd: os.Handle, +} + +Buffer :: struct { + data: []u8, + head: int, + tid: u32, + pid: u32, +} + +BUFFER_DEFAULT_SIZE :: 0x10_0000 + + +context_create :: proc(filename: string) -> (ctx: Context, ok: bool) #optional_ok { + fd, err := os.open(filename, os.O_WRONLY | os.O_APPEND | os.O_CREATE | os.O_TRUNC, 0o600) + if err != os.ERROR_NONE { + return + } + ctx.fd = fd + + freq, freq_ok := time.tsc_frequency() + ctx.precise_time = freq_ok + ctx.timestamp_scale = ((1 / f64(freq)) * 1_000_000) if freq_ok else 1 + + temp := [size_of(Manual_Header)]u8{} + _build_header(temp[:], ctx.timestamp_scale) + os.write(ctx.fd, temp[:]) + ok = true + return +} + +context_destroy :: proc(ctx: ^Context) { + if ctx == nil { + return + } + + os.close(ctx.fd) + ctx^ = Context{} +} + +buffer_create :: proc(data: []byte, tid: u32 = 0, pid: u32 = 0) -> (buffer: Buffer, ok: bool) #optional_ok { + assert(len(data) > 0) + buffer.data = data + buffer.tid = tid + buffer.pid = pid + buffer.head = 0 + ok = true + return +} + +buffer_flush :: proc(ctx: ^Context, buffer: ^Buffer) { + os.write(ctx.fd, buffer.data[:buffer.head]) + buffer.head = 0 +} + +buffer_destroy :: proc(ctx: ^Context, buffer: ^Buffer) { + buffer_flush(ctx, buffer) + + buffer^ = Buffer{} +} + + + +@(deferred_in=_scoped_buffer_end) +SCOPED_EVENT :: proc(ctx: ^Context, buffer: ^Buffer, name: string, args: string = "", location := #caller_location) -> bool { + _buffer_begin(ctx, buffer, name, args, location) + return true +} + +@(private) +_scoped_buffer_end :: proc(ctx: ^Context, buffer: ^Buffer, _, _: string, _ := #caller_location) { + _buffer_end(ctx, buffer) +} + + +_trace_now :: proc "contextless" (ctx: ^Context) -> f64 { + if !ctx.precise_time { + return f64(time.tick_now()._nsec) / 1_000 + } + + return f64(intrinsics.read_cycle_counter()) +} + +_build_header :: proc "contextless" (buffer: []u8, timestamp_scale: f64) -> (header_size: int, ok: bool) #optional_ok { + header_size = size_of(Manual_Header) + if header_size > len(buffer) { + return 0, false + } + + hdr := (^Manual_Header)(raw_data(buffer)) + hdr.magic = MANUAL_MAGIC + hdr.version = 1 + hdr.timestamp_scale = f64le(timestamp_scale) + hdr.reserved = 0 + ok = true + return +} + +_build_begin :: proc "contextless" (buffer: []u8, name: string, args: string, ts: f64, tid: u32, pid: u32) -> (event_size: int, ok: bool) #optional_ok { + ev := (^Begin_Event)(raw_data(buffer)) + name_len := min(len(name), 255) + args_len := min(len(args), 255) + + event_size = size_of(Begin_Event) + name_len + args_len + if event_size > len(buffer) { + return 0, false + } + + ev.type = .Begin + ev.pid = u32le(pid) + ev.tid = u32le(tid) + ev.ts = f64le(ts) + ev.name_len = u8(name_len) + ev.args_len = u8(args_len) + mem.copy(raw_data(buffer[size_of(Begin_Event):]), raw_data(name), name_len) + mem.copy(raw_data(buffer[size_of(Begin_Event)+name_len:]), raw_data(args), args_len) + ok = true + return +} + +_build_end :: proc(buffer: []u8, ts: f64, tid: u32, pid: u32) -> (event_size: int, ok: bool) #optional_ok { + ev := (^End_Event)(raw_data(buffer)) + event_size = size_of(End_Event) + if event_size > len(buffer) { + return 0, false + } + + ev.type = .End + ev.pid = u32le(pid) + ev.tid = u32le(tid) + ev.ts = f64le(ts) + ok = true + return +} + +_buffer_begin :: proc(ctx: ^Context, buffer: ^Buffer, name: string, args: string = "", location := #caller_location) { + if buffer.head + BEGIN_EVENT_MAX > len(buffer.data) { + buffer_flush(ctx, buffer) + } + name := location.procedure if name == "" else name + buffer.head += _build_begin(buffer.data[buffer.head:], name, args, _trace_now(ctx), buffer.tid, buffer.pid) +} + +_buffer_end :: proc(ctx: ^Context, buffer: ^Buffer) { + ts := _trace_now(ctx) + + if buffer.head + size_of(End_Event) > len(buffer.data) { + buffer_flush(ctx, buffer) + } + + buffer.head += _build_end(buffer.data[buffer.head:], ts, buffer.tid, buffer.pid) +} diff --git a/core/runtime/core.odin b/core/runtime/core.odin index c64ab7d3b..2d20310ae 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -507,11 +507,8 @@ Odin_Endian_Type :: type_of(ODIN_ENDIAN) foreign { @(link_name="__$startup_runtime") _startup_runtime :: proc "odin" () --- -} - -@(link_name="__$cleanup_runtime") -_cleanup_runtime :: proc() { - default_temp_allocator_destroy(&global_default_temp_allocator_data) + @(link_name="__$cleanup_runtime") + _cleanup_runtime :: proc "odin" () --- } _cleanup_runtime_contextless :: proc "contextless" () { diff --git a/core/runtime/default_temporary_allocator.odin b/core/runtime/default_temporary_allocator.odin index 3bfdaab3d..296ead722 100644 --- a/core/runtime/default_temporary_allocator.odin +++ b/core/runtime/default_temporary_allocator.odin @@ -72,3 +72,8 @@ default_temp_allocator :: proc(allocator: ^Default_Temp_Allocator) -> Allocator data = allocator, } } + +@(fini, private) +_destroy_temp_allocator_fini :: proc() { + default_temp_allocator_destroy(&global_default_temp_allocator_data) +} diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index cb04ff0aa..3c8cade39 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -184,32 +184,33 @@ mem_free_all :: #force_inline proc(allocator := context.allocator, loc := #calle return } -mem_resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) { +mem_resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (data: []byte, err: Allocator_Error) { if allocator.procedure == nil { return nil, nil } if new_size == 0 { if ptr != nil { - _, err := allocator.procedure(allocator.data, .Free, 0, 0, ptr, old_size, loc) - return nil, err + _, err = allocator.procedure(allocator.data, .Free, 0, 0, ptr, old_size, loc) + return } - return nil, nil + return } else if ptr == nil { return allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc) } else if old_size == new_size && uintptr(ptr) % uintptr(alignment) == 0 { - return ([^]byte)(ptr)[:old_size], nil + data = ([^]byte)(ptr)[:old_size] + return } - data, err := allocator.procedure(allocator.data, .Resize, new_size, alignment, ptr, old_size, loc) + data, err = allocator.procedure(allocator.data, .Resize, new_size, alignment, ptr, old_size, loc) if err == .Mode_Not_Implemented { data, err = allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc) if err != nil { - return data, err + return } copy(data, ([^]byte)(ptr)[:old_size]) _, err = allocator.procedure(allocator.data, .Free, 0, 0, ptr, old_size, loc) } - return data, err + return } memory_equal :: proc "contextless" (x, y: rawptr, n: int) -> bool { @@ -223,7 +224,7 @@ memory_equal :: proc "contextless" (x, y: rawptr, n: int) -> bool { when size_of(uint) == 8 { if word_length := length >> 3; word_length != 0 { - for i in 0..<word_length { + for _ in 0..<word_length { if intrinsics.unaligned_load((^u64)(a)) != intrinsics.unaligned_load((^u64)(b)) { return false } @@ -254,7 +255,7 @@ memory_equal :: proc "contextless" (x, y: rawptr, n: int) -> bool { return true } else { if word_length := length >> 2; word_length != 0 { - for i in 0..<word_length { + for _ in 0..<word_length { if intrinsics.unaligned_load((^u32)(a)) != intrinsics.unaligned_load((^u32)(b)) { return false } diff --git a/core/runtime/print.odin b/core/runtime/print.odin index 819cd5796..9696488a4 100644 --- a/core/runtime/print.odin +++ b/core/runtime/print.odin @@ -2,6 +2,9 @@ package runtime _INTEGER_DIGITS :: "0123456789abcdefghijklmnopqrstuvwxyz" +@(private="file") +_INTEGER_DIGITS_VAR := _INTEGER_DIGITS + when !ODIN_DISALLOW_RTTI { print_any_single :: proc(arg: any) { x := arg @@ -105,14 +108,14 @@ encode_rune :: proc "contextless" (c: rune) -> ([4]u8, int) { return buf, 4 } -print_string :: proc "contextless" (str: string) -> (int, _OS_Errno) { - return os_write(transmute([]byte)str) +print_string :: proc "contextless" (str: string) -> (n: int) { + n, _ = os_write(transmute([]byte)str) + return } -print_strings :: proc "contextless" (args: ..string) -> (n: int, err: _OS_Errno) { +print_strings :: proc "contextless" (args: ..string) -> (n: int) { for str in args { - m: int - m, err = os_write(transmute([]byte)str) + m, err := os_write(transmute([]byte)str) n += m if err != 0 { break @@ -121,8 +124,9 @@ print_strings :: proc "contextless" (args: ..string) -> (n: int, err: _OS_Errno) return } -print_byte :: proc "contextless" (b: byte) -> (int, _OS_Errno) { - return os_write([]byte{b}) +print_byte :: proc "contextless" (b: byte) -> (n: int) { + n, _ = os_write([]byte{b}) + return } print_encoded_rune :: proc "contextless" (r: rune) { @@ -141,11 +145,10 @@ print_encoded_rune :: proc "contextless" (r: rune) { if r <= 0 { print_string("\\x00") } else if r < 32 { - digits := _INTEGER_DIGITS n0, n1 := u8(r) >> 4, u8(r) & 0xf print_string("\\x") - print_byte(digits[n0]) - print_byte(digits[n1]) + print_byte(_INTEGER_DIGITS_VAR[n0]) + print_byte(_INTEGER_DIGITS_VAR[n1]) } else { print_rune(r) } @@ -153,7 +156,7 @@ print_encoded_rune :: proc "contextless" (r: rune) { print_byte('\'') } -print_rune :: proc "contextless" (r: rune) -> (int, _OS_Errno) #no_bounds_check { +print_rune :: proc "contextless" (r: rune) -> int #no_bounds_check { RUNE_SELF :: 0x80 if r < RUNE_SELF { @@ -161,29 +164,27 @@ print_rune :: proc "contextless" (r: rune) -> (int, _OS_Errno) #no_bounds_check } b, n := encode_rune(r) - return os_write(b[:n]) + m, _ := os_write(b[:n]) + return m } print_u64 :: proc "contextless" (x: u64) #no_bounds_check { - digits := _INTEGER_DIGITS - a: [129]byte i := len(a) b := u64(10) u := x for u >= b { - i -= 1; a[i] = digits[u % b] + i -= 1; a[i] = _INTEGER_DIGITS_VAR[u % b] u /= b } - i -= 1; a[i] = digits[u % b] + i -= 1; a[i] = _INTEGER_DIGITS_VAR[u % b] os_write(a[i:]) } print_i64 :: proc "contextless" (x: i64) #no_bounds_check { - digits := _INTEGER_DIGITS b :: i64(10) u := x @@ -193,10 +194,10 @@ print_i64 :: proc "contextless" (x: i64) #no_bounds_check { a: [129]byte i := len(a) for u >= b { - i -= 1; a[i] = digits[u % b] + i -= 1; a[i] = _INTEGER_DIGITS_VAR[u % b] u /= b } - i -= 1; a[i] = digits[u % b] + i -= 1; a[i] = _INTEGER_DIGITS_VAR[u % b] if neg { i -= 1; a[i] = '-' } diff --git a/core/sync/primitives.odin b/core/sync/primitives.odin index 00d7812a8..8d6ce6e48 100644 --- a/core/sync/primitives.odin +++ b/core/sync/primitives.odin @@ -236,4 +236,4 @@ _panic :: proc "contextless" (msg: string) -> ! { runtime.print_string(msg) runtime.print_byte('\n') runtime.trap() -}
\ No newline at end of file +} diff --git a/core/sys/darwin/xnu_system_call_numbers.odin b/core/sys/darwin/xnu_system_call_numbers.odin index b90373fdc..429d18964 100644 --- a/core/sys/darwin/xnu_system_call_numbers.odin +++ b/core/sys/darwin/xnu_system_call_numbers.odin @@ -1,6 +1,6 @@ package darwin -unix_offset_syscall :: proc(number: System_Call_Number) -> uintptr { +unix_offset_syscall :: proc "contextless" (number: System_Call_Number) -> uintptr { return uintptr(number) + uintptr(0x2000000) } diff --git a/core/sys/darwin/xnu_system_call_wrappers.odin b/core/sys/darwin/xnu_system_call_wrappers.odin index 685f75ffa..c7a6d6bc4 100644 --- a/core/sys/darwin/xnu_system_call_wrappers.odin +++ b/core/sys/darwin/xnu_system_call_wrappers.odin @@ -229,191 +229,191 @@ _Proc_Bsdinfo :: struct { /*--==========================================================================--*/ -syscall_fsync :: #force_inline proc(fildes: c.int) -> bool { +syscall_fsync :: #force_inline proc "contextless" (fildes: c.int) -> bool { return !(cast(bool)intrinsics.syscall(unix_offset_syscall(.fsync), uintptr(fildes))) } -syscall_write :: #force_inline proc (fildes: c.int, buf: ^byte, nbyte: u64) -> bool { +syscall_write :: #force_inline proc "contextless" (fildes: c.int, buf: ^byte, nbyte: u64) -> bool { return !(cast(bool)intrinsics.syscall(unix_offset_syscall(.write), uintptr(fildes), uintptr(buf), uintptr(nbyte))) } -syscall_read :: #force_inline proc(fildes: c.int, buf: ^byte, nbyte: u64) -> i64 { +syscall_read :: #force_inline proc "contextless" (fildes: c.int, buf: ^byte, nbyte: u64) -> i64 { return cast(i64)intrinsics.syscall(unix_offset_syscall(.read), uintptr(fildes), uintptr(buf), uintptr(nbyte)) } -syscall_open :: #force_inline proc(path: cstring, oflag: u32, mode: u32) -> c.int { +syscall_open :: #force_inline proc "contextless" (path: cstring, oflag: u32, mode: u32) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.open), transmute(uintptr)path, uintptr(oflag), uintptr(mode)) } -syscall_close :: #force_inline proc(fd: c.int) -> bool { +syscall_close :: #force_inline proc "contextless" (fd: c.int) -> bool { return !(cast(bool)intrinsics.syscall(unix_offset_syscall(.close), uintptr(fd))) } -syscall_fchmod :: #force_inline proc(fildes: c.int, mode: u32) -> c.int { +syscall_fchmod :: #force_inline proc "contextless" (fildes: c.int, mode: u32) -> c.int { return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.fchmod), uintptr(fildes), uintptr(mode))) } -syscall_chmod :: #force_inline proc(path: cstring, mode: u32) -> c.int { +syscall_chmod :: #force_inline proc "contextless" (path: cstring, mode: u32) -> c.int { return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.chmod), transmute(uintptr)path, uintptr(mode))) } -syscall_mkdir :: #force_inline proc(path: cstring, mode: u32) -> c.int { +syscall_mkdir :: #force_inline proc "contextless" (path: cstring, mode: u32) -> c.int { return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.mkdir), transmute(uintptr)path, uintptr(mode))) } -syscall_mkdir_at :: #force_inline proc(fd: c.int, path: cstring, mode: u32) -> c.int { +syscall_mkdir_at :: #force_inline proc "contextless" (fd: c.int, path: cstring, mode: u32) -> c.int { return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.mkdir), uintptr(fd), transmute(uintptr)path, uintptr(mode))) } -syscall_rmdir :: #force_inline proc(path: cstring, mode: u32) -> c.int { +syscall_rmdir :: #force_inline proc "contextless" (path: cstring, mode: u32) -> c.int { return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.rmdir), transmute(uintptr)path, uintptr(mode))) } -syscall_rename :: #force_inline proc(path_old: cstring, path_new: cstring) -> c.int { +syscall_rename :: #force_inline proc "contextless" (path_old: cstring, path_new: cstring) -> c.int { return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.rename), transmute(uintptr)path_old, transmute(uintptr)path_new)) } -syscall_rename_at :: #force_inline proc(from_fd: c.int, from: cstring, to_fd: c.int, to: cstring) -> c.int { +syscall_rename_at :: #force_inline proc "contextless" (from_fd: c.int, from: cstring, to_fd: c.int, to: cstring) -> c.int { return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.renameat), uintptr(from_fd), transmute(uintptr)from, uintptr(to_fd), transmute(uintptr)to)) } -syscall_lseek :: #force_inline proc(fd: c.int, offset: i64, whence: c.int) -> i64 { +syscall_lseek :: #force_inline proc "contextless" (fd: c.int, offset: i64, whence: c.int) -> i64 { return cast(i64)intrinsics.syscall(unix_offset_syscall(.lseek), uintptr(fd), uintptr(offset), uintptr(whence)) } -syscall_gettid :: #force_inline proc() -> u64 { +syscall_gettid :: #force_inline proc "contextless" () -> u64 { return cast(u64)intrinsics.syscall(unix_offset_syscall(.gettid)) } -syscall_fstat :: #force_inline proc(fd: c.int, status: ^stat) -> c.int { +syscall_fstat :: #force_inline proc "contextless" (fd: c.int, status: ^stat) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.fstat), uintptr(fd), uintptr(status)) } -syscall_lstat :: #force_inline proc(path: cstring, status: ^stat) -> c.int { +syscall_lstat :: #force_inline proc "contextless" (path: cstring, status: ^stat) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.lstat), transmute(uintptr)path, uintptr(status)) } -syscall_stat :: #force_inline proc(path: cstring, status: ^stat) -> c.int { +syscall_stat :: #force_inline proc "contextless" (path: cstring, status: ^stat) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.stat), transmute(uintptr)path, uintptr(status)) } -syscall_fstatat :: #force_inline proc(fd: c.int, path: cstring, status: ^stat) -> c.int { +syscall_fstatat :: #force_inline proc "contextless" (fd: c.int, path: cstring, status: ^stat) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.fstatat), uintptr(fd), transmute(uintptr)path, uintptr(status)) } -syscall_link :: #force_inline proc(path: cstring, to_link: cstring) -> c.int { +syscall_link :: #force_inline proc "contextless" (path: cstring, to_link: cstring) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.link), transmute(uintptr)path, transmute(uintptr)to_link) } -syscall_linkat :: #force_inline proc(fd: c.int, path: cstring, fd2: c.int, to_link: cstring) -> c.int { +syscall_linkat :: #force_inline proc "contextless" (fd: c.int, path: cstring, fd2: c.int, to_link: cstring) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.linkat), uintptr(fd), transmute(uintptr)path, uintptr(fd2), transmute(uintptr)to_link) } -syscall_readlink :: #force_inline proc(path: cstring, buf: ^u8, buf_size: u64) -> i64 { +syscall_readlink :: #force_inline proc "contextless" (path: cstring, buf: ^u8, buf_size: u64) -> i64 { return cast(i64)intrinsics.syscall(unix_offset_syscall(.readlink), transmute(uintptr)path, uintptr(buf), uintptr(buf_size)) } -syscall_readlinkat :: #force_inline proc(fd: c.int, path: cstring, buf: ^u8, buf_size: u64) -> i64 { +syscall_readlinkat :: #force_inline proc "contextless" (fd: c.int, path: cstring, buf: ^u8, buf_size: u64) -> i64 { return cast(i64)intrinsics.syscall(unix_offset_syscall(.readlinkat), uintptr(fd), transmute(uintptr)path, uintptr(buf), uintptr(buf_size)) } -syscall_access :: #force_inline proc(path: cstring, mode: c.int) -> c.int { +syscall_access :: #force_inline proc "contextless" (path: cstring, mode: c.int) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.access), transmute(uintptr)path, uintptr(mode)) } -syscall_faccessat :: #force_inline proc(fd: c.int, path: cstring, mode: c.int, flag: c.int) -> c.int { +syscall_faccessat :: #force_inline proc "contextless" (fd: c.int, path: cstring, mode: c.int, flag: c.int) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.faccessat), uintptr(fd), transmute(uintptr)path, uintptr(mode), uintptr(flag)) } -syscall_getdirentries :: #force_inline proc(fd: c.int, buf: ^u8, nbytes: c.int, base_pointer: ^u32) -> c.int { +syscall_getdirentries :: #force_inline proc "contextless" (fd: c.int, buf: ^u8, nbytes: c.int, base_pointer: ^u32) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getdirentries), uintptr(fd), uintptr(buf), uintptr(nbytes), uintptr(base_pointer)) } -syscall_truncate :: #force_inline proc (path: cstring, length: off_t) -> c.int { +syscall_truncate :: #force_inline proc "contextless" (path: cstring, length: off_t) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.truncate), transmute(uintptr)path, uintptr(length)) } -syscall_ftruncate :: #force_inline proc (fd: c.int, length: off_t) -> c.int { +syscall_ftruncate :: #force_inline proc "contextless" (fd: c.int, length: off_t) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.ftruncate), uintptr(fd), uintptr(length)) } -syscall_sysctl :: #force_inline proc (name: ^c.int, namelen: c.uint, oldp: rawptr, oldlenp: ^i64, newp: ^i8, newlen: i64) -> c.int { +syscall_sysctl :: #force_inline proc "contextless" (name: ^c.int, namelen: c.uint, oldp: rawptr, oldlenp: ^i64, newp: ^i8, newlen: i64) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.sysctl), uintptr(name), uintptr(namelen), uintptr(oldp), uintptr(oldlenp), uintptr(newp), uintptr(newlen)) } -syscall_copyfile :: #force_inline proc(from: cstring, to: cstring, state: rawptr, flags: u32) -> c.int { +syscall_copyfile :: #force_inline proc "contextless" (from: cstring, to: cstring, state: rawptr, flags: u32) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.copyfile), transmute(uintptr)from, transmute(uintptr)to, uintptr(state), uintptr(flags)) } // think about this? last arg should be more than one -syscall_fcntl :: #force_inline proc(fd: c.int, cmd: c.int, other: rawptr) -> c.int { +syscall_fcntl :: #force_inline proc "contextless" (fd: c.int, cmd: c.int, other: rawptr) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.fsctl), uintptr(fd), uintptr(cmd), uintptr(other)) } -syscall_exit :: #force_inline proc(code: c.int) { +syscall_exit :: #force_inline proc "contextless" (code: c.int) { intrinsics.syscall(unix_offset_syscall(.exit), uintptr(code)) } -syscall_kill :: #force_inline proc(pid: pid_t, sig: c.int) -> c.int { +syscall_kill :: #force_inline proc "contextless" (pid: pid_t, sig: c.int) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.kill), uintptr(pid), uintptr(sig)) } -syscall_dup :: #force_inline proc(fd: c.int) -> c.int { +syscall_dup :: #force_inline proc "contextless" (fd: c.int) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.dup), uintptr(fd)) } -syscall_execve :: #force_inline proc(path: cstring, argv: [^]cstring, env: [^]cstring) -> c.int { +syscall_execve :: #force_inline proc "contextless" (path: cstring, argv: [^]cstring, env: [^]cstring) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.execve), transmute(uintptr)path, transmute(uintptr)argv, transmute(uintptr)env) } -syscall_munmap :: #force_inline proc(addr: rawptr, len: u64) -> c.int { +syscall_munmap :: #force_inline proc "contextless" (addr: rawptr, len: u64) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.mmap), uintptr(addr), uintptr(len)) } -syscall_mmap :: #force_inline proc(addr: ^u8, len: u64, port: c.int, flags: c.int, fd: int, offset: off_t) -> ^u8 { +syscall_mmap :: #force_inline proc "contextless" (addr: ^u8, len: u64, port: c.int, flags: c.int, fd: int, offset: off_t) -> ^u8 { return cast(^u8)intrinsics.syscall(unix_offset_syscall(.mmap), uintptr(addr), uintptr(len), uintptr(port), uintptr(flags), uintptr(fd), uintptr(offset)) } -syscall_flock :: #force_inline proc(fd: c.int, operation: c.int) -> c.int { +syscall_flock :: #force_inline proc "contextless" (fd: c.int, operation: c.int) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.flock), uintptr(fd), uintptr(operation)) } -syscall_utimes :: #force_inline proc(path: cstring, times: ^timeval) -> c.int { +syscall_utimes :: #force_inline proc "contextless" (path: cstring, times: ^timeval) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.utimes), transmute(uintptr)path, uintptr(times)) } -syscall_futimes :: #force_inline proc(fd: c.int, times: ^timeval) -> c.int { +syscall_futimes :: #force_inline proc "contextless" (fd: c.int, times: ^timeval) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.futimes), uintptr(fd), uintptr(times)) } -syscall_adjtime :: #force_inline proc(delta: ^timeval, old_delta: ^timeval) -> c.int { +syscall_adjtime :: #force_inline proc "contextless" (delta: ^timeval, old_delta: ^timeval) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.adjtime), uintptr(delta), uintptr(old_delta)) } -syscall_sysctlbyname :: #force_inline proc(name: cstring, oldp: rawptr, oldlenp: ^i64, newp: rawptr, newlen: i64) -> c.int { +syscall_sysctlbyname :: #force_inline proc "contextless" (name: cstring, oldp: rawptr, oldlenp: ^i64, newp: rawptr, newlen: i64) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.sysctlbyname), transmute(uintptr)name, uintptr(oldp), uintptr(oldlenp), uintptr(newp), uintptr(newlen)) } -syscall_proc_info :: #force_inline proc(num: c.int, pid: u32, flavor: c.int, arg: u64, buffer: rawptr, buffer_size: c.int) -> c.int { +syscall_proc_info :: #force_inline proc "contextless" (num: c.int, pid: u32, flavor: c.int, arg: u64, buffer: rawptr, buffer_size: c.int) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.proc_info), uintptr(num), uintptr(pid), uintptr(flavor), uintptr(arg), uintptr(buffer), uintptr(buffer_size)) } -syscall_openat :: #force_inline proc(fd: int, path: cstring, oflag: u32, mode: u32) -> c.int { +syscall_openat :: #force_inline proc "contextless" (fd: int, path: cstring, oflag: u32, mode: u32) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.openat), uintptr(fd), transmute(uintptr)path, uintptr(oflag), uintptr(mode)) } -syscall_getentropy :: #force_inline proc(buf: [^]u8, buflen: u64) -> c.int { +syscall_getentropy :: #force_inline proc "contextless" (buf: [^]u8, buflen: u64) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getentropy), uintptr(buf), uintptr(buflen)) } -syscall_pipe :: #force_inline proc(fds: [^]c.int) -> c.int { +syscall_pipe :: #force_inline proc "contextless" (fds: [^]c.int) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getentropy), uintptr(&fds[0]), uintptr(&fds[1])) } -syscall_chdir :: #force_inline proc(path: cstring) -> c.int { +syscall_chdir :: #force_inline proc "contextless" (path: cstring) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getentropy), transmute(uintptr)path) } -syscall_fchdir :: #force_inline proc(fd: c.int, path: cstring) -> c.int { +syscall_fchdir :: #force_inline proc "contextless" (fd: c.int, path: cstring) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getentropy), uintptr(fd), transmute(uintptr)path) -}
\ No newline at end of file +} diff --git a/core/sys/unix/syscalls_linux.odin b/core/sys/unix/syscalls_linux.odin index 8ce3ca3cb..91c0accfa 100644 --- a/core/sys/unix/syscalls_linux.odin +++ b/core/sys/unix/syscalls_linux.odin @@ -1563,15 +1563,167 @@ MADV_WIPEONFORK :: 18 MADV_KEEPONFORK :: 19 MADV_HWPOISON :: 100 +// pipe2 flags +O_CLOEXEC :: 0o2000000 + +// perf event data +Perf_Sample :: struct #raw_union { + period: u64, + frequency: u64, +} +Perf_Wakeup :: struct #raw_union { + events: u32, + watermark: u32, +} +Perf_Field1 :: struct #raw_union { + breakpoint_addr: u64, + kprobe_func: u64, + uprobe_path: u64, + config1: u64, +} +Perf_Field2 :: struct #raw_union { + breakpoint_len: u64, + kprobe_addr: u64, + uprobe_offset: u64, + config2: u64, +} +Perf_Event_Attr :: struct #packed { + type: u32, + size: u32, + config: u64, + sample: Perf_Sample, + sample_type: u64, + read_format: u64, + flags: Perf_Flags, + wakeup: Perf_Wakeup, + breakpoint_type: u32, + field1: Perf_Field1, + field2: Perf_Field2, + branch_sample_type: u64, + sample_regs_user: u64, + sample_stack_user: u32, + clock_id: i32, + sample_regs_intr: u64, + aux_watermark: u32, + sample_max_stack: u16, + _padding: u16, +} + +Perf_Event_Flags :: distinct bit_set[Perf_Event_Flag; u64] +Perf_Event_Flag :: enum u64 { + Bit0 = 0, + Bit0_Is_Deprecated = 1, + User_Rdpmc = 2, + User_Time = 3, + User_Time_Zero = 4, + User_Time_Short = 5, +} +Perf_Capabilities :: struct #raw_union { + capabilities: u64, + flags: Perf_Event_Flags, +} +Perf_Event_mmap_Page :: struct #packed { + version: u32, + compat_version: u32, + lock: u32, + index: u32, + offset: i64, + time_enabled: u64, + time_running: u64, + cap: Perf_Capabilities, + pmc_width: u16, + time_shift: u16, + time_mult: u32, + time_offset: u64, + time_zero: u64, + size: u32, + reserved1: u32, + time_cycles: u64, + time_mask: u64, + reserved2: [116*8]u8, + data_head: u64, + data_tail: u64, + data_offset: u64, + data_size: u64, + aux_head: u64, + aux_tail: u64, + aux_offset: u64, + aux_size: u64, +} + +Perf_Type_Id :: enum u32 { + Hardware = 0, + Software = 1, + Tracepoint = 2, + HW_Cache = 3, + Raw = 4, + Breakpoint = 5, +} + +Perf_Hardware_Id :: enum u64 { + CPU_Cycles = 0, + Instructions = 1, + Cache_References = 2, + Cache_Misses = 3, + Branch_Instructions = 4, + Branch_Misses = 5, + Bus_Cycles = 6, + Stalled_Cycles_Frontend = 7, + Stalled_Cycles_Backend = 8, + Ref_CPU_Cycles = 9, +} + +Perf_Flags :: distinct bit_set[Perf_Flag; u64] +Perf_Flag :: enum u64 { + Disabled = 0, + Inherit = 1, + Pinned = 2, + Exclusive = 3, + Exclude_User = 4, + Exclude_Kernel = 5, + Exclude_HV = 6, + Exclude_Idle = 7, + mmap = 8, + Comm = 9, + Freq = 10, + Inherit_Stat = 11, + Enable_On_Exec = 12, + Task = 13, + Watermark = 14, + Precise_IP_0 = 15, + Precise_IP_1 = 16, + mmap_Data = 17, + Sample_Id_All = 18, + Exclude_Host = 19, + Exclude_Guest = 20, + Exclude_Callchain_Kernel = 21, + Exclude_Callchain_User = 22, + mmap2 = 23, + Comm_Exec = 24, + Use_Clockid = 25, + Context_Switch = 26, + Write_Backward = 27, + Namespaces = 28, + KSymbol = 29, + BPF_Event = 30, + Aux_Output = 31, + CGroup = 32, + Text_Poke = 33, + Build_Id = 34, + Inherit_Thread = 35, + Remove_On_Exec = 36, + Sigtrap = 37, +} + sys_gettid :: proc "contextless" () -> int { - return cast(int)intrinsics.syscall(SYS_gettid) + return int(intrinsics.syscall(SYS_gettid)) } -sys_getrandom :: proc "contextless" (buf: [^]byte, buflen: int, flags: uint) -> int { - return cast(int)intrinsics.syscall(SYS_getrandom, uintptr(buf), uintptr(buflen), uintptr(flags)) +sys_getrandom :: proc "contextless" (buf: [^]byte, buflen: uint, flags: int) -> int { + return int(intrinsics.syscall(SYS_getrandom, uintptr(buf), uintptr(buflen), uintptr(flags))) } -sys_open :: proc "contextless" (path: cstring, flags: int, mode: int = 0o000) -> int { +sys_open :: proc "contextless" (path: cstring, flags: int, mode: uint = 0o000) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_open, uintptr(rawptr(path)), uintptr(flags), uintptr(mode))) } else { // NOTE: arm64 does not have open @@ -1579,7 +1731,7 @@ sys_open :: proc "contextless" (path: cstring, flags: int, mode: int = 0o000) -> } } -sys_openat :: proc "contextless" (dfd: int, path: cstring, flags: int, mode: int = 0o000) -> int { +sys_openat :: proc "contextless" (dfd: int, path: cstring, flags: int, mode: uint = 0o000) -> int { return int(intrinsics.syscall(SYS_openat, uintptr(dfd), uintptr(rawptr(path)), uintptr(flags), uintptr(mode))) } @@ -1691,7 +1843,7 @@ sys_fchdir :: proc "contextless" (fd: int) -> int { return int(intrinsics.syscall(SYS_fchdir, uintptr(fd))) } -sys_chmod :: proc "contextless" (path: cstring, mode: int) -> int { +sys_chmod :: proc "contextless" (path: cstring, mode: uint) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_chmod, uintptr(rawptr(path)), uintptr(mode))) } else { // NOTE: arm64 does not have chmod @@ -1699,7 +1851,7 @@ sys_chmod :: proc "contextless" (path: cstring, mode: int) -> int { } } -sys_fchmod :: proc "contextless" (fd: int, mode: int) -> int { +sys_fchmod :: proc "contextless" (fd: int, mode: uint) -> int { return int(intrinsics.syscall(SYS_fchmod, uintptr(fd), uintptr(mode))) } @@ -1759,7 +1911,7 @@ sys_rmdir :: proc "contextless" (path: cstring) -> int { } } -sys_mkdir :: proc "contextless" (path: cstring, mode: int) -> int { +sys_mkdir :: proc "contextless" (path: cstring, mode: uint) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_mkdir, uintptr(rawptr(path)), uintptr(mode))) } else { // NOTE: arm64 does not have mkdir @@ -1767,11 +1919,11 @@ sys_mkdir :: proc "contextless" (path: cstring, mode: int) -> int { } } -sys_mkdirat :: proc "contextless" (dfd: int, path: cstring, mode: int) -> int { +sys_mkdirat :: proc "contextless" (dfd: int, path: cstring, mode: uint) -> int { return int(intrinsics.syscall(SYS_mkdirat, uintptr(dfd), uintptr(rawptr(path)), uintptr(mode))) } -sys_mknod :: proc "contextless" (path: cstring, mode: int, dev: int) -> int { +sys_mknod :: proc "contextless" (path: cstring, mode: uint, dev: int) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_mknod, uintptr(rawptr(path)), uintptr(mode), uintptr(dev))) } else { // NOTE: arm64 does not have mknod @@ -1779,7 +1931,7 @@ sys_mknod :: proc "contextless" (path: cstring, mode: int, dev: int) -> int { } } -sys_mknodat :: proc "contextless" (dfd: int, path: cstring, mode: int, dev: int) -> int { +sys_mknodat :: proc "contextless" (dfd: int, path: cstring, mode: uint, dev: int) -> int { return int(intrinsics.syscall(SYS_mknodat, uintptr(dfd), uintptr(rawptr(path)), uintptr(mode), uintptr(dev))) } @@ -1818,6 +1970,16 @@ sys_fork :: proc "contextless" () -> int { return int(intrinsics.syscall(SYS_clone, SIGCHLD)) } } +sys_pipe2 :: proc "contextless" (fds: rawptr, flags: int) -> int { + return int(intrinsics.syscall(SYS_pipe2, uintptr(fds), uintptr(flags))) +} +sys_dup2 :: proc "contextless" (oldfd: int, newfd: int) -> int { + when ODIN_ARCH != .arm64 { + return int(intrinsics.syscall(SYS_dup2, uintptr(oldfd), uintptr(newfd))) + } else { + return int(intrinsics.syscall(SYS_dup3, uintptr(oldfd), uintptr(newfd), 0)) + } +} sys_mmap :: proc "contextless" (addr: rawptr, length: uint, prot, flags, fd: int, offset: uintptr) -> int { return int(intrinsics.syscall(SYS_mmap, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), offset)) @@ -1846,6 +2008,14 @@ sys_utimensat :: proc "contextless" (dfd: int, path: cstring, times: rawptr, fla return int(intrinsics.syscall(SYS_utimensat, uintptr(dfd), uintptr(rawptr(path)), uintptr(times), uintptr(flags))) } +sys_perf_event_open :: proc "contextless" (event_attr: rawptr, pid: i32, cpu: i32, group_fd: i32, flags: u32) -> int { + return int(intrinsics.syscall(SYS_perf_event_open, uintptr(event_attr), uintptr(pid), uintptr(cpu), uintptr(group_fd), uintptr(flags))) +} + +sys_personality :: proc(persona: u64) -> int { + return int(intrinsics.syscall(SYS_personality, uintptr(persona))) +} + get_errno :: proc "contextless" (res: int) -> i32 { if res < 0 && res > -4096 { return i32(-res) diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin index 6def41c5d..f736696e1 100644 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -315,6 +315,13 @@ foreign kernel32 { lpOverlapped: LPOVERLAPPED, lpCompletionRoutine: LPOVERLAPPED_COMPLETION_ROUTINE, ) -> BOOL --- + FindFirstChangeNotificationW :: proc( + lpPathName: LPWSTR, + bWatchSubtree: BOOL, + dwNotifyFilter: DWORD, + ) -> HANDLE --- + FindNextChangeNotification :: proc(hChangeHandle: HANDLE) -> BOOL --- + FindCloseChangeNotification :: proc(hChangeHandle: HANDLE) -> BOOL --- InitializeSRWLock :: proc(SRWLock: ^SRWLOCK) --- AcquireSRWLockExclusive :: proc(SRWLock: ^SRWLOCK) --- diff --git a/core/time/perf.odin b/core/time/perf.odin index 53406646f..e51b17441 100644 --- a/core/time/perf.odin +++ b/core/time/perf.odin @@ -1,11 +1,11 @@ package time import "core:runtime" +import "core:intrinsics" Tick :: struct { _nsec: i64, // relative amount } - tick_now :: proc "contextless" () -> Tick { return _tick_now() } @@ -40,6 +40,53 @@ _tick_duration_end :: proc "contextless" (d: ^Duration, t: Tick) { d^ = tick_since(t) } +when ODIN_ARCH == .amd64 { + @(private) + x86_has_invariant_tsc :: proc "contextless" () -> bool { + eax, _, _, _ := intrinsics.x86_cpuid(0x80_000_000, 0) + + // Is this processor *really* ancient? + if eax < 0x80_000_007 { + return false + } + + // check if the invariant TSC bit is set + _, _, _, edx := intrinsics.x86_cpuid(0x80_000_007, 0) + return (edx & (1 << 8)) != 0 + } +} + +has_invariant_tsc :: proc "contextless" () -> bool { + when ODIN_ARCH == .amd64 { + return x86_has_invariant_tsc() + } + + return false +} + +tsc_frequency :: proc "contextless" () -> (u64, bool) { + if !has_invariant_tsc() { + return 0, false + } + + hz, ok := _get_tsc_frequency() + if !ok { + // fallback to approximate TSC + tsc_begin := intrinsics.read_cycle_counter() + tick_begin := tick_now() + + sleep(2 * Second) + + tsc_end := intrinsics.read_cycle_counter() + tick_end := tick_now() + + time_diff := u128(duration_nanoseconds(tick_diff(tick_begin, tick_end))) + hz = u64((u128(tsc_end - tsc_begin) * 1_000_000_000) / time_diff) + } + + return hz, true +} + /* Benchmark helpers */ @@ -94,4 +141,4 @@ benchmark :: proc(options: ^Benchmark_Options, allocator := context.allocator) - options->teardown(allocator) or_return } return -}
\ No newline at end of file +} diff --git a/core/time/tsc_darwin.odin b/core/time/tsc_darwin.odin new file mode 100644 index 000000000..9e54ee8f7 --- /dev/null +++ b/core/time/tsc_darwin.odin @@ -0,0 +1,21 @@ +//+private +//+build darwin +package time + +import "core:c" + +foreign import libc "System.framework" +foreign libc { + @(link_name="sysctlbyname") _sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> c.int --- +} + +_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { + tmp_freq : u64 = 0 + tmp_size : i64 = size_of(tmp_freq) + ret := _sysctlbyname("machdep.tsc.frequency", &tmp_freq, &tmp_size, nil, 0) + if ret < 0 { + return 0, false + } + + return tmp_freq, true +} diff --git a/core/time/tsc_freebsd.odin b/core/time/tsc_freebsd.odin new file mode 100644 index 000000000..f4d6ccc3a --- /dev/null +++ b/core/time/tsc_freebsd.odin @@ -0,0 +1,21 @@ +//+private +//+build freebsd +package time + +import "core:c" + +foreign import libc "system:c" +foreign libc { + @(link_name="sysctlbyname") _sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> c.int --- +} + +_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { + tmp_freq : u64 = 0 + tmp_size : i64 = size_of(tmp_freq) + ret := _sysctlbyname("machdep.tsc_freq", &tmp_freq, &tmp_size, nil, 0) + if ret < 0 { + return 0, false + } + + return tmp_freq, true +} diff --git a/core/time/tsc_linux.odin b/core/time/tsc_linux.odin new file mode 100644 index 000000000..c5f2902e9 --- /dev/null +++ b/core/time/tsc_linux.odin @@ -0,0 +1,35 @@ +//+private +//+build linux +package time + +import "core:intrinsics" +import "core:sys/unix" + +_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { + perf_attr := unix.Perf_Event_Attr{} + perf_attr.type = u32(unix.Perf_Type_Id.Hardware) + perf_attr.config = u64(unix.Perf_Hardware_Id.Instructions) + perf_attr.size = size_of(perf_attr) + perf_attr.flags = {.Disabled, .Exclude_Kernel, .Exclude_HV} + fd := unix.sys_perf_event_open(&perf_attr, 0, -1, -1, 0) + if fd == -1 { + return 0, false + } + defer unix.sys_close(fd) + + page_size : uint = 4096 + ret := unix.sys_mmap(nil, page_size, unix.PROT_READ, unix.MAP_SHARED, fd, 0) + if ret < 0 && ret > -4096 { + return 0, false + } + addr := rawptr(uintptr(ret)) + defer unix.sys_munmap(addr, page_size) + + event_page := (^unix.Perf_Event_mmap_Page)(addr) + if .User_Time not_in event_page.cap.flags { + return 0, false + } + + frequency := u64((u128(1_000_000_000) << u128(event_page.time_shift)) / u128(event_page.time_mult)) + return frequency, true +} diff --git a/core/time/tsc_openbsd.odin b/core/time/tsc_openbsd.odin new file mode 100644 index 000000000..ab126d5c1 --- /dev/null +++ b/core/time/tsc_openbsd.odin @@ -0,0 +1,7 @@ +//+private +//+build openbsd +package time + +_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { + return 0, false +} diff --git a/core/time/tsc_windows.odin b/core/time/tsc_windows.odin new file mode 100644 index 000000000..7f7be6393 --- /dev/null +++ b/core/time/tsc_windows.odin @@ -0,0 +1,7 @@ +//+private +//+build windows +package time + +_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { + return 0, false +} |