diff options
Diffstat (limited to 'src/base')
-rw-r--r-- | src/base/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/base/platform/unix/PosixSpawnSubProcess.cpp | 119 | ||||
-rw-r--r-- | src/base/platform/unix/UnixFile.cpp | 96 | ||||
-rw-r--r-- | src/base/platform/unix/UnixFileStream.cpp | 20 | ||||
-rw-r--r-- | src/base/platform/unix/UnixPipe.cpp | 51 |
5 files changed, 152 insertions, 136 deletions
diff --git a/src/base/CMakeLists.txt b/src/base/CMakeLists.txt index 6f33441d..e0a16768 100644 --- a/src/base/CMakeLists.txt +++ b/src/base/CMakeLists.txt @@ -25,8 +25,8 @@ target_compile_definitions(CruBase PUBLIC $<$<CONFIG:Debug>:CRU_DEBUG>) if (UNIX AND NOT EMSCRIPTEN) target_sources(CruBase PRIVATE platform/unix/PosixSpawnSubProcess.cpp + platform/unix/UnixFile.cpp platform/unix/UnixFileStream.cpp - platform/unix/UnixPipe.cpp ) if (NOT APPLE) diff --git a/src/base/platform/unix/PosixSpawnSubProcess.cpp b/src/base/platform/unix/PosixSpawnSubProcess.cpp index 631c14b8..25e6c38c 100644 --- a/src/base/platform/unix/PosixSpawnSubProcess.cpp +++ b/src/base/platform/unix/PosixSpawnSubProcess.cpp @@ -14,24 +14,7 @@ #include <unordered_map> namespace cru::platform::unix { -PosixSpawnSubProcessImpl::PosixSpawnSubProcessImpl() - : pid_(0), - exit_code_(0), - stdin_pipe_(UnixPipe::Usage::Send, false), - stdout_pipe_(UnixPipe::Usage::Receive, false), - stderr_pipe_(UnixPipe::Usage::Receive, false) { - stdin_stream_ = std::make_unique<UnixFileStream>( - stdin_pipe_.GetSelfFileDescriptor(), false, false, true, true); - stdout_stream_ = std::make_unique<UnixFileStream>( - stdout_pipe_.GetSelfFileDescriptor(), false, true, false, true); - stderr_stream_ = std::make_unique<UnixFileStream>( - stderr_pipe_.GetSelfFileDescriptor(), false, true, false, true); - - stdout_buffer_stream_ = - std::make_unique<io::AutoReadStream>(stdout_stream_.get(), true, false); - stderr_buffer_stream_ = - std::make_unique<io::AutoReadStream>(stderr_stream_.get(), true, false); -} +PosixSpawnSubProcessImpl::PosixSpawnSubProcessImpl() : pid_(0), exit_code_(0) {} PosixSpawnSubProcessImpl::~PosixSpawnSubProcessImpl() {} @@ -71,8 +54,7 @@ void DestroyCstrArray(char** argv) { void PosixSpawnSubProcessImpl::PlatformCreateProcess( const SubProcessStartInfo& start_info) { - int error; - auto check_error = [&error](String message) { + auto check_error = [](int error, String message) { if (error == 0) return; std::unique_ptr<ErrnoException> inner(new ErrnoException({}, error)); throw SubProcessFailedToStartException(std::move(message), @@ -80,54 +62,45 @@ void PosixSpawnSubProcessImpl::PlatformCreateProcess( }; posix_spawn_file_actions_t file_actions; - error = posix_spawn_file_actions_init(&file_actions); - check_error(u"Failed to call posix_spawn_file_actions_init."); + check_error(posix_spawn_file_actions_init(&file_actions), + u"Failed to call posix_spawn_file_actions_init."); Guard file_actions_guard( [&file_actions] { posix_spawn_file_actions_destroy(&file_actions); }); - // dup2 stdin/stdout/stderr - error = posix_spawn_file_actions_adddup2( - &file_actions, stdin_pipe_.GetOtherFileDescriptor(), STDIN_FILENO); - check_error(u"Failed to call posix_spawn_file_actions_adddup2 on stdin."); - error = posix_spawn_file_actions_adddup2( - &file_actions, stdout_pipe_.GetOtherFileDescriptor(), STDOUT_FILENO); - check_error(u"Failed to call posix_spawn_file_actions_adddup2 on stdout."); - error = posix_spawn_file_actions_adddup2( - &file_actions, stderr_pipe_.GetOtherFileDescriptor(), STDERR_FILENO); - check_error(u"Failed to call posix_spawn_file_actions_adddup2 on stderr."); - - error = posix_spawn_file_actions_addclose( - &file_actions, stdin_pipe_.GetOtherFileDescriptor()); - check_error( - u"Failed to call posix_spawn_file_actions_addclose on self fd of stdin."); - error = posix_spawn_file_actions_addclose( - &file_actions, stdout_pipe_.GetOtherFileDescriptor()); - check_error( - u"Failed to call posix_spawn_file_actions_addclose on self fd stdout."); - error = posix_spawn_file_actions_addclose( - &file_actions, stderr_pipe_.GetOtherFileDescriptor()); - check_error( - u"Failed to call posix_spawn_file_actions_addclose on self fd stderr."); + auto add_dup2 = [&check_error, &file_actions](int from, int to, + StringView name) { + check_error( + posix_spawn_file_actions_adddup2(&file_actions, from, to), + Format(u"Failed to call posix_spawn_file_actions_adddup2 on {}.", + name)); + }; - error = posix_spawn_file_actions_addclose( - &file_actions, stdin_pipe_.GetSelfFileDescriptor()); - check_error( - u"Failed to call posix_spawn_file_actions_addclose on parent fd of " - u"stdin."); - error = posix_spawn_file_actions_addclose( - &file_actions, stdout_pipe_.GetSelfFileDescriptor()); - check_error( - u"Failed to call posix_spawn_file_actions_addclose on parent fd of " - u"stdout."); - error = posix_spawn_file_actions_addclose( - &file_actions, stderr_pipe_.GetSelfFileDescriptor()); - check_error( - u"Failed to call posix_spawn_file_actions_addclose on parent fd of " - u"stderr."); + auto add_close = [&check_error, &file_actions]( + UniDirectionalUnixPipeResult& pipe, StringView name) { + check_error(posix_spawn_file_actions_addclose(&file_actions, pipe.read), + Format(u"Failed to call posix_spawn_file_actions_addclose on " + u"read end of pipe {}.", + name)); + check_error(posix_spawn_file_actions_addclose(&file_actions, pipe.write), + Format(u"Failed to call posix_spawn_file_actions_addclose on " + u"write end of pipe {}.", + name)); + }; + + auto my_stdin = OpenUniDirectionalPipe(); + auto my_stdout = OpenUniDirectionalPipe(); + auto my_stderr = OpenUniDirectionalPipe(); + + add_dup2(my_stdin.read, STDIN_FILENO, u"stdin"); + add_dup2(my_stdout.write, STDOUT_FILENO, u"stdout"); + add_dup2(my_stderr.write, STDERR_FILENO, u"stderr"); + add_close(my_stdin, u"stdin"); + add_close(my_stdout, u"stdout"); + add_close(my_stderr, u"stderr"); posix_spawnattr_t attr; - error = posix_spawnattr_init(&attr); - check_error(u"Failed to call posix_spawnattr_init."); + check_error(posix_spawnattr_init(&attr), + u"Failed to call posix_spawnattr_init."); Guard attr_guard([&attr] { posix_spawnattr_destroy(&attr); }); #ifdef CRU_PLATFORM_OSX @@ -146,15 +119,21 @@ void PosixSpawnSubProcessImpl::PlatformCreateProcess( auto envp = CreateCstrArray(start_info.environments); Guard envp_guard([envp] { DestroyCstrArray(envp); }); - error = posix_spawnp(&pid_, exe.c_str(), &file_actions, &attr, argv, envp); - check_error(u"Failed to call posix_spawnp."); + check_error( + posix_spawnp(&pid_, exe.c_str(), &file_actions, &attr, argv, envp), + u"Failed to call posix_spawnp."); - error = ::close(stdin_pipe_.GetOtherFileDescriptor()); - check_error(u"Failed to close child stdin."); - error = ::close(stdout_pipe_.GetOtherFileDescriptor()); - check_error(u"Failed to close child stdout."); - error = ::close(stderr_pipe_.GetOtherFileDescriptor()); - check_error(u"Failed to close child stderr."); + stdin_stream_ = std::make_unique<UnixFileStream>(std::move(my_stdin.write), + false, false, true); + stdout_stream_ = std::make_unique<UnixFileStream>(std::move(my_stdout.read), + false, true, false); + stderr_stream_ = std::make_unique<UnixFileStream>(std::move(my_stderr.read), + false, true, false); + + stdout_buffer_stream_ = + std::make_unique<io::AutoReadStream>(stdout_stream_.get(), true, false); + stderr_buffer_stream_ = + std::make_unique<io::AutoReadStream>(stderr_stream_.get(), true, false); } SubProcessExitResult PosixSpawnSubProcessImpl::PlatformWaitForProcess() { diff --git a/src/base/platform/unix/UnixFile.cpp b/src/base/platform/unix/UnixFile.cpp new file mode 100644 index 00000000..b9af109a --- /dev/null +++ b/src/base/platform/unix/UnixFile.cpp @@ -0,0 +1,96 @@ +#include "cru/base/platform/unix/UnixFile.h" +#include "cru/base/Exception.h" +#include "cru/base/log/Logger.h" + +#include <fcntl.h> +#include <sys/fcntl.h> +#include <unistd.h> + +namespace cru::platform::unix { + +UnixFileDescriptor::UnixFileDescriptor() + : descriptor_(-1), auto_close_(false) {} + +UnixFileDescriptor::UnixFileDescriptor(int descriptor, bool auto_close, + std::function<int(int)> close) + : descriptor_(descriptor), + auto_close_(auto_close), + close_(std::move(close)) {} + +UnixFileDescriptor::~UnixFileDescriptor() { + constexpr auto kLogTag = u"cru::platform::unix::UnixFileDescriptor"; + if (this->IsValid() && this->IsAutoClose()) { + if (!this->DoClose()) { + CRU_LOG_TAG_ERROR(u"Failed to close file descriptor {}, errno {}.", + descriptor_, errno); + } + } +} + +UnixFileDescriptor::UnixFileDescriptor(UnixFileDescriptor&& other) noexcept + : descriptor_(other.descriptor_), + auto_close_(other.auto_close_), + close_(std::move(other.close_)) { + other.descriptor_ = -1; + other.auto_close_ = false; + other.close_ = nullptr; +} + +UnixFileDescriptor& UnixFileDescriptor::operator=( + UnixFileDescriptor&& other) noexcept { + if (this != &other) { + if (this->IsValid()) { + this->Close(); + } + this->descriptor_ = other.descriptor_; + this->auto_close_ = other.auto_close_; + this->close_ = other.close_; + other.descriptor_ = -1; + other.auto_close_ = false; + other.close_ = nullptr; + } + return *this; +} + +bool UnixFileDescriptor::IsValid() const { return this->descriptor_ >= 0; } + +int UnixFileDescriptor::GetValue() const { + if (!this->IsValid()) { + throw Exception("Can't get value of an invalid unix file descriptor."); + } + return this->descriptor_; +} + +void UnixFileDescriptor::Close() { + if (!this->IsValid()) { + throw Exception("Can't close an invalid unix file descriptor."); + } + if (!this->DoClose()) { + throw ErrnoException(u"Failed to call close on file descriptor."); + } + descriptor_ = -1; + auto_close_ = false; +} + +bool UnixFileDescriptor::DoClose() { + if (this->close_) { + return this->close_(this->descriptor_) == 0; + } else { + return ::close(this->descriptor_) == 0; + } +} + +UniDirectionalUnixPipeResult OpenUniDirectionalPipe(UnixPipeFlag flags) { + int fds[2]; + if (::pipe(fds) != 0) { + throw ErrnoException(u"Failed to create unix pipe."); + } + + if (flags & UnixPipeFlags::NonBlock) { + ::fcntl(fds[0], F_SETFL, O_NONBLOCK); + ::fcntl(fds[1], F_SETFL, O_NONBLOCK); + } + + return {UnixFileDescriptor(fds[0]), UnixFileDescriptor(fds[1])}; +} +} // namespace cru::platform::unix diff --git a/src/base/platform/unix/UnixFileStream.cpp b/src/base/platform/unix/UnixFileStream.cpp index 6d8bab25..e1a6080b 100644 --- a/src/base/platform/unix/UnixFileStream.cpp +++ b/src/base/platform/unix/UnixFileStream.cpp @@ -2,12 +2,10 @@ #include "cru/base/Exception.h" #include "cru/base/Format.h" #include "cru/base/io/Stream.h" -#include "cru/base/log/Logger.h" #include <fcntl.h> #include <sys/fcntl.h> #include <unistd.h> -#include <cerrno> namespace cru::platform::unix { using namespace cru::io; @@ -41,7 +39,7 @@ int MapSeekOrigin(Stream::SeekOrigin origin) { } // namespace UnixFileStream::UnixFileStream(const char *path, int oflag, mode_t mode) { - file_descriptor_ = ::open(path, oflag, mode); + file_descriptor_ = UnixFileDescriptor(::open(path, oflag, mode)); if (file_descriptor_ == -1) { throw ErrnoException( Format(u"Failed to open file {} with oflag {}, mode {}.", @@ -50,16 +48,11 @@ UnixFileStream::UnixFileStream(const char *path, int oflag, mode_t mode) { SetSupportedOperations( {OflagCanSeek(oflag), OflagCanRead(oflag), OflagCanWrite(oflag)}); - - auto_close_ = true; } -UnixFileStream::UnixFileStream(int fd, bool can_seek, bool can_read, - bool can_write, bool auto_close) - : Stream(can_seek, can_read, can_write) { - file_descriptor_ = fd; - auto_close_ = auto_close; -} +UnixFileStream::UnixFileStream(UnixFileDescriptor fd, bool can_seek, + bool can_read, bool can_write) + : Stream(can_seek, can_read, can_write), file_descriptor_(std::move(fd)) {} UnixFileStream::~UnixFileStream() { DoClose(); } @@ -90,9 +83,8 @@ Index UnixFileStream::DoWrite(const std::byte *buffer, Index offset, void UnixFileStream::DoClose() { CRU_STREAM_BEGIN_CLOSE - if (auto_close_ && ::close(file_descriptor_) == -1) { - throw ErrnoException(u"Failed to close file."); + if (file_descriptor_) { + file_descriptor_ = {}; } - file_descriptor_ = -1; } } // namespace cru::platform::unix diff --git a/src/base/platform/unix/UnixPipe.cpp b/src/base/platform/unix/UnixPipe.cpp deleted file mode 100644 index f512c2f4..00000000 --- a/src/base/platform/unix/UnixPipe.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "cru/base/platform/unix/UnixPipe.h" -#include "cru/base/Exception.h" -#include "cru/base/log/Logger.h" - -#include <fcntl.h> -#include <sys/fcntl.h> -#include <unistd.h> - -namespace cru::platform::unix { -UnixPipe::UnixPipe(Usage usage, bool auto_close, UnixPipeFlag flags) - : usage_(usage), auto_close_(auto_close), flags_(flags) { - int fds[2]; - if (pipe(fds) != 0) { - throw ErrnoException(u"Failed to create unix pipe."); - } - - if (flags & UnixPipeFlags::NonBlock) { - fcntl(fds[0], F_SETFL, O_NONBLOCK); - fcntl(fds[1], F_SETFL, O_NONBLOCK); - } - - read_fd_ = fds[0]; - write_fd_ = fds[1]; -} - -int UnixPipe::GetSelfFileDescriptor() { - if (usage_ == Usage::Send) { - return write_fd_; - } else { - return read_fd_; - } -} - -int UnixPipe::GetOtherFileDescriptor() { - if (usage_ == Usage::Send) { - return read_fd_; - } else { - return write_fd_; - } -} - -UnixPipe::~UnixPipe() { - if (auto_close_) { - auto self_fd = GetSelfFileDescriptor(); - if (::close(self_fd) != 0) { - CRU_LOG_TAG_ERROR(u"Failed to close unix pipe file descriptor {}, errno {}.", - self_fd, errno); - } - } -} -} // namespace cru::platform::unix |