Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add OS.get_process_exit_code() method #90358

Merged
merged 1 commit into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions core/core_bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,10 @@ bool OS::is_process_running(int p_pid) const {
return ::OS::get_singleton()->is_process_running(p_pid);
}

int OS::get_process_exit_code(int p_pid) const {
return ::OS::get_singleton()->get_process_exit_code(p_pid);
}

int OS::get_process_id() const {
return ::OS::get_singleton()->get_process_id();
}
Expand Down Expand Up @@ -602,6 +606,7 @@ void OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("shell_open", "uri"), &OS::shell_open);
ClassDB::bind_method(D_METHOD("shell_show_in_file_manager", "file_or_dir_path", "open_folder"), &OS::shell_show_in_file_manager, DEFVAL(true));
ClassDB::bind_method(D_METHOD("is_process_running", "pid"), &OS::is_process_running);
ClassDB::bind_method(D_METHOD("get_process_exit_code", "pid"), &OS::get_process_exit_code);
ClassDB::bind_method(D_METHOD("get_process_id"), &OS::get_process_id);

ClassDB::bind_method(D_METHOD("has_environment", "variable"), &OS::has_environment);
Expand Down
1 change: 1 addition & 0 deletions core/core_bind.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ class OS : public Object {
Error shell_show_in_file_manager(const String &p_path, bool p_open_folder = true);

bool is_process_running(int p_pid) const;
int get_process_exit_code(int p_pid) const;
int get_process_id() const;

void set_restart_on_exit(bool p_restart, const Vector<String> &p_restart_arguments = Vector<String>());
Expand Down
1 change: 1 addition & 0 deletions core/os/os.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ class OS {
virtual Error kill(const ProcessID &p_pid) = 0;
virtual int get_process_id() const;
virtual bool is_process_running(const ProcessID &p_pid) const = 0;
virtual int get_process_exit_code(const ProcessID &p_pid) const = 0;
virtual void vibrate_handheld(int p_duration_ms = 500) {}

virtual Error shell_open(const String &p_uri);
Expand Down
13 changes: 11 additions & 2 deletions doc/classes/OS.xml
Original file line number Diff line number Diff line change
Expand Up @@ -408,11 +408,20 @@
[b]Note:[/b] On Web platforms, it is still possible to determine the host platform's OS with feature tags. See [method has_feature].
</description>
</method>
<method name="get_process_exit_code" qualifiers="const">
<return type="int" />
<param index="0" name="pid" type="int" />
<description>
Returns the exit code of a spawned process once it has finished running (see [method is_process_running]).
Returns [code]-1[/code] if the [param pid] is not a PID of a spawned child process, the process is still running, or the method is not implemented for the current platform.
[b]Note:[/b] This method is implemented on Android, Linux, macOS and Windows.
KoBeWi marked this conversation as resolved.
Show resolved Hide resolved
</description>
</method>
<method name="get_process_id" qualifiers="const">
<return type="int" />
<description>
Returns the number used by the host machine to uniquely identify this application.
[b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and Windows.
[b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS, and Windows.
</description>
</method>
<method name="get_processor_count" qualifiers="const">
Expand Down Expand Up @@ -592,7 +601,7 @@
<param index="0" name="pid" type="int" />
<description>
Returns [code]true[/code] if the child process ID ([param pid]) is still running or [code]false[/code] if it has terminated. [param pid] must be a valid ID generated from [method create_process].
[b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and Windows.
[b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS, and Windows.
</description>
</method>
<method name="is_restart_on_exit_set" qualifiers="const">
Expand Down
43 changes: 43 additions & 0 deletions drivers/unix/os_unix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,13 @@ void OS_Unix::initialize_core() {

NetSocketPosix::make_default();
IPUnix::make_default();
process_map = memnew((HashMap<ProcessID, ProcessInfo>));

_setup_clock();
}

void OS_Unix::finalize_core() {
memdelete(process_map);
NetSocketPosix::cleanup();
}

Expand Down Expand Up @@ -582,6 +584,11 @@ Dictionary OS_Unix::execute_with_pipe(const String &p_path, const List<String> &
err_pipe.instantiate();
err_pipe->open_existing(pipe_err[0], 0);

ProcessInfo pi;
process_map_mutex.lock();
process_map->insert(pid, pi);
KoBeWi marked this conversation as resolved.
Show resolved Hide resolved
process_map_mutex.unlock();

ret["stdio"] = main_pipe;
ret["stderr"] = err_pipe;
ret["pid"] = pid;
Expand Down Expand Up @@ -698,6 +705,11 @@ Error OS_Unix::create_process(const String &p_path, const List<String> &p_argume
raise(SIGKILL);
}

ProcessInfo pi;
process_map_mutex.lock();
process_map->insert(pid, pi);
process_map_mutex.unlock();

if (r_child_id) {
*r_child_id = pid;
}
Expand All @@ -720,14 +732,45 @@ int OS_Unix::get_process_id() const {
}

bool OS_Unix::is_process_running(const ProcessID &p_pid) const {
MutexLock lock(process_map_mutex);
const ProcessInfo *pi = process_map->getptr(p_pid);

if (pi && !pi->is_running) {
return false;
}

int status = 0;
if (waitpid(p_pid, &status, WNOHANG) != 0) {
if (pi) {
pi->is_running = false;
pi->exit_code = status;
}
return false;
}

return true;
}

int OS_Unix::get_process_exit_code(const ProcessID &p_pid) const {
MutexLock lock(process_map_mutex);
const ProcessInfo *pi = process_map->getptr(p_pid);

if (pi && !pi->is_running) {
return pi->exit_code;
KoBeWi marked this conversation as resolved.
Show resolved Hide resolved
}

int status = 0;
if (waitpid(p_pid, &status, WNOHANG) != 0) {
status = WIFEXITED(status) ? WEXITSTATUS(status) : status;
if (pi) {
pi->is_running = false;
pi->exit_code = status;
}
return status;
}
return -1;
}

String OS_Unix::get_locale() const {
if (!has_environment("LANG")) {
return "en";
Expand Down
8 changes: 8 additions & 0 deletions drivers/unix/os_unix.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@
#include "drivers/unix/ip_unix.h"

class OS_Unix : public OS {
struct ProcessInfo {
mutable bool is_running = true;
mutable int exit_code = -1;
};
HashMap<ProcessID, ProcessInfo> *process_map = nullptr;
Mutex process_map_mutex;

protected:
// UNIX only handles the core functions.
// inheriting platforms under unix (eg. X11) should handle the rest
Expand Down Expand Up @@ -81,6 +88,7 @@ class OS_Unix : public OS {
virtual Error kill(const ProcessID &p_pid) override;
virtual int get_process_id() const override;
virtual bool is_process_running(const ProcessID &p_pid) const override;
virtual int get_process_exit_code(const ProcessID &p_pid) const override;

virtual bool has_environment(const String &p_var) const override;
virtual String get_environment(const String &p_var) const override;
Expand Down
4 changes: 4 additions & 0 deletions platform/web/os_web.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ bool OS_Web::is_process_running(const ProcessID &p_pid) const {
return false;
}

int OS_Web::get_process_exit_code(const ProcessID &p_pid) const {
return -1;
}

int OS_Web::get_processor_count() const {
return godot_js_os_hw_concurrency_get();
}
Expand Down
1 change: 1 addition & 0 deletions platform/web/os_web.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ class OS_Web : public OS_Unix {
Error kill(const ProcessID &p_pid) override;
int get_process_id() const override;
bool is_process_running(const ProcessID &p_pid) const override;
int get_process_exit_code(const ProcessID &p_pid) const override;
int get_processor_count() const override;
String get_unique_id() const override;
int get_default_thread_pool_size() const override { return 1; }
Expand Down
41 changes: 40 additions & 1 deletion platform/windows/os_windows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -867,7 +867,9 @@ Dictionary OS_Windows::execute_with_pipe(const String &p_path, const List<String
CloseHandle(pipe_err[1]);

ProcessID pid = pi.pi.dwProcessId;
process_map_mutex.lock();
process_map->insert(pid, pi);
process_map_mutex.unlock();

Ref<FileAccessWindowsPipe> main_pipe;
main_pipe.instantiate();
Expand Down Expand Up @@ -1014,13 +1016,16 @@ Error OS_Windows::create_process(const String &p_path, const List<String> &p_arg
if (r_child_id) {
*r_child_id = pid;
}
process_map_mutex.lock();
process_map->insert(pid, pi);
process_map_mutex.unlock();

return OK;
}

Error OS_Windows::kill(const ProcessID &p_pid) {
int ret = 0;
MutexLock lock(process_map_mutex);
if (process_map->has(p_pid)) {
const PROCESS_INFORMATION pi = (*process_map)[p_pid].pi;
process_map->erase(p_pid);
Expand All @@ -1046,24 +1051,58 @@ int OS_Windows::get_process_id() const {
}

bool OS_Windows::is_process_running(const ProcessID &p_pid) const {
MutexLock lock(process_map_mutex);
if (!process_map->has(p_pid)) {
return false;
}

const PROCESS_INFORMATION &pi = (*process_map)[p_pid].pi;
const ProcessInfo &info = (*process_map)[p_pid];
if (!info.is_running) {
return false;
}

const PROCESS_INFORMATION &pi = info.pi;
DWORD dw_exit_code = 0;
if (!GetExitCodeProcess(pi.hProcess, &dw_exit_code)) {
return false;
}

if (dw_exit_code != STILL_ACTIVE) {
info.is_running = false;
info.exit_code = dw_exit_code;
return false;
}

return true;
}

int OS_Windows::get_process_exit_code(const ProcessID &p_pid) const {
MutexLock lock(process_map_mutex);
if (!process_map->has(p_pid)) {
return -1;
}

const ProcessInfo &info = (*process_map)[p_pid];
if (!info.is_running) {
return info.exit_code;
}

const PROCESS_INFORMATION &pi = info.pi;

DWORD dw_exit_code = 0;
if (!GetExitCodeProcess(pi.hProcess, &dw_exit_code)) {
return -1;
}

if (dw_exit_code == STILL_ACTIVE) {
return -1;
}

info.is_running = false;
info.exit_code = dw_exit_code;
return dw_exit_code;
}

Error OS_Windows::set_cwd(const String &p_cwd) {
if (_wchdir((LPCWSTR)(p_cwd.utf16().get_data())) != 0) {
return ERR_CANT_OPEN;
Expand Down
4 changes: 4 additions & 0 deletions platform/windows/os_windows.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,11 @@ class OS_Windows : public OS {
struct ProcessInfo {
STARTUPINFO si;
PROCESS_INFORMATION pi;
mutable bool is_running = true;
mutable int exit_code = -1;
};
HashMap<ProcessID, ProcessInfo> *process_map = nullptr;
Mutex process_map_mutex;

public:
virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override;
Expand Down Expand Up @@ -189,6 +192,7 @@ class OS_Windows : public OS {
virtual Error kill(const ProcessID &p_pid) override;
virtual int get_process_id() const override;
virtual bool is_process_running(const ProcessID &p_pid) const override;
virtual int get_process_exit_code(const ProcessID &p_pid) const override;

virtual bool has_environment(const String &p_var) const override;
virtual String get_environment(const String &p_var) const override;
Expand Down
Loading