连接器客户端
This commit is contained in:
1 parent
d10807d877
commit
41151b7f8b
28 files changed
+2195
-12
No files matched your search
@@ -0,0 +1,75 @@
|
||||
#ifndef _WIN32
|
||||
|
||||
#include "platform.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <csignal>
|
||||
#include <fcntl.h>
|
||||
#include <stdexcept>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <thread>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace connector {
|
||||
|
||||
ProcessResult run_process(const std::string& executable,
|
||||
const std::vector<std::string>& arguments,
|
||||
const std::filesystem::path& working_directory,
|
||||
int timeout_seconds) {
|
||||
int output_pipe[2];
|
||||
if (pipe(output_pipe) != 0) throw std::runtime_error("无法创建 Spine 输出管道");
|
||||
const pid_t child = fork();
|
||||
if (child < 0) {
|
||||
close(output_pipe[0]);
|
||||
close(output_pipe[1]);
|
||||
throw std::runtime_error("无法启动 Spine 进程");
|
||||
}
|
||||
if (child == 0) {
|
||||
close(output_pipe[0]);
|
||||
dup2(output_pipe[1], STDOUT_FILENO);
|
||||
dup2(output_pipe[1], STDERR_FILENO);
|
||||
close(output_pipe[1]);
|
||||
if (!working_directory.empty()) chdir(working_directory.c_str());
|
||||
std::vector<char*> argv;
|
||||
argv.push_back(const_cast<char*>(executable.c_str()));
|
||||
for (const std::string& argument : arguments) argv.push_back(const_cast<char*>(argument.c_str()));
|
||||
argv.push_back(nullptr);
|
||||
execv(executable.c_str(), argv.data());
|
||||
_exit(127);
|
||||
}
|
||||
|
||||
close(output_pipe[1]);
|
||||
fcntl(output_pipe[0], F_SETFL, fcntl(output_pipe[0], F_GETFL) | O_NONBLOCK);
|
||||
ProcessResult result;
|
||||
int status = 0;
|
||||
const auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(timeout_seconds);
|
||||
while (true) {
|
||||
char buffer[8192];
|
||||
const ssize_t count = read(output_pipe[0], buffer, sizeof(buffer));
|
||||
if (count > 0 && result.output.size() < 4 * 1024 * 1024) result.output.append(buffer, static_cast<std::size_t>(count));
|
||||
const pid_t state = waitpid(child, &status, WNOHANG);
|
||||
if (state == child) break;
|
||||
if (std::chrono::steady_clock::now() >= deadline) {
|
||||
result.timed_out = true;
|
||||
kill(child, SIGKILL);
|
||||
waitpid(child, &status, 0);
|
||||
break;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
}
|
||||
while (true) {
|
||||
char buffer[8192];
|
||||
const ssize_t count = read(output_pipe[0], buffer, sizeof(buffer));
|
||||
if (count <= 0) break;
|
||||
if (result.output.size() < 4 * 1024 * 1024) result.output.append(buffer, static_cast<std::size_t>(count));
|
||||
}
|
||||
close(output_pipe[0]);
|
||||
if (WIFEXITED(status)) result.exit_code = WEXITSTATUS(status);
|
||||
else if (WIFSIGNALED(status)) result.exit_code = 128 + WTERMSIG(status);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace connector
|
||||
|
||||
#endif
|
||||
Reference in new issue
Block a user