#ifndef _WIN32 #include "platform.hpp" #include #include #include #include #include #include #include #include namespace connector { ProcessResult run_process(const std::string& executable, const std::vector& 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 argv; argv.push_back(const_cast(executable.c_str())); for (const std::string& argument : arguments) argv.push_back(const_cast(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(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(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