From 2e2d1bd3b6c7776b77c33b94f30ead89367a71e6 Mon Sep 17 00:00:00 2001 From: Lexi Winter Date: Tue, 1 Jul 2025 17:07:04 +0100 Subject: add nihil.std --- nihil.posix/spawn.ccm | 128 ++++++++++++++++++-------------------------------- 1 file changed, 46 insertions(+), 82 deletions(-) (limited to 'nihil.posix/spawn.ccm') diff --git a/nihil.posix/spawn.ccm b/nihil.posix/spawn.ccm index a185bb3..1e4102a 100644 --- a/nihil.posix/spawn.ccm +++ b/nihil.posix/spawn.ccm @@ -1,52 +1,27 @@ // This source code is released into the public domain. -module; - -/* - * spawn(): fork and execute a child process. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - export module nihil.posix:spawn; +// spawn(): fork and execute a child process. + import nihil.monad; import :argv; import :executor; +import :fd; import :open; import :process; +import :unistd; namespace nihil { -// Useful constants -export inline int constexpr stdin_fileno = STDIN_FILENO; -export inline int constexpr stdout_fileno = STDOUT_FILENO; -export inline int constexpr stderr_fileno = STDERR_FILENO; - -/* - * fd_{read,write}_pipe: create a pipe with one end in the child and the other in the parent. - * The child's side will be dup2()'d to the provided fd number. - * The parent side fd can be retrieved via parent_fd(). - * - * fd_read_pipe() puts the reading side in the child, while fd_write_pipe() puts the writing - * side in the child. - */ +// fd_{read,write}_pipe: create a pipe with one end in the child and the other in the parent. +// The child's side will be dup2()'d to the provided fd number. +// The parent side fd can be retrieved via parent_fd(). +// +// fd_read_pipe() puts the reading side in the child, while fd_write_pipe() puts the writing +// side in the child. -struct fd_pipe_base { +struct fd_pipe_base +{ fd_pipe_base(int fdno, fd &&child_fd, fd &&parent_fd) : m_fdno(fdno) , m_child_fd(std::move(child_fd)) @@ -58,8 +33,8 @@ struct fd_pipe_base { { auto err = raw_dup(self.m_child_fd, self.m_fdno); if (!err) { - std::print("dup: {}\n", err.error()); - _exit(1); + std::println("dup: {}", err.error()); + std::quick_exit(1); } /* @@ -81,35 +56,34 @@ struct fd_pipe_base { } private: - int m_fdno; - fd m_child_fd; - fd m_parent_fd; - + int m_fdno; + fd m_child_fd; + fd m_parent_fd; }; -export struct fd_read_pipe final : fd_pipe_base { +export struct fd_read_pipe final : fd_pipe_base +{ fd_read_pipe(int fdno, fd &&read_fd, fd &&write_fd) : fd_pipe_base(fdno, std::move(read_fd), std::move(write_fd)) { } }; -export struct fd_write_pipe final : fd_pipe_base { +export struct fd_write_pipe final : fd_pipe_base +{ fd_write_pipe(int fdno, fd &&read_fd, fd &&write_fd) : fd_pipe_base(fdno, std::move(write_fd), std::move(read_fd)) { } }; -export [[nodiscard]] auto -make_fd_read_pipe(int fdno) -> std::expected +export [[nodiscard]] auto make_fd_read_pipe(int fdno) -> std::expected { auto fds = co_await pipe(); co_return fd_read_pipe(fdno, std::move(fds.first), std::move(fds.second)); } -export [[nodiscard]] auto -make_fd_write_pipe(int fdno) -> std::expected +export [[nodiscard]] auto make_fd_write_pipe(int fdno) -> std::expected { auto fds = co_await pipe(); co_return fd_write_pipe(fdno, std::move(fds.first), std::move(fds.second)); @@ -119,7 +93,8 @@ make_fd_write_pipe(int fdno) -> std::expected * fd_file: open a file and provide it to the child as a file descriptor. * open_flags and open_mode are as for ::open(). */ -export struct fd_file final { +export struct fd_file final +{ fd_file(int fdno, fd &&file_fd) : m_fdno(fdno) , m_file_fd(std::move(file_fd)) @@ -136,20 +111,19 @@ export struct fd_file final { auto err = raw_dup(self.m_file_fd, self.m_fdno); if (!err) { std::print("dup: {}\n", err.error()); - _exit(1); + std::quick_exit(1); } std::ignore = self.m_file_fd.close(); } private: - int m_fdno; - fd m_file_fd; + int m_fdno; + fd m_file_fd; }; export [[nodiscard]] auto -make_fd_file(int fdno, std::filesystem::path const &file, - open_flags flags, int mode = 0777) +make_fd_file(int fdno, std::filesystem::path const &file, open_flags flags, int mode = 0777) -> std::expected { auto fd = co_await open(file, flags, mode); @@ -160,20 +134,17 @@ make_fd_file(int fdno, std::filesystem::path const &file, * Shorthand for fd_file with /dev/null as the file. */ -export [[nodiscard]] inline auto -stdin_devnull() -> std::expected +export [[nodiscard]] inline auto stdin_devnull() -> std::expected { return make_fd_file(stdin_fileno, "/dev/null", open_read); } -export [[nodiscard]] inline auto -stdout_devnull() -> std::expected +export [[nodiscard]] inline auto stdout_devnull() -> std::expected { return make_fd_file(stdout_fileno, "/dev/null", open_write); } -export [[nodiscard]] inline auto -stderr_devnull() -> std::expected +export [[nodiscard]] inline auto stderr_devnull() -> std::expected { return make_fd_file(stderr_fileno, "/dev/null", open_write); } @@ -182,8 +153,9 @@ stderr_devnull() -> std::expected * Capture the output of a pipe in the parent and read it into an * output iterator. */ -export template Iterator> -struct fd_capture final { +export template Iterator> +struct fd_capture final +{ fd_capture(fd_write_pipe &&pipe, Iterator it) : m_pipe(std::move(pipe)) , m_iterator(std::move(it)) @@ -204,7 +176,7 @@ struct fd_capture final { auto &fd = self.m_pipe.parent_fd(); for (;;) { auto ret = read(fd, buffer); - if (!ret || ret->size() == 0) + if (!ret || ret->empty()) break; std::ranges::copy(*ret, self.m_iterator); @@ -215,21 +187,18 @@ struct fd_capture final { } private: - fd_write_pipe m_pipe; - Iterator m_iterator; + fd_write_pipe m_pipe; + Iterator m_iterator; }; -export [[nodiscard]] auto -make_capture(int fdno, std::output_iterator auto &&it) +export [[nodiscard]] auto make_capture(int fdno, std::output_iterator auto &&it) -> std::expected, error> { auto pipe = co_await make_fd_write_pipe(fdno); - co_return fd_capture(std::move(pipe), - std::forward(it)); + co_return fd_capture(std::move(pipe), std::forward(it)); } -export [[nodiscard]] auto -make_capture(int fdno, std::string &str) +export [[nodiscard]] auto make_capture(int fdno, std::string &str) -> std::expected, error> { auto pipe = co_await make_fd_write_pipe(fdno); @@ -241,14 +210,9 @@ make_capture(int fdno, std::string &str) * Throws exec_error() on failure. */ export [[nodiscard]] auto -spawn(executor auto &&executor, auto &&...actions) - -> std::expected +spawn(executor auto &&executor, auto &&...actions) -> std::expected { - auto const pid = ::fork(); - if (pid == -1) - return std::unexpected(error("fork failed", - error(std::errc(errno)))); - + auto const pid = co_await fork(); auto proc = process(pid); if (pid == 0) { @@ -257,13 +221,13 @@ spawn(executor auto &&executor, auto &&...actions) std::ignore = std::move(proc).release(); auto err = executor.exec(); - std::print("{}\n", err.error()); - _exit(1); + std::println("{}", err.error()); + std::quick_exit(1); } (actions.run_in_parent(proc), ...); - return proc; + co_return proc; } } // namespace nihil -- cgit v1.2.3