use more iterators; global "has pidfd open" state is now thread-safe

This commit is contained in:
jason
2024-07-24 08:43:22 -04:00
parent 0455e4b60f
commit 16bdc6d240
2 changed files with 27 additions and 15 deletions
-1
View File
@@ -399,7 +399,6 @@ _read_entire_pseudo_file :: proc { _read_entire_pseudo_file_string, _read_entire
_read_entire_pseudo_file_string :: proc(name: string, allocator: runtime.Allocator) -> (b: []u8, e: Error) { _read_entire_pseudo_file_string :: proc(name: string, allocator: runtime.Allocator) -> (b: []u8, e: Error) {
TEMP_ALLOCATOR_GUARD() TEMP_ALLOCATOR_GUARD()
name_cstr := clone_to_cstring(name, temp_allocator()) or_return name_cstr := clone_to_cstring(name, temp_allocator()) or_return
defer delete(name, temp_allocator())
return _read_entire_pseudo_file_cstring(name_cstr, allocator) return _read_entire_pseudo_file_cstring(name_cstr, allocator)
} }
+27 -14
View File
@@ -6,7 +6,9 @@ import "base:runtime"
import "core:fmt" import "core:fmt"
import "core:mem" import "core:mem"
import "core:sync"
import "core:time" import "core:time"
import "core:slice"
import "core:strings" import "core:strings"
import "core:strconv" import "core:strconv"
import "core:sys/linux" import "core:sys/linux"
@@ -14,7 +16,16 @@ import "core:path/filepath"
PIDFD_UNASSIGNED :: ~uintptr(0) PIDFD_UNASSIGNED :: ~uintptr(0)
_has_pidfd_open: bool = true // pidfd is still fairly new (Linux 5.3) _default_has_pidfd_open: bool = true
// pidfd is still fairly new (Linux 5.3)
_has_pidfd_open :: proc () -> bool {
@thread_local has_pidfd_open: bool = true
if has_pidfd_open {
has_pidfd_open = sync.atomic_load(&_default_has_pidfd_open)
}
return has_pidfd_open
}
@(private="package") @(private="package")
_exit :: proc "contextless" (code: int) -> ! { _exit :: proc "contextless" (code: int) -> ! {
@@ -65,7 +76,7 @@ _process_list :: proc(allocator: runtime.Allocator) -> ([]int, Error) {
} }
defer linux.close(dir_fd) defer linux.close(dir_fd)
dynamic_list := make([dynamic]int, allocator) dynamic_list := make([dynamic]int, temp_allocator())
buf := make([dynamic]u8, 128, 128, temp_allocator()) buf := make([dynamic]u8, 128, 128, temp_allocator())
loop: for { loop: for {
@@ -94,7 +105,7 @@ _process_list :: proc(allocator: runtime.Allocator) -> ([]int, Error) {
} }
} }
return dynamic_list[:], nil return slice.clone(dynamic_list[:], allocator), nil
} }
@(private="package") @(private="package")
@@ -174,7 +185,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
if .Priority in selection { if .Priority in selection {
// On 4th field. Priority is field 18 and niceness is field 19. // On 4th field. Priority is field 18 and niceness is field 19.
for i := 4; i < 19; i += 1 { for _ in 4..<19 {
stats = stats[strings.index_byte(stats, ' ') + 1:] stats = stats[strings.index_byte(stats, ' ') + 1:]
} }
nice_str := stats[strings.index_byte(stats, ' '):] nice_str := stats[strings.index_byte(stats, ' '):]
@@ -249,13 +260,13 @@ _current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime
_process_open :: proc(pid: int, _: Process_Open_Flags) -> (process: Process, err: Error) { _process_open :: proc(pid: int, _: Process_Open_Flags) -> (process: Process, err: Error) {
process.pid = pid process.pid = pid
process.handle = PIDFD_UNASSIGNED process.handle = PIDFD_UNASSIGNED
if !_has_pidfd_open { if _has_pidfd_open() {
return process, .Unsupported return process, .Unsupported
} }
pidfd, errno := linux.pidfd_open(linux.Pid(pid), {}) pidfd, errno := linux.pidfd_open(linux.Pid(pid), {})
if errno == .ENOSYS { if errno == .ENOSYS {
_has_pidfd_open = false sync.atomic_store(&_default_has_pidfd_open, false)
return process, .Unsupported return process, .Unsupported
} }
if errno != nil { if errno != nil {
@@ -289,7 +300,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
// search PATH if just a plain name is provided // search PATH if just a plain name is provided
executable_name := desc.command[0] executable_name := desc.command[0]
executable_path: cstring executable_path: cstring
if !strings.contains_rune(executable_name, '/') { if strings.index_byte(executable_name, '/') == -1 {
path_env := get_env("PATH", temp_allocator()) path_env := get_env("PATH", temp_allocator())
path_dirs := filepath.split_list(path_env, temp_allocator()) path_dirs := filepath.split_list(path_env, temp_allocator())
found: bool found: bool
@@ -321,8 +332,8 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
// args and environment need to be a list of cstrings // args and environment need to be a list of cstrings
// that are terminated by a nil pointer. // that are terminated by a nil pointer.
cargs := make([]cstring, len(desc.command) + 1, temp_allocator()) cargs := make([]cstring, len(desc.command) + 1, temp_allocator())
for i := 0; i < len(desc.command); i += 1{ for command, i in desc.command {
cargs[i] = temp_cstring(desc.command[i]) or_return cargs[i] = temp_cstring(command) or_return
} }
// Use current process' environment if description didn't provide it. // Use current process' environment if description didn't provide it.
@@ -332,8 +343,8 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
env = raw_data(export_cstring_environment(temp_allocator())) env = raw_data(export_cstring_environment(temp_allocator()))
} else { } else {
cenv := make([]cstring, len(desc.env) + 1, temp_allocator()) cenv := make([]cstring, len(desc.env) + 1, temp_allocator())
for i := 0; i < len(desc.env); i += 1 { for env, i in desc.env {
cenv[i] = temp_cstring(desc.env[i]) or_return cenv[i] = temp_cstring(env) or_return
} }
env = &cenv[0] env = &cenv[0]
} }
@@ -409,7 +420,7 @@ _process_state_update_times :: proc(p: Process, state: ^Process_State) -> (err:
// utime and stime are the 14 and 15th items, respectively, and we are // utime and stime are the 14 and 15th items, respectively, and we are
// currently on item 3. Skip 11 items here. // currently on item 3. Skip 11 items here.
for i := 0; i < 11; i += 1 { for _ in 0..<11 {
stats = stats[strings.index_byte(stats, ' ') + 1:] stats = stats[strings.index_byte(stats, ' ') + 1:]
} }
@@ -445,7 +456,7 @@ _process_wait :: proc(process: Process, timeout: time.Duration) -> (process_stat
// pidfd_open is fairly new, so don't error out on ENOSYS // pidfd_open is fairly new, so don't error out on ENOSYS
pid_fd: linux.Pid_FD pid_fd: linux.Pid_FD
errno: linux.Errno errno: linux.Errno
if _has_pidfd_open { if _has_pidfd_open() {
if process.handle == PIDFD_UNASSIGNED { if process.handle == PIDFD_UNASSIGNED {
pid_fd, errno = linux.pidfd_open(linux.Pid(process.pid), nil) pid_fd, errno = linux.pidfd_open(linux.Pid(process.pid), nil)
if errno != .NONE && errno != .ENOSYS { if errno != .NONE && errno != .ENOSYS {
@@ -481,7 +492,9 @@ _process_wait :: proc(process: Process, timeout: time.Duration) -> (process_stat
break break
} }
} else { } else {
mask: bit_set[0..=63] sync.atomic_store(&_default_has_pidfd_open, false)
mask: bit_set[0..<64; u64]
mask += { int(linux.Signal.SIGCHLD) - 1 } mask += { int(linux.Signal.SIGCHLD) - 1 }
org_sigset: linux.Sig_Set org_sigset: linux.Sig_Set