mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 15:18:49 +00:00
[os2/process]: Implement missing functionality, update docs
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user