[os2/process]: Implement missing functionality, update docs

This commit is contained in:
flysand7
2024-07-15 20:24:05 +11:00
parent b7ccfed9af
commit 255f00d971
2 changed files with 40 additions and 17 deletions
+9 -6
View File
@@ -131,7 +131,7 @@ Process_Info_Field :: enum {
Command_Args, Command_Args,
Environment, Environment,
Username, Username,
CWD, Working_Dir,
} }
/* /*
@@ -159,7 +159,7 @@ Process_Info :: struct {
// The username of the user who started the process. // The username of the user who started the process.
username: string, username: string,
// The current working directory of the process. // The current working directory of the process.
cwd: string, working_dir: string,
} }
/* /*
@@ -244,7 +244,7 @@ free_process_info :: proc(pi: Process_Info, allocator: runtime.Allocator) {
delete(s, allocator) delete(s, allocator)
} }
delete(pi.environment, allocator) delete(pi.environment, allocator)
delete(pi.cwd, allocator) delete(pi.working_dir, allocator)
} }
/* /*
@@ -288,8 +288,10 @@ process_open :: proc(pid: int, flags := Process_Open_Flags {}) -> (Process, Erro
Process_Desc :: struct { Process_Desc :: struct {
// OS-specific attributes. // OS-specific attributes.
sys_attr: _Sys_Process_Attributes, sys_attr: _Sys_Process_Attributes,
// The working directory of the process. // The working directory of the process. If the string has length 0, the
dir: string, // working directory is assumed to be the current working directory of the
// current process.
working_dir: string,
// The command to run. Each element of the slice is a separate argument to // The command to run. Each element of the slice is a separate argument to
// the process. The first element of the slice would be the executable. // the process. The first element of the slice would be the executable.
command: []string, command: []string,
@@ -329,7 +331,8 @@ Process_Desc :: struct {
the function returns an error, an invalid handle is returned. the function returns an error, an invalid handle is returned.
This procedure is not thread-safe. It may alter the inheritance properties This procedure is not thread-safe. It may alter the inheritance properties
of file handles. of file handles in an unpredictable manner. In case multiple threads change
handle inheritance properties, make sure to serialize all those calls.
*/ */
process_start :: proc(desc := Process_Desc {}) -> (Process, Error) { process_start :: proc(desc := Process_Desc {}) -> (Process, Error) {
return _process_start(desc) return _process_start(desc)
+31 -11
View File
@@ -79,7 +79,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
need_peb := \ need_peb := \
.Command_Line in selection || .Command_Line in selection ||
.Environment in selection || .Environment in selection ||
.CWD in selection .Working_Dir in selection
need_process_handle := need_peb || .Username in selection need_process_handle := need_peb || .Username in selection
// Data obtained from process snapshots // Data obtained from process snapshots
if need_snapprocess { if need_snapprocess {
@@ -122,6 +122,8 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
windows.CloseHandle(ph) windows.CloseHandle(ph)
} }
if need_peb { if need_peb {
// TODO(flysand): This was not tested with WOW64 or 32-bit processes,
// might need to be revised later when issues occur.
ntdll_lib := windows.LoadLibraryW(windows.L("ntdll.dll")) ntdll_lib := windows.LoadLibraryW(windows.L("ntdll.dll"))
if ntdll_lib == nil { if ntdll_lib == nil {
err = _get_platform_error() err = _get_platform_error()
@@ -206,7 +208,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
info.fields |= {.Environment} info.fields |= {.Environment}
info.environment = envs info.environment = envs
} }
if .CWD in selection { if .Working_Dir in selection {
TEMP_ALLOCATOR_GUARD() TEMP_ALLOCATOR_GUARD()
cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator()) cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator())
if !read_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w, &bytes_read) { if !read_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w, &bytes_read) {
@@ -218,8 +220,8 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
err = cwd_err err = cwd_err
return return
} }
info.fields |= {.CWD} info.fields |= {.Working_Dir}
info.cwd = cwd info.working_dir = cwd
} }
} }
if .Username in selection { if .Username in selection {
@@ -249,7 +251,7 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields
need_peb := \ need_peb := \
.Command_Line in selection || .Command_Line in selection ||
.Environment in selection || .Environment in selection ||
.CWD in selection .Working_Dir in selection
// Data obtained from process snapshots // Data obtained from process snapshots
if need_snapprocess { if need_snapprocess {
entry, entry_err := _process_entry_by_pid(info.pid) entry, entry_err := _process_entry_by_pid(info.pid)
@@ -361,7 +363,7 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields
info.fields |= {.Environment} info.fields |= {.Environment}
info.environment = envs info.environment = envs
} }
if .CWD in selection { if .Working_Dir in selection {
TEMP_ALLOCATOR_GUARD() TEMP_ALLOCATOR_GUARD()
cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator()) cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator())
if !read_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w, &bytes_read) { if !read_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w, &bytes_read) {
@@ -373,8 +375,8 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields
err = cwd_err err = cwd_err
return return
} }
info.fields |= {.CWD} info.fields |= {.Working_Dir}
info.cwd = cwd info.working_dir = cwd
} }
} }
if .Username in selection { if .Username in selection {
@@ -463,11 +465,18 @@ _current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime
info.fields += {.Username} info.fields += {.Username}
info.username = username info.username = username
} }
if .Working_Dir in selection {
// TODO(flysand): Implement this by reading PEB
err = .Mode_Not_Implemented
return
}
err = nil err = nil
return return
} }
_process_open :: proc(pid: int, flags: Process_Open_Flags) -> (Process, Error) { _process_open :: proc(pid: int, flags: Process_Open_Flags) -> (Process, Error) {
// Note(flysand): The handle will be used for querying information so we
// take the necessary permissions right away.
dwDesiredAccess := windows.PROCESS_QUERY_LIMITED_INFORMATION | windows.SYNCHRONIZE dwDesiredAccess := windows.PROCESS_QUERY_LIMITED_INFORMATION | windows.SYNCHRONIZE
if .Mem_Read in flags { if .Mem_Read in flags {
dwDesiredAccess |= windows.PROCESS_VM_READ dwDesiredAccess |= windows.PROCESS_VM_READ
@@ -505,10 +514,17 @@ _process_start :: proc(desc: Process_Desc) -> (Process, Error) {
stdout_handle := windows.GetStdHandle(windows.STD_OUTPUT_HANDLE) stdout_handle := windows.GetStdHandle(windows.STD_OUTPUT_HANDLE)
stdin_handle := windows.GetStdHandle(windows.STD_INPUT_HANDLE) stdin_handle := windows.GetStdHandle(windows.STD_INPUT_HANDLE)
if desc.stdout != nil { if desc.stdout != nil {
stdout_handle = windows.HANDLE(desc.stdout.impl.fd) stdout_handle = windows.HANDLE((^File_Impl)(desc.stdout.impl).fd)
} }
if desc.stderr != nil { if desc.stderr != nil {
stderr_handle = windows.HANDLE(desc.stderr.impl.fd) stderr_handle = windows.HANDLE((^File_Impl)(desc.stderr.impl).fd)
}
if desc.stdin != nil {
stdin_handle = windows.HANDLE((^File_Impl)(desc.stderr.impl).fd)
}
working_dir_w := windows.wstring(nil)
if len(desc.working_dir) > 0 {
working_dir_w = windows.utf8_to_wstring(desc.working_dir, temp_allocator())
} }
process_info: windows.PROCESS_INFORMATION = --- process_info: windows.PROCESS_INFORMATION = ---
process_ok := windows.CreateProcessW( process_ok := windows.CreateProcessW(
@@ -519,7 +535,7 @@ _process_start :: proc(desc: Process_Desc) -> (Process, Error) {
true, true,
windows.CREATE_UNICODE_ENVIRONMENT|windows.NORMAL_PRIORITY_CLASS, windows.CREATE_UNICODE_ENVIRONMENT|windows.NORMAL_PRIORITY_CLASS,
raw_data(environment_block_w), raw_data(environment_block_w),
nil, working_dir_w,
&windows.STARTUPINFOW { &windows.STARTUPINFOW {
cb = size_of(windows.STARTUPINFOW), cb = size_of(windows.STARTUPINFOW),
hStdError = stderr_handle, hStdError = stderr_handle,
@@ -578,6 +594,10 @@ _process_close :: proc(process: Process) -> (Error) {
} }
_process_kill :: proc(process: Process) -> (Error) { _process_kill :: proc(process: Process) -> (Error) {
// Note(flysand): This is different than what the task manager's "kill process"
// functionality does, as we don't try to send WM_CLOSE message first. This
// is quite a rough way to kill the process, which should be consistent with
// linux. The error code 9 is to mimic SIGKILL event.
if !windows.TerminateProcess(windows.HANDLE(process.handle), 9) { if !windows.TerminateProcess(windows.HANDLE(process.handle), 9) {
return _get_platform_error() return _get_platform_error()
} }