diff options
| author | gingerBill <bill@gingerbill.org> | 2020-09-29 11:11:28 +0100 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2020-09-29 11:11:28 +0100 |
| commit | 519dcc2b76c9bfcf4be84c9ced0c0072d117a4c6 (patch) | |
| tree | 73d50b2e59898e2c52882d4f16d4eb376659e846 | |
| parent | e95addb1f4f298a7befa2a45dadbce9fcb7a0e00 (diff) | |
Add os.read_at and for Windows; fix mem.clone_slice; fix current directory locking code
| -rw-r--r-- | core/mem/mem.odin | 2 | ||||
| -rw-r--r-- | core/os/file_windows.odin | 122 | ||||
| -rw-r--r-- | core/os/os_windows.odin | 2 |
3 files changed, 109 insertions, 17 deletions
diff --git a/core/mem/mem.odin b/core/mem/mem.odin index 91e28b48c..79e3b5529 100644 --- a/core/mem/mem.odin +++ b/core/mem/mem.odin @@ -290,6 +290,6 @@ calc_padding_with_header :: proc(ptr: uintptr, align: uintptr, header_size: int) clone_slice :: proc(slice: $T/[]$E, allocator := context.allocator, loc := #caller_location) -> T { new_slice := make(T, len(slice), allocator, loc); - copy(new_slice, slice); + runtime.copy(new_slice, slice); return new_slice; } diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin index bf9784319..deddc40d4 100644 --- a/core/os/file_windows.odin +++ b/core/os/file_windows.odin @@ -77,8 +77,7 @@ write :: proc(fd: Handle, data: []byte) -> (int, Errno) { for total_write < length { remaining := length - total_write; - MAX :: 1<<31-1; - to_write := win32.DWORD(min(i32(remaining), MAX)); + to_write := win32.DWORD(min(i32(remaining), MAX_RW)); e := win32.WriteFile(win32.HANDLE(fd), &data[total_write], to_write, &single_write_length, nil); if single_write_length <= 0 || !e { @@ -101,8 +100,7 @@ read :: proc(fd: Handle, data: []byte) -> (int, Errno) { for total_read < length { remaining := length - total_read; - MAX :: 1<<32-1; - to_read := win32.DWORD(min(u32(remaining), MAX)); + to_read := win32.DWORD(min(u32(remaining), MAX_RW)); e := win32.ReadFile(win32.HANDLE(fd), &data[total_read], to_read, &single_read_length, nil); if single_read_length <= 0 || !e { @@ -146,6 +144,101 @@ file_size :: proc(fd: Handle) -> (i64, Errno) { } +@(private) +MAX_RW :: 1<<30; + +@(private) +pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { + buf := data; + if len(buf) > MAX_RW { + 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), + Offset = u32(offset), + }; + + h := win32.HANDLE(fd); + done: win32.DWORD; + if !win32.ReadFile(h, raw_data(buf), u32(len(buf)), &done, &o) { + e = Errno(win32.GetLastError()); + done = 0; + } + return int(done), e; +} +@(private) +pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { + buf := data; + if len(buf) > MAX_RW { + 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), + Offset = u32(offset), + }; + + h := win32.HANDLE(fd); + done: win32.DWORD; + if !win32.WriteFile(h, raw_data(buf), u32(len(buf)), &done, &o) { + e = Errno(win32.GetLastError()); + done = 0; + } + return int(done), e; +} + +read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) { + if offset < 0 { + return 0, ERROR_NEGATIVE_OFFSET; + } + + b, offset := data, offset; + for len(b) > 0 { + m, e := pread(fd, b, offset); + if e != 0 { + err = e; + break; + } + n += m; + b = b[m:]; + offset += i64(m); + } + return; +} +write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) { + if offset < 0 { + return 0, ERROR_NEGATIVE_OFFSET; + } + + b, offset := data, offset; + for len(b) > 0 { + m, e := pwrite(fd, b, offset); + if e != 0 { + err = e; + break; + } + n += m; + b = b[m:]; + offset += i64(m); + } + return; +} + + + // NOTE(bill): Uses startup to initialize it stdin := get_std_handle(uint(win32.STD_INPUT_HANDLE)); stdout := get_std_handle(uint(win32.STD_OUTPUT_HANDLE)); @@ -188,20 +281,19 @@ is_dir :: proc(path: string) -> bool { return false; } -// NOTE(tetra): GetCurrentDirectory is not thread safe with SetCurrentDirectory and GetFullPathName; -// The current directory is stored as a global variable in the process. -@private cwd_gate := false; +// NOTE(tetra): GetCurrentDirectory is not thread safe with SetCurrentDirectory and GetFullPathName +@private cwd_lock := win32.SRWLOCK{}; // zero is initialized get_current_directory :: proc(allocator := context.allocator) -> string { - for intrinsics.atomic_xchg(&cwd_gate, true) {} + win32.AcquireSRWLockExclusive(&cwd_lock); sz_utf16 := win32.GetCurrentDirectoryW(0, nil); dir_buf_wstr := make([]u16, sz_utf16, context.temp_allocator); // the first time, it _includes_ the NUL. - sz_utf16 = win32.GetCurrentDirectoryW(win32.DWORD(len(dir_buf_wstr)), auto_cast &dir_buf_wstr[0]); + sz_utf16 = win32.GetCurrentDirectoryW(win32.DWORD(len(dir_buf_wstr)), raw_data(dir_buf_wstr)); assert(int(sz_utf16)+1 == len(dir_buf_wstr)); // the second time, it _excludes_ the NUL. - intrinsics.atomic_store(&cwd_gate, false); + win32.ReleaseSRWLockExclusive(&cwd_lock); return win32.utf16_to_utf8(dir_buf_wstr, allocator); } @@ -209,14 +301,14 @@ get_current_directory :: proc(allocator := context.allocator) -> string { set_current_directory :: proc(path: string) -> (err: Errno) { wstr := win32.utf8_to_wstring(path); - for intrinsics.atomic_xchg(&cwd_gate, true) {} - defer intrinsics.atomic_store(&cwd_gate, false); + win32.AcquireSRWLockExclusive(&cwd_lock); - res := win32.SetCurrentDirectoryW(auto_cast wstr); - if !res { - return Errno(win32.GetLastError()); + if !win32.SetCurrentDirectoryW(wstr) { + err = Errno(win32.GetLastError()); } + win32.ReleaseSRWLockExclusive(&cwd_lock); + return; } diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin index b8c171008..86c4b4df2 100644 --- a/core/os/os_windows.odin +++ b/core/os/os_windows.odin @@ -56,7 +56,7 @@ WSAECONNRESET: Errno : 10054; // Windows reserves errors >= 1<<29 for application use ERROR_FILE_IS_PIPE: Errno : 1<<29 + 0; ERROR_FILE_IS_NOT_DIR: Errno : 1<<29 + 1; - +ERROR_NEGATIVE_OFFSET: Errno : 1<<29 + 2; // "Argv" arguments converted to Odin strings args := _alloc_command_line_arguments(); |