diff options
-rw-r--r-- | include/cru/common/platform/unix/PosixSpawnSubProcess.h | 11 | ||||
-rw-r--r-- | include/cru/common/platform/unix/UnixPipe.h | 59 | ||||
-rw-r--r-- | src/common/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/common/platform/unix/UnixPipe.cpp | 38 |
4 files changed, 110 insertions, 1 deletions
diff --git a/include/cru/common/platform/unix/PosixSpawnSubProcess.h b/include/cru/common/platform/unix/PosixSpawnSubProcess.h index 02b9e7e2..a55c2c1c 100644 --- a/include/cru/common/platform/unix/PosixSpawnSubProcess.h +++ b/include/cru/common/platform/unix/PosixSpawnSubProcess.h @@ -6,6 +6,9 @@ #include "../../SubProcess.h" +#include "UnixFileStream.h" +#include "UnixPipe.h" + #include <spawn.h> namespace cru::platform::unix { @@ -17,6 +20,14 @@ class PosixSpawnSubProcess : public PlatformSubProcessBase { private: pid_t pid_; int exit_code_; + + UnixPipe stdin_pipe_; + UnixPipe stdout_pipe_; + UnixPipe stderr_pipe_; + + std::unique_ptr<UnixFileStream> stdin_stream_; + std::unique_ptr<UnixFileStream> stdout_stream_; + std::unique_ptr<UnixFileStream> stderr_stream_; }; } // namespace cru::platform::unix diff --git a/include/cru/common/platform/unix/UnixPipe.h b/include/cru/common/platform/unix/UnixPipe.h new file mode 100644 index 00000000..153c52bf --- /dev/null +++ b/include/cru/common/platform/unix/UnixPipe.h @@ -0,0 +1,59 @@ +#pragma once + +#include "../../PreConfig.h" + +#ifdef CRU_PLATFORM_UNIX + +#include "../../Base.h" + +namespace cru::platform::unix { +/** + * @brief an unix pipe, commonly for communication of parent process and child + * process. + * + * There are two types of pipes sorted by its usage. For stdin, parent process + * SEND data to child process. For stdout and stderr, parent process RECEIVE + * data from child process. Each pipe has two ends, one for read and the other + * for write. But for send and receive, they are reversed. It is a little + * confused to consider which end should be used by parent and which end should + * be used by child. So this class help you make it clear. You specify SEND or + * RECEIVE, and this class give you a parent used end and a child used end. + * + * This class will only close the end used by parent when it is destructed. It + * is the user's duty to close the one used by child. + */ +class UnixPipe : public Object { + private: + constexpr static auto kLogTag = u"cru::platform::unix::UnixPipe"; + + public: + enum class Usage { + Send, + Receive, + }; + + explicit UnixPipe(Usage usage); + + CRU_DELETE_COPY(UnixPipe) + CRU_DELETE_MOVE(UnixPipe) + + ~UnixPipe(); + + /** + * @brief aka, the one used by parent process. + */ + int GetSelfFileDescriptor(); + + /** + * @brief aka, the one used by child process. + */ + int GetOtherFileDescriptor(); + + private: + Usage usage_; + int read_fd_; + int write_fd_; +}; +} // namespace cru::platform::unix + +#endif diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 2414831b..aaff70fe 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -22,8 +22,9 @@ target_compile_definitions(CruBase PUBLIC $<$<CONFIG:Debug>:CRU_DEBUG>) if (UNIX AND NOT EMSCRIPTEN) target_sources(CruBase PRIVATE + platform/unix/PosixSpawnSubProcess.cpp platform/unix/UnixFileStream.cpp - platform/unix/UnixFileStream.cpp + platform/unix/UnixPipe.cpp ) if (NOT APPLE) diff --git a/src/common/platform/unix/UnixPipe.cpp b/src/common/platform/unix/UnixPipe.cpp new file mode 100644 index 00000000..8393f022 --- /dev/null +++ b/src/common/platform/unix/UnixPipe.cpp @@ -0,0 +1,38 @@ +#include "cru/common/platform/unix/UnixPipe.h" +#include "cru/common/Exception.h" +#include "cru/common/log/Logger.h" + +#include <unistd.h> + +namespace cru::platform::unix { +UnixPipe::UnixPipe(Usage usage) : usage_(usage) { + int fds[2]; + if (pipe(fds) != 0) { + throw ErrnoException(u"Failed to create unix pipe."); + } + 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 (close(GetSelfFileDescriptor()) != 0) { + CRU_LOG_ERROR(u"Failed to close unix pipe file descriptor."); + } +} +} // namespace cru::platform::unix |