commit cf910ba4f353e80592135912e4d8b42415bffb1e
parent 4e698dee2fb03a902881aa74a33092053a82612e
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date: Wed, 6 Dec 2023 20:48:12 +0000
Fix leaking pipes
Diffstat:
3 files changed, 44 insertions(+), 22 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
@@ -3,7 +3,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
project(
Stellar
- VERSION 1.1.1
+ VERSION 1.1.2
DESCRIPTION "Chess engine written in C++"
HOMEPAGE_URL https://git.dimitrijedobrota.com/stellar.git
LANGUAGES CXX
diff --git a/src/arena/engine.cpp b/src/arena/engine.cpp
@@ -6,26 +6,31 @@
#include <sys/wait.h>
#include <unistd.h>
-
-uint16_t Engine::id_t = 0;
-Engine::Engine(const char *file) : file(file) {
- if (pipe(fd_to) < 0 || pipe(fd_from) < 0) {
+Engine::Pipes::Pipes() {
+ if (pipe(fd) < 0 || pipe(fd) < 0) {
logger::error("pipe");
throw std::runtime_error("pipe failed");
}
+}
+
- if ((engine_pid = fork()) > 0) {
+void Engine::Pipes::close() {
+ if (::close(fd[0]) < 0 || ::close(fd[1])) {
+ logger::error("close");
+ throw std::runtime_error("close failed");
+ }
+ closed = true;
+}
+
+uint16_t Engine::id_t = 0;
+Engine::Engine(const char *file) : file(file) {
+ if ((engine_pid = fork()) == 0) {
start_engine();
} else if (engine_pid < 0) {
logger::error("fork");
throw std::runtime_error("fork failed");
}
- if (close(fd_to[0]) < 0 || close(fd_from[1])) {
- logger::error("close");
- throw std::runtime_error("close failed");
- }
-
send("uci");
logger::log(std::format("Engine {}: waiting for uciok from {}", id, file));
@@ -47,8 +52,8 @@ Engine::~Engine() {
waitpid(engine_pid, nullptr, 0);
// kill(engine_pid, SIGKILL);
- if (close(fd_to[1]) < 0) logger::error("close");
- if (close(fd_from[0]) < 0) logger::error("close");
+ pipeFrom.close();
+ pripeTo.close();
logger::log("Engine: destroyed", logger::Debug);
}
@@ -57,7 +62,7 @@ void Engine::send(std::string &&command) {
const char *buffer = command.data();
size_t to_write = command.size();
while (to_write) {
- ssize_t size = write(fd_to[1], buffer, to_write);
+ ssize_t size = write(pripeTo[1], buffer, to_write);
if (size == -1) {
logger::error("write");
throw std::runtime_error("write failed");
@@ -80,7 +85,7 @@ std::string Engine::receive() {
return response;
}
- if ((size = read(fd_from[0], rb + rb_size, sizeof(rb) - rb_size)) == -1) {
+ if ((size = read(pipeFrom[0], rb + rb_size, sizeof(rb) - rb_size)) == -1) {
logger::error("read");
throw std::runtime_error("read failed");
}
@@ -105,16 +110,14 @@ std::string Engine::receive() {
}
[[noreturn]] void Engine::start_engine() {
- if (close(fd_to[1]) < 0 || close(fd_from[0])) {
- logger::error("close");
- throw std::runtime_error("close failed");
- }
-
- if (dup2(fd_to[0], 0) < 0 || dup2(fd_from[1], 1) < 0) {
+ if (dup2(pripeTo[0], 0) < 0 || dup2(pipeFrom[1], 1) < 0) {
logger::error("dup2");
throw std::runtime_error("dup2 failed");
}
+ pipeFrom.close();
+ pripeTo.close();
+
execl(file, file, (char *)nullptr);
logger::error("execl");
throw std::runtime_error("execl failed");
diff --git a/src/arena/engine.hpp b/src/arena/engine.hpp
@@ -18,10 +18,29 @@ class Engine {
std::string receive();
private:
+ class Pipes {
+ public:
+ Pipes();
+ Pipes(const Pipes &) = delete;
+ Pipes &operator=(const Pipes &) = delete;
+
+ ~Pipes() {
+ if (!closed) close();
+ }
+
+ void close();
+
+ int operator[](int idx) { return fd[idx]; }
+
+ private:
+ int fd[2]{};
+ bool closed = false;
+ };
+
[[noreturn]] void start_engine();
const char *file = nullptr;
- int fd_to[2]{}, fd_from[2]{};
+ Pipes pipeFrom, pripeTo;
pid_t engine_pid;
std::string name, author;