Merge branch 'master' into new-temp-allocator

This commit is contained in:
gingerBill
2023-02-28 12:15:54 +00:00
committed by GitHub
55 changed files with 2758 additions and 554 deletions
+1 -1
View File
@@ -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:
+2 -2
View File
@@ -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() ---
__entry_point :: proc() ---
+42 -34
View File
@@ -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)
bytes_total := len(data)
bytes_read_total := 0
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
if len(data) == 0 {
return 0, ERROR_NONE
}
return bytes_read_total, 0
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_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
}
write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
if len(data) == 0 {
return 0, ERROR_NONE
}
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) {
+70 -157
View File
@@ -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 int(bytes_written), ERROR_NONE
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 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)
}
+208
View File
@@ -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)
}
+2 -5
View File
@@ -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" () {
@@ -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)
}
+11 -10
View File
@@ -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
}
+20 -19
View File
@@ -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] = '-'
}
+1 -1
View File
@@ -236,4 +236,4 @@ _panic :: proc "contextless" (msg: string) -> ! {
runtime.print_string(msg)
runtime.print_byte('\n')
runtime.trap()
}
}
+1 -1
View File
@@ -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)
}
+48 -48
View File
@@ -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)
}
}
+181 -11
View File
@@ -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)
+7
View File
@@ -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) ---
+49 -2
View File
@@ -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
}
}
+21
View File
@@ -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
}
+21
View File
@@ -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
}
+35
View File
@@ -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
}
+7
View File
@@ -0,0 +1,7 @@
//+private
//+build openbsd
package time
_get_tsc_frequency :: proc "contextless" () -> (u64, bool) {
return 0, false
}
+7
View File
@@ -0,0 +1,7 @@
//+private
//+build windows
package time
_get_tsc_frequency :: proc "contextless" () -> (u64, bool) {
return 0, false
}