/* * This source code is released into the public domain. */ module; #include #include #include #include #include export module nihil.posix:process; import nihil.error; namespace nihil { /* * 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); // Return the exit status, if any. [[nodiscard]] auto status(this wait_result const &self) -> std::optional; // Return the exit signal, if any. [[nodiscard]] auto signal(this wait_result const &self) -> std::optional; private: friend struct process; int _status; // Construct a new wait_result from the output of waitpid(). wait_result(int status); }; /* * process: 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); // When destroyed, we automatically wait for the process to // avoid creating zombie processes. ~process(); // Movable. process(process &&) noexcept; auto operator=(this process &, process &&) noexcept -> process &; // 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; /* * Release this process so we won't try to wait for it when * destroying this object. */ [[nodiscard]] auto release(this process &&self) -> ::pid_t; private: ::pid_t m_pid; }; } // namespace nihil