1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

os: reduce heap allocations done by os.real_path, os.executable, os.getwd

This commit is contained in:
Delyan Angelov 2022-08-17 17:06:38 +03:00
parent 0e62344043
commit 7585e86868
3 changed files with 34 additions and 51 deletions

View File

@ -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.

View File

@ -1,5 +1,7 @@
module os
const max_path_buffer_size = 2 * max_path_len
// Ref - winnt.h
const (
success = 0x0000 // ERROR_SUCCESS

View File

@ -609,13 +609,9 @@ pub fn read_file_array<T>(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