Added a new execute method to Platform, and moved the execute method from the crash handler to platform linux.

This commit is contained in:
Relintai 2021-11-09 19:46:08 +01:00
parent c94c465d78
commit 8bd6f0aea6
5 changed files with 117 additions and 106 deletions

View File

@ -10,6 +10,10 @@ String Platform::get_executable_path() {
return arg_parser.executable_name; return arg_parser.executable_name;
} }
int Platform::execute(const String &p_path, const Vector<String> &p_arguments, bool p_blocking, int64_t *r_child_id, String *r_pipe, int *r_exitcode, Mutex *p_pipe_mutex, bool read_stderr) {
return 0;
}
Platform *Platform::get_singleton() { Platform *Platform::get_singleton() {
return _self; return _self;
} }

View File

@ -3,12 +3,16 @@
#include "arg_parser.h" #include "arg_parser.h"
#include "core/threading/mutex.h"
class Platform { class Platform {
public: public:
virtual void arg_setup(int argc, char **argv, char **envp); virtual void arg_setup(int argc, char **argv, char **envp);
virtual String get_executable_path(); virtual String get_executable_path();
virtual int execute(const String &p_path, const Vector<String> &p_arguments, bool p_blocking, int64_t *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, Mutex *p_pipe_mutex = nullptr, bool read_stderr = false);
static Platform *get_singleton(); static Platform *get_singleton();
Platform(); Platform();

View File

@ -48,111 +48,7 @@
#include "core/containers/vector.h" #include "core/containers/vector.h"
#include "core/os/platform.h" #include "core/os/platform.h"
#include "core/error_macros.h"
int execute(const String &p_path, const Vector<String> &p_arguments, bool p_blocking, int64_t *r_child_id, String *r_pipe, int *r_exitcode) {
#ifdef __EMSCRIPTEN__
// Don't compile this code at all to avoid undefined references.
// Actual virtual call goes to OS_JavaScript.
ERR_FAIL_V(ERR_BUG);
#else
bool read_stderr = false;
//Mutex *p_pipe_mutex;
if (p_blocking && r_pipe) {
String argss;
argss = "\"" + p_path + "\"";
for (int i = 0; i < p_arguments.size(); i++) {
argss += String(" \"");
argss += p_arguments[i];
argss += String("\"");
}
if (read_stderr) {
argss += " 2>&1"; // Read stderr too
} else {
argss += " 2>/dev/null"; //silence stderr
}
FILE *f = popen(argss.data(), "r");
if (!f) {
return 2;
}
//ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot pipe stream from process running with following arguments '" + argss + "'.");
char buf[65535];
while (fgets(buf, 65535, f)) {
//if (p_pipe_mutex) {
// p_pipe_mutex->lock();
//}
(*r_pipe) += String::utf8(buf);
//if (p_pipe_mutex) {
// p_pipe_mutex->unlock();
//}
}
int rv = pclose(f);
if (r_exitcode) {
*r_exitcode = WEXITSTATUS(rv);
}
return 0;
}
pid_t pid = fork();
//ERR_FAIL_COND_V(pid < 0, ERR_CANT_FORK);
return 1;
if (pid == 0) {
// is child
if (!p_blocking) {
// For non blocking calls, create a new session-ID so parent won't wait for it.
// This ensures the process won't go zombie at end.
setsid();
}
Vector<String> cs;
cs.push_back(p_path);
for (int i = 0; i < p_arguments.size(); i++) {
cs.push_back(p_arguments[i]);
}
Vector<char *> args;
for (int i = 0; i < cs.size(); i++) {
args.push_back((char *)cs[i].c_str());
}
args.push_back(0);
execvp(p_path.c_str(), &args[0]);
// still alive? something failed..
fprintf(stderr, "**ERROR** OS_Unix::execute - Could not create child process while executing: %s\n", p_path.data());
raise(SIGKILL);
}
if (p_blocking) {
int status;
waitpid(pid, &status, 0);
if (r_exitcode) {
*r_exitcode = WIFEXITED(status) ? WEXITSTATUS(status) : status;
}
} else {
if (r_child_id) {
*r_child_id = pid;
}
}
return 0;
#endif
}
static void handle_crash(int sig) { static void handle_crash(int sig) {
void *bt_buffer[256]; void *bt_buffer[256];
@ -200,7 +96,7 @@ static void handle_crash(int sig) {
// Try to get the file/line number using addr2line // Try to get the file/line number using addr2line
int ret; int ret;
int err = execute(String("addr2line"), args, true, nullptr, &output, &ret); int err = Platform::get_singleton()->execute(String("addr2line"), args, true, nullptr, &output, &ret);
if (err == 0) { if (err == 0) {
output.erase(output.size() - 1, 1); output.erase(output.size() - 1, 1);

View File

@ -65,6 +65,111 @@ String PlatformLinux::get_executable_path() {
#endif #endif
} }
//Based on Godot Engine's implementation (MIT license)
//Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.
//Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).
int PlatformLinux::execute(const String &p_path, const Vector<String> &p_arguments, bool p_blocking, int64_t *r_child_id, String *r_pipe, int *r_exitcode, Mutex *p_pipe_mutex, bool read_stderr) {
#ifdef __EMSCRIPTEN__
// Don't compile this code at all to avoid undefined references.
// Actual virtual call goes to OS_JavaScript.
RLOG_ERR("ERROR execute\n");
return;
#else
if (p_blocking && r_pipe) {
String argss;
argss = "\"" + p_path + "\"";
for (int i = 0; i < p_arguments.size(); i++) {
argss += String(" \"");
argss += p_arguments[i];
argss += String("\"");
}
if (read_stderr) {
argss += " 2>&1"; // Read stderr too
} else {
argss += " 2>/dev/null"; //silence stderr
}
FILE *f = popen(argss.data(), "r");
if (!f) {
RLOG_ERR("Cannot pipe stream from process running with following arguments '" + argss + "'.\n");
ERR_FAIL_COND_V(!f, 2); //ERR_CANT_OPEN
}
char buf[65535];
while (fgets(buf, 65535, f)) {
if (p_pipe_mutex) {
p_pipe_mutex->lock();
}
(*r_pipe) += String::utf8(buf);
if (p_pipe_mutex) {
p_pipe_mutex->unlock();
}
}
int rv = pclose(f);
if (r_exitcode) {
*r_exitcode = WEXITSTATUS(rv);
}
return 0;
}
pid_t pid = fork();
//ERR_FAIL_COND_V(pid < 0, ERR_CANT_FORK);
return 1;
if (pid == 0) {
// is child
if (!p_blocking) {
// For non blocking calls, create a new session-ID so parent won't wait for it.
// This ensures the process won't go zombie at end.
setsid();
}
Vector<String> cs;
cs.push_back(p_path);
for (int i = 0; i < p_arguments.size(); i++) {
cs.push_back(p_arguments[i]);
}
Vector<char *> args;
for (int i = 0; i < cs.size(); i++) {
args.push_back((char *)cs[i].c_str());
}
args.push_back(0);
execvp(p_path.c_str(), &args[0]);
// still alive? something failed..
fprintf(stderr, "**ERROR** OS_Unix::execute - Could not create child process while executing: %s\n", p_path.data());
raise(SIGKILL);
}
if (p_blocking) {
int status;
waitpid(pid, &status, 0);
if (r_exitcode) {
*r_exitcode = WIFEXITED(status) ? WEXITSTATUS(status) : status;
}
} else {
if (r_child_id) {
*r_child_id = pid;
}
}
return 0;
#endif
}
PlatformLinux::PlatformLinux() : Platform() { PlatformLinux::PlatformLinux() : Platform() {
} }
PlatformLinux::~PlatformLinux() { PlatformLinux::~PlatformLinux() {

View File

@ -7,6 +7,8 @@ class PlatformLinux : public Platform {
public: public:
virtual String get_executable_path(); virtual String get_executable_path();
virtual int execute(const String &p_path, const Vector<String> &p_arguments, bool p_blocking, int64_t *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, Mutex *p_pipe_mutex = nullptr, bool read_stderr = false);
PlatformLinux(); PlatformLinux();
virtual ~PlatformLinux(); virtual ~PlatformLinux();