diff options
Diffstat (limited to 'nihil.posix/process.ccm')
| -rw-r--r-- | nihil.posix/process.ccm | 132 |
1 files changed, 88 insertions, 44 deletions
diff --git a/nihil.posix/process.ccm b/nihil.posix/process.ccm index 425deac..ee7de15 100644 --- a/nihil.posix/process.ccm +++ b/nihil.posix/process.ccm @@ -1,7 +1,4 @@ -/* - * This source code is released into the public domain. - */ - +// This source code is released into the public domain. module; #include <expected> @@ -9,7 +6,7 @@ module; #include <system_error> #include <utility> -#include <sys/types.h> +#include <sys/wait.h> export module nihil.posix:process; @@ -17,72 +14,119 @@ import nihil.error; namespace nihil { -/* - * wait_result: the exit status of a process. - */ -export struct wait_result final { +// wait_result: the exit status of a process. +export struct wait_result final +{ // Return true if the process exited normally with an exit code of // zero, otherwise false. - [[nodiscard]] auto okay(this wait_result const &self) -> bool; - [[nodiscard]] explicit operator bool(this wait_result const &self); + [[nodiscard]] auto okay(this wait_result const &self) -> bool + { + return self.status() == 0; + } + + [[nodiscard]] explicit operator bool(this wait_result const &self) + { + return self.okay(); + } // Return the exit status, if any. - [[nodiscard]] auto status(this wait_result const &self) - -> std::optional<int>; + [[nodiscard]] auto status(this wait_result const &self) -> std::optional<int> + { + if (WIFEXITED(self.m_status)) + return WEXITSTATUS(self.m_status); + return {}; + } // Return the exit signal, if any. - [[nodiscard]] auto signal(this wait_result const &self) - -> std::optional<int>; + [[nodiscard]] auto signal(this wait_result const &self) -> std::optional<int> + { + if (WIFSIGNALED(self.m_status)) + return WTERMSIG(self.m_status); + return {}; + } private: friend struct process; - int _status; + int m_status; // Construct a new wait_result from the output of waitpid(). - wait_result(int status); + explicit wait_result(int status) + : m_status(status) + { + } }; -/* - * process: represents a process we created, which can be waited for. - */ -export struct process final { +// Represents a process we created, which can be waited for. +export struct process final +{ process() = delete; - /* - * Create a new process from a pid, which must be a child of the - * current process. - */ - process(::pid_t pid); + // Create a new process from a pid, which must be a child of the + // current process. + explicit process(::pid_t pid) + : m_pid(pid) + { + } // When destroyed, we automatically wait for the process to // avoid creating zombie processes. - ~process(); + ~process() + { + if (m_pid == -1) + return; + + auto status = int{}; + std::ignore = ::waitpid(m_pid, &status, WEXITED); + } // Movable. - process(process &&) noexcept; - auto operator=(this process &, process &&) noexcept -> process &; + process(process &&other) noexcept + : m_pid(std::exchange(other.m_pid, -1)) + {} + + auto operator=(this process &self, process &&other) noexcept -> process & + { + if (&self != &other) { + self.m_pid = std::exchange(other.m_pid, -1); + } + + return self; // NOLINT + } // Not copyable. process(process const &) = delete; auto operator=(this process &, process const &) -> process & = delete; // Get the child's process id. - [[nodiscard]] auto pid(this process const &self) noexcept -> ::pid_t; - - /* - * Wait for this process to exit (by calling waitpid()) and return - * its exit status. This destroys the process state, leaving this - * object in a moved-from state. - */ - [[nodiscard]] auto wait(this process &&self) - -> std::expected<wait_result, error>; - - /* - * Release this process so we won't try to wait for it when - * destroying this object. - */ - [[nodiscard]] auto release(this process &&self) -> ::pid_t; + [[nodiscard]] auto pid(this process const &self) noexcept -> ::pid_t + { + return self.m_pid; + } + + // Wait for this process to exit (by calling waitpid()) and return + // its exit status. This destroys the process state, leaving this + // object in a moved-from state. + [[nodiscard]] auto wait(this process &&self) // NOLINT + -> std::expected<wait_result, error> + { + auto status = int{}; + auto ret = waitpid(self.m_pid, &status, 0); + if (ret == -1) + return std::unexpected(error(std::errc(errno))); + + return wait_result(status); + } + + // Release this process so we won't try to wait for it when + // destroying this object. This will leave a zombie process + // unless the wait is done another way. + [[nodiscard]] auto release(this process &&self) -> ::pid_t // NOLINT + { + auto const ret = self.pid(); + self.m_pid = -1; + return ret; + } private: ::pid_t m_pid; |
