/* * @project The CERN Tape Archive (CTA) * @copyright Copyright © 2021-2022 CERN * @license This program is free software, distributed under the terms of the GNU General Public * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License for more details. * * In applying this licence, CERN does not waive the privileges and immunities * granted to it by virtue of its status as an Intergovernmental Organization or * submit itself to any jurisdiction. */ #pragma once #include "common/exception/Errnum.hpp" #include "common/exception/Exception.hpp" #include namespace cta::threading { /** * A class allowing forking of a child process, and subsequent follow up * of the child process. Status check, killing, return code collection. */ class ChildProcess { public: /** * Helper functor for child to clean up unneeded parent resources * after forking. */ class Cleanup { public: virtual void operator() () = 0; virtual ~Cleanup() = default; }; /** * Exceptions for wrong usage. */ class ProcessStillRunning : public exception::Exception { public: explicit ProcessStillRunning(const std::string& what = "Process still running"): cta::exception::Exception::Exception(what) {} }; class ProcessNeverStarted : public exception::Exception { public: explicit ProcessNeverStarted(const std::string& what = "Process never started"): cta::exception::Exception::Exception(what) {} }; class ProcessWasKilled : public exception::Exception { public: explicit ProcessWasKilled(const std::string& what = "Process was killed"): cta::exception::Exception::Exception(what) {} }; ChildProcess() : m_started(false), m_finished(false), m_exited(false), m_wasKilled(false), m_exitCode(0) {} /* Clean up leftover child processes (hopefully not useful) */ virtual ~ChildProcess() { try { if (!m_finished) kill(); } catch(ProcessNeverStarted&) { } }; /** start function, taking as an argument a callback for parent's * resources cleanup. A child process can only be fired once. */ void start(Cleanup & cleanup) ; /** Check running status */ bool running() ; /** Wait for completion */ void wait() ; /** collect exit code */ int exitCode() ; /** kill */ void kill() ; private: pid_t m_pid; /** Was the process started? */ bool m_started; /** As the process finished? */ bool m_finished; /** Did the process exit cleanly? */ bool m_exited; /** Was the process killed? */ bool m_wasKilled; int m_exitCode; /** The function actually being run in the child process. The value returned * by run() will be the exit code of the process (if we get that far) */ virtual int run() = 0; void parseStatus(int status); }; } // namespace cta::threading