mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-03 14:18:47 +00:00
revert os2/process
This commit is contained in:
+35
-53
@@ -2,42 +2,36 @@ package os2
|
|||||||
|
|
||||||
import "core:sync"
|
import "core:sync"
|
||||||
import "core:time"
|
import "core:time"
|
||||||
import "core:c"
|
import "base:runtime"
|
||||||
|
|
||||||
args: []string = _alloc_command_line_arguments()
|
args: []string
|
||||||
|
|
||||||
exit :: proc "contextless" (code: int) -> ! {
|
exit :: proc "contextless" (code: int) -> ! {
|
||||||
_exit(code)
|
runtime.trap()
|
||||||
}
|
}
|
||||||
|
|
||||||
@(require_results)
|
|
||||||
get_uid :: proc() -> int {
|
get_uid :: proc() -> int {
|
||||||
return _get_uid()
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
@(require_results)
|
|
||||||
get_euid :: proc() -> int {
|
get_euid :: proc() -> int {
|
||||||
return _get_euid()
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
@(require_results)
|
|
||||||
get_gid :: proc() -> int {
|
get_gid :: proc() -> int {
|
||||||
return _get_gid()
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
@(require_results)
|
|
||||||
get_egid :: proc() -> int {
|
get_egid :: proc() -> int {
|
||||||
return _get_euid()
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
@(require_results)
|
|
||||||
get_pid :: proc() -> int {
|
get_pid :: proc() -> int {
|
||||||
return _get_pid()
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
@(require_results)
|
|
||||||
get_ppid :: proc() -> int {
|
get_ppid :: proc() -> int {
|
||||||
return _get_ppid()
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -52,12 +46,16 @@ Process :: struct {
|
|||||||
Process_Attributes :: struct {
|
Process_Attributes :: struct {
|
||||||
dir: string,
|
dir: string,
|
||||||
env: []string,
|
env: []string,
|
||||||
stdin: ^File,
|
files: []^File,
|
||||||
stdout: ^File,
|
|
||||||
stderr: ^File,
|
|
||||||
sys: ^Process_Attributes_OS_Specific,
|
sys: ^Process_Attributes_OS_Specific,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Process_Attributes_OS_Specific :: struct{}
|
||||||
|
|
||||||
|
Process_Error :: enum {
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
Process_State :: struct {
|
Process_State :: struct {
|
||||||
pid: int,
|
pid: int,
|
||||||
exit_code: int,
|
exit_code: int,
|
||||||
@@ -68,53 +66,37 @@ Process_State :: struct {
|
|||||||
sys: rawptr,
|
sys: rawptr,
|
||||||
}
|
}
|
||||||
|
|
||||||
Signal :: enum {
|
Signal :: #type proc()
|
||||||
Abort,
|
|
||||||
Floating_Point_Exception,
|
Kill: Signal = nil
|
||||||
Illegal_Instruction,
|
Interrupt: Signal = nil
|
||||||
Interrupt,
|
|
||||||
Segmentation_Fault,
|
|
||||||
Termination,
|
find_process :: proc(pid: int) -> (^Process, Process_Error) {
|
||||||
|
return nil, .None
|
||||||
}
|
}
|
||||||
|
|
||||||
Signal_Handler_Proc :: #type proc "c" (c.int)
|
|
||||||
Signal_Handler_Special :: enum {
|
process_start :: proc(name: string, argv: []string, attr: ^Process_Attributes) -> (^Process, Process_Error) {
|
||||||
Default,
|
return nil, .None
|
||||||
Ignore,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Signal_Handler :: union {
|
process_release :: proc(p: ^Process) -> Process_Error {
|
||||||
Signal_Handler_Proc,
|
return .None
|
||||||
Signal_Handler_Special,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@(require_results)
|
process_kill :: proc(p: ^Process) -> Process_Error {
|
||||||
process_find :: proc(pid: int) -> (Process, Error) {
|
return .None
|
||||||
return _process_find(pid)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@(require_results)
|
process_signal :: proc(p: ^Process, sig: Signal) -> Process_Error {
|
||||||
process_get_state :: proc(p: Process) -> (Process_State, Error) {
|
return .None
|
||||||
return _process_get_state(p)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@(require_results)
|
process_wait :: proc(p: ^Process) -> (Process_State, Process_Error) {
|
||||||
process_start :: proc(name: string, argv: []string, attr: ^Process_Attributes = nil) -> (Process, Error) {
|
return {}, .None
|
||||||
return _process_start(name, argv, attr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
process_release :: proc(p: ^Process) -> Error {
|
|
||||||
return _process_release(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
process_kill :: proc(p: ^Process) -> Error {
|
|
||||||
return _process_kill(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
process_signal :: proc(sig: Signal, h: Signal_Handler) -> Error {
|
|
||||||
return _process_signal(sig, h)
|
|
||||||
}
|
|
||||||
|
|
||||||
process_wait :: proc(p: ^Process, t: time.Duration = time.MAX_DURATION) -> (Process_State, Error) {
|
|
||||||
return _process_wait(p, t)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,428 +0,0 @@
|
|||||||
//+private
|
|
||||||
package os2
|
|
||||||
|
|
||||||
import "base:runtime"
|
|
||||||
|
|
||||||
import "core:fmt"
|
|
||||||
import "core:mem"
|
|
||||||
import "core:time"
|
|
||||||
import "core:strings"
|
|
||||||
import "core:strconv"
|
|
||||||
import "core:sys/linux"
|
|
||||||
import "core:path/filepath"
|
|
||||||
|
|
||||||
_alloc_command_line_arguments :: proc() -> []string {
|
|
||||||
res := make([]string, len(runtime.args__), heap_allocator())
|
|
||||||
for arg, i in runtime.args__ {
|
|
||||||
res[i] = string(arg)
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
_exit :: proc "contextless" (code: int) -> ! {
|
|
||||||
linux.exit_group(i32(code))
|
|
||||||
}
|
|
||||||
|
|
||||||
_get_uid :: proc() -> int {
|
|
||||||
return int(linux.getuid())
|
|
||||||
}
|
|
||||||
|
|
||||||
_get_euid :: proc() -> int {
|
|
||||||
return int(linux.geteuid())
|
|
||||||
}
|
|
||||||
|
|
||||||
_get_gid :: proc() -> int {
|
|
||||||
return int(linux.getgid())
|
|
||||||
}
|
|
||||||
|
|
||||||
_get_egid :: proc() -> int {
|
|
||||||
return int(linux.getegid())
|
|
||||||
}
|
|
||||||
|
|
||||||
_get_pid :: proc() -> int {
|
|
||||||
return int(linux.getpid())
|
|
||||||
}
|
|
||||||
|
|
||||||
_get_ppid :: proc() -> int {
|
|
||||||
return int(linux.getppid())
|
|
||||||
}
|
|
||||||
|
|
||||||
Process_Attributes_OS_Specific :: struct {}
|
|
||||||
|
|
||||||
_process_find :: proc(pid: int) -> (Process, Error) {
|
|
||||||
TEMP_ALLOCATOR_GUARD()
|
|
||||||
pid_path := fmt.ctprintf("/proc/%d", pid)
|
|
||||||
|
|
||||||
p: Process
|
|
||||||
dir_fd: linux.Fd
|
|
||||||
errno: linux.Errno
|
|
||||||
|
|
||||||
#partial switch dir_fd, errno = linux.open(pid_path, _OPENDIR_FLAGS); errno {
|
|
||||||
case .NONE:
|
|
||||||
linux.close(dir_fd)
|
|
||||||
p.pid = pid
|
|
||||||
return p, nil
|
|
||||||
case .ENOTDIR:
|
|
||||||
return p, .Invalid_Dir
|
|
||||||
case .ENOENT:
|
|
||||||
return p, .Not_Exist
|
|
||||||
}
|
|
||||||
return p, _get_platform_error(errno)
|
|
||||||
}
|
|
||||||
|
|
||||||
_process_get_state :: proc(p: Process) -> (state: Process_State, err: Error) {
|
|
||||||
TEMP_ALLOCATOR_GUARD()
|
|
||||||
|
|
||||||
stat_name := fmt.ctprintf("/proc/%d/stat", p.pid)
|
|
||||||
stat_buf: []u8
|
|
||||||
stat_buf, err = _read_entire_pseudo_file(stat_name, temp_allocator())
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
idx := strings.last_index_byte(string(stat_buf), ')')
|
|
||||||
stats := string(stat_buf[idx + 2:])
|
|
||||||
|
|
||||||
// utime and stime are the 12 and 13th items, respectively
|
|
||||||
// skip the first 11 items here.
|
|
||||||
for i := 0; i < 11; i += 1 {
|
|
||||||
stats = stats[strings.index_byte(stats, ' ') + 1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
idx = strings.index_byte(stats, ' ')
|
|
||||||
utime_str := stats[:idx]
|
|
||||||
|
|
||||||
stats = stats[idx + 1:]
|
|
||||||
stime_str := stats[:strings.index_byte(stats, ' ')]
|
|
||||||
|
|
||||||
utime, _ := strconv.parse_int(utime_str, 10)
|
|
||||||
stime, _ := strconv.parse_int(stime_str, 10)
|
|
||||||
|
|
||||||
// NOTE: Assuming HZ of 100, 1 jiffy == 10 ms
|
|
||||||
state.user_time = time.Duration(utime) * 10 * time.Millisecond
|
|
||||||
state.system_time = time.Duration(stime) * 10 * time.Millisecond
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_process_start :: proc(name: string, argv: []string, attr: ^Process_Attributes) -> (child: Process, err: Error) {
|
|
||||||
TEMP_ALLOCATOR_GUARD()
|
|
||||||
|
|
||||||
dir_fd := linux.AT_FDCWD
|
|
||||||
errno: linux.Errno
|
|
||||||
if attr != nil && attr.dir != "" {
|
|
||||||
dir_cstr := temp_cstring(attr.dir) or_return
|
|
||||||
if dir_fd, errno = linux.open(dir_cstr, _OPENDIR_FLAGS); errno != .NONE {
|
|
||||||
return child, _get_platform_error(errno)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// search PATH if just a plain name is provided
|
|
||||||
executable: cstring
|
|
||||||
if !strings.contains_rune(name, '/') {
|
|
||||||
path_env := get_env("PATH", temp_allocator())
|
|
||||||
path_dirs := filepath.split_list(path_env, temp_allocator())
|
|
||||||
found: bool
|
|
||||||
for dir in path_dirs {
|
|
||||||
executable = fmt.ctprintf("%s/%s", dir, name)
|
|
||||||
fail: bool
|
|
||||||
if fail, errno = linux.faccessat(dir_fd, executable, linux.F_OK); errno == .NONE && !fail {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
// check in cwd to match windows behavior
|
|
||||||
executable = fmt.ctprintf("./%s", name)
|
|
||||||
fail: bool
|
|
||||||
if fail, errno = linux.faccessat(dir_fd, executable, linux.F_OK); errno != .NONE || fail {
|
|
||||||
return child, .Not_Exist
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
executable = temp_cstring(name) or_return
|
|
||||||
}
|
|
||||||
|
|
||||||
not_exec: bool
|
|
||||||
if not_exec, errno = linux.faccessat(dir_fd, executable, linux.F_OK | linux.X_OK); errno != .NONE || not_exec {
|
|
||||||
return child, errno == .NONE ? .Permission_Denied : _get_platform_error(errno)
|
|
||||||
}
|
|
||||||
|
|
||||||
// args and environment need to be a list of cstrings
|
|
||||||
// that are terminated by a nil pointer.
|
|
||||||
// The first argument is a copy of the executable name.
|
|
||||||
cargs := make([]cstring, len(argv) + 2, temp_allocator())
|
|
||||||
cargs[0] = executable
|
|
||||||
for i := 0; i < len(argv); i += 1 {
|
|
||||||
cargs[i + 1] = temp_cstring(argv[i]) or_return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use current process's environment if attributes not provided
|
|
||||||
env: [^]cstring
|
|
||||||
if attr == nil {
|
|
||||||
// take this process's current environment
|
|
||||||
env = raw_data(export_cstring_environment(temp_allocator()))
|
|
||||||
} else {
|
|
||||||
cenv := make([]cstring, len(attr.env) + 1, temp_allocator())
|
|
||||||
for i := 0; i < len(attr.env); i += 1 {
|
|
||||||
cenv[i] = temp_cstring(attr.env[i]) or_return
|
|
||||||
}
|
|
||||||
env = &cenv[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: This is the traditional textbook implementation with fork.
|
|
||||||
// A more efficient implementation with vfork:
|
|
||||||
//
|
|
||||||
// 1. retrieve signal handlers
|
|
||||||
// 2. block all signals
|
|
||||||
// 3. allocate some stack space
|
|
||||||
// 4. vfork (waits for child exit or execve); In child:
|
|
||||||
// a. set child signal handlers
|
|
||||||
// b. set up any necessary pipes
|
|
||||||
// c. execve
|
|
||||||
// 5. restore signal handlers
|
|
||||||
//
|
|
||||||
stdin_fds: [2]linux.Fd
|
|
||||||
stdout_fds: [2]linux.Fd
|
|
||||||
stderr_fds: [2]linux.Fd
|
|
||||||
if attr != nil && attr.stdin != nil {
|
|
||||||
if errno = linux.pipe2(&stdin_fds, nil); errno != .NONE {
|
|
||||||
return child, _get_platform_error(errno)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if attr != nil && attr.stdout != nil {
|
|
||||||
if errno = linux.pipe2(&stdout_fds, nil); errno != .NONE {
|
|
||||||
return child, _get_platform_error(errno)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if attr != nil && attr.stderr != nil {
|
|
||||||
if errno = linux.pipe2(&stderr_fds, nil); errno != .NONE {
|
|
||||||
return child, _get_platform_error(errno)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pid: linux.Pid
|
|
||||||
if pid, errno = linux.fork(); errno != .NONE {
|
|
||||||
return child, _get_platform_error(errno)
|
|
||||||
}
|
|
||||||
|
|
||||||
IN :: 1
|
|
||||||
OUT :: 0
|
|
||||||
|
|
||||||
STDIN :: linux.Fd(0)
|
|
||||||
STDOUT :: linux.Fd(1)
|
|
||||||
STDERR :: linux.Fd(2)
|
|
||||||
|
|
||||||
if pid == 0 {
|
|
||||||
// in child process now
|
|
||||||
if attr != nil && attr.stdin != nil {
|
|
||||||
if linux.close(stdin_fds[IN]) != .NONE { linux.exit(1) }
|
|
||||||
if _, errno = linux.dup2(stdin_fds[OUT], STDIN); errno != .NONE { linux.exit(1) }
|
|
||||||
if linux.close(stdin_fds[OUT]) != .NONE { linux.exit(1) }
|
|
||||||
}
|
|
||||||
if attr != nil && attr.stdout != nil {
|
|
||||||
if linux.close(stdout_fds[OUT]) != .NONE { linux.exit(1) }
|
|
||||||
if _, errno = linux.dup2(stdout_fds[IN], STDOUT); errno != .NONE { linux.exit(1) }
|
|
||||||
if linux.close(stdout_fds[IN]) != .NONE { linux.exit(1) }
|
|
||||||
}
|
|
||||||
if attr != nil && attr.stderr != nil {
|
|
||||||
if linux.close(stderr_fds[OUT]) != .NONE { linux.exit(1) }
|
|
||||||
if _, errno = linux.dup2(stderr_fds[IN], STDERR); errno != .NONE { linux.exit(1) }
|
|
||||||
if linux.close(stderr_fds[IN]) != .NONE { linux.exit(1) }
|
|
||||||
}
|
|
||||||
|
|
||||||
if errno = linux.execveat(dir_fd, executable, &cargs[OUT], env); errno != .NONE {
|
|
||||||
print_error(stderr, _get_platform_error(errno), string(executable))
|
|
||||||
panic("execve failed to replace process")
|
|
||||||
}
|
|
||||||
unreachable()
|
|
||||||
}
|
|
||||||
|
|
||||||
// in parent process
|
|
||||||
if attr != nil && attr.stdin != nil {
|
|
||||||
linux.close(stdin_fds[OUT])
|
|
||||||
_construct_file(attr.stdin, uintptr(stdin_fds[IN]))
|
|
||||||
}
|
|
||||||
if attr != nil && attr.stdout != nil {
|
|
||||||
linux.close(stdout_fds[IN])
|
|
||||||
_construct_file(attr.stdout, uintptr(stdout_fds[OUT]))
|
|
||||||
}
|
|
||||||
if attr != nil && attr.stderr != nil {
|
|
||||||
linux.close(stderr_fds[IN])
|
|
||||||
_construct_file(attr.stderr, uintptr(stderr_fds[OUT]))
|
|
||||||
}
|
|
||||||
|
|
||||||
child.pid = int(pid)
|
|
||||||
return child, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
_process_release :: proc(p: ^Process) -> Error {
|
|
||||||
// We didn't allocate...
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
_process_kill :: proc(p: ^Process) -> Error {
|
|
||||||
res := linux.kill(linux.Pid(p.pid), .SIGKILL)
|
|
||||||
return _get_platform_error(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
_process_signal :: proc(sig: Signal, h: Signal_Handler) -> Error {
|
|
||||||
signo: linux.Signal
|
|
||||||
switch sig {
|
|
||||||
case .Abort: signo = .SIGABRT
|
|
||||||
case .Floating_Point_Exception: signo = .SIGFPE
|
|
||||||
case .Illegal_Instruction: signo = .SIGILL
|
|
||||||
case .Interrupt: signo = .SIGINT
|
|
||||||
case .Segmentation_Fault: signo = .SIGSEGV
|
|
||||||
case .Termination: signo = .SIGTERM
|
|
||||||
}
|
|
||||||
|
|
||||||
sigact: linux.Sig_Action(int)
|
|
||||||
old: ^linux.Sig_Action(int) = nil
|
|
||||||
|
|
||||||
switch v in h {
|
|
||||||
case Signal_Handler_Special:
|
|
||||||
switch v {
|
|
||||||
case .Default:
|
|
||||||
sigact.special = .SIG_DFL
|
|
||||||
case .Ignore:
|
|
||||||
sigact.special = .SIG_IGN
|
|
||||||
}
|
|
||||||
case Signal_Handler_Proc:
|
|
||||||
sigact.handler = (linux.Sig_Handler_Fn)(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
return _get_platform_error(linux.rt_sigaction(signo, &sigact, old))
|
|
||||||
}
|
|
||||||
|
|
||||||
_process_wait :: proc(p: ^Process, t: time.Duration) -> (state: Process_State, err: Error) {
|
|
||||||
safe_state :: proc(p: Process, state: Process_State = {}) -> (Process_State, Error) {
|
|
||||||
// process_get_state can fail, so we don't want to return it directly.
|
|
||||||
if new_state, err := _process_get_state(p); err == nil {
|
|
||||||
return new_state, nil
|
|
||||||
}
|
|
||||||
return state, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
state.pid = p.pid
|
|
||||||
|
|
||||||
options: linux.Wait_Options
|
|
||||||
big_if: if t == 0 {
|
|
||||||
options += {.WNOHANG}
|
|
||||||
} else if t != time.MAX_DURATION {
|
|
||||||
ts: linux.Time_Spec = {
|
|
||||||
time_sec = uint(t / time.Second),
|
|
||||||
time_nsec = uint(t % time.Second),
|
|
||||||
}
|
|
||||||
|
|
||||||
@static has_pidfd_open: bool = true
|
|
||||||
|
|
||||||
// pidfd_open is fairly new, so don't error out on ENOSYS
|
|
||||||
pid_fd: linux.Pid_FD
|
|
||||||
errno: linux.Errno
|
|
||||||
if has_pidfd_open {
|
|
||||||
pid_fd, errno = linux.pidfd_open(linux.Pid(p.pid), nil)
|
|
||||||
if errno != .NONE && errno != .ENOSYS {
|
|
||||||
return state, _get_platform_error(errno)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if has_pidfd_open && errno != .ENOSYS {
|
|
||||||
defer linux.close(linux.Fd(pid_fd))
|
|
||||||
pollfd: [1]linux.Poll_Fd = {
|
|
||||||
{
|
|
||||||
fd = linux.Fd(pid_fd),
|
|
||||||
events = {.IN},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for {
|
|
||||||
n, e := linux.ppoll(pollfd[:], &ts, nil)
|
|
||||||
if e == .EINTR {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if e != .NONE {
|
|
||||||
return state, _get_platform_error(errno)
|
|
||||||
}
|
|
||||||
if n == 0 {
|
|
||||||
return safe_state(p^, state)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
has_pidfd_open = false
|
|
||||||
mask: bit_set[0..=63]
|
|
||||||
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 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(p.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
|
|
||||||
return safe_state(p^, state)
|
|
||||||
case .EINVAL:
|
|
||||||
return state, _get_platform_error(errno)
|
|
||||||
case .EINTR:
|
|
||||||
continue
|
|
||||||
case:
|
|
||||||
if int(info.pid) == p.pid {
|
|
||||||
break loop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
state, _ = safe_state(p^, state)
|
|
||||||
|
|
||||||
status: u32
|
|
||||||
errno: linux.Errno = .EINTR
|
|
||||||
for errno == .EINTR {
|
|
||||||
_, errno = linux.wait4(linux.Pid(p.pid), &status, options, nil)
|
|
||||||
if errno != .NONE {
|
|
||||||
return state, _get_platform_error(errno)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// terminated by exit
|
|
||||||
if linux.WIFEXITED(status) {
|
|
||||||
p.is_done = true
|
|
||||||
state.exited = true
|
|
||||||
state.exit_code = int(linux.WEXITSTATUS(status))
|
|
||||||
state.success = state.exit_code == 0
|
|
||||||
return state, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// terminated by signal
|
|
||||||
if linux.WIFSIGNALED(status) {
|
|
||||||
// NOTE: what's the correct behavior here??
|
|
||||||
p.is_done = true
|
|
||||||
state.exited = false
|
|
||||||
state.exit_code = int(linux.WTERMSIG(status))
|
|
||||||
state.success = false
|
|
||||||
return state, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return safe_state(p^, state)
|
|
||||||
}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
//+private
|
|
||||||
package os2
|
|
||||||
|
|
||||||
import "core:runtime"
|
|
||||||
import "core:time"
|
|
||||||
|
|
||||||
_alloc_command_line_arguments :: proc() -> []string {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
_exit :: proc "contextless" (_: int) -> ! {
|
|
||||||
runtime.trap()
|
|
||||||
}
|
|
||||||
|
|
||||||
_get_uid :: proc() -> int {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
_get_euid :: proc() -> int {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
_get_gid :: proc() -> int {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
_get_egid :: proc() -> int {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
_get_pid :: proc() -> int {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
_get_ppid :: proc() -> int {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
Process_Attributes_OS_Specific :: struct{}
|
|
||||||
|
|
||||||
_process_find :: proc(pid: int) -> (Process, Error) {
|
|
||||||
return Process{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
_process_get_state :: proc(p: Process) -> (Process_State, Error) {
|
|
||||||
return Process_State{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
_process_start :: proc(name: string, argv: []string, attr: ^Process_Attributes) -> (Process, Error) {
|
|
||||||
return Process{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
_process_release :: proc(p: ^Process) -> Error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
_process_kill :: proc(p: ^Process) -> Error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
_process_signal :: proc(sig: Signal, handler: Signal_Handler) -> Error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
_process_wait :: proc(p: ^Process, t: time.Duration) -> (Process_State, Error) {
|
|
||||||
return Process_State{}, nil
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user