mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00:00
os2 linux process_wait rework; add Sig_Child_Code to sys/linux bits
This commit is contained in:
+156
-93
@@ -6,7 +6,6 @@ import "base:runtime"
|
|||||||
import "base:intrinsics"
|
import "base:intrinsics"
|
||||||
|
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
import "core:mem"
|
|
||||||
import "core:time"
|
import "core:time"
|
||||||
import "core:slice"
|
import "core:slice"
|
||||||
import "core:strings"
|
import "core:strings"
|
||||||
@@ -504,11 +503,11 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_process_state_update_times :: proc(p: Process, state: ^Process_State) -> (err: Error) {
|
_process_state_update_times :: proc(state: ^Process_State) -> (err: Error) {
|
||||||
TEMP_ALLOCATOR_GUARD()
|
TEMP_ALLOCATOR_GUARD()
|
||||||
|
|
||||||
stat_path_buf: [32]u8
|
stat_path_buf: [32]u8
|
||||||
_ = fmt.bprintf(stat_path_buf[:], "/proc/%d/stat", p.pid)
|
_ = fmt.bprintf(stat_path_buf[:], "/proc/%d/stat", state.pid)
|
||||||
stat_buf: []u8
|
stat_buf: []u8
|
||||||
stat_buf, err = _read_entire_pseudo_file(cstring(&stat_path_buf[0]), temp_allocator())
|
stat_buf, err = _read_entire_pseudo_file(cstring(&stat_path_buf[0]), temp_allocator())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -547,115 +546,179 @@ _process_state_update_times :: proc(p: Process, state: ^Process_State) -> (err:
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@(private="package")
|
_reap_terminated :: proc(process: Process) -> (state: Process_State, err: Error) {
|
||||||
_process_wait :: proc(process: Process, timeout: time.Duration) -> (process_state: Process_State, err: Error) {
|
state.pid = process.pid
|
||||||
|
_process_state_update_times(&state)
|
||||||
|
|
||||||
|
info: linux.Sig_Info
|
||||||
|
errno := linux.Errno.EINTR
|
||||||
|
for errno == .EINTR {
|
||||||
|
errno = linux.waitid(.PID, linux.Id(process.pid), &info, {.WEXITED}, nil)
|
||||||
|
}
|
||||||
|
err = _get_platform_error(errno)
|
||||||
|
|
||||||
|
switch linux.Sig_Child_Code(info.code) {
|
||||||
|
case .NONE, .CONTINUED, .STOPPED:
|
||||||
|
case .EXITED:
|
||||||
|
state.exited = true
|
||||||
|
state.exit_code = int(info.status)
|
||||||
|
state.success = state.exit_code == 0
|
||||||
|
case .KILLED, .DUMPED, .TRAPPED:
|
||||||
|
state.exited = true
|
||||||
|
state.exit_code = int(info.status)
|
||||||
|
state.success = false
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_timed_wait_on_handle :: proc(process: Process, timeout: time.Duration) -> (process_state: Process_State, err: Error) {
|
||||||
|
timeout := timeout
|
||||||
|
|
||||||
process_state.pid = process.pid
|
process_state.pid = process.pid
|
||||||
|
pidfd := linux.Fd(process.handle)
|
||||||
|
pollfd: [1]linux.Poll_Fd = {
|
||||||
|
{
|
||||||
|
fd = pidfd,
|
||||||
|
events = {.IN},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
start_tick := time.tick_now()
|
||||||
|
|
||||||
|
mask: bit_set[0..<64; u64]
|
||||||
|
mask += { int(linux.Signal.SIGCHLD) - 1 }
|
||||||
|
sigchld_set := transmute(linux.Sig_Set)(mask)
|
||||||
|
|
||||||
|
info: linux.Sig_Info
|
||||||
|
for {
|
||||||
|
if timeout <= 0 {
|
||||||
|
_process_state_update_times(&process_state)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
errno: linux.Errno
|
|
||||||
options: linux.Wait_Options
|
|
||||||
big_if: if timeout == 0 {
|
|
||||||
options += {.WNOHANG}
|
|
||||||
} else if timeout > 0 {
|
|
||||||
ts: linux.Time_Spec = {
|
ts: linux.Time_Spec = {
|
||||||
time_sec = uint(timeout / time.Second),
|
time_sec = uint(timeout / time.Second),
|
||||||
time_nsec = uint(timeout % time.Second),
|
time_nsec = uint(timeout % time.Second),
|
||||||
}
|
}
|
||||||
|
|
||||||
if false {//process.handle != PIDFD_UNASSIGNED {
|
n, errno := linux.ppoll(pollfd[:], &ts, &sigchld_set)
|
||||||
pollfd: [1]linux.Poll_Fd = {
|
if errno != .NONE {
|
||||||
{
|
if errno == .EINTR {
|
||||||
fd = linux.Fd(process.handle),
|
new_tick := time.tick_now()
|
||||||
events = {.IN},
|
timeout -= time.tick_diff(start_tick, new_tick)
|
||||||
},
|
start_tick = new_tick
|
||||||
}
|
continue
|
||||||
|
|
||||||
for {
|
|
||||||
n, e := linux.ppoll(pollfd[:], &ts, nil)
|
|
||||||
if e == .EINTR {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if e != .NONE {
|
|
||||||
return process_state, _get_platform_error(errno)
|
|
||||||
}
|
|
||||||
if n == 0 {
|
|
||||||
_process_state_update_times(process, &process_state)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mask: bit_set[0..<64; u64]
|
|
||||||
mask += { int(linux.Signal.SIGCHLD) - 1 }
|
|
||||||
|
|
||||||
org_sigset: linux.Sig_Set
|
|
||||||
sigset: linux.Sig_Set
|
|
||||||
mem.copy(&sigset, &mask, size_of(mask))
|
|
||||||
errno = linux.rt_sigprocmask(.SIG_BLOCK, &sigset, &org_sigset)
|
|
||||||
if errno != .NONE {
|
|
||||||
return process_state, _get_platform_error(errno)
|
|
||||||
}
|
|
||||||
defer linux.rt_sigprocmask(.SIG_SETMASK, &org_sigset, nil)
|
|
||||||
|
|
||||||
// In case there was a signal handler on SIGCHLD, avoid race
|
|
||||||
// condition by checking wait first.
|
|
||||||
options += {.WNOHANG}
|
|
||||||
waitid_options := options + {.WNOWAIT, .WEXITED}
|
|
||||||
info: linux.Sig_Info
|
|
||||||
errno = linux.waitid(.PID, linux.Id(process.pid), &info, waitid_options, nil)
|
|
||||||
if errno == .NONE && info.code != 0 {
|
|
||||||
break big_if
|
|
||||||
}
|
|
||||||
|
|
||||||
loop: for {
|
|
||||||
sigset = {}
|
|
||||||
mem.copy(&sigset, &mask, size_of(mask))
|
|
||||||
|
|
||||||
_, errno = linux.rt_sigtimedwait(&sigset, &info, &ts)
|
|
||||||
#partial switch errno {
|
|
||||||
case .EAGAIN: // timeout
|
|
||||||
_process_state_update_times(process, &process_state)
|
|
||||||
return
|
|
||||||
case .EINVAL:
|
|
||||||
return process_state, _get_platform_error(errno)
|
|
||||||
case .EINTR:
|
|
||||||
continue
|
|
||||||
case:
|
|
||||||
if info.pid == linux.Pid(process.pid) {
|
|
||||||
break loop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return process_state, _get_platform_error(errno)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if n == 0 { // timeout with no events
|
||||||
|
_process_state_update_times(&process_state)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// This throws EBADF with pidfd
|
||||||
|
if errno = linux.waitid(.PID, linux.Id(process.pid), &info, {.WEXITED, .WNOHANG, .WNOWAIT}, nil); errno != .NONE {
|
||||||
|
return process_state, _get_platform_error(errno)
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.signo == .SIGCHLD {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
new_tick := time.tick_now()
|
||||||
|
timeout -= time.tick_diff(start_tick, new_tick)
|
||||||
|
start_tick = new_tick
|
||||||
}
|
}
|
||||||
|
|
||||||
status: u32
|
return _reap_terminated(process)
|
||||||
errno = .EINTR
|
}
|
||||||
for errno == .EINTR {
|
|
||||||
_, errno = linux.wait4(linux.Pid(process.pid), &status, options, nil)
|
_timed_wait_on_pid :: proc(process: Process, timeout: time.Duration) -> (process_state: Process_State, err: Error) {
|
||||||
if errno != .NONE {
|
timeout := timeout
|
||||||
_process_state_update_times(process, &process_state)
|
process_state.pid = process.pid
|
||||||
|
|
||||||
|
mask: bit_set[0..<64; u64]
|
||||||
|
mask += { int(linux.Signal.SIGCHLD) - 1 }
|
||||||
|
sigchld_set := transmute(linux.Sig_Set)(mask)
|
||||||
|
|
||||||
|
start_tick := time.tick_now()
|
||||||
|
|
||||||
|
org_sigset: linux.Sig_Set
|
||||||
|
errno := linux.rt_sigprocmask(.SIG_BLOCK, &sigchld_set, &org_sigset)
|
||||||
|
if errno != .NONE {
|
||||||
|
return process_state, _get_platform_error(errno)
|
||||||
|
}
|
||||||
|
defer linux.rt_sigprocmask(.SIG_SETMASK, &org_sigset, nil)
|
||||||
|
|
||||||
|
// In case there was a signal handler on SIGCHLD, avoid race
|
||||||
|
// condition by checking wait first.
|
||||||
|
info: linux.Sig_Info
|
||||||
|
errno = linux.waitid(.PID, linux.Id(process.pid), &info, {.WNOWAIT, .WEXITED, .WNOHANG}, nil)
|
||||||
|
|
||||||
|
for errno != .NONE || info.code == 0 || info.pid != linux.Pid(process.pid) {
|
||||||
|
if timeout <= 0 {
|
||||||
|
_process_state_update_times(&process_state)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ts: linux.Time_Spec = {
|
||||||
|
time_sec = uint(timeout / time.Second),
|
||||||
|
time_nsec = uint(timeout % time.Second),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, errno = linux.rt_sigtimedwait(&sigchld_set, &info, &ts)
|
||||||
|
#partial switch errno {
|
||||||
|
case .EAGAIN: // timeout
|
||||||
|
_process_state_update_times(&process_state)
|
||||||
|
return
|
||||||
|
case .EINTR:
|
||||||
|
new_tick := time.tick_now()
|
||||||
|
timeout -= time.tick_diff(start_tick, new_tick)
|
||||||
|
start_tick = new_tick
|
||||||
|
case .EINVAL:
|
||||||
return process_state, _get_platform_error(errno)
|
return process_state, _get_platform_error(errno)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_process_state_update_times(process, &process_state)
|
return _reap_terminated(process)
|
||||||
|
}
|
||||||
|
|
||||||
// terminated by exit
|
@(private="package")
|
||||||
if linux.WIFEXITED(status) {
|
_process_wait :: proc(process: Process, timeout: time.Duration) -> (Process_State, Error) {
|
||||||
process_state.exited = true
|
if timeout > 0 {
|
||||||
process_state.exit_code = int(linux.WEXITSTATUS(status))
|
if process.handle == PIDFD_UNASSIGNED {
|
||||||
process_state.success = process_state.exit_code == 0
|
return _timed_wait_on_pid(process, timeout)
|
||||||
return
|
} else {
|
||||||
|
return _timed_wait_on_handle(process, timeout)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// terminated by signal
|
process_state: Process_State = {
|
||||||
if linux.WIFSIGNALED(status) {
|
pid = process.pid,
|
||||||
process_state.exited = false
|
|
||||||
process_state.exit_code = int(linux.WTERMSIG(status))
|
|
||||||
process_state.success = false
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
return
|
|
||||||
|
errno: linux.Errno
|
||||||
|
options: linux.Wait_Options = {.WEXITED}
|
||||||
|
if timeout == 0 {
|
||||||
|
options += {.WNOHANG}
|
||||||
|
}
|
||||||
|
|
||||||
|
info: linux.Sig_Info
|
||||||
|
|
||||||
|
errno = .EINTR
|
||||||
|
for errno == .EINTR {
|
||||||
|
errno = linux.waitid(.PID, linux.Id(process.pid), &info, options + {.WNOWAIT}, nil)
|
||||||
|
}
|
||||||
|
if errno == .EAGAIN || (errno == .NONE && info.signo != .SIGCHLD) {
|
||||||
|
_process_state_update_times(&process_state)
|
||||||
|
return process_state, nil
|
||||||
|
}
|
||||||
|
if errno != .NONE {
|
||||||
|
return process_state, _get_platform_error(errno)
|
||||||
|
}
|
||||||
|
|
||||||
|
return _reap_terminated(process)
|
||||||
}
|
}
|
||||||
|
|
||||||
@(private="package")
|
@(private="package")
|
||||||
|
|||||||
@@ -983,6 +983,20 @@ Sig_Action_Flag :: enum u32 {
|
|||||||
RESETHAND = 31,
|
RESETHAND = 31,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Translation of code in Sig_Info for when signo is SIGCHLD
|
||||||
|
*/
|
||||||
|
Sig_Child_Code :: enum {
|
||||||
|
NONE,
|
||||||
|
EXITED,
|
||||||
|
KILLED,
|
||||||
|
DUMPED,
|
||||||
|
TRAPPED,
|
||||||
|
STOPPED,
|
||||||
|
CONTINUED,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Type of socket to create
|
Type of socket to create
|
||||||
- For TCP you want to use SOCK_STREAM
|
- For TCP you want to use SOCK_STREAM
|
||||||
|
|||||||
Reference in New Issue
Block a user