From 7585e8686844648edfee4b567e9a5d6c3856c256 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Wed, 17 Aug 2022 17:06:38 +0300 Subject: [PATCH] os: reduce heap allocations done by os.real_path, os.executable, os.getwd --- vlib/os/const_nix.c.v | 2 + vlib/os/const_windows.c.v | 2 + vlib/os/os.c.v | 81 +++++++++++++++------------------------ 3 files changed, 34 insertions(+), 51 deletions(-) diff --git a/vlib/os/const_nix.c.v b/vlib/os/const_nix.c.v index 7f4c378a6..6b24a03cc 100644 --- a/vlib/os/const_nix.c.v +++ b/vlib/os/const_nix.c.v @@ -1,5 +1,7 @@ module os +const max_path_buffer_size = max_path_len + const ( o_binary = 0 // input and output is not translated; the default on unix o_rdonly = C.O_RDONLY // open the file read-only. diff --git a/vlib/os/const_windows.c.v b/vlib/os/const_windows.c.v index 4b87c8bf6..dbbac405f 100644 --- a/vlib/os/const_windows.c.v +++ b/vlib/os/const_windows.c.v @@ -1,5 +1,7 @@ module os +const max_path_buffer_size = 2 * max_path_len + // Ref - winnt.h const ( success = 0x0000 // ERROR_SUCCESS diff --git a/vlib/os/os.c.v b/vlib/os/os.c.v index 2a3913cb2..80ed28151 100644 --- a/vlib/os/os.c.v +++ b/vlib/os/os.c.v @@ -609,13 +609,9 @@ pub fn read_file_array(path string) []T { // process. [manualfree] pub fn executable() string { - size := max_path_bufffer_size() - mut result := unsafe { vcalloc_noscan(size) } - defer { - unsafe { free(result) } - } + mut result := [max_path_buffer_size]u8{} $if windows { - pu16_result := unsafe { &u16(result) } + pu16_result := unsafe { &u16(&result) } len := C.GetModuleFileName(0, pu16_result, 512) // determine if the file is a windows symlink attrs := C.GetFileAttributesW(pu16_result) @@ -627,15 +623,12 @@ pub fn executable() string { defer { C.CloseHandle(file) } - final_path := unsafe { vcalloc_noscan(size) } - defer { - unsafe { free(final_path) } - } + final_path := [max_path_buffer_size]u8{} // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew - final_len := C.GetFinalPathNameByHandleW(file, unsafe { &u16(final_path) }, - size, 0) - if final_len < size { - sret := unsafe { string_from_wide2(&u16(final_path), final_len) } + final_len := C.GetFinalPathNameByHandleW(file, unsafe { &u16(&final_path) }, + max_path_buffer_size, 0) + if final_len < max_path_buffer_size { + sret := unsafe { string_from_wide2(&u16(&final_path), final_len) } defer { unsafe { sret.free() } } @@ -653,46 +646,46 @@ pub fn executable() string { } $if macos { pid := C.getpid() - ret := proc_pidpath(pid, result, max_path_len) + ret := proc_pidpath(pid, &result, max_path_len) if ret <= 0 { eprintln('os.executable() failed at calling proc_pidpath with pid: $pid . proc_pidpath returned $ret ') return executable_fallback() } - res := unsafe { tos_clone(result) } + res := unsafe { tos_clone(&result) } return res } $if freebsd { - bufsize := usize(size) + bufsize := usize(max_path_buffer_size) mib := [1 /* CTL_KERN */, 14 /* KERN_PROC */, 12 /* KERN_PROC_PATHNAME */, -1] - unsafe { C.sysctl(mib.data, mib.len, result, &bufsize, 0, 0) } - res := unsafe { tos_clone(result) } + unsafe { C.sysctl(mib.data, mib.len, &result, &bufsize, 0, 0) } + res := unsafe { tos_clone(&result) } return res } $if netbsd { - count := C.readlink(c'/proc/curproc/exe', &char(result), max_path_len) + count := C.readlink(c'/proc/curproc/exe', &char(&result), max_path_len) if count < 0 { eprintln('os.executable() failed at reading /proc/curproc/exe to get exe path') return executable_fallback() } - res := unsafe { tos_clone(result) } + res := unsafe { tos_clone(&result) } return res } $if dragonfly { - count := C.readlink(c'/proc/curproc/file', &char(result), max_path_len) + count := C.readlink(c'/proc/curproc/file', &char(&result), max_path_len) if count < 0 { eprintln('os.executable() failed at reading /proc/curproc/file to get exe path') return executable_fallback() } - res := unsafe { tos_clone(result) } + res := unsafe { tos_clone(&result) } return res } $if linux { - count := C.readlink(c'/proc/self/exe', &char(result), max_path_len) + count := C.readlink(c'/proc/self/exe', &char(&result), max_path_len) if count < 0 { eprintln('os.executable() failed at reading /proc/self/exe to get exe path') return executable_fallback() } - res := unsafe { tos_clone(result) } + res := unsafe { tos_clone(&result) } return res } // "Sadly there is no way to get the full path of the executed file in OpenBSD." @@ -753,33 +746,22 @@ pub fn chdir(path string) ? { } } -fn max_path_bufffer_size() int { - mut size := max_path_len - $if windows { - size *= 2 - } - return size -} - // getwd returns the absolute path of the current directory. [manualfree] pub fn getwd() string { unsafe { - buf := vcalloc_noscan(max_path_bufffer_size()) - defer { - free(buf) - } + buf := [max_path_buffer_size]u8{} $if windows { - if C._wgetcwd(&u16(buf), max_path_len) == 0 { + if C._wgetcwd(&u16(&buf), max_path_len) == 0 { return '' } - res := string_from_wide(&u16(buf)) + res := string_from_wide(&u16(&buf)) return res } $else { - if C.getcwd(&char(buf), max_path_len) == 0 { + if C.getcwd(&char(&buf), max_path_len) == 0 { return '' } - res := tos_clone(buf) + res := tos_clone(&buf) return res } } @@ -792,14 +774,10 @@ pub fn getwd() string { // Note: this particular rabbit hole is *deep* ... [manualfree] pub fn real_path(fpath string) string { - size := max_path_bufffer_size() - mut fullpath := unsafe { vcalloc_noscan(size) } - defer { - unsafe { free(fullpath) } - } + mut fullpath := [max_path_buffer_size]u8{} mut res := '' $if windows { - pu16_fullpath := unsafe { &u16(fullpath) } + pu16_fullpath := unsafe { &u16(&fullpath) } // gets handle with GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 // use C.CreateFile(fpath.to_wide(), 0x80000000, 1, 0, 3, 0x80, 0) instead of get_file_handle // try to open the file to get symbolic link path @@ -813,8 +791,9 @@ pub fn real_path(fpath string) string { C.CloseHandle(file) } // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew - final_len := C.GetFinalPathNameByHandleW(file, pu16_fullpath, size, 0) - if final_len < size { + final_len := C.GetFinalPathNameByHandleW(file, pu16_fullpath, max_path_buffer_size, + 0) + if final_len < max_path_buffer_size { rt := unsafe { string_from_wide2(pu16_fullpath, final_len) } srt := rt[4..] unsafe { res.free() } @@ -836,7 +815,7 @@ pub fn real_path(fpath string) string { res = unsafe { string_from_wide(pu16_fullpath) } } } $else { - ret := &char(C.realpath(&char(fpath.str), &char(fullpath))) + ret := &char(C.realpath(&char(fpath.str), &char(&fullpath))) if ret == 0 { unsafe { res.free() } return fpath.clone() @@ -846,7 +825,7 @@ pub fn real_path(fpath string) string { // resulting string from that buffer, to a shorter one, and then free the // 4KB fullpath buffer. unsafe { res.free() } - res = unsafe { tos_clone(fullpath) } + res = unsafe { tos_clone(&fullpath) } } unsafe { normalize_drive_letter(res) } return res -- 2.30.2