mirror of
https://github.com/odin-lang/Odin.git
synced 2026-03-02 14:48:20 +00:00
Merge pull request #2327 from odin-lang/new-temp-allocator
New default `context.temp_allocator`
This commit is contained in:
@@ -212,6 +212,8 @@ read_slice_from_memory :: #force_inline proc(z: ^Context_Memory_Input, size: int
|
||||
|
||||
@(optimization_mode="speed")
|
||||
read_slice_from_stream :: #force_inline proc(z: ^Context_Stream_Input, size: int) -> (res: []u8, err: io.Error) {
|
||||
// TODO: REMOVE ALL USE OF context.temp_allocator here
|
||||
// the is literally no need for it
|
||||
b := make([]u8, size, context.temp_allocator)
|
||||
_, e := z.input->impl_read(b[:])
|
||||
if e == .None {
|
||||
|
||||
@@ -4,10 +4,12 @@ package dynlib
|
||||
|
||||
import win32 "core:sys/windows"
|
||||
import "core:strings"
|
||||
import "core:runtime"
|
||||
|
||||
_load_library :: proc(path: string, global_symbols := false) -> (Library, bool) {
|
||||
// NOTE(bill): 'global_symbols' is here only for consistency with POSIX which has RTLD_GLOBAL
|
||||
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
wide_path := win32.utf8_to_wstring(path, context.temp_allocator)
|
||||
handle := cast(Library)win32.LoadLibraryW(wide_path)
|
||||
return handle, handle != nil
|
||||
@@ -19,6 +21,7 @@ _unload_library :: proc(library: Library) -> bool {
|
||||
}
|
||||
|
||||
_symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
c_str := strings.clone_to_cstring(symbol, context.temp_allocator)
|
||||
ptr = win32.GetProcAddress(cast(win32.HMODULE)library, c_str)
|
||||
found = ptr != nil
|
||||
|
||||
@@ -346,6 +346,8 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
|
||||
|
||||
fields := reflect.struct_fields_zipped(ti.id)
|
||||
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
|
||||
|
||||
field_used := make([]bool, len(fields), context.temp_allocator)
|
||||
|
||||
use_field_idx := -1
|
||||
|
||||
@@ -33,6 +33,7 @@ import "core:intrinsics"
|
||||
import "core:mem"
|
||||
import "core:os"
|
||||
import "core:strings"
|
||||
import "core:runtime"
|
||||
|
||||
likely :: intrinsics.expect
|
||||
|
||||
@@ -408,7 +409,7 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
|
||||
next := scan(t)
|
||||
#partial switch next.kind {
|
||||
case .Ident:
|
||||
if len(next.text) == 3 && strings.to_lower(next.text, context.temp_allocator) == "xml" {
|
||||
if len(next.text) == 3 && strings.equal_fold(next.text, "xml") {
|
||||
parse_prologue(doc) or_return
|
||||
} else if len(doc.prologue) > 0 {
|
||||
/*
|
||||
@@ -614,6 +615,7 @@ parse_prologue :: proc(doc: ^Document) -> (err: Error) {
|
||||
}
|
||||
|
||||
case "encoding":
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
switch strings.to_lower(attr.val, context.temp_allocator) {
|
||||
case "utf-8", "utf8":
|
||||
doc.encoding = .UTF_8
|
||||
|
||||
@@ -8,6 +8,7 @@ import "core:os"
|
||||
import "core:strconv"
|
||||
import "core:strings"
|
||||
import "core:unicode"
|
||||
import "core:runtime"
|
||||
|
||||
Image :: image.Image
|
||||
Format :: image.Netpbm_Format
|
||||
@@ -407,6 +408,8 @@ _parse_header_pam :: proc(data: []byte, allocator := context.allocator) -> (head
|
||||
}
|
||||
length = header_end_index + len(HEADER_END)
|
||||
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
|
||||
|
||||
// string buffer for the tupltype
|
||||
tupltype: strings.Builder
|
||||
strings.builder_init(&tupltype, context.temp_allocator); defer strings.builder_destroy(&tupltype)
|
||||
|
||||
@@ -16,6 +16,7 @@ import coretime "core:time"
|
||||
import "core:strings"
|
||||
import "core:bytes"
|
||||
import "core:mem"
|
||||
import "core:runtime"
|
||||
|
||||
/*
|
||||
Cleanup of image-specific data.
|
||||
@@ -91,6 +92,8 @@ core_time :: proc(c: image.PNG_Chunk) -> (t: coretime.Time, ok: bool) {
|
||||
}
|
||||
|
||||
text :: proc(c: image.PNG_Chunk) -> (res: Text, ok: bool) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
|
||||
|
||||
assert(len(c.data) == int(c.header.length))
|
||||
#partial switch c.header.type {
|
||||
case .tEXt:
|
||||
@@ -194,18 +197,18 @@ text_destroy :: proc(text: Text) {
|
||||
}
|
||||
|
||||
iccp :: proc(c: image.PNG_Chunk) -> (res: iCCP, ok: bool) {
|
||||
ok = true
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
|
||||
|
||||
fields := bytes.split_n(s=c.data, sep=[]u8{0}, n=3, allocator=context.temp_allocator)
|
||||
|
||||
if len(fields[0]) < 1 || len(fields[0]) > 79 {
|
||||
// Invalid profile name
|
||||
ok = false; return
|
||||
return
|
||||
}
|
||||
|
||||
if len(fields[1]) != 0 {
|
||||
// Compression method should be a zero, which the split turned into an empty slice.
|
||||
ok = false; return
|
||||
return
|
||||
}
|
||||
|
||||
// Set up ZLIB context and decompress iCCP payload
|
||||
@@ -213,12 +216,12 @@ iccp :: proc(c: image.PNG_Chunk) -> (res: iCCP, ok: bool) {
|
||||
zlib_error := zlib.inflate_from_byte_array(fields[2], &buf)
|
||||
if zlib_error != nil {
|
||||
bytes.buffer_destroy(&buf)
|
||||
ok = false; return
|
||||
return
|
||||
}
|
||||
|
||||
res.name = strings.clone(string(fields[0]))
|
||||
res.profile = bytes.buffer_to_bytes(&buf)
|
||||
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
|
||||
@@ -256,18 +259,18 @@ plte :: proc(c: image.PNG_Chunk) -> (res: PLTE, ok: bool) {
|
||||
|
||||
splt :: proc(c: image.PNG_Chunk) -> (res: sPLT, ok: bool) {
|
||||
if c.header.type != .sPLT {
|
||||
return {}, false
|
||||
return
|
||||
}
|
||||
ok = true
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
|
||||
|
||||
fields := bytes.split_n(s=c.data, sep=[]u8{0}, n=2, allocator=context.temp_allocator)
|
||||
if len(fields) != 2 {
|
||||
return {}, false
|
||||
return
|
||||
}
|
||||
|
||||
res.depth = fields[1][0]
|
||||
if res.depth != 8 && res.depth != 16 {
|
||||
return {}, false
|
||||
return
|
||||
}
|
||||
|
||||
data := fields[1][1:]
|
||||
@@ -275,21 +278,21 @@ splt :: proc(c: image.PNG_Chunk) -> (res: sPLT, ok: bool) {
|
||||
|
||||
if res.depth == 8 {
|
||||
if len(data) % 6 != 0 {
|
||||
return {}, false
|
||||
return
|
||||
}
|
||||
count = len(data) / 6
|
||||
if count > 256 {
|
||||
return {}, false
|
||||
return
|
||||
}
|
||||
|
||||
res.entries = mem.slice_data_cast([][4]u8, data)
|
||||
} else { // res.depth == 16
|
||||
if len(data) % 10 != 0 {
|
||||
return {}, false
|
||||
return
|
||||
}
|
||||
count = len(data) / 10
|
||||
if count > 256 {
|
||||
return {}, false
|
||||
return
|
||||
}
|
||||
|
||||
res.entries = mem.slice_data_cast([][4]u16, data)
|
||||
@@ -297,7 +300,7 @@ splt :: proc(c: image.PNG_Chunk) -> (res: sPLT, ok: bool) {
|
||||
|
||||
res.name = strings.clone(string(fields[0]))
|
||||
res.used = u16(count)
|
||||
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import "core:bytes"
|
||||
import "core:io"
|
||||
import "core:mem"
|
||||
import "core:intrinsics"
|
||||
import "core:runtime"
|
||||
|
||||
// Limit chunk sizes.
|
||||
// By default: IDAT = 8k x 8k x 16-bits + 8k filter bytes.
|
||||
@@ -1247,6 +1248,8 @@ defilter_8 :: proc(params: ^Filter_Params) -> (ok: bool) {
|
||||
|
||||
// TODO: See about doing a Duff's #unroll where practicable
|
||||
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
|
||||
// Apron so we don't need to special case first rows.
|
||||
up := make([]u8, row_stride, context.temp_allocator)
|
||||
ok = true
|
||||
@@ -1299,10 +1302,9 @@ defilter_8 :: proc(params: ^Filter_Params) -> (ok: bool) {
|
||||
}
|
||||
|
||||
// @(optimization_mode="speed")
|
||||
defilter_less_than_8 :: proc(params: ^Filter_Params) -> (ok: bool) #no_bounds_check {
|
||||
defilter_less_than_8 :: proc(params: ^Filter_Params) -> bool #no_bounds_check {
|
||||
|
||||
using params
|
||||
ok = true
|
||||
|
||||
row_stride_in := ((channels * width * depth) + 7) >> 3
|
||||
row_stride_out := channels * width
|
||||
@@ -1314,6 +1316,8 @@ defilter_less_than_8 :: proc(params: ^Filter_Params) -> (ok: bool) #no_bounds_ch
|
||||
|
||||
// TODO: See about doing a Duff's #unroll where practicable
|
||||
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
|
||||
// Apron so we don't need to special case first rows.
|
||||
up := make([]u8, row_stride_out, context.temp_allocator)
|
||||
|
||||
@@ -1457,18 +1461,18 @@ defilter_less_than_8 :: proc(params: ^Filter_Params) -> (ok: bool) #no_bounds_ch
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
return true
|
||||
}
|
||||
|
||||
// @(optimization_mode="speed")
|
||||
defilter_16 :: proc(params: ^Filter_Params) -> (ok: bool) {
|
||||
|
||||
defilter_16 :: proc(params: ^Filter_Params) -> bool {
|
||||
using params
|
||||
ok = true
|
||||
|
||||
stride := channels * 2
|
||||
row_stride := width * stride
|
||||
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
|
||||
// TODO: See about doing a Duff's #unroll where practicable
|
||||
// Apron so we don't need to special case first rows.
|
||||
up := make([]u8, row_stride, context.temp_allocator)
|
||||
@@ -1518,7 +1522,7 @@ defilter_16 :: proc(params: ^Filter_Params) -> (ok: bool) {
|
||||
dest = dest[row_stride:]
|
||||
}
|
||||
|
||||
return
|
||||
return true
|
||||
}
|
||||
|
||||
defilter :: proc(img: ^Image, filter_bytes: ^bytes.Buffer, header: ^image.PNG_IHDR, options: Options) -> (err: Error) {
|
||||
|
||||
@@ -148,12 +148,12 @@ arena_growing_free_last_memory_block :: proc(arena: ^Arena, loc := #caller_locat
|
||||
}
|
||||
}
|
||||
|
||||
arena_free_all :: proc(arena: ^Arena) {
|
||||
arena_free_all :: proc(arena: ^Arena, loc := #caller_location) {
|
||||
switch arena.kind {
|
||||
case .Growing:
|
||||
sync.mutex_guard(&arena.mutex)
|
||||
for arena.curr_block != nil {
|
||||
arena_growing_free_last_memory_block(arena)
|
||||
arena_growing_free_last_memory_block(arena, loc)
|
||||
}
|
||||
arena.total_reserved = 0
|
||||
case .Static, .Buffer:
|
||||
@@ -240,17 +240,17 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
||||
|
||||
switch mode {
|
||||
case .Alloc, .Alloc_Non_Zeroed:
|
||||
return arena_alloc(arena, size, alignment)
|
||||
return arena_alloc(arena, size, alignment, location)
|
||||
case .Free:
|
||||
err = .Mode_Not_Implemented
|
||||
case .Free_All:
|
||||
arena_free_all(arena)
|
||||
arena_free_all(arena, location)
|
||||
case .Resize:
|
||||
old_data := ([^]byte)(old_memory)
|
||||
|
||||
switch {
|
||||
case old_data == nil:
|
||||
return arena_alloc(arena, size, alignment)
|
||||
return arena_alloc(arena, size, alignment, location)
|
||||
case size == old_size:
|
||||
// return old memory
|
||||
data = old_data[:size]
|
||||
@@ -264,7 +264,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
||||
return
|
||||
}
|
||||
|
||||
new_memory := arena_alloc(arena, size, alignment) or_return
|
||||
new_memory := arena_alloc(arena, size, alignment, location) or_return
|
||||
if new_memory == nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F
|
||||
continue
|
||||
}
|
||||
|
||||
fullpath := make([]byte, len(dirpath)+1+len(filename))
|
||||
fullpath := make([]byte, len(dirpath)+1+len(filename), context.temp_allocator)
|
||||
copy(fullpath, dirpath)
|
||||
copy(fullpath[len(dirpath):], "/")
|
||||
copy(fullpath[len(dirpath)+1:], filename)
|
||||
|
||||
@@ -2,6 +2,7 @@ package os
|
||||
|
||||
import "core:strings"
|
||||
import "core:mem"
|
||||
import "core:runtime"
|
||||
|
||||
read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) {
|
||||
dirp: Dir
|
||||
@@ -51,6 +52,7 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F
|
||||
continue
|
||||
}
|
||||
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
|
||||
fullpath := strings.join( []string{ dirpath, filename }, "/", context.temp_allocator)
|
||||
defer delete(fullpath, context.temp_allocator)
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package os
|
||||
|
||||
import win32 "core:sys/windows"
|
||||
import "core:strings"
|
||||
import "core:runtime"
|
||||
|
||||
read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) {
|
||||
find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW) -> (fi: File_Info) {
|
||||
@@ -65,13 +66,16 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F
|
||||
n = -1
|
||||
size = 100
|
||||
}
|
||||
dfi := make([dynamic]File_Info, 0, size)
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
|
||||
|
||||
wpath: []u16
|
||||
wpath, err = cleanpath_from_handle_u16(fd)
|
||||
wpath, err = cleanpath_from_handle_u16(fd, context.temp_allocator)
|
||||
if len(wpath) == 0 || err != ERROR_NONE {
|
||||
return
|
||||
}
|
||||
|
||||
dfi := make([dynamic]File_Info, 0, size)
|
||||
|
||||
wpath_search := make([]u16, len(wpath)+3, context.temp_allocator)
|
||||
copy(wpath_search, wpath)
|
||||
wpath_search[len(wpath)+0] = '\\'
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package os
|
||||
|
||||
import win32 "core:sys/windows"
|
||||
import "core:runtime"
|
||||
|
||||
// lookup_env gets the value of the environment variable named by the key
|
||||
// If the variable is found in the environment the value (which can be empty) is returned and the boolean is true
|
||||
@@ -18,6 +19,8 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
|
||||
|
||||
b := make([dynamic]u16, n, context.temp_allocator)
|
||||
n = win32.GetEnvironmentVariableW(wkey, raw_data(b), u32(len(b)))
|
||||
if n == 0 {
|
||||
@@ -87,6 +90,7 @@ environ :: proc(allocator := context.allocator) -> []string {
|
||||
|
||||
// clear_env deletes all environment variables
|
||||
clear_env :: proc() {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
envs := environ(context.temp_allocator)
|
||||
for env in envs {
|
||||
for j in 1..<len(env) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package os
|
||||
|
||||
import win32 "core:sys/windows"
|
||||
import "core:intrinsics"
|
||||
import "core:runtime"
|
||||
import "core:unicode/utf16"
|
||||
|
||||
is_path_separator :: proc(c: byte) -> bool {
|
||||
@@ -327,6 +328,7 @@ get_std_handle :: proc "contextless" (h: uint) -> Handle {
|
||||
|
||||
|
||||
exists :: proc(path: string) -> bool {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
wpath := win32.utf8_to_wstring(path, context.temp_allocator)
|
||||
attribs := win32.GetFileAttributesW(wpath)
|
||||
|
||||
@@ -334,6 +336,7 @@ exists :: proc(path: string) -> bool {
|
||||
}
|
||||
|
||||
is_file :: proc(path: string) -> bool {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
wpath := win32.utf8_to_wstring(path, context.temp_allocator)
|
||||
attribs := win32.GetFileAttributesW(wpath)
|
||||
|
||||
@@ -344,6 +347,7 @@ is_file :: proc(path: string) -> bool {
|
||||
}
|
||||
|
||||
is_dir :: proc(path: string) -> bool {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
wpath := win32.utf8_to_wstring(path, context.temp_allocator)
|
||||
attribs := win32.GetFileAttributesW(wpath)
|
||||
|
||||
@@ -359,6 +363,8 @@ is_dir :: proc(path: string) -> bool {
|
||||
get_current_directory :: proc(allocator := context.allocator) -> string {
|
||||
win32.AcquireSRWLockExclusive(&cwd_lock)
|
||||
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
|
||||
|
||||
sz_utf16 := win32.GetCurrentDirectoryW(0, nil)
|
||||
dir_buf_wstr := make([]u16, sz_utf16, context.temp_allocator) // the first time, it _includes_ the NUL.
|
||||
|
||||
@@ -387,6 +393,7 @@ set_current_directory :: proc(path: string) -> (err: Errno) {
|
||||
|
||||
|
||||
change_directory :: proc(path: string) -> (err: Errno) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
wpath := win32.utf8_to_wstring(path, context.temp_allocator)
|
||||
|
||||
if !win32.SetCurrentDirectoryW(wpath) {
|
||||
@@ -396,6 +403,7 @@ change_directory :: proc(path: string) -> (err: Errno) {
|
||||
}
|
||||
|
||||
make_directory :: proc(path: string, mode: u32 = 0) -> (err: Errno) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
// Mode is unused on Windows, but is needed on *nix
|
||||
wpath := win32.utf8_to_wstring(path, context.temp_allocator)
|
||||
|
||||
@@ -407,6 +415,7 @@ make_directory :: proc(path: string, mode: u32 = 0) -> (err: Errno) {
|
||||
|
||||
|
||||
remove_directory :: proc(path: string) -> (err: Errno) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
wpath := win32.utf8_to_wstring(path, context.temp_allocator)
|
||||
|
||||
if !win32.RemoveDirectoryW(wpath) {
|
||||
@@ -479,12 +488,14 @@ fix_long_path :: proc(path: string) -> string {
|
||||
|
||||
|
||||
link :: proc(old_name, new_name: string) -> (err: Errno) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
n := win32.utf8_to_wstring(fix_long_path(new_name))
|
||||
o := win32.utf8_to_wstring(fix_long_path(old_name))
|
||||
return Errno(win32.CreateHardLinkW(n, o, nil))
|
||||
}
|
||||
|
||||
unlink :: proc(path: string) -> (err: Errno) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
wpath := win32.utf8_to_wstring(path, context.temp_allocator)
|
||||
|
||||
if !win32.DeleteFileW(wpath) {
|
||||
@@ -496,6 +507,7 @@ unlink :: proc(path: string) -> (err: Errno) {
|
||||
|
||||
|
||||
rename :: proc(old_path, new_path: string) -> (err: Errno) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
from := win32.utf8_to_wstring(old_path, context.temp_allocator)
|
||||
to := win32.utf8_to_wstring(new_path, context.temp_allocator)
|
||||
|
||||
|
||||
@@ -39,10 +39,8 @@ _file_allocator :: proc() -> runtime.Allocator {
|
||||
}
|
||||
|
||||
_open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (^File, Error) {
|
||||
name_cstr, allocated := _name_to_cstring(name)
|
||||
defer if allocated {
|
||||
delete(name_cstr)
|
||||
}
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
name_cstr := _name_to_cstring(name)
|
||||
|
||||
flags_i: int
|
||||
switch flags & O_RDONLY|O_WRONLY|O_RDWR {
|
||||
@@ -411,12 +409,7 @@ _is_dir_fd :: proc(fd: int) -> bool {
|
||||
// defined as 512, however, it is well known that paths can exceed that limit.
|
||||
// So, in theory you could have a path larger than the entire temp_allocator's
|
||||
// buffer. Therefor, any large paths will use context.allocator.
|
||||
_name_to_cstring :: proc(name: string) -> (cname: cstring, allocated: bool) {
|
||||
if len(name) > _CSTRING_NAME_HEAP_THRESHOLD {
|
||||
cname = strings.clone_to_cstring(name)
|
||||
allocated = true
|
||||
return
|
||||
}
|
||||
cname = strings.clone_to_cstring(name, context.temp_allocator)
|
||||
return
|
||||
@(private="file")
|
||||
_temp_name_to_cstring :: proc(name: string) -> (cname: cstring) {
|
||||
return strings.clone_to_cstring(name, context.temp_allocator)
|
||||
}
|
||||
|
||||
@@ -355,6 +355,7 @@ open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (Handle, Errno
|
||||
flags = O_RDONLY
|
||||
}
|
||||
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
handle := _unix_open(cstr, i32(flags), u16(mode))
|
||||
if handle == -1 {
|
||||
@@ -516,24 +517,28 @@ is_file :: proc {is_file_path, is_file_handle}
|
||||
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)
|
||||
return res == 0
|
||||
}
|
||||
|
||||
rename :: proc(old: string, new: string) -> bool {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
old_cstr := strings.clone_to_cstring(old, context.temp_allocator)
|
||||
new_cstr := strings.clone_to_cstring(new, context.temp_allocator)
|
||||
return _unix_rename(old_cstr, new_cstr) != -1
|
||||
}
|
||||
|
||||
remove :: proc(path: string) -> bool {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
return _unix_remove(path_cstr) != -1
|
||||
}
|
||||
|
||||
@private
|
||||
_stat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
|
||||
s: OS_Stat
|
||||
@@ -546,6 +551,7 @@ _stat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||
|
||||
@private
|
||||
_lstat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
|
||||
s: OS_Stat
|
||||
@@ -611,6 +617,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool)
|
||||
|
||||
@private
|
||||
_readlink :: proc(path: string) -> (string, Errno) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
|
||||
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
|
||||
bufsz : uint = 256
|
||||
@@ -648,6 +655,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) {
|
||||
rel = "."
|
||||
}
|
||||
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
|
||||
rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator)
|
||||
|
||||
path_ptr := _unix_realpath(rel_cstr, nil)
|
||||
@@ -663,6 +671,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) {
|
||||
}
|
||||
|
||||
access :: proc(path: string, mask: int) -> bool {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
return _unix_access(cstr, mask) == 0
|
||||
}
|
||||
@@ -687,6 +696,7 @@ heap_free :: proc(ptr: rawptr) {
|
||||
}
|
||||
|
||||
lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
|
||||
path_str := strings.clone_to_cstring(key, context.temp_allocator)
|
||||
cstr := _unix_getenv(path_str)
|
||||
if cstr == nil {
|
||||
@@ -718,6 +728,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)
|
||||
if res == -1 {
|
||||
@@ -727,6 +738,7 @@ set_current_directory :: proc(path: string) -> (err: Errno) {
|
||||
}
|
||||
|
||||
make_directory :: proc(path: string, mode: u16 = 0o775) -> Errno {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
res := _unix_mkdir(path_cstr, mode)
|
||||
if res == -1 {
|
||||
@@ -751,12 +763,14 @@ current_thread_id :: proc "contextless" () -> int {
|
||||
}
|
||||
|
||||
dlopen :: proc(filename: string, flags: int) -> rawptr {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
cstr := strings.clone_to_cstring(filename, context.temp_allocator)
|
||||
handle := _unix_dlopen(cstr, flags)
|
||||
return handle
|
||||
}
|
||||
dlsym :: proc(handle: rawptr, symbol: string) -> rawptr {
|
||||
assert(handle != nil)
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
cstr := strings.clone_to_cstring(symbol, context.temp_allocator)
|
||||
proc_handle := _unix_dlsym(handle, cstr)
|
||||
return proc_handle
|
||||
|
||||
@@ -309,6 +309,7 @@ get_last_error :: proc "contextless" () -> int {
|
||||
}
|
||||
|
||||
open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
handle := _unix_open(cstr, c.int(flags), c.int(mode))
|
||||
if handle == -1 {
|
||||
@@ -361,6 +362,7 @@ file_size :: proc(fd: Handle) -> (i64, Errno) {
|
||||
}
|
||||
|
||||
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)
|
||||
res := _unix_rename(old_path_cstr, new_path_cstr)
|
||||
@@ -371,6 +373,7 @@ rename :: proc(old_path, new_path: string) -> Errno {
|
||||
}
|
||||
|
||||
remove :: proc(path: string) -> Errno {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
res := _unix_unlink(path_cstr)
|
||||
if res == -1 {
|
||||
@@ -380,6 +383,7 @@ remove :: proc(path: string) -> Errno {
|
||||
}
|
||||
|
||||
make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
res := _unix_mkdir(path_cstr, mode)
|
||||
if res == -1 {
|
||||
@@ -389,6 +393,7 @@ make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno {
|
||||
}
|
||||
|
||||
remove_directory :: proc(path: string) -> Errno {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
res := _unix_rmdir(path_cstr)
|
||||
if res == -1 {
|
||||
@@ -474,6 +479,7 @@ last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) {
|
||||
|
||||
@private
|
||||
_stat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
s: OS_Stat = ---
|
||||
result := _unix_lstat(cstr, &s)
|
||||
@@ -485,6 +491,7 @@ _stat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||
|
||||
@private
|
||||
_lstat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
|
||||
// deliberately uninitialized
|
||||
@@ -550,6 +557,8 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool)
|
||||
|
||||
@private
|
||||
_readlink :: proc(path: string) -> (string, Errno) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
|
||||
|
||||
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
|
||||
bufsz : uint = MAX_PATH
|
||||
@@ -567,7 +576,8 @@ _readlink :: proc(path: string) -> (string, Errno) {
|
||||
return strings.string_from_ptr(&buf[0], rc), ERROR_NONE
|
||||
}
|
||||
}
|
||||
unreachable()
|
||||
|
||||
return "", Errno{}
|
||||
}
|
||||
|
||||
// XXX FreeBSD
|
||||
@@ -580,6 +590,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) {
|
||||
if rel == "" {
|
||||
rel = "."
|
||||
}
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
|
||||
|
||||
rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator)
|
||||
|
||||
@@ -596,6 +607,8 @@ 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, c.int(mask))
|
||||
if result == -1 {
|
||||
@@ -626,6 +639,8 @@ heap_free :: proc(ptr: rawptr) {
|
||||
}
|
||||
|
||||
lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
|
||||
|
||||
path_str := strings.clone_to_cstring(key, context.temp_allocator)
|
||||
cstr := _unix_getenv(path_str)
|
||||
if cstr == nil {
|
||||
@@ -660,6 +675,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)
|
||||
if res == -1 do return Errno(get_last_error())
|
||||
@@ -676,12 +692,14 @@ current_thread_id :: proc "contextless" () -> int {
|
||||
}
|
||||
|
||||
dlopen :: proc(filename: string, flags: int) -> rawptr {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
cstr := strings.clone_to_cstring(filename, context.temp_allocator)
|
||||
handle := _unix_dlopen(cstr, c.int(flags))
|
||||
return handle
|
||||
}
|
||||
dlsym :: proc(handle: rawptr, symbol: string) -> rawptr {
|
||||
assert(handle != nil)
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
cstr := strings.clone_to_cstring(symbol, context.temp_allocator)
|
||||
proc_handle := _unix_dlsym(handle, cstr)
|
||||
return proc_handle
|
||||
|
||||
@@ -346,7 +346,9 @@ execvp :: proc(path: string, args: []string) -> Errno {
|
||||
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.sys_open(cstr, flags, uint(mode))
|
||||
if handle < 0 {
|
||||
@@ -425,22 +427,26 @@ file_size :: proc(fd: Handle) -> (i64, Errno) {
|
||||
}
|
||||
|
||||
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.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.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.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.sys_rmdir(path_cstr))
|
||||
}
|
||||
@@ -494,6 +500,7 @@ is_file :: proc {is_file_path, is_file_handle}
|
||||
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.sys_access(cpath, O_RDONLY)
|
||||
return res == 0
|
||||
@@ -529,6 +536,7 @@ last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) {
|
||||
|
||||
@private
|
||||
_stat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
|
||||
// deliberately uninitialized; the syscall fills this buffer for us
|
||||
@@ -542,6 +550,7 @@ _stat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||
|
||||
@private
|
||||
_lstat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
|
||||
// deliberately uninitialized; the syscall fills this buffer for us
|
||||
@@ -609,6 +618,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool)
|
||||
|
||||
@private
|
||||
_readlink :: proc(path: string) -> (string, Errno) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
|
||||
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
|
||||
bufsz : uint = 256
|
||||
@@ -644,6 +654,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) {
|
||||
if rel == "" {
|
||||
rel = "."
|
||||
}
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
|
||||
|
||||
rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator)
|
||||
|
||||
@@ -660,6 +671,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.sys_access(cstr, mask)
|
||||
if result < 0 {
|
||||
@@ -690,6 +702,7 @@ heap_free :: proc(ptr: rawptr) {
|
||||
}
|
||||
|
||||
lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
|
||||
path_str := strings.clone_to_cstring(key, context.temp_allocator)
|
||||
// NOTE(tetra): Lifetime of 'cstr' is unclear, but _unix_free(cstr) segfaults.
|
||||
cstr := _unix_getenv(path_str)
|
||||
@@ -705,6 +718,7 @@ get_env :: proc(key: string, allocator := context.allocator) -> (value: string)
|
||||
}
|
||||
|
||||
set_env :: proc(key, value: string) -> Errno {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
s := strings.concatenate({key, "=", value, "\x00"}, context.temp_allocator)
|
||||
res := _unix_putenv(strings.unsafe_string_to_cstring(s))
|
||||
if res < 0 {
|
||||
@@ -714,6 +728,7 @@ set_env :: proc(key, value: string) -> Errno {
|
||||
}
|
||||
|
||||
unset_env :: proc(key: string) -> Errno {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
s := strings.clone_to_cstring(key, context.temp_allocator)
|
||||
res := _unix_putenv(s)
|
||||
if res < 0 {
|
||||
@@ -744,6 +759,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.sys_chdir(cstr)
|
||||
if res < 0 {
|
||||
@@ -762,12 +778,14 @@ current_thread_id :: proc "contextless" () -> int {
|
||||
}
|
||||
|
||||
dlopen :: proc(filename: string, flags: int) -> rawptr {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
cstr := strings.clone_to_cstring(filename, context.temp_allocator)
|
||||
handle := _unix_dlopen(cstr, c.int(flags))
|
||||
return handle
|
||||
}
|
||||
dlsym :: proc(handle: rawptr, symbol: string) -> rawptr {
|
||||
assert(handle != nil)
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
cstr := strings.clone_to_cstring(symbol, context.temp_allocator)
|
||||
proc_handle := _unix_dlsym(handle, cstr)
|
||||
return proc_handle
|
||||
|
||||
@@ -308,6 +308,7 @@ fork :: proc() -> (Pid, Errno) {
|
||||
}
|
||||
|
||||
open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
handle := _unix_open(cstr, c.int(flags), c.int(mode))
|
||||
if handle == -1 {
|
||||
@@ -360,6 +361,7 @@ file_size :: proc(fd: Handle) -> (i64, Errno) {
|
||||
}
|
||||
|
||||
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)
|
||||
res := _unix_rename(old_path_cstr, new_path_cstr)
|
||||
@@ -370,6 +372,7 @@ rename :: proc(old_path, new_path: string) -> Errno {
|
||||
}
|
||||
|
||||
remove :: proc(path: string) -> Errno {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
res := _unix_unlink(path_cstr)
|
||||
if res == -1 {
|
||||
@@ -379,6 +382,7 @@ remove :: proc(path: string) -> Errno {
|
||||
}
|
||||
|
||||
make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
res := _unix_mkdir(path_cstr, mode)
|
||||
if res == -1 {
|
||||
@@ -388,6 +392,7 @@ make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno {
|
||||
}
|
||||
|
||||
remove_directory :: proc(path: string) -> Errno {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
res := _unix_rmdir(path_cstr)
|
||||
if res == -1 {
|
||||
@@ -473,6 +478,7 @@ last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) {
|
||||
|
||||
@private
|
||||
_stat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
|
||||
// deliberately uninitialized
|
||||
@@ -486,6 +492,7 @@ _stat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||
|
||||
@private
|
||||
_lstat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
|
||||
// deliberately uninitialized
|
||||
@@ -552,6 +559,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool)
|
||||
|
||||
@private
|
||||
_readlink :: proc(path: string) -> (string, Errno) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
|
||||
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
|
||||
bufsz : uint = MAX_PATH
|
||||
@@ -569,7 +577,6 @@ _readlink :: proc(path: string) -> (string, Errno) {
|
||||
return strings.string_from_ptr(&buf[0], rc), ERROR_NONE
|
||||
}
|
||||
}
|
||||
unreachable()
|
||||
}
|
||||
|
||||
// XXX OpenBSD
|
||||
@@ -583,6 +590,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) {
|
||||
rel = "."
|
||||
}
|
||||
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
|
||||
rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator)
|
||||
|
||||
path_ptr := _unix_realpath(rel_cstr, nil)
|
||||
@@ -598,6 +606,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)
|
||||
res := _unix_access(cstr, c.int(mask))
|
||||
if res == -1 {
|
||||
@@ -628,6 +637,7 @@ heap_free :: proc(ptr: rawptr) {
|
||||
}
|
||||
|
||||
lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
|
||||
path_str := strings.clone_to_cstring(key, context.temp_allocator)
|
||||
cstr := _unix_getenv(path_str)
|
||||
if cstr == nil {
|
||||
@@ -658,6 +668,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)
|
||||
if res == -1 {
|
||||
@@ -676,12 +687,14 @@ current_thread_id :: proc "contextless" () -> int {
|
||||
}
|
||||
|
||||
dlopen :: proc(filename: string, flags: int) -> rawptr {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
cstr := strings.clone_to_cstring(filename, context.temp_allocator)
|
||||
handle := _unix_dlopen(cstr, c.int(flags))
|
||||
return handle
|
||||
}
|
||||
dlsym :: proc(handle: rawptr, symbol: string) -> rawptr {
|
||||
assert(handle != nil)
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
cstr := strings.clone_to_cstring(symbol, context.temp_allocator)
|
||||
proc_handle := _unix_dlsym(handle, cstr)
|
||||
return proc_handle
|
||||
|
||||
@@ -134,6 +134,7 @@ _processor_core_count :: proc() -> int {
|
||||
|
||||
thread_count := 0
|
||||
if !result && win32.GetLastError() == 122 && length > 0 {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
processors := make([]win32.SYSTEM_LOGICAL_PROCESSOR_INFORMATION, length, context.temp_allocator)
|
||||
|
||||
result = win32.GetLogicalProcessorInformation(&processors[0], &length)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package os
|
||||
|
||||
import "core:time"
|
||||
import "core:runtime"
|
||||
import win32 "core:sys/windows"
|
||||
|
||||
@(private)
|
||||
@@ -11,6 +12,7 @@ full_path_from_name :: proc(name: string, allocator := context.allocator) -> (pa
|
||||
if name == "" {
|
||||
name = "."
|
||||
}
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
|
||||
p := win32.utf8_to_utf16(name, context.temp_allocator)
|
||||
buf := make([dynamic]u16, 100)
|
||||
defer delete(buf)
|
||||
@@ -36,6 +38,7 @@ _stat :: proc(name: string, create_file_attributes: u32, allocator := context.al
|
||||
|
||||
context.allocator = allocator
|
||||
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
|
||||
|
||||
wname := win32.utf8_to_wstring(fix_long_path(name), context.temp_allocator)
|
||||
fa: win32.WIN32_FILE_ATTRIBUTE_DATA
|
||||
@@ -132,14 +135,15 @@ cleanpath_strip_prefix :: proc(buf: []u16) -> []u16 {
|
||||
|
||||
@(private)
|
||||
cleanpath_from_handle :: proc(fd: Handle) -> (string, Errno) {
|
||||
buf, err := cleanpath_from_handle_u16(fd)
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
|
||||
buf, err := cleanpath_from_handle_u16(fd, context.temp_allocator)
|
||||
if err != 0 {
|
||||
return "", err
|
||||
}
|
||||
return win32.utf16_to_utf8(buf, context.allocator) or_else "", err
|
||||
}
|
||||
@(private)
|
||||
cleanpath_from_handle_u16 :: proc(fd: Handle) -> ([]u16, Errno) {
|
||||
cleanpath_from_handle_u16 :: proc(fd: Handle, allocator: runtime.Allocator) -> ([]u16, Errno) {
|
||||
if fd == 0 {
|
||||
return nil, ERROR_INVALID_HANDLE
|
||||
}
|
||||
@@ -149,7 +153,7 @@ cleanpath_from_handle_u16 :: proc(fd: Handle) -> ([]u16, Errno) {
|
||||
if n == 0 {
|
||||
return nil, Errno(win32.GetLastError())
|
||||
}
|
||||
buf := make([]u16, max(n, win32.DWORD(260))+1, context.temp_allocator)
|
||||
buf := make([]u16, max(n, win32.DWORD(260))+1, allocator)
|
||||
buf_len := win32.GetFinalPathNameByHandleW(h, raw_data(buf), n, 0)
|
||||
return buf[:buf_len], ERROR_NONE
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:c"
|
||||
}
|
||||
|
||||
import "core:runtime"
|
||||
import "core:strings"
|
||||
|
||||
SEPARATOR :: '/'
|
||||
@@ -41,6 +42,7 @@ abs :: proc(path: string, allocator := context.allocator) -> (string, bool) {
|
||||
join :: proc(elems: []string, allocator := context.allocator) -> string {
|
||||
for e, i in elems {
|
||||
if e != "" {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
|
||||
p := strings.join(elems[i:], SEPARATOR_STRING, context.temp_allocator)
|
||||
return clean(p, allocator)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package filepath
|
||||
|
||||
import "core:strings"
|
||||
import "core:runtime"
|
||||
import "core:os"
|
||||
import win32 "core:sys/windows"
|
||||
|
||||
@@ -60,25 +61,25 @@ temp_full_path :: proc(name: string) -> (path: string, err: os.Errno) {
|
||||
}
|
||||
|
||||
p := win32.utf8_to_utf16(name, ta)
|
||||
buf := make([dynamic]u16, 100, ta)
|
||||
for {
|
||||
n := win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil)
|
||||
if n == 0 {
|
||||
delete(buf)
|
||||
return "", os.Errno(win32.GetLastError())
|
||||
}
|
||||
if n <= u32(len(buf)) {
|
||||
return win32.utf16_to_utf8(buf[:n], ta) or_else "", os.ERROR_NONE
|
||||
}
|
||||
resize(&buf, len(buf)*2)
|
||||
n := win32.GetFullPathNameW(raw_data(p), 0, nil, nil)
|
||||
if n == 0 {
|
||||
return "", os.Errno(win32.GetLastError())
|
||||
}
|
||||
|
||||
return
|
||||
buf := make([]u16, n, ta)
|
||||
n = win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil)
|
||||
if n == 0 {
|
||||
delete(buf)
|
||||
return "", os.Errno(win32.GetLastError())
|
||||
}
|
||||
|
||||
return win32.utf16_to_utf8(buf[:n], ta) or_else "", os.ERROR_NONE
|
||||
}
|
||||
|
||||
|
||||
|
||||
abs :: proc(path: string, allocator := context.allocator) -> (string, bool) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = allocator == context.temp_allocator)
|
||||
full_path, err := temp_full_path(path)
|
||||
if err != 0 {
|
||||
return "", false
|
||||
@@ -99,6 +100,8 @@ join :: proc(elems: []string, allocator := context.allocator) -> string {
|
||||
|
||||
join_non_empty :: proc(elems: []string, allocator := context.allocator) -> string {
|
||||
context.allocator = allocator
|
||||
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = allocator == context.temp_allocator)
|
||||
|
||||
if len(elems[0]) == 2 && elems[0][1] == ':' {
|
||||
i := 1
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
// To manipulate operating system specific paths, use the path/filepath package
|
||||
package slashpath
|
||||
|
||||
import "core:runtime"
|
||||
import "core:strings"
|
||||
|
||||
// is_separator checks whether the byte is a valid separator character
|
||||
@@ -150,8 +151,9 @@ join :: proc(elems: []string, allocator := context.allocator) -> string {
|
||||
context.allocator = allocator
|
||||
for elem, i in elems {
|
||||
if elem != "" {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
|
||||
s := strings.join(elems[i:], "/", context.temp_allocator)
|
||||
return clean(s)
|
||||
return clean(s, allocator)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
|
||||
304
core/runtime/default_allocators_arena.odin
Normal file
304
core/runtime/default_allocators_arena.odin
Normal file
@@ -0,0 +1,304 @@
|
||||
package runtime
|
||||
|
||||
import "core:intrinsics"
|
||||
|
||||
DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE :: uint(DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE)
|
||||
|
||||
Memory_Block :: struct {
|
||||
prev: ^Memory_Block,
|
||||
allocator: Allocator,
|
||||
base: [^]byte,
|
||||
used: uint,
|
||||
capacity: uint,
|
||||
}
|
||||
|
||||
Arena :: struct {
|
||||
backing_allocator: Allocator,
|
||||
curr_block: ^Memory_Block,
|
||||
total_used: uint,
|
||||
total_capacity: uint,
|
||||
minimum_block_size: uint,
|
||||
temp_count: uint,
|
||||
}
|
||||
|
||||
@(private, require_results)
|
||||
safe_add :: #force_inline proc "contextless" (x, y: uint) -> (uint, bool) {
|
||||
z, did_overflow := intrinsics.overflow_add(x, y)
|
||||
return z, !did_overflow
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
memory_block_alloc :: proc(allocator: Allocator, capacity: uint, loc := #caller_location) -> (block: ^Memory_Block, err: Allocator_Error) {
|
||||
total_size := uint(capacity + size_of(Memory_Block))
|
||||
base_offset := uintptr(size_of(Memory_Block))
|
||||
|
||||
min_alignment: int = max(16, align_of(Memory_Block))
|
||||
data := mem_alloc(int(total_size), min_alignment, allocator, loc) or_return
|
||||
block = (^Memory_Block)(raw_data(data))
|
||||
end := uintptr(raw_data(data)[len(data):])
|
||||
|
||||
block.allocator = allocator
|
||||
block.base = ([^]byte)(uintptr(block) + base_offset)
|
||||
block.capacity = uint(end - uintptr(block.base))
|
||||
|
||||
// Should be zeroed
|
||||
assert(block.used == 0)
|
||||
assert(block.prev == nil)
|
||||
return
|
||||
}
|
||||
|
||||
memory_block_dealloc :: proc(block_to_free: ^Memory_Block, loc := #caller_location) {
|
||||
if block_to_free != nil {
|
||||
allocator := block_to_free.allocator
|
||||
mem_free(block_to_free, allocator, loc)
|
||||
}
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint) -> (data: []byte, err: Allocator_Error) {
|
||||
calc_alignment_offset :: proc "contextless" (block: ^Memory_Block, alignment: uintptr) -> uint {
|
||||
alignment_offset := uint(0)
|
||||
ptr := uintptr(block.base[block.used:])
|
||||
mask := alignment-1
|
||||
if ptr & mask != 0 {
|
||||
alignment_offset = uint(alignment - (ptr & mask))
|
||||
}
|
||||
return alignment_offset
|
||||
|
||||
}
|
||||
if block == nil {
|
||||
return nil, .Out_Of_Memory
|
||||
}
|
||||
alignment_offset := calc_alignment_offset(block, uintptr(alignment))
|
||||
size, size_ok := safe_add(min_size, alignment_offset)
|
||||
if !size_ok {
|
||||
err = .Out_Of_Memory
|
||||
return
|
||||
}
|
||||
|
||||
if to_be_used, ok := safe_add(block.used, size); !ok || to_be_used > block.capacity {
|
||||
err = .Out_Of_Memory
|
||||
return
|
||||
}
|
||||
data = block.base[block.used+alignment_offset:][:min_size]
|
||||
block.used += size
|
||||
return
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
arena_alloc :: proc(arena: ^Arena, size, alignment: uint, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
|
||||
align_forward_uint :: proc "contextless" (ptr, align: uint) -> uint {
|
||||
p := ptr
|
||||
modulo := p & (align-1)
|
||||
if modulo != 0 {
|
||||
p += align - modulo
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
assert(alignment & (alignment-1) == 0, "non-power of two alignment", loc)
|
||||
|
||||
size := size
|
||||
if size == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if arena.curr_block == nil || (safe_add(arena.curr_block.used, size) or_else 0) > arena.curr_block.capacity {
|
||||
size = align_forward_uint(size, alignment)
|
||||
if arena.minimum_block_size == 0 {
|
||||
arena.minimum_block_size = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE
|
||||
}
|
||||
|
||||
block_size := max(size, arena.minimum_block_size)
|
||||
|
||||
if arena.backing_allocator.procedure == nil {
|
||||
arena.backing_allocator = default_allocator()
|
||||
}
|
||||
|
||||
new_block := memory_block_alloc(arena.backing_allocator, block_size, loc) or_return
|
||||
new_block.prev = arena.curr_block
|
||||
arena.curr_block = new_block
|
||||
arena.total_capacity += new_block.capacity
|
||||
}
|
||||
|
||||
prev_used := arena.curr_block.used
|
||||
data, err = alloc_from_memory_block(arena.curr_block, size, alignment)
|
||||
arena.total_used += arena.curr_block.used - prev_used
|
||||
return
|
||||
}
|
||||
|
||||
// `arena_init` will initialize the arena with a usuable block.
|
||||
// This procedure is not necessary to use the Arena as the default zero as `arena_alloc` will set things up if necessary
|
||||
@(require_results)
|
||||
arena_init :: proc(arena: ^Arena, size: uint, backing_allocator: Allocator, loc := #caller_location) -> Allocator_Error {
|
||||
arena^ = {}
|
||||
arena.backing_allocator = backing_allocator
|
||||
arena.minimum_block_size = max(size, 1<<12) // minimum block size of 4 KiB
|
||||
new_block := memory_block_alloc(arena.backing_allocator, arena.minimum_block_size, loc) or_return
|
||||
arena.curr_block = new_block
|
||||
arena.total_capacity += new_block.capacity
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
arena_free_last_memory_block :: proc(arena: ^Arena, loc := #caller_location) {
|
||||
if free_block := arena.curr_block; free_block != nil {
|
||||
arena.curr_block = free_block.prev
|
||||
|
||||
arena.total_capacity -= free_block.capacity
|
||||
memory_block_dealloc(free_block, loc)
|
||||
}
|
||||
}
|
||||
|
||||
// `arena_free_all` will free all but the first memory block, and then reset the memory block
|
||||
arena_free_all :: proc(arena: ^Arena, loc := #caller_location) {
|
||||
for arena.curr_block != nil && arena.curr_block.prev != nil {
|
||||
arena_free_last_memory_block(arena, loc)
|
||||
}
|
||||
|
||||
if arena.curr_block != nil {
|
||||
intrinsics.mem_zero(arena.curr_block.base, arena.curr_block.used)
|
||||
arena.curr_block.used = 0
|
||||
}
|
||||
arena.total_used = 0
|
||||
}
|
||||
|
||||
arena_destroy :: proc(arena: ^Arena, loc := #caller_location) {
|
||||
for arena.curr_block != nil {
|
||||
free_block := arena.curr_block
|
||||
arena.curr_block = free_block.prev
|
||||
|
||||
arena.total_capacity -= free_block.capacity
|
||||
memory_block_dealloc(free_block, loc)
|
||||
}
|
||||
arena.total_used = 0
|
||||
arena.total_capacity = 0
|
||||
}
|
||||
|
||||
arena_allocator :: proc(arena: ^Arena) -> Allocator {
|
||||
return Allocator{arena_allocator_proc, arena}
|
||||
}
|
||||
|
||||
arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int,
|
||||
location := #caller_location) -> (data: []byte, err: Allocator_Error) {
|
||||
arena := (^Arena)(allocator_data)
|
||||
|
||||
size, alignment := uint(size), uint(alignment)
|
||||
old_size := uint(old_size)
|
||||
|
||||
switch mode {
|
||||
case .Alloc, .Alloc_Non_Zeroed:
|
||||
return arena_alloc(arena, size, alignment, location)
|
||||
case .Free:
|
||||
err = .Mode_Not_Implemented
|
||||
case .Free_All:
|
||||
arena_free_all(arena, location)
|
||||
case .Resize:
|
||||
old_data := ([^]byte)(old_memory)
|
||||
|
||||
switch {
|
||||
case old_data == nil:
|
||||
return arena_alloc(arena, size, alignment, location)
|
||||
case size == old_size:
|
||||
// return old memory
|
||||
data = old_data[:size]
|
||||
return
|
||||
case size == 0:
|
||||
err = .Mode_Not_Implemented
|
||||
return
|
||||
case (uintptr(old_data) & uintptr(alignment-1) == 0) && size < old_size:
|
||||
// shrink data in-place
|
||||
data = old_data[:size]
|
||||
return
|
||||
}
|
||||
|
||||
new_memory := arena_alloc(arena, size, alignment, location) or_return
|
||||
if new_memory == nil {
|
||||
return
|
||||
}
|
||||
copy(new_memory, old_data[:old_size])
|
||||
return new_memory, nil
|
||||
case .Query_Features:
|
||||
set := (^Allocator_Mode_Set)(old_memory)
|
||||
if set != nil {
|
||||
set^ = {.Alloc, .Alloc_Non_Zeroed, .Free_All, .Resize, .Query_Features}
|
||||
}
|
||||
case .Query_Info:
|
||||
err = .Mode_Not_Implemented
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Arena_Temp :: struct {
|
||||
arena: ^Arena,
|
||||
block: ^Memory_Block,
|
||||
used: uint,
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
arena_temp_begin :: proc(arena: ^Arena, loc := #caller_location) -> (temp: Arena_Temp) {
|
||||
assert(arena != nil, "nil arena", loc)
|
||||
|
||||
temp.arena = arena
|
||||
temp.block = arena.curr_block
|
||||
if arena.curr_block != nil {
|
||||
temp.used = arena.curr_block.used
|
||||
}
|
||||
arena.temp_count += 1
|
||||
return
|
||||
}
|
||||
|
||||
arena_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) {
|
||||
if temp.arena == nil {
|
||||
assert(temp.block == nil)
|
||||
assert(temp.used == 0)
|
||||
return
|
||||
}
|
||||
arena := temp.arena
|
||||
|
||||
if temp.block != nil {
|
||||
memory_block_found := false
|
||||
for block := arena.curr_block; block != nil; block = block.prev {
|
||||
if block == temp.block {
|
||||
memory_block_found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !memory_block_found {
|
||||
assert(arena.curr_block == temp.block, "memory block stored within Arena_Temp not owned by Arena", loc)
|
||||
}
|
||||
|
||||
for arena.curr_block != temp.block {
|
||||
arena_free_last_memory_block(arena)
|
||||
}
|
||||
|
||||
if block := arena.curr_block; block != nil {
|
||||
assert(block.used >= temp.used, "out of order use of arena_temp_end", loc)
|
||||
amount_to_zero := min(block.used-temp.used, block.capacity-block.used)
|
||||
intrinsics.mem_zero(block.base[temp.used:], amount_to_zero)
|
||||
block.used = temp.used
|
||||
}
|
||||
}
|
||||
|
||||
assert(arena.temp_count > 0, "double-use of arena_temp_end", loc)
|
||||
arena.temp_count -= 1
|
||||
}
|
||||
|
||||
// Ignore the use of a `arena_temp_begin` entirely
|
||||
arena_temp_ignore :: proc(temp: Arena_Temp, loc := #caller_location) {
|
||||
assert(temp.arena != nil, "nil arena", loc)
|
||||
arena := temp.arena
|
||||
|
||||
assert(arena.temp_count > 0, "double-use of arena_temp_end", loc)
|
||||
arena.temp_count -= 1
|
||||
}
|
||||
|
||||
arena_check_temp :: proc(arena: ^Arena, loc := #caller_location) {
|
||||
assert(arena.temp_count == 0, "Arena_Temp not been ended", loc)
|
||||
}
|
||||
@@ -6,154 +6,33 @@ DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE: int : #config(DEFAULT_TEMP_ALLOCATOR_BACKIN
|
||||
when ODIN_OS == .Freestanding || ODIN_OS == .JS || ODIN_DEFAULT_TO_NIL_ALLOCATOR {
|
||||
Default_Temp_Allocator :: struct {}
|
||||
|
||||
default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backup_allocator := context.allocator) {}
|
||||
default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backing_allocator := context.allocator) {}
|
||||
|
||||
default_temp_allocator_destroy :: proc(s: ^Default_Temp_Allocator) {}
|
||||
|
||||
default_temp_allocator_proc :: nil_allocator_proc
|
||||
|
||||
@(require_results)
|
||||
default_temp_allocator_temp_begin :: proc(loc := #caller_location) -> (temp: Arena_Temp) {
|
||||
return
|
||||
}
|
||||
|
||||
default_temp_allocator_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) {
|
||||
}
|
||||
} else {
|
||||
Default_Temp_Allocator :: struct {
|
||||
data: []byte,
|
||||
curr_offset: int,
|
||||
prev_allocation: rawptr,
|
||||
backup_allocator: Allocator,
|
||||
leaked_allocations: [dynamic][]byte,
|
||||
arena: Arena,
|
||||
}
|
||||
|
||||
default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backup_allocator := context.allocator) {
|
||||
s.data = make_aligned([]byte, size, 2*align_of(rawptr), backup_allocator)
|
||||
s.curr_offset = 0
|
||||
s.prev_allocation = nil
|
||||
s.backup_allocator = backup_allocator
|
||||
s.leaked_allocations.allocator = backup_allocator
|
||||
default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backing_allocator := context.allocator) {
|
||||
_ = arena_init(&s.arena, uint(size), backing_allocator)
|
||||
}
|
||||
|
||||
default_temp_allocator_destroy :: proc(s: ^Default_Temp_Allocator) {
|
||||
if s == nil {
|
||||
return
|
||||
if s != nil {
|
||||
arena_destroy(&s.arena)
|
||||
s^ = {}
|
||||
}
|
||||
for ptr in s.leaked_allocations {
|
||||
free(raw_data(ptr), s.backup_allocator)
|
||||
}
|
||||
delete(s.leaked_allocations)
|
||||
delete(s.data, s.backup_allocator)
|
||||
s^ = {}
|
||||
}
|
||||
|
||||
@(private)
|
||||
default_temp_allocator_alloc :: proc(s: ^Default_Temp_Allocator, size, alignment: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
|
||||
size := size
|
||||
size = align_forward_int(size, alignment)
|
||||
|
||||
switch {
|
||||
case s.curr_offset+size <= len(s.data):
|
||||
start := uintptr(raw_data(s.data))
|
||||
ptr := start + uintptr(s.curr_offset)
|
||||
ptr = align_forward_uintptr(ptr, uintptr(alignment))
|
||||
mem_zero(rawptr(ptr), size)
|
||||
|
||||
s.prev_allocation = rawptr(ptr)
|
||||
offset := int(ptr - start)
|
||||
s.curr_offset = offset + size
|
||||
return byte_slice(rawptr(ptr), size), .None
|
||||
|
||||
case size <= len(s.data):
|
||||
start := uintptr(raw_data(s.data))
|
||||
ptr := align_forward_uintptr(start, uintptr(alignment))
|
||||
mem_zero(rawptr(ptr), size)
|
||||
|
||||
s.prev_allocation = rawptr(ptr)
|
||||
offset := int(ptr - start)
|
||||
s.curr_offset = offset + size
|
||||
return byte_slice(rawptr(ptr), size), .None
|
||||
}
|
||||
a := s.backup_allocator
|
||||
if a.procedure == nil {
|
||||
a = context.allocator
|
||||
s.backup_allocator = a
|
||||
}
|
||||
|
||||
data, err := mem_alloc_bytes(size, alignment, a, loc)
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
if s.leaked_allocations == nil {
|
||||
s.leaked_allocations = make([dynamic][]byte, a)
|
||||
}
|
||||
append(&s.leaked_allocations, data)
|
||||
|
||||
// TODO(bill): Should leaks be notified about?
|
||||
if logger := context.logger; logger.lowest_level <= .Warning {
|
||||
if logger.procedure != nil {
|
||||
logger.procedure(logger.data, .Warning, "default temp allocator resorted to backup_allocator" , logger.options, loc)
|
||||
}
|
||||
}
|
||||
|
||||
return data, .None
|
||||
}
|
||||
|
||||
@(private)
|
||||
default_temp_allocator_free :: proc(s: ^Default_Temp_Allocator, old_memory: rawptr, loc := #caller_location) -> Allocator_Error {
|
||||
if old_memory == nil {
|
||||
return .None
|
||||
}
|
||||
|
||||
start := uintptr(raw_data(s.data))
|
||||
end := start + uintptr(len(s.data))
|
||||
old_ptr := uintptr(old_memory)
|
||||
|
||||
if s.prev_allocation == old_memory {
|
||||
s.curr_offset = int(uintptr(s.prev_allocation) - start)
|
||||
s.prev_allocation = nil
|
||||
return .None
|
||||
}
|
||||
|
||||
if start <= old_ptr && old_ptr < end {
|
||||
// NOTE(bill): Cannot free this pointer but it is valid
|
||||
return .None
|
||||
}
|
||||
|
||||
if len(s.leaked_allocations) != 0 {
|
||||
for data, i in s.leaked_allocations {
|
||||
ptr := raw_data(data)
|
||||
if ptr == old_memory {
|
||||
free(ptr, s.backup_allocator)
|
||||
ordered_remove(&s.leaked_allocations, i)
|
||||
return .None
|
||||
}
|
||||
}
|
||||
}
|
||||
return .Invalid_Pointer
|
||||
// panic("invalid pointer passed to default_temp_allocator");
|
||||
}
|
||||
|
||||
@(private)
|
||||
default_temp_allocator_free_all :: proc(s: ^Default_Temp_Allocator, loc := #caller_location) {
|
||||
s.curr_offset = 0
|
||||
s.prev_allocation = nil
|
||||
for data in s.leaked_allocations {
|
||||
free(raw_data(data), s.backup_allocator)
|
||||
}
|
||||
clear(&s.leaked_allocations)
|
||||
}
|
||||
|
||||
@(private)
|
||||
default_temp_allocator_resize :: proc(s: ^Default_Temp_Allocator, old_memory: rawptr, old_size, size, alignment: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
|
||||
begin := uintptr(raw_data(s.data))
|
||||
end := begin + uintptr(len(s.data))
|
||||
old_ptr := uintptr(old_memory)
|
||||
if old_memory == s.prev_allocation && old_ptr & uintptr(alignment)-1 == 0 {
|
||||
if old_ptr+uintptr(size) < end {
|
||||
s.curr_offset = int(old_ptr-begin)+size
|
||||
return byte_slice(old_memory, size), .None
|
||||
}
|
||||
}
|
||||
data, err := default_temp_allocator_alloc(s, size, alignment, loc)
|
||||
if err == .None {
|
||||
copy(data, byte_slice(old_memory, old_size))
|
||||
err = default_temp_allocator_free(s, old_memory, loc)
|
||||
}
|
||||
return data, err
|
||||
}
|
||||
|
||||
default_temp_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
@@ -161,41 +40,36 @@ when ODIN_OS == .Freestanding || ODIN_OS == .JS || ODIN_DEFAULT_TO_NIL_ALLOCATOR
|
||||
old_memory: rawptr, old_size: int, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
|
||||
|
||||
s := (^Default_Temp_Allocator)(allocator_data)
|
||||
return arena_allocator_proc(&s.arena, mode, size, alignment, old_memory, old_size, loc)
|
||||
}
|
||||
|
||||
if s.data == nil {
|
||||
default_temp_allocator_init(s, DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE, default_allocator())
|
||||
@(require_results)
|
||||
default_temp_allocator_temp_begin :: proc(loc := #caller_location) -> (temp: Arena_Temp) {
|
||||
if context.temp_allocator.data == &global_default_temp_allocator_data {
|
||||
temp = arena_temp_begin(&global_default_temp_allocator_data.arena, loc)
|
||||
}
|
||||
|
||||
switch mode {
|
||||
case .Alloc, .Alloc_Non_Zeroed:
|
||||
data, err = default_temp_allocator_alloc(s, size, alignment, loc)
|
||||
case .Free:
|
||||
err = default_temp_allocator_free(s, old_memory, loc)
|
||||
|
||||
case .Free_All:
|
||||
default_temp_allocator_free_all(s, loc)
|
||||
|
||||
case .Resize:
|
||||
data, err = default_temp_allocator_resize(s, old_memory, old_size, size, alignment, loc)
|
||||
|
||||
case .Query_Features:
|
||||
set := (^Allocator_Mode_Set)(old_memory)
|
||||
if set != nil {
|
||||
set^ = {.Alloc, .Alloc_Non_Zeroed, .Free, .Free_All, .Resize, .Query_Features}
|
||||
}
|
||||
|
||||
case .Query_Info:
|
||||
return nil, .Mode_Not_Implemented
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
default_temp_allocator_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) {
|
||||
arena_temp_end(temp, loc)
|
||||
}
|
||||
}
|
||||
|
||||
@(deferred_out=default_temp_allocator_temp_end)
|
||||
DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD :: #force_inline proc(ignore := false, loc := #caller_location) -> (Arena_Temp, Source_Code_Location) {
|
||||
if ignore {
|
||||
return {}, loc
|
||||
} else {
|
||||
return default_temp_allocator_temp_begin(loc), loc
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
default_temp_allocator :: proc(allocator: ^Default_Temp_Allocator) -> Allocator {
|
||||
return Allocator{
|
||||
procedure = default_temp_allocator_proc,
|
||||
data = allocator,
|
||||
data = allocator,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import "core:io"
|
||||
import "core:mem"
|
||||
import "core:slice"
|
||||
import "core:unicode"
|
||||
import "core:runtime"
|
||||
import "core:unicode/utf8"
|
||||
|
||||
// returns a clone of the string `s` allocated using the `allocator`
|
||||
@@ -1425,7 +1426,9 @@ split_multi :: proc(s: string, substrs: []string, allocator := context.allocator
|
||||
|
||||
// TODO maybe remove duplicate substrs
|
||||
// sort substrings by string size, largest to smallest
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
temp_substrs := slice.clone(substrs, context.temp_allocator)
|
||||
defer delete(temp_substrs)
|
||||
slice.sort_by(temp_substrs, proc(a, b: string) -> bool {
|
||||
return len(a) > len(b)
|
||||
})
|
||||
|
||||
@@ -97,6 +97,7 @@ clone_to_cstring :: proc(s: string, allocator: runtime.Allocator, loc := #caller
|
||||
|
||||
|
||||
sys_open :: proc(path: string, oflag: Open_Flags, mode: Permission) -> (c.int, bool) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
|
||||
cmode: u32 = 0
|
||||
cflags: u32 = 0
|
||||
@@ -132,30 +133,35 @@ sys_open :: proc(path: string, oflag: Open_Flags, mode: Permission) -> (c.int, b
|
||||
}
|
||||
|
||||
sys_mkdir :: proc(path: string, mode: Permission) -> bool {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
cpath: cstring = clone_to_cstring(path, context.temp_allocator)
|
||||
cflags := _sys_permission_mode(mode)
|
||||
return syscall_mkdir(cpath, cflags) != -1
|
||||
}
|
||||
|
||||
sys_mkdir_at :: proc(fd: c.int, path: string, mode: Permission) -> bool {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
cpath: cstring = clone_to_cstring(path, context.temp_allocator)
|
||||
cflags := _sys_permission_mode(mode)
|
||||
return syscall_mkdir_at(fd, cpath, cflags) != -1
|
||||
}
|
||||
|
||||
sys_rmdir :: proc(path: string, mode: Permission) -> bool {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
cpath: cstring = clone_to_cstring(path, context.temp_allocator)
|
||||
cflags := _sys_permission_mode(mode)
|
||||
return syscall_rmdir(cpath, cflags) != -1
|
||||
}
|
||||
|
||||
sys_rename :: proc(path: string, new_path: string) -> bool {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
cpath: cstring = clone_to_cstring(path, context.temp_allocator)
|
||||
cnpath: cstring = clone_to_cstring(new_path, context.temp_allocator)
|
||||
return syscall_rename(cpath, cnpath) != -1
|
||||
}
|
||||
|
||||
sys_rename_at :: proc(fd: c.int, path: string, to_fd: c.int, new_path: string) -> bool {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
cpath: cstring = clone_to_cstring(path, context.temp_allocator)
|
||||
cnpath: cstring = clone_to_cstring(new_path, context.temp_allocator)
|
||||
return syscall_rename_at(fd, cpath, to_fd, cnpath) != -1
|
||||
@@ -166,12 +172,14 @@ sys_lseek :: proc(fd: c.int, offset: i64, whence: Offset_From) -> i64 {
|
||||
}
|
||||
|
||||
sys_chmod :: proc(path: string, mode: Permission) -> bool {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
cpath: cstring = clone_to_cstring(path, context.temp_allocator)
|
||||
cmode := _sys_permission_mode(mode)
|
||||
return syscall_chmod(cpath, cmode) != -1
|
||||
}
|
||||
|
||||
sys_lstat :: proc(path: string, status: ^stat) -> bool {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
cpath: cstring = clone_to_cstring(path, context.temp_allocator)
|
||||
return syscall_lstat(cpath, status) != -1
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ package sysinfo
|
||||
import sys "core:sys/unix"
|
||||
import "core:strconv"
|
||||
import "core:strings"
|
||||
import "core:runtime"
|
||||
|
||||
@(private)
|
||||
version_string_buf: [1024]u8
|
||||
@@ -41,6 +42,8 @@ init_os_version :: proc () {
|
||||
|
||||
major_ok, minor_ok, patch_ok: bool
|
||||
|
||||
tmp := runtime.default_temp_allocator_temp_begin()
|
||||
|
||||
triplet := strings.split(string(cstring(&version_bits[0])), ".", context.temp_allocator)
|
||||
if len(triplet) != 3 {
|
||||
have_kernel_version = false
|
||||
@@ -54,6 +57,8 @@ init_os_version :: proc () {
|
||||
}
|
||||
}
|
||||
|
||||
runtime.default_temp_allocator_temp_end(tmp)
|
||||
|
||||
if !have_kernel_version {
|
||||
// We don't know the kernel version, but we do know the build
|
||||
strings.write_string(&b, "macOS Unknown (build ")
|
||||
|
||||
@@ -4,6 +4,7 @@ package sysinfo
|
||||
import sys "core:sys/unix"
|
||||
import "core:strings"
|
||||
import "core:strconv"
|
||||
import "core:runtime"
|
||||
|
||||
@(private)
|
||||
version_string_buf: [1024]u8
|
||||
@@ -47,6 +48,8 @@ init_os_version :: proc () {
|
||||
return
|
||||
}
|
||||
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
|
||||
// Parse kernel version
|
||||
release := string(cstring(raw_data(kernel_version_buf[:])))
|
||||
version_bits := strings.split_n(release, "-", 2, context.temp_allocator)
|
||||
|
||||
@@ -4,6 +4,7 @@ package sysinfo
|
||||
import "core:c"
|
||||
import sys "core:sys/unix"
|
||||
import "core:intrinsics"
|
||||
import "core:runtime"
|
||||
import "core:os"
|
||||
import "core:strings"
|
||||
import "core:strconv"
|
||||
@@ -69,6 +70,8 @@ init_os_version :: proc () {
|
||||
l := strings.builder_len(b)
|
||||
strings.write_string(&b, string(cstring(&uts.release[0])))
|
||||
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
|
||||
// Parse kernel version, as substrings of the version info in `version_string_buf`
|
||||
version_bits := strings.split_n(strings.to_string(b)[l:], "-", 2, context.temp_allocator)
|
||||
if len(version_bits) > 1 {
|
||||
|
||||
@@ -4,6 +4,7 @@ package sysinfo
|
||||
import sys "core:sys/unix"
|
||||
import "core:strings"
|
||||
import "core:strconv"
|
||||
import "core:runtime"
|
||||
|
||||
@(private)
|
||||
version_string_buf: [1024]u8
|
||||
@@ -32,7 +33,9 @@ init_os_version :: proc () {
|
||||
version := string(cstring(raw_data(kernel_version_buf[:])))
|
||||
strings.write_string(&b, version)
|
||||
|
||||
// // Parse kernel version
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
|
||||
// Parse kernel version
|
||||
triplet := strings.split(version, ".", context.temp_allocator)
|
||||
if len(triplet) == 2 {
|
||||
major, major_ok := strconv.parse_int(triplet[0])
|
||||
|
||||
@@ -7,6 +7,7 @@ import "core:strings"
|
||||
import "core:unicode/utf16"
|
||||
|
||||
import "core:fmt"
|
||||
import "core:runtime"
|
||||
|
||||
@(private)
|
||||
version_string_buf: [1024]u8
|
||||
@@ -314,6 +315,8 @@ read_reg :: proc(hkey: sys.HKEY, subkey, val: string, $T: typeid) -> (res: T, ok
|
||||
return {}, false
|
||||
}
|
||||
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
|
||||
key_name_wide := make([]u16, BUF_SIZE, context.temp_allocator)
|
||||
val_name_wide := make([]u16, BUF_SIZE, context.temp_allocator)
|
||||
|
||||
|
||||
@@ -6840,6 +6840,10 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
|
||||
|
||||
if (operand->mode == Addressing_Builtin) {
|
||||
i32 id = operand->builtin_id;
|
||||
Entity *e = entity_of_node(operand->expr);
|
||||
if (e != nullptr && e->token.string == "expand_to_tuple") {
|
||||
warning(operand->expr, "'expand_to_tuple' has been replaced with 'expand_values'");
|
||||
}
|
||||
if (!check_builtin_procedure(c, operand, call, id, type_hint)) {
|
||||
operand->mode = Addressing_Invalid;
|
||||
operand->type = t_invalid;
|
||||
|
||||
@@ -1070,6 +1070,13 @@ gb_internal void init_universal(void) {
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
BuiltinProcId id = BuiltinProc_expand_values;
|
||||
String name = str_lit("expand_to_tuple");
|
||||
Entity *entity = alloc_entity(Entity_Builtin, nullptr, make_token_ident(name), t_invalid);
|
||||
entity->Builtin.id = id;
|
||||
add_global_entity(entity, builtin_pkg->scope);
|
||||
}
|
||||
|
||||
bool defined_values_double_declaration = false;
|
||||
for (auto const &entry : bc->defined_values) {
|
||||
|
||||
Reference in New Issue
Block a user