diff --git a/core/os/os2/file.odin b/core/os/os2/file.odin index 52fd02478..2c042e0c5 100644 --- a/core/os/os2/file.odin +++ b/core/os/os2/file.odin @@ -104,6 +104,15 @@ open :: proc(name: string, flags := File_Flags{.Read}, perm := 0o777) -> (^File, return _open(name, flags, perm) } +@(require_results) +open_buffered :: proc(name: string, buffer_size: uint, flags := File_Flags{.Read}, perm := 0o777) -> (^File, Error) { + if buffer_size == 0 { + return _open(name, flags, perm) + } + return _open_buffered(name, buffer_size, flags, perm) +} + + @(require_results) new_file :: proc(handle: uintptr, name: string) -> ^File { return _new_file(handle, name) or_else panic("Out of memory") diff --git a/core/os/os2/file_linux.odin b/core/os/os2/file_linux.odin index d2a7483ca..6b981cca1 100644 --- a/core/os/os2/file_linux.odin +++ b/core/os/os2/file_linux.odin @@ -1,9 +1,10 @@ //+private package os2 +import "base:runtime" import "core:io" import "core:time" -import "base:runtime" +import "core:sync" import "core:sys/linux" File_Impl :: struct { @@ -11,13 +12,17 @@ File_Impl :: struct { name: string, fd: linux.Fd, allocator: runtime.Allocator, + + buffer: []byte, + rw_mutex: sync.RW_Mutex, // read write calls + p_mutex: sync.Mutex, // pread pwrite calls } _stdin := File{ impl = &File_Impl{ name = "/proc/self/fd/0", fd = 0, - allocator = _file_allocator(), + allocator = file_allocator(), }, stream = { procedure = _file_stream_proc, @@ -28,7 +33,7 @@ _stdout := File{ impl = &File_Impl{ name = "/proc/self/fd/1", fd = 1, - allocator = _file_allocator(), + allocator = file_allocator(), }, stream = { procedure = _file_stream_proc, @@ -39,7 +44,7 @@ _stderr := File{ impl = &File_Impl{ name = "/proc/self/fd/2", fd = 2, - allocator = _file_allocator(), + allocator = file_allocator(), }, stream = { procedure = _file_stream_proc, @@ -59,10 +64,6 @@ _standard_stream_init :: proc() { stderr = &_stderr } -_file_allocator :: proc() -> runtime.Allocator { - return heap_allocator() -} - _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) { TEMP_ALLOCATOR_GUARD() name_cstr := temp_cstring(name) or_return @@ -108,13 +109,30 @@ _new_file :: proc(fd: uintptr, _: string = "") -> (f: ^File, err: Error) { return &impl.file, nil } + +@(require_results) +_open_buffered :: proc(name: string, buffer_size: uint, flags := File_Flags{.Read}, perm := 0o777) -> (f: ^File, err: Error) { + assert(buffer_size > 0) + f, err = _open(name, flags, perm) + if f != nil && err == nil { + impl := (^File_Impl)(f.impl) + impl.buffer = make([]byte, buffer_size, file_allocator()) + f.stream.procedure = _file_stream_buffered_proc + } + return +} + _destroy :: proc(f: ^File_Impl) -> Error { if f == nil { return nil } a := f.allocator - delete(f.name, a) - free(f, a) + err0 := delete(f.name, a) + err1 := delete(f.buffer, a) + err2 := free(f, a) + err0 or_return + err1 or_return + err2 or_return return nil } @@ -463,3 +481,47 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, return 0, .Empty } + +@(private="package") +_file_stream_buffered_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) { + f := (^File_Impl)(stream_data) + ferr: Error + switch mode { + case .Read: + n, ferr = _read(f, p) + err = error_to_io_error(ferr) + return + case .Read_At: + n, ferr = _read_at(f, p, offset) + err = error_to_io_error(ferr) + return + case .Write: + n, ferr = _write(f, p) + err = error_to_io_error(ferr) + return + case .Write_At: + n, ferr = _write_at(f, p, offset) + err = error_to_io_error(ferr) + return + case .Seek: + n, ferr = _seek(f, offset, whence) + err = error_to_io_error(ferr) + return + case .Size: + n, ferr = _file_size(f) + err = error_to_io_error(ferr) + return + case .Flush: + ferr = _flush(f) + err = error_to_io_error(ferr) + return + case .Close, .Destroy: + ferr = _close(f) + err = error_to_io_error(ferr) + return + case .Query: + return io.query_utility({.Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Flush, .Close, .Destroy, .Query}) + } + return 0, .Empty +} + diff --git a/core/os/os2/file_windows.odin b/core/os/os2/file_windows.odin index 48a5427f1..c037e3f93 100644 --- a/core/os/os2/file_windows.odin +++ b/core/os/os2/file_windows.odin @@ -33,6 +33,7 @@ File_Impl :: struct { allocator: runtime.Allocator, + buffer: []byte, rw_mutex: sync.RW_Mutex, // read write calls p_mutex: sync.Mutex, // pread pwrite calls } @@ -165,6 +166,26 @@ _new_file :: proc(handle: uintptr, name: string) -> (f: ^File, err: Error) { return &impl.file, nil } + +@(require_results) +_open_buffered :: proc(name: string, buffer_size: uint, flags := File_Flags{.Read}, perm := 0o777) -> (f: ^File, err: Error) { + assert(buffer_size > 0) + flags := flags if flags != nil else {.Read} + handle := _open_internal(name, flags, perm) or_return + return _new_file_buffered(handle, name, buffer_size) +} + +_new_file_buffered :: proc(handle: uintptr, name: string, buffer_size: uint) -> (f: ^File, err: Error) { + f, err = _new_file(handle, name) + if f != nil && err == nil { + impl := (^File_Impl)(f.impl) + impl.buffer = make([]byte, buffer_size, file_allocator()) + f.stream.procedure = _file_stream_buffered_proc + } + return +} + + _fd :: proc(f: ^File) -> uintptr { if f == nil || f.impl == nil { return INVALID_HANDLE @@ -181,9 +202,11 @@ _destroy :: proc(f: ^File_Impl) -> Error { err0 := free(f.wname, a) err1 := delete(f.name, a) err2 := free(f, a) + err3 := delete(f.buffer, a) err0 or_return err1 or_return err2 or_return + err3 or_return return nil } @@ -780,6 +803,52 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, } +@(private="package") +_file_stream_buffered_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) { + f := (^File_Impl)(stream_data) + ferr: Error + switch mode { + case .Read: + n, ferr = _read(f, p) + err = error_to_io_error(ferr) + return + case .Read_At: + n, ferr = _read_at(f, p, offset) + err = error_to_io_error(ferr) + return + case .Write: + n, ferr = _write(f, p) + err = error_to_io_error(ferr) + return + case .Write_At: + n, ferr = _write_at(f, p, offset) + err = error_to_io_error(ferr) + return + case .Seek: + n, ferr = _seek(f, offset, whence) + err = error_to_io_error(ferr) + return + case .Size: + n, ferr = _file_size(f) + err = error_to_io_error(ferr) + return + case .Flush: + ferr = _flush(f) + err = error_to_io_error(ferr) + return + case .Close, .Destroy: + ferr = _close(f) + err = error_to_io_error(ferr) + return + case .Query: + return io.query_utility({.Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Flush, .Close, .Query}) + } + return 0, .Empty +} + + + + @(private="package", require_results) win32_utf8_to_wstring :: proc(s: string, allocator: runtime.Allocator) -> (ws: [^]u16, err: runtime.Allocator_Error) {