stellar

Stellar - UCI Chess engine written in C++20
git clone git://git.dimitrijedobrota.com/stellar.git
Log | Files | Refs | README | LICENSE

commit cf910ba4f353e80592135912e4d8b42415bffb1e
parent 4e698dee2fb03a902881aa74a33092053a82612e
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date:   Wed,  6 Dec 2023 20:48:12 +0000

Fix leaking pipes

Diffstat:
MCMakeLists.txt | 2+-
Msrc/arena/engine.cpp | 43+++++++++++++++++++++++--------------------
Msrc/arena/engine.hpp | 21++++++++++++++++++++-
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;