mirror of
https://github.com/odin-lang/Odin.git
synced 2026-02-16 08:04:07 +00:00
[os2/process]: Implement missing functionality, update docs
This commit is contained in:
@@ -131,7 +131,7 @@ Process_Info_Field :: enum {
|
||||
Command_Args,
|
||||
Environment,
|
||||
Username,
|
||||
CWD,
|
||||
Working_Dir,
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -159,7 +159,7 @@ Process_Info :: struct {
|
||||
// The username of the user who started the process.
|
||||
username: string,
|
||||
// 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(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 {
|
||||
// OS-specific attributes.
|
||||
sys_attr: _Sys_Process_Attributes,
|
||||
// The working directory of the process.
|
||||
dir: string,
|
||||
// The working directory of the process. If the string has length 0, the
|
||||
// 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 process. The first element of the slice would be the executable.
|
||||
command: []string,
|
||||
@@ -329,7 +331,8 @@ Process_Desc :: struct {
|
||||
the function returns an error, an invalid handle is returned.
|
||||
|
||||
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) {
|
||||
return _process_start(desc)
|
||||
|
||||
@@ -79,7 +79,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
|
||||
need_peb := \
|
||||
.Command_Line in selection ||
|
||||
.Environment in selection ||
|
||||
.CWD in selection
|
||||
.Working_Dir in selection
|
||||
need_process_handle := need_peb || .Username in selection
|
||||
// Data obtained from process snapshots
|
||||
if need_snapprocess {
|
||||
@@ -122,6 +122,8 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
|
||||
windows.CloseHandle(ph)
|
||||
}
|
||||
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"))
|
||||
if ntdll_lib == nil {
|
||||
err = _get_platform_error()
|
||||
@@ -206,7 +208,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
|
||||
info.fields |= {.Environment}
|
||||
info.environment = envs
|
||||
}
|
||||
if .CWD in selection {
|
||||
if .Working_Dir in selection {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator())
|
||||
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
|
||||
return
|
||||
}
|
||||
info.fields |= {.CWD}
|
||||
info.cwd = cwd
|
||||
info.fields |= {.Working_Dir}
|
||||
info.working_dir = cwd
|
||||
}
|
||||
}
|
||||
if .Username in selection {
|
||||
@@ -249,7 +251,7 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields
|
||||
need_peb := \
|
||||
.Command_Line in selection ||
|
||||
.Environment in selection ||
|
||||
.CWD in selection
|
||||
.Working_Dir in selection
|
||||
// Data obtained from process snapshots
|
||||
if need_snapprocess {
|
||||
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.environment = envs
|
||||
}
|
||||
if .CWD in selection {
|
||||
if .Working_Dir in selection {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator())
|
||||
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
|
||||
return
|
||||
}
|
||||
info.fields |= {.CWD}
|
||||
info.cwd = cwd
|
||||
info.fields |= {.Working_Dir}
|
||||
info.working_dir = cwd
|
||||
}
|
||||
}
|
||||
if .Username in selection {
|
||||
@@ -463,11 +465,18 @@ _current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime
|
||||
info.fields += {.Username}
|
||||
info.username = username
|
||||
}
|
||||
if .Working_Dir in selection {
|
||||
// TODO(flysand): Implement this by reading PEB
|
||||
err = .Mode_Not_Implemented
|
||||
return
|
||||
}
|
||||
err = nil
|
||||
return
|
||||
}
|
||||
|
||||
_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
|
||||
if .Mem_Read in flags {
|
||||
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)
|
||||
stdin_handle := windows.GetStdHandle(windows.STD_INPUT_HANDLE)
|
||||
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 {
|
||||
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_ok := windows.CreateProcessW(
|
||||
@@ -519,7 +535,7 @@ _process_start :: proc(desc: Process_Desc) -> (Process, Error) {
|
||||
true,
|
||||
windows.CREATE_UNICODE_ENVIRONMENT|windows.NORMAL_PRIORITY_CLASS,
|
||||
raw_data(environment_block_w),
|
||||
nil,
|
||||
working_dir_w,
|
||||
&windows.STARTUPINFOW {
|
||||
cb = size_of(windows.STARTUPINFOW),
|
||||
hStdError = stderr_handle,
|
||||
@@ -578,6 +594,10 @@ _process_close :: 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) {
|
||||
return _get_platform_error()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user