Merge pull request #90358 from KoBeWi/finding_errors_in_other_apps
Add `OS.get_process_exit_code()` method
This commit is contained in:
commit
7210d6cb43
|
@ -338,6 +338,10 @@ bool OS::is_process_running(int p_pid) const {
|
||||||
return ::OS::get_singleton()->is_process_running(p_pid);
|
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 {
|
int OS::get_process_id() const {
|
||||||
return ::OS::get_singleton()->get_process_id();
|
return ::OS::get_singleton()->get_process_id();
|
||||||
}
|
}
|
||||||
|
@ -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_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("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("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("get_process_id"), &OS::get_process_id);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("has_environment", "variable"), &OS::has_environment);
|
ClassDB::bind_method(D_METHOD("has_environment", "variable"), &OS::has_environment);
|
||||||
|
|
|
@ -164,6 +164,7 @@ public:
|
||||||
Error shell_show_in_file_manager(const String &p_path, bool p_open_folder = true);
|
Error shell_show_in_file_manager(const String &p_path, bool p_open_folder = true);
|
||||||
|
|
||||||
bool is_process_running(int p_pid) const;
|
bool is_process_running(int p_pid) const;
|
||||||
|
int get_process_exit_code(int p_pid) const;
|
||||||
int get_process_id() const;
|
int get_process_id() const;
|
||||||
|
|
||||||
void set_restart_on_exit(bool p_restart, const Vector<String> &p_restart_arguments = Vector<String>());
|
void set_restart_on_exit(bool p_restart, const Vector<String> &p_restart_arguments = Vector<String>());
|
||||||
|
|
|
@ -176,6 +176,7 @@ public:
|
||||||
virtual Error kill(const ProcessID &p_pid) = 0;
|
virtual Error kill(const ProcessID &p_pid) = 0;
|
||||||
virtual int get_process_id() const;
|
virtual int get_process_id() const;
|
||||||
virtual bool is_process_running(const ProcessID &p_pid) const = 0;
|
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 void vibrate_handheld(int p_duration_ms = 500) {}
|
||||||
|
|
||||||
virtual Error shell_open(const String &p_uri);
|
virtual Error shell_open(const String &p_uri);
|
||||||
|
|
|
@ -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].
|
[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>
|
</description>
|
||||||
</method>
|
</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.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="get_process_id" qualifiers="const">
|
<method name="get_process_id" qualifiers="const">
|
||||||
<return type="int" />
|
<return type="int" />
|
||||||
<description>
|
<description>
|
||||||
Returns the number used by the host machine to uniquely identify this application.
|
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>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="get_processor_count" qualifiers="const">
|
<method name="get_processor_count" qualifiers="const">
|
||||||
|
@ -592,7 +601,7 @@
|
||||||
<param index="0" name="pid" type="int" />
|
<param index="0" name="pid" type="int" />
|
||||||
<description>
|
<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].
|
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>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="is_restart_on_exit_set" qualifiers="const">
|
<method name="is_restart_on_exit_set" qualifiers="const">
|
||||||
|
|
|
@ -168,11 +168,13 @@ void OS_Unix::initialize_core() {
|
||||||
|
|
||||||
NetSocketPosix::make_default();
|
NetSocketPosix::make_default();
|
||||||
IPUnix::make_default();
|
IPUnix::make_default();
|
||||||
|
process_map = memnew((HashMap<ProcessID, ProcessInfo>));
|
||||||
|
|
||||||
_setup_clock();
|
_setup_clock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OS_Unix::finalize_core() {
|
void OS_Unix::finalize_core() {
|
||||||
|
memdelete(process_map);
|
||||||
NetSocketPosix::cleanup();
|
NetSocketPosix::cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -582,6 +584,11 @@ Dictionary OS_Unix::execute_with_pipe(const String &p_path, const List<String> &
|
||||||
err_pipe.instantiate();
|
err_pipe.instantiate();
|
||||||
err_pipe->open_existing(pipe_err[0], 0);
|
err_pipe->open_existing(pipe_err[0], 0);
|
||||||
|
|
||||||
|
ProcessInfo pi;
|
||||||
|
process_map_mutex.lock();
|
||||||
|
process_map->insert(pid, pi);
|
||||||
|
process_map_mutex.unlock();
|
||||||
|
|
||||||
ret["stdio"] = main_pipe;
|
ret["stdio"] = main_pipe;
|
||||||
ret["stderr"] = err_pipe;
|
ret["stderr"] = err_pipe;
|
||||||
ret["pid"] = pid;
|
ret["pid"] = pid;
|
||||||
|
@ -698,6 +705,11 @@ Error OS_Unix::create_process(const String &p_path, const List<String> &p_argume
|
||||||
raise(SIGKILL);
|
raise(SIGKILL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ProcessInfo pi;
|
||||||
|
process_map_mutex.lock();
|
||||||
|
process_map->insert(pid, pi);
|
||||||
|
process_map_mutex.unlock();
|
||||||
|
|
||||||
if (r_child_id) {
|
if (r_child_id) {
|
||||||
*r_child_id = pid;
|
*r_child_id = pid;
|
||||||
}
|
}
|
||||||
|
@ -720,14 +732,45 @@ int OS_Unix::get_process_id() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OS_Unix::is_process_running(const ProcessID &p_pid) 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;
|
int status = 0;
|
||||||
if (waitpid(p_pid, &status, WNOHANG) != 0) {
|
if (waitpid(p_pid, &status, WNOHANG) != 0) {
|
||||||
|
if (pi) {
|
||||||
|
pi->is_running = false;
|
||||||
|
pi->exit_code = status;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
String OS_Unix::get_locale() const {
|
||||||
if (!has_environment("LANG")) {
|
if (!has_environment("LANG")) {
|
||||||
return "en";
|
return "en";
|
||||||
|
|
|
@ -37,6 +37,13 @@
|
||||||
#include "drivers/unix/ip_unix.h"
|
#include "drivers/unix/ip_unix.h"
|
||||||
|
|
||||||
class OS_Unix : public OS {
|
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:
|
protected:
|
||||||
// UNIX only handles the core functions.
|
// UNIX only handles the core functions.
|
||||||
// inheriting platforms under unix (eg. X11) should handle the rest
|
// inheriting platforms under unix (eg. X11) should handle the rest
|
||||||
|
@ -81,6 +88,7 @@ public:
|
||||||
virtual Error kill(const ProcessID &p_pid) override;
|
virtual Error kill(const ProcessID &p_pid) override;
|
||||||
virtual int get_process_id() const override;
|
virtual int get_process_id() const override;
|
||||||
virtual bool is_process_running(const ProcessID &p_pid) 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 bool has_environment(const String &p_var) const override;
|
||||||
virtual String get_environment(const String &p_var) const override;
|
virtual String get_environment(const String &p_var) const override;
|
||||||
|
|
|
@ -132,6 +132,10 @@ bool OS_Web::is_process_running(const ProcessID &p_pid) const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int OS_Web::get_process_exit_code(const ProcessID &p_pid) const {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int OS_Web::get_processor_count() const {
|
int OS_Web::get_processor_count() const {
|
||||||
return godot_js_os_hw_concurrency_get();
|
return godot_js_os_hw_concurrency_get();
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,6 +85,7 @@ public:
|
||||||
Error kill(const ProcessID &p_pid) override;
|
Error kill(const ProcessID &p_pid) override;
|
||||||
int get_process_id() const override;
|
int get_process_id() const override;
|
||||||
bool is_process_running(const ProcessID &p_pid) 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;
|
int get_processor_count() const override;
|
||||||
String get_unique_id() const override;
|
String get_unique_id() const override;
|
||||||
int get_default_thread_pool_size() const override { return 1; }
|
int get_default_thread_pool_size() const override { return 1; }
|
||||||
|
|
|
@ -867,7 +867,9 @@ Dictionary OS_Windows::execute_with_pipe(const String &p_path, const List<String
|
||||||
CloseHandle(pipe_err[1]);
|
CloseHandle(pipe_err[1]);
|
||||||
|
|
||||||
ProcessID pid = pi.pi.dwProcessId;
|
ProcessID pid = pi.pi.dwProcessId;
|
||||||
|
process_map_mutex.lock();
|
||||||
process_map->insert(pid, pi);
|
process_map->insert(pid, pi);
|
||||||
|
process_map_mutex.unlock();
|
||||||
|
|
||||||
Ref<FileAccessWindowsPipe> main_pipe;
|
Ref<FileAccessWindowsPipe> main_pipe;
|
||||||
main_pipe.instantiate();
|
main_pipe.instantiate();
|
||||||
|
@ -1014,13 +1016,16 @@ Error OS_Windows::create_process(const String &p_path, const List<String> &p_arg
|
||||||
if (r_child_id) {
|
if (r_child_id) {
|
||||||
*r_child_id = pid;
|
*r_child_id = pid;
|
||||||
}
|
}
|
||||||
|
process_map_mutex.lock();
|
||||||
process_map->insert(pid, pi);
|
process_map->insert(pid, pi);
|
||||||
|
process_map_mutex.unlock();
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error OS_Windows::kill(const ProcessID &p_pid) {
|
Error OS_Windows::kill(const ProcessID &p_pid) {
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
MutexLock lock(process_map_mutex);
|
||||||
if (process_map->has(p_pid)) {
|
if (process_map->has(p_pid)) {
|
||||||
const PROCESS_INFORMATION pi = (*process_map)[p_pid].pi;
|
const PROCESS_INFORMATION pi = (*process_map)[p_pid].pi;
|
||||||
process_map->erase(p_pid);
|
process_map->erase(p_pid);
|
||||||
|
@ -1046,24 +1051,58 @@ int OS_Windows::get_process_id() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OS_Windows::is_process_running(const ProcessID &p_pid) const {
|
bool OS_Windows::is_process_running(const ProcessID &p_pid) const {
|
||||||
|
MutexLock lock(process_map_mutex);
|
||||||
if (!process_map->has(p_pid)) {
|
if (!process_map->has(p_pid)) {
|
||||||
return false;
|
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;
|
DWORD dw_exit_code = 0;
|
||||||
if (!GetExitCodeProcess(pi.hProcess, &dw_exit_code)) {
|
if (!GetExitCodeProcess(pi.hProcess, &dw_exit_code)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dw_exit_code != STILL_ACTIVE) {
|
if (dw_exit_code != STILL_ACTIVE) {
|
||||||
|
info.is_running = false;
|
||||||
|
info.exit_code = dw_exit_code;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
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) {
|
Error OS_Windows::set_cwd(const String &p_cwd) {
|
||||||
if (_wchdir((LPCWSTR)(p_cwd.utf16().get_data())) != 0) {
|
if (_wchdir((LPCWSTR)(p_cwd.utf16().get_data())) != 0) {
|
||||||
return ERR_CANT_OPEN;
|
return ERR_CANT_OPEN;
|
||||||
|
|
|
@ -150,8 +150,11 @@ protected:
|
||||||
struct ProcessInfo {
|
struct ProcessInfo {
|
||||||
STARTUPINFO si;
|
STARTUPINFO si;
|
||||||
PROCESS_INFORMATION pi;
|
PROCESS_INFORMATION pi;
|
||||||
|
mutable bool is_running = true;
|
||||||
|
mutable int exit_code = -1;
|
||||||
};
|
};
|
||||||
HashMap<ProcessID, ProcessInfo> *process_map = nullptr;
|
HashMap<ProcessID, ProcessInfo> *process_map = nullptr;
|
||||||
|
Mutex process_map_mutex;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override;
|
virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override;
|
||||||
|
@ -189,6 +192,7 @@ public:
|
||||||
virtual Error kill(const ProcessID &p_pid) override;
|
virtual Error kill(const ProcessID &p_pid) override;
|
||||||
virtual int get_process_id() const override;
|
virtual int get_process_id() const override;
|
||||||
virtual bool is_process_running(const ProcessID &p_pid) 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 bool has_environment(const String &p_var) const override;
|
||||||
virtual String get_environment(const String &p_var) const override;
|
virtual String get_environment(const String &p_var) const override;
|
||||||
|
|
Loading…
Reference in New Issue