diff options
| author | gingerBill <bill@gingerbill.org> | 2023-05-18 11:26:57 +0100 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2023-05-18 11:26:57 +0100 |
| commit | 49d1f6aca03672469d8fda0dedd27e330e698edc (patch) | |
| tree | f762ab6c9b9d5ae0d374eda0b31a3c164fc94455 /core | |
| parent | e82146bf17908dcc3619c8ec34bb0e902d7c213d (diff) | |
| parent | 49cd9648b05c6eda252122104cb9b1faa2502602 (diff) | |
Merge branch 'master' into separate-int-word-sizes
Diffstat (limited to 'core')
| -rw-r--r-- | core/bytes/buffer.odin | 5 | ||||
| -rw-r--r-- | core/encoding/hex/hex.odin | 73 | ||||
| -rw-r--r-- | core/net/url.odin | 54 | ||||
| -rw-r--r-- | core/os/file_windows.odin | 37 | ||||
| -rw-r--r-- | core/os/os.odin | 2 | ||||
| -rw-r--r-- | core/os/os2/env_linux.odin | 2 | ||||
| -rw-r--r-- | core/os/os2/file_linux.odin | 125 | ||||
| -rw-r--r-- | core/os/os2/heap_linux.odin | 2 | ||||
| -rw-r--r-- | core/os/os2/heap_windows.odin | 2 | ||||
| -rw-r--r-- | core/os/os2/path_linux.odin | 22 | ||||
| -rw-r--r-- | core/os/os2/stat_linux.odin | 17 | ||||
| -rw-r--r-- | core/os/os2/user.odin | 12 | ||||
| -rw-r--r-- | core/prof/spall/spall.odin | 17 | ||||
| -rw-r--r-- | core/runtime/core_builtin.odin | 2 | ||||
| -rw-r--r-- | core/runtime/os_specific_windows.odin | 2 | ||||
| -rw-r--r-- | core/sys/info/cpu_intel.odin | 11 | ||||
| -rw-r--r-- | core/time/perf.odin | 4 | ||||
| -rw-r--r-- | core/time/time.odin | 6 |
18 files changed, 209 insertions, 186 deletions
diff --git a/core/bytes/buffer.odin b/core/bytes/buffer.odin index bba834f7e..b60a8e877 100644 --- a/core/bytes/buffer.odin +++ b/core/bytes/buffer.odin @@ -38,6 +38,11 @@ buffer_init_string :: proc(b: ^Buffer, s: string) { } buffer_init_allocator :: proc(b: ^Buffer, len, cap: int, allocator := context.allocator) { + if b.buf == nil { + b.buf = make([dynamic]byte, len, cap, allocator) + return + } + b.buf.allocator = allocator reserve(&b.buf, cap) resize(&b.buf, len) diff --git a/core/encoding/hex/hex.odin b/core/encoding/hex/hex.odin new file mode 100644 index 000000000..ef0bab1d0 --- /dev/null +++ b/core/encoding/hex/hex.odin @@ -0,0 +1,73 @@ +package hex + +import "core:strings" + +encode :: proc(src: []byte, allocator := context.allocator) -> []byte #no_bounds_check { + dst := make([]byte, len(src) * 2, allocator) + for i, j := 0, 0; i < len(src); i += 1 { + v := src[i] + dst[j] = HEXTABLE[v>>4] + dst[j+1] = HEXTABLE[v&0x0f] + j += 2 + } + + return dst +} + + +decode :: proc(src: []byte, allocator := context.allocator) -> (dst: []byte, ok: bool) #no_bounds_check { + if len(src) % 2 == 1 { + return + } + + dst = make([]byte, len(src) / 2, allocator) + for i, j := 0, 1; j < len(src); j += 2 { + p := src[j-1] + q := src[j] + + a := hex_digit(p) or_return + b := hex_digit(q) or_return + + dst[i] = (a << 4) | b + i += 1 + } + + return dst, true +} + +// Decodes the given sequence into one byte. +// Should be called with one byte worth of the source, eg: 0x23 -> '#'. +decode_sequence :: proc(str: string) -> (res: byte, ok: bool) { + str := str + if strings.has_prefix(str, "0x") || strings.has_prefix(str, "0X") { + str = str[2:] + } + + if len(str) != 2 { + return 0, false + } + + upper := hex_digit(str[0]) or_return + lower := hex_digit(str[1]) or_return + + return upper << 4 | lower, true +} + +@(private) +HEXTABLE := [16]byte { + '0', '1', '2', '3', + '4', '5', '6', '7', + '8', '9', 'a', 'b', + 'c', 'd', 'e', 'f', +} + +@(private) +hex_digit :: proc(char: byte) -> (u8, bool) { + switch char { + case '0' ..= '9': return char - '0', true + case 'a' ..= 'f': return char - 'a' + 10, true + case 'A' ..= 'F': return char - 'A' + 10, true + case: return 0, false + } +} + diff --git a/core/net/url.odin b/core/net/url.odin index a5e529928..ed39f7859 100644 --- a/core/net/url.odin +++ b/core/net/url.odin @@ -19,7 +19,7 @@ package net import "core:strings" import "core:strconv" import "core:unicode/utf8" -import "core:mem" +import "core:encoding/hex" split_url :: proc(url: string, allocator := context.allocator) -> (scheme, host, path: string, queries: map[string]string) { s := url @@ -36,9 +36,11 @@ split_url :: proc(url: string, allocator := context.allocator) -> (scheme, host, s = s[:i] if query_str != "" { queries_parts := strings.split(query_str, "&") + defer delete(queries_parts) queries = make(map[string]string, len(queries_parts), allocator) for q in queries_parts { parts := strings.split(q, "=") + defer delete(parts) switch len(parts) { case 1: queries[parts[0]] = "" // NOTE(tetra): Query not set to anything, was but present. case 2: queries[parts[0]] = parts[1] // NOTE(tetra): Query set to something. @@ -76,13 +78,19 @@ join_url :: proc(scheme, host, path: string, queries: map[string]string, allocat } - if len(queries) > 0 do write_string(&b, "?") + query_length := len(queries) + if query_length > 0 do write_string(&b, "?") + i := 0 for query_name, query_value in queries { write_string(&b, query_name) if query_value != "" { write_string(&b, "=") write_string(&b, query_value) } + if i < query_length - 1 { + write_string(&b, "&") + } + i += 1 } return to_string(b) @@ -119,12 +127,10 @@ percent_decode :: proc(encoded_string: string, allocator := context.allocator) - builder_grow(&b, len(encoded_string)) defer if !ok do builder_destroy(&b) - stack_buf: [4]u8 - pending := mem.buffer_from_slice(stack_buf[:]) s := encoded_string for len(s) > 0 { - i := index_rune(s, '%') + i := index_byte(s, '%') if i == -1 { write_string(&b, s) // no '%'s; the string is already decoded break @@ -137,47 +143,15 @@ percent_decode :: proc(encoded_string: string, allocator := context.allocator) - s = s[1:] if s[0] == '%' { - write_rune(&b, '%') + write_byte(&b, '%') s = s[1:] continue } if len(s) < 2 do return // percent without encoded value - n: int - n, _ = strconv.parse_int(s[:2], 16) - switch n { - case 0x20: write_rune(&b, ' ') - case 0x21: write_rune(&b, '!') - case 0x23: write_rune(&b, '#') - case 0x24: write_rune(&b, '$') - case 0x25: write_rune(&b, '%') - case 0x26: write_rune(&b, '&') - case 0x27: write_rune(&b, '\'') - case 0x28: write_rune(&b, '(') - case 0x29: write_rune(&b, ')') - case 0x2A: write_rune(&b, '*') - case 0x2B: write_rune(&b, '+') - case 0x2C: write_rune(&b, ',') - case 0x2F: write_rune(&b, '/') - case 0x3A: write_rune(&b, ':') - case 0x3B: write_rune(&b, ';') - case 0x3D: write_rune(&b, '=') - case 0x3F: write_rune(&b, '?') - case 0x40: write_rune(&b, '@') - case 0x5B: write_rune(&b, '[') - case 0x5D: write_rune(&b, ']') - case: - // utf-8 bytes - // TODO(tetra): Audit this - 4 bytes??? - append(&pending, s[0]) - append(&pending, s[1]) - if len(pending) == 4 { - r, _ := utf8.decode_rune(pending[:]) - write_rune(&b, r) - clear(&pending) - } - } + val := hex.decode_sequence(s[:2]) or_return + write_byte(&b, val) s = s[2:] } diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin index a5f329d45..9d62014af 100644 --- a/core/os/file_windows.odin +++ b/core/os/file_windows.odin @@ -220,6 +220,7 @@ file_size :: proc(fd: Handle) -> (i64, Errno) { @(private) MAX_RW :: 1<<30 +ERROR_EOF :: 38 @(private) pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { @@ -228,11 +229,6 @@ pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { buf = buf[:MAX_RW] } - curr_offset, e := seek(fd, offset, 1) - if e != 0 { - return 0, e - } - defer seek(fd, curr_offset, 0) o := win32.OVERLAPPED{ OffsetHigh = u32(offset>>32), @@ -243,6 +239,7 @@ pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { h := win32.HANDLE(fd) done: win32.DWORD + e: Errno if !win32.ReadFile(h, raw_data(buf), u32(len(buf)), &done, &o) { e = Errno(win32.GetLastError()) done = 0 @@ -256,11 +253,6 @@ pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { buf = buf[:MAX_RW] } - curr_offset, e := seek(fd, offset, 1) - if e != 0 { - return 0, e - } - defer seek(fd, curr_offset, 0) o := win32.OVERLAPPED{ OffsetHigh = u32(offset>>32), @@ -269,6 +261,7 @@ pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { h := win32.HANDLE(fd) done: win32.DWORD + e: Errno if !win32.WriteFile(h, raw_data(buf), u32(len(buf)), &done, &o) { e = Errno(win32.GetLastError()) done = 0 @@ -276,6 +269,16 @@ pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { return int(done), e } +/* +read_at returns n: 0, err: 0 on EOF +on Windows, read_at changes the position of the file cursor, on *nix, it does not. + + bytes: [8]u8{} + read_at(fd, bytes, 0) + read(fd, bytes) + +will read from the location twice on *nix, and from two different locations on Windows +*/ read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) { if offset < 0 { return 0, ERROR_NEGATIVE_OFFSET @@ -284,6 +287,10 @@ read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) { b, offset := data, offset for len(b) > 0 { m, e := pread(fd, b, offset) + if e == ERROR_EOF { + err = 0 + break + } if e != 0 { err = e break @@ -294,6 +301,16 @@ read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) { } return } + +/* +on Windows, write_at changes the position of the file cursor, on *nix, it does not. + + bytes: [8]u8{} + write_at(fd, bytes, 0) + write(fd, bytes) + +will write to the location twice on *nix, and to two different locations on Windows +*/ write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) { if offset < 0 { return 0, ERROR_NEGATIVE_OFFSET diff --git a/core/os/os.odin b/core/os/os.odin index 971abd911..b71ea261e 100644 --- a/core/os/os.odin +++ b/core/os/os.odin @@ -194,7 +194,7 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, ptr := uintptr(aligned_mem) aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a) diff := int(aligned_ptr - ptr) - if (size + diff) > space { + if (size + diff) > space || allocated_mem == nil { return nil, .Out_Of_Memory } diff --git a/core/os/os2/env_linux.odin b/core/os/os2/env_linux.odin index 9a2c52739..e7165b583 100644 --- a/core/os/os2/env_linux.odin +++ b/core/os/os2/env_linux.odin @@ -3,7 +3,7 @@ package os2 import "core:runtime" -_get_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) { +_lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) { //TODO return } diff --git a/core/os/os2/file_linux.odin b/core/os/os2/file_linux.odin index 1a6f69d31..890bbfc43 100644 --- a/core/os/os2/file_linux.odin +++ b/core/os/os2/file_linux.odin @@ -9,19 +9,20 @@ import "core:sys/unix" INVALID_HANDLE :: -1 -_O_RDONLY :: 0o0 -_O_WRONLY :: 0o1 -_O_RDWR :: 0o2 -_O_CREAT :: 0o100 -_O_EXCL :: 0o200 -_O_TRUNC :: 0o1000 -_O_APPEND :: 0o2000 -_O_NONBLOCK :: 0o4000 -_O_LARGEFILE :: 0o100000 -_O_DIRECTORY :: 0o200000 -_O_NOFOLLOW :: 0o400000 -_O_SYNC :: 0o4010000 -_O_CLOEXEC :: 0o2000000 +_O_RDONLY :: 0o00000000 +_O_WRONLY :: 0o00000001 +_O_RDWR :: 0o00000002 +_O_CREAT :: 0o00000100 +_O_EXCL :: 0o00000200 +_O_NOCTTY :: 0o00000400 +_O_TRUNC :: 0o00001000 +_O_APPEND :: 0o00002000 +_O_NONBLOCK :: 0o00004000 +_O_LARGEFILE :: 0o00100000 +_O_DIRECTORY :: 0o00200000 +_O_NOFOLLOW :: 0o00400000 +_O_SYNC :: 0o04010000 +_O_CLOEXEC :: 0o02000000 _O_PATH :: 0o10000000 _AT_FDCWD :: -100 @@ -40,9 +41,12 @@ _file_allocator :: proc() -> runtime.Allocator { _open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (^File, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() - name_cstr := _name_to_cstring(name) + name_cstr := strings.clone_to_cstring(name, context.temp_allocator) - flags_i: int + // Just default to using O_NOCTTY because needing to open a controlling + // terminal would be incredibly rare. This has no effect on files while + // allowing us to open serial devices. + flags_i: int = _O_NOCTTY switch flags & O_RDONLY|O_WRONLY|O_RDWR { case O_RDONLY: flags_i = _O_RDONLY case O_WRONLY: flags_i = _O_WRONLY @@ -56,7 +60,7 @@ _open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (^File, Error flags_i |= (_O_TRUNC * int(.Trunc in flags)) flags_i |= (_O_CLOEXEC * int(.Close_On_Exec in flags)) - fd := unix.sys_open(name_cstr, flags_i, int(perm)) + fd := unix.sys_open(name_cstr, flags_i, uint(perm)) if fd < 0 { return nil, _get_platform_error(fd) } @@ -196,10 +200,7 @@ _truncate :: proc(f: ^File, size: i64) -> Error { } _remove :: proc(name: string) -> Error { - name_cstr, allocated := _name_to_cstring(name) - defer if allocated { - delete(name_cstr) - } + name_cstr := strings.clone_to_cstring(name, context.temp_allocator) fd := unix.sys_open(name_cstr, int(File_Flags.Read)) if fd < 0 { @@ -214,40 +215,22 @@ _remove :: proc(name: string) -> Error { } _rename :: proc(old_name, new_name: string) -> Error { - old_name_cstr, old_allocated := _name_to_cstring(old_name) - new_name_cstr, new_allocated := _name_to_cstring(new_name) - defer if old_allocated { - delete(old_name_cstr) - } - defer if new_allocated { - delete(new_name_cstr) - } + old_name_cstr := strings.clone_to_cstring(old_name, context.temp_allocator) + new_name_cstr := strings.clone_to_cstring(new_name, context.temp_allocator) return _ok_or_error(unix.sys_rename(old_name_cstr, new_name_cstr)) } _link :: proc(old_name, new_name: string) -> Error { - old_name_cstr, old_allocated := _name_to_cstring(old_name) - new_name_cstr, new_allocated := _name_to_cstring(new_name) - defer if old_allocated { - delete(old_name_cstr) - } - defer if new_allocated { - delete(new_name_cstr) - } + old_name_cstr := strings.clone_to_cstring(old_name, context.temp_allocator) + new_name_cstr := strings.clone_to_cstring(new_name, context.temp_allocator) return _ok_or_error(unix.sys_link(old_name_cstr, new_name_cstr)) } _symlink :: proc(old_name, new_name: string) -> Error { - old_name_cstr, old_allocated := _name_to_cstring(old_name) - new_name_cstr, new_allocated := _name_to_cstring(new_name) - defer if old_allocated { - delete(old_name_cstr) - } - defer if new_allocated { - delete(new_name_cstr) - } + old_name_cstr := strings.clone_to_cstring(old_name, context.temp_allocator) + new_name_cstr := strings.clone_to_cstring(new_name, context.temp_allocator) return _ok_or_error(unix.sys_symlink(old_name_cstr, new_name_cstr)) } @@ -271,26 +254,17 @@ _read_link_cstr :: proc(name_cstr: cstring, allocator: runtime.Allocator) -> (st } _read_link :: proc(name: string, allocator: runtime.Allocator) -> (string, Error) { - name_cstr, allocated := _name_to_cstring(name) - defer if allocated { - delete(name_cstr) - } + name_cstr := strings.clone_to_cstring(name, context.temp_allocator) return _read_link_cstr(name_cstr, allocator) } _unlink :: proc(name: string) -> Error { - name_cstr, allocated := _name_to_cstring(name) - defer if allocated { - delete(name_cstr) - } + name_cstr := strings.clone_to_cstring(name, context.temp_allocator) return _ok_or_error(unix.sys_unlink(name_cstr)) } _chdir :: proc(name: string) -> Error { - name_cstr, allocated := _name_to_cstring(name) - defer if allocated { - delete(name_cstr) - } + name_cstr := strings.clone_to_cstring(name, context.temp_allocator) return _ok_or_error(unix.sys_chdir(name_cstr)) } @@ -299,32 +273,23 @@ _fchdir :: proc(f: ^File) -> Error { } _chmod :: proc(name: string, mode: File_Mode) -> Error { - name_cstr, allocated := _name_to_cstring(name) - defer if allocated { - delete(name_cstr) - } - return _ok_or_error(unix.sys_chmod(name_cstr, int(mode))) + name_cstr := strings.clone_to_cstring(name, context.temp_allocator) + return _ok_or_error(unix.sys_chmod(name_cstr, uint(mode))) } _fchmod :: proc(f: ^File, mode: File_Mode) -> Error { - return _ok_or_error(unix.sys_fchmod(f.impl.fd, int(mode))) + return _ok_or_error(unix.sys_fchmod(f.impl.fd, uint(mode))) } // NOTE: will throw error without super user priviledges _chown :: proc(name: string, uid, gid: int) -> Error { - name_cstr, allocated := _name_to_cstring(name) - defer if allocated { - delete(name_cstr) - } + name_cstr := strings.clone_to_cstring(name, context.temp_allocator) return _ok_or_error(unix.sys_chown(name_cstr, uid, gid)) } // NOTE: will throw error without super user priviledges _lchown :: proc(name: string, uid, gid: int) -> Error { - name_cstr, allocated := _name_to_cstring(name) - defer if allocated { - delete(name_cstr) - } + name_cstr := strings.clone_to_cstring(name, context.temp_allocator) return _ok_or_error(unix.sys_lchown(name_cstr, uid, gid)) } @@ -334,10 +299,7 @@ _fchown :: proc(f: ^File, uid, gid: int) -> Error { } _chtimes :: proc(name: string, atime, mtime: time.Time) -> Error { - name_cstr, allocated := _name_to_cstring(name) - defer if allocated { - delete(name_cstr) - } + name_cstr := strings.clone_to_cstring(name, context.temp_allocator) times := [2]Unix_File_Time { { atime._nsec, 0 }, { mtime._nsec, 0 }, @@ -354,18 +316,12 @@ _fchtimes :: proc(f: ^File, atime, mtime: time.Time) -> Error { } _exists :: proc(name: string) -> bool { - name_cstr, allocated := _name_to_cstring(name) - defer if allocated { - delete(name_cstr) - } + name_cstr := strings.clone_to_cstring(name, context.temp_allocator) return unix.sys_access(name_cstr, F_OK) == 0 } _is_file :: proc(name: string) -> bool { - name_cstr, allocated := _name_to_cstring(name) - defer if allocated { - delete(name_cstr) - } + name_cstr := strings.clone_to_cstring(name, context.temp_allocator) s: _Stat res := unix.sys_stat(name_cstr, &s) if res < 0 { @@ -384,10 +340,7 @@ _is_file_fd :: proc(fd: int) -> bool { } _is_dir :: proc(name: string) -> bool { - name_cstr, allocated := _name_to_cstring(name) - defer if allocated { - delete(name_cstr) - } + name_cstr := strings.clone_to_cstring(name, context.temp_allocator) s: _Stat res := unix.sys_stat(name_cstr, &s) if res < 0 { diff --git a/core/os/os2/heap_linux.odin b/core/os/os2/heap_linux.odin index b631268a1..136c3e6cb 100644 --- a/core/os/os2/heap_linux.odin +++ b/core/os/os2/heap_linux.odin @@ -166,7 +166,7 @@ _heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, ptr := uintptr(aligned_mem) aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a) diff := int(aligned_ptr - ptr) - if (size + diff) > space { + if (size + diff) > space || allocated_mem == nil { return nil, .Out_Of_Memory } diff --git a/core/os/os2/heap_windows.odin b/core/os/os2/heap_windows.odin index 0f154cd8c..eba403c1d 100644 --- a/core/os/os2/heap_windows.odin +++ b/core/os/os2/heap_windows.odin @@ -52,7 +52,7 @@ _heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, ptr := uintptr(aligned_mem) aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a) diff := int(aligned_ptr - ptr) - if (size + diff) > space { + if (size + diff) > space || allocated_mem == nil { return nil, .Out_Of_Memory } diff --git a/core/os/os2/path_linux.odin b/core/os/os2/path_linux.odin index 3120fcda3..2a0ef29d8 100644 --- a/core/os/os2/path_linux.odin +++ b/core/os/os2/path_linux.odin @@ -31,11 +31,8 @@ _mkdir :: proc(path: string, perm: File_Mode) -> Error { return .Invalid_Argument } - path_cstr, allocated := _name_to_cstring(path) - defer if allocated { - delete(path_cstr) - } - return _ok_or_error(unix.sys_mkdir(path_cstr, int(perm & 0o777))) + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) + return _ok_or_error(unix.sys_mkdir(path_cstr, uint(perm & 0o777))) } _mkdir_all :: proc(path: string, perm: File_Mode) -> Error { @@ -49,7 +46,7 @@ _mkdir_all :: proc(path: string, perm: File_Mode) -> Error { new_dfd := unix.sys_openat(dfd, cstring(&path[0]), _OPENDIR_FLAGS) switch new_dfd { case -ENOENT: - if res := unix.sys_mkdirat(dfd, cstring(&path[0]), perm); res < 0 { + if res := unix.sys_mkdirat(dfd, cstring(&path[0]), uint(perm)); res < 0 { return _get_platform_error(res) } has_created^ = true @@ -83,9 +80,6 @@ _mkdir_all :: proc(path: string, perm: File_Mode) -> Error { } else { path_bytes = make([]u8, len(path) + 1, context.temp_allocator) } - defer if allocated { - delete(path_bytes) - } // NULL terminate the byte slice to make it a valid cstring copy(path_bytes, path) @@ -182,10 +176,7 @@ _remove_all :: proc(path: string) -> Error { return nil } - path_cstr, allocated := _name_to_cstring(path) - defer if allocated { - delete(path_cstr) - } + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) fd := unix.sys_open(path_cstr, _OPENDIR_FLAGS) switch fd { @@ -222,10 +213,7 @@ _getwd :: proc(allocator: runtime.Allocator) -> (string, Error) { } _setwd :: proc(dir: string) -> Error { - dir_cstr, allocated := _name_to_cstring(dir) - defer if allocated { - delete(dir_cstr) - } + dir_cstr := strings.clone_to_cstring(dir, context.temp_allocator) return _ok_or_error(unix.sys_chdir(dir_cstr)) } diff --git a/core/os/os2/stat_linux.odin b/core/os/os2/stat_linux.odin index 2f99f6d2e..530e0e7d0 100644 --- a/core/os/os2/stat_linux.odin +++ b/core/os/os2/stat_linux.odin @@ -3,6 +3,7 @@ package os2 import "core:time" import "core:runtime" +import "core:strings" import "core:sys/unix" import "core:path/filepath" @@ -112,10 +113,7 @@ _fstat_internal :: proc(fd: int, allocator: runtime.Allocator) -> (File_Info, Er // NOTE: _stat and _lstat are using _fstat to avoid a race condition when populating fullpath _stat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) { - name_cstr, allocated := _name_to_cstring(name) - defer if allocated { - delete(name_cstr) - } + name_cstr := strings.clone_to_cstring(name, context.temp_allocator) fd := unix.sys_open(name_cstr, _O_RDONLY) if fd < 0 { @@ -126,10 +124,8 @@ _stat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) } _lstat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) { - name_cstr, allocated := _name_to_cstring(name) - defer if allocated { - delete(name_cstr) - } + name_cstr := strings.clone_to_cstring(name, context.temp_allocator) + fd := unix.sys_open(name_cstr, _O_RDONLY | _O_PATH | _O_NOFOLLOW) if fd < 0 { return {}, _get_platform_error(fd) @@ -143,10 +139,7 @@ _same_file :: proc(fi1, fi2: File_Info) -> bool { } _stat_internal :: proc(name: string) -> (s: _Stat, res: int) { - name_cstr, allocated := _name_to_cstring(name) - defer if allocated { - delete(name_cstr) - } + name_cstr := strings.clone_to_cstring(name, context.temp_allocator) res = unix.sys_stat(name_cstr, &s) return } diff --git a/core/os/os2/user.odin b/core/os/os2/user.odin index 00cccd2a7..0e9f126aa 100644 --- a/core/os/os2/user.odin +++ b/core/os/os2/user.odin @@ -8,12 +8,12 @@ user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error case .Windows: dir = get_env("LocalAppData", allocator) if dir != "" { - dir = strings.clone_safe(dir, allocator) or_return + dir = strings.clone(dir, allocator) or_return } case .Darwin: dir = get_env("HOME", allocator) if dir != "" { - dir = strings.concatenate_safe({dir, "/Library/Caches"}, allocator) or_return + dir = strings.concatenate({dir, "/Library/Caches"}, allocator) or_return } case: // All other UNIX systems dir = get_env("XDG_CACHE_HOME", allocator) @@ -22,7 +22,7 @@ user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error if dir == "" { return } - dir = strings.concatenate_safe({dir, "/.cache"}, allocator) or_return + dir = strings.concatenate({dir, "/.cache"}, allocator) or_return } } if dir == "" { @@ -36,12 +36,12 @@ user_config_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Erro case .Windows: dir = get_env("AppData", allocator) if dir != "" { - dir = strings.clone_safe(dir, allocator) or_return + dir = strings.clone(dir, allocator) or_return } case .Darwin: dir = get_env("HOME", allocator) if dir != "" { - dir = strings.concatenate_safe({dir, "/Library/Application Support"}, allocator) or_return + dir = strings.concatenate({dir, "/Library/Application Support"}, allocator) or_return } case: // All other UNIX systems dir = get_env("XDG_CACHE_HOME", allocator) @@ -50,7 +50,7 @@ user_config_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Erro if dir == "" { return } - dir = strings.concatenate_safe({dir, "/.config"}, allocator) or_return + dir = strings.concatenate({dir, "/.config"}, allocator) or_return } } if dir == "" { diff --git a/core/prof/spall/spall.odin b/core/prof/spall/spall.odin index 6a78c466e..19a05d70a 100644 --- a/core/prof/spall/spall.odin +++ b/core/prof/spall/spall.odin @@ -67,16 +67,15 @@ Buffer :: struct { BUFFER_DEFAULT_SIZE :: 0x10_0000 -context_create :: proc(filename: string) -> (ctx: Context, ok: bool) #optional_ok { +context_create_with_scale :: proc(filename: string, precise_time: bool, timestamp_scale: f64) -> (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 + ctx.fd = fd + ctx.precise_time = precise_time + ctx.timestamp_scale = timestamp_scale temp := [size_of(Manual_Header)]u8{} _build_header(temp[:], ctx.timestamp_scale) @@ -85,6 +84,14 @@ context_create :: proc(filename: string) -> (ctx: Context, ok: bool) #optional_o return } +context_create_with_sleep :: proc(filename: string, sleep := 2 * time.Second) -> (ctx: Context, ok: bool) #optional_ok { + freq, freq_ok := time.tsc_frequency(sleep) + timestamp_scale: f64 = ((1 / f64(freq)) * 1_000_000) if freq_ok else 1 + return context_create_with_scale(filename, freq_ok, timestamp_scale) +} + +context_create :: proc{context_create_with_scale, context_create_with_sleep} + context_destroy :: proc(ctx: ^Context) { if ctx == nil { return diff --git a/core/runtime/core_builtin.odin b/core/runtime/core_builtin.odin index 4b152e7cc..bd919247e 100644 --- a/core/runtime/core_builtin.odin +++ b/core/runtime/core_builtin.odin @@ -401,7 +401,7 @@ append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> int { return 0 } prev_len := len(array) - resize(array, len(array)+1) + resize(array, len(array)+1, loc) return len(array)-prev_len } diff --git a/core/runtime/os_specific_windows.odin b/core/runtime/os_specific_windows.odin index 6e7474257..732715793 100644 --- a/core/runtime/os_specific_windows.odin +++ b/core/runtime/os_specific_windows.odin @@ -112,7 +112,7 @@ _windows_default_alloc_or_resize :: proc "contextless" (size, alignment: int, ol ptr := uintptr(aligned_mem) aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a) diff := int(aligned_ptr - ptr) - if (size + diff) > space { + if (size + diff) > space || allocated_mem == nil { return nil, .Out_Of_Memory } diff --git a/core/sys/info/cpu_intel.odin b/core/sys/info/cpu_intel.odin index 8cd723203..5a11863d4 100644 --- a/core/sys/info/cpu_intel.odin +++ b/core/sys/info/cpu_intel.odin @@ -38,7 +38,7 @@ cpu_name: Maybe(string) @(init, private) init_cpu_features :: proc "c" () { is_set :: #force_inline proc "c" (hwc: u32, value: u32) -> bool { - return hwc&value != 0 + return hwc&(1 << value) != 0 } try_set :: #force_inline proc "c" (set: ^CPU_Features, feature: CPU_Feature, hwc: u32, value: u32) { if is_set(hwc, value) { @@ -74,8 +74,15 @@ init_cpu_features :: proc "c" () { return } + // In certain rare cases (reason unknown), XGETBV generates an + // illegal instruction, even if OSXSAVE is set per CPUID. + // + // When Chrome ran into this problem, the problem went away + // after they started checking both OSXSAVE and XSAVE. + // + // See: crbug.com/375968 os_supports_avx := false - if .os_xsave in set { + if .os_xsave in set && is_set(26, ecx1) { eax, _ := xgetbv(0) os_supports_avx = is_set(1, eax) && is_set(2, eax) } diff --git a/core/time/perf.odin b/core/time/perf.odin index 69f7eceaa..87192093a 100644 --- a/core/time/perf.odin +++ b/core/time/perf.odin @@ -70,7 +70,7 @@ has_invariant_tsc :: proc "contextless" () -> bool { return false } -tsc_frequency :: proc "contextless" () -> (u64, bool) { +tsc_frequency :: proc "contextless" (fallback_sleep := 2 * Second) -> (u64, bool) { if !has_invariant_tsc() { return 0, false } @@ -81,7 +81,7 @@ tsc_frequency :: proc "contextless" () -> (u64, bool) { tsc_begin := intrinsics.read_cycle_counter() tick_begin := tick_now() - sleep(2 * Second) + sleep(fallback_sleep) tsc_end := intrinsics.read_cycle_counter() tick_end := tick_now() diff --git a/core/time/time.odin b/core/time/time.odin index 74c80c8f7..6c424a62e 100644 --- a/core/time/time.odin +++ b/core/time/time.odin @@ -170,6 +170,12 @@ day :: proc "contextless" (t: Time) -> (day: int) { return } +weekday :: proc "contextless" (t: Time) -> (weekday: Weekday) { + abs := _time_abs(t) + sec := (abs + u64(Weekday.Monday) * SECONDS_PER_DAY) % SECONDS_PER_WEEK + return Weekday(int(sec) / SECONDS_PER_DAY) +} + clock :: proc { clock_from_time, clock_from_duration, clock_from_stopwatch } clock_from_time :: proc "contextless" (t: Time) -> (hour, min, sec: int) { |