aboutsummaryrefslogtreecommitdiff
path: root/source/Host/posix/PipePosix.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Host/posix/PipePosix.cpp')
-rw-r--r--source/Host/posix/PipePosix.cpp541
1 files changed, 211 insertions, 330 deletions
diff --git a/source/Host/posix/PipePosix.cpp b/source/Host/posix/PipePosix.cpp
index 353faae1628e..4e0810c1a9b3 100644
--- a/source/Host/posix/PipePosix.cpp
+++ b/source/Host/posix/PipePosix.cpp
@@ -10,6 +10,7 @@
#include "lldb/Host/posix/PipePosix.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostInfo.h"
+#include "lldb/Utility/SelectHelper.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/FileSystem.h"
@@ -25,9 +26,9 @@
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
-#include <unistd.h>
-#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
using namespace lldb;
using namespace lldb_private;
@@ -38,400 +39,280 @@ enum PIPES { READ, WRITE }; // Constants 0 and 1 for READ and WRITE
// pipe2 is supported by a limited set of platforms
// TODO: Add more platforms that support pipe2.
-#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__NetBSD__)
+#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 10) || \
+ defined(__NetBSD__)
#define PIPE2_SUPPORTED 1
#else
#define PIPE2_SUPPORTED 0
#endif
-namespace
-{
+namespace {
constexpr auto OPEN_WRITER_SLEEP_TIMEOUT_MSECS = 100;
#if defined(FD_CLOEXEC) && !PIPE2_SUPPORTED
-bool SetCloexecFlag(int fd)
-{
- int flags = ::fcntl(fd, F_GETFD);
- if (flags == -1)
- return false;
- return (::fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == 0);
+bool SetCloexecFlag(int fd) {
+ int flags = ::fcntl(fd, F_GETFD);
+ if (flags == -1)
+ return false;
+ return (::fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == 0);
}
#endif
-std::chrono::time_point<std::chrono::steady_clock>
-Now()
-{
- return std::chrono::steady_clock::now();
+std::chrono::time_point<std::chrono::steady_clock> Now() {
+ return std::chrono::steady_clock::now();
}
-
-Error
-SelectIO(int handle, bool is_read, const std::function<Error(bool&)> &io_handler, const std::chrono::microseconds &timeout)
-{
- Error error;
- fd_set fds;
- bool done = false;
-
- using namespace std::chrono;
-
- const auto finish_time = Now() + timeout;
-
- while (!done)
- {
- struct timeval tv = {0, 0};
- if (timeout != microseconds::zero())
- {
- const auto remaining_dur = duration_cast<microseconds>(finish_time - Now());
- if (remaining_dur.count() <= 0)
- {
- error.SetErrorString("timeout exceeded");
- break;
- }
- const auto dur_secs = duration_cast<seconds>(remaining_dur);
- const auto dur_usecs = remaining_dur % seconds(1);
-
- tv.tv_sec = dur_secs.count();
- tv.tv_usec = dur_usecs.count();
- }
- else
- tv.tv_sec = 1;
-
- FD_ZERO(&fds);
- FD_SET(handle, &fds);
-
- const auto retval = ::select(handle + 1,
- (is_read) ? &fds : nullptr,
- (is_read) ? nullptr : &fds,
- nullptr, &tv);
- if (retval == -1)
- {
- if (errno == EINTR)
- continue;
- error.SetErrorToErrno();
- break;
- }
- if (retval == 0)
- {
- error.SetErrorString("timeout exceeded");
- break;
- }
- if (!FD_ISSET(handle, &fds))
- {
- error.SetErrorString("invalid state");
- break;
- }
-
- error = io_handler(done);
- if (error.Fail())
- {
- if (error.GetError() == EINTR)
- continue;
- break;
- }
- }
- return error;
-}
-
}
PipePosix::PipePosix()
- : m_fds{
- PipePosix::kInvalidDescriptor,
- PipePosix::kInvalidDescriptor
- } {}
+ : m_fds{PipePosix::kInvalidDescriptor, PipePosix::kInvalidDescriptor} {}
-PipePosix::PipePosix(int read_fd, int write_fd)
- : m_fds{read_fd, write_fd} {}
+PipePosix::PipePosix(int read_fd, int write_fd) : m_fds{read_fd, write_fd} {}
PipePosix::PipePosix(PipePosix &&pipe_posix)
: PipeBase{std::move(pipe_posix)},
- m_fds{
- pipe_posix.ReleaseReadFileDescriptor(),
- pipe_posix.ReleaseWriteFileDescriptor()
- } {}
-
-PipePosix &PipePosix::operator=(PipePosix &&pipe_posix)
-{
- PipeBase::operator=(std::move(pipe_posix));
- m_fds[READ] = pipe_posix.ReleaseReadFileDescriptor();
- m_fds[WRITE] = pipe_posix.ReleaseWriteFileDescriptor();
- return *this;
+ m_fds{pipe_posix.ReleaseReadFileDescriptor(),
+ pipe_posix.ReleaseWriteFileDescriptor()} {}
+
+PipePosix &PipePosix::operator=(PipePosix &&pipe_posix) {
+ PipeBase::operator=(std::move(pipe_posix));
+ m_fds[READ] = pipe_posix.ReleaseReadFileDescriptor();
+ m_fds[WRITE] = pipe_posix.ReleaseWriteFileDescriptor();
+ return *this;
}
-PipePosix::~PipePosix()
-{
- Close();
-}
+PipePosix::~PipePosix() { Close(); }
-Error
-PipePosix::CreateNew(bool child_processes_inherit)
-{
- if (CanRead() || CanWrite())
- return Error(EINVAL, eErrorTypePOSIX);
+Error PipePosix::CreateNew(bool child_processes_inherit) {
+ if (CanRead() || CanWrite())
+ return Error(EINVAL, eErrorTypePOSIX);
- Error error;
+ Error error;
#if PIPE2_SUPPORTED
- if (::pipe2(m_fds, (child_processes_inherit) ? 0 : O_CLOEXEC) == 0)
- return error;
+ if (::pipe2(m_fds, (child_processes_inherit) ? 0 : O_CLOEXEC) == 0)
+ return error;
#else
- if (::pipe(m_fds) == 0)
- {
+ if (::pipe(m_fds) == 0) {
#ifdef FD_CLOEXEC
- if (!child_processes_inherit)
- {
- if (!SetCloexecFlag(m_fds[0]) || !SetCloexecFlag(m_fds[1]))
- {
- error.SetErrorToErrno();
- Close();
- return error;
- }
- }
-#endif
+ if (!child_processes_inherit) {
+ if (!SetCloexecFlag(m_fds[0]) || !SetCloexecFlag(m_fds[1])) {
+ error.SetErrorToErrno();
+ Close();
return error;
+ }
}
#endif
-
- error.SetErrorToErrno();
- m_fds[READ] = PipePosix::kInvalidDescriptor;
- m_fds[WRITE] = PipePosix::kInvalidDescriptor;
return error;
+ }
+#endif
+
+ error.SetErrorToErrno();
+ m_fds[READ] = PipePosix::kInvalidDescriptor;
+ m_fds[WRITE] = PipePosix::kInvalidDescriptor;
+ return error;
}
-Error
-PipePosix::CreateNew(llvm::StringRef name, bool child_process_inherit)
-{
- if (CanRead() || CanWrite())
- return Error("Pipe is already opened");
+Error PipePosix::CreateNew(llvm::StringRef name, bool child_process_inherit) {
+ if (CanRead() || CanWrite())
+ return Error("Pipe is already opened");
- Error error;
- if (::mkfifo(name.data(), 0660) != 0)
- error.SetErrorToErrno();
+ Error error;
+ if (::mkfifo(name.data(), 0660) != 0)
+ error.SetErrorToErrno();
- return error;
+ return error;
}
-Error
-PipePosix::CreateWithUniqueName(llvm::StringRef prefix, bool child_process_inherit, llvm::SmallVectorImpl<char>& name)
-{
- llvm::SmallString<PATH_MAX> named_pipe_path;
- llvm::SmallString<PATH_MAX> pipe_spec((prefix + ".%%%%%%").str());
- FileSpec tmpdir_file_spec;
- tmpdir_file_spec.Clear();
- if (HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
- {
- tmpdir_file_spec.AppendPathComponent(pipe_spec.c_str());
- }
- else
- {
- tmpdir_file_spec.AppendPathComponent("/tmp");
- tmpdir_file_spec.AppendPathComponent(pipe_spec.c_str());
- }
-
- // It's possible that another process creates the target path after we've
- // verified it's available but before we create it, in which case we
- // should try again.
- Error error;
- do {
- llvm::sys::fs::createUniqueFile(tmpdir_file_spec.GetPath().c_str(), named_pipe_path);
- error = CreateNew(named_pipe_path, child_process_inherit);
- } while (error.GetError() == EEXIST);
-
- if (error.Success())
- name = named_pipe_path;
- return error;
+Error PipePosix::CreateWithUniqueName(llvm::StringRef prefix,
+ bool child_process_inherit,
+ llvm::SmallVectorImpl<char> &name) {
+ llvm::SmallString<PATH_MAX> named_pipe_path;
+ llvm::SmallString<PATH_MAX> pipe_spec((prefix + ".%%%%%%").str());
+ FileSpec tmpdir_file_spec;
+ tmpdir_file_spec.Clear();
+ if (HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) {
+ tmpdir_file_spec.AppendPathComponent(pipe_spec.c_str());
+ } else {
+ tmpdir_file_spec.AppendPathComponent("/tmp");
+ tmpdir_file_spec.AppendPathComponent(pipe_spec.c_str());
+ }
+
+ // It's possible that another process creates the target path after we've
+ // verified it's available but before we create it, in which case we
+ // should try again.
+ Error error;
+ do {
+ llvm::sys::fs::createUniqueFile(tmpdir_file_spec.GetPath(),
+ named_pipe_path);
+ error = CreateNew(named_pipe_path, child_process_inherit);
+ } while (error.GetError() == EEXIST);
+
+ if (error.Success())
+ name = named_pipe_path;
+ return error;
}
-Error
-PipePosix::OpenAsReader(llvm::StringRef name, bool child_process_inherit)
-{
- if (CanRead() || CanWrite())
- return Error("Pipe is already opened");
+Error PipePosix::OpenAsReader(llvm::StringRef name,
+ bool child_process_inherit) {
+ if (CanRead() || CanWrite())
+ return Error("Pipe is already opened");
- int flags = O_RDONLY | O_NONBLOCK;
- if (!child_process_inherit)
- flags |= O_CLOEXEC;
+ int flags = O_RDONLY | O_NONBLOCK;
+ if (!child_process_inherit)
+ flags |= O_CLOEXEC;
- Error error;
- int fd = ::open(name.data(), flags);
- if (fd != -1)
- m_fds[READ] = fd;
- else
- error.SetErrorToErrno();
+ Error error;
+ int fd = ::open(name.data(), flags);
+ if (fd != -1)
+ m_fds[READ] = fd;
+ else
+ error.SetErrorToErrno();
- return error;
+ return error;
}
-Error
-PipePosix::OpenAsWriterWithTimeout(llvm::StringRef name, bool child_process_inherit, const std::chrono::microseconds &timeout)
-{
- if (CanRead() || CanWrite())
- return Error("Pipe is already opened");
-
- int flags = O_WRONLY | O_NONBLOCK;
- if (!child_process_inherit)
- flags |= O_CLOEXEC;
-
- using namespace std::chrono;
- const auto finish_time = Now() + timeout;
-
- while (!CanWrite())
- {
- if (timeout != microseconds::zero())
- {
- const auto dur = duration_cast<microseconds>(finish_time - Now()).count();
- if (dur <= 0)
- return Error("timeout exceeded - reader hasn't opened so far");
- }
-
- errno = 0;
- int fd = ::open(name.data(), flags);
- if (fd == -1)
- {
- const auto errno_copy = errno;
- // We may get ENXIO if a reader side of the pipe hasn't opened yet.
- if (errno_copy != ENXIO)
- return Error(errno_copy, eErrorTypePOSIX);
-
- std::this_thread::sleep_for(milliseconds(OPEN_WRITER_SLEEP_TIMEOUT_MSECS));
- }
- else
- {
- m_fds[WRITE] = fd;
- }
+Error PipePosix::OpenAsWriterWithTimeout(
+ llvm::StringRef name, bool child_process_inherit,
+ const std::chrono::microseconds &timeout) {
+ if (CanRead() || CanWrite())
+ return Error("Pipe is already opened");
+
+ int flags = O_WRONLY | O_NONBLOCK;
+ if (!child_process_inherit)
+ flags |= O_CLOEXEC;
+
+ using namespace std::chrono;
+ const auto finish_time = Now() + timeout;
+
+ while (!CanWrite()) {
+ if (timeout != microseconds::zero()) {
+ const auto dur = duration_cast<microseconds>(finish_time - Now()).count();
+ if (dur <= 0)
+ return Error("timeout exceeded - reader hasn't opened so far");
}
- return Error();
-}
+ errno = 0;
+ int fd = ::open(name.data(), flags);
+ if (fd == -1) {
+ const auto errno_copy = errno;
+ // We may get ENXIO if a reader side of the pipe hasn't opened yet.
+ if (errno_copy != ENXIO)
+ return Error(errno_copy, eErrorTypePOSIX);
+
+ std::this_thread::sleep_for(
+ milliseconds(OPEN_WRITER_SLEEP_TIMEOUT_MSECS));
+ } else {
+ m_fds[WRITE] = fd;
+ }
+ }
-int
-PipePosix::GetReadFileDescriptor() const
-{
- return m_fds[READ];
+ return Error();
}
-int
-PipePosix::GetWriteFileDescriptor() const
-{
- return m_fds[WRITE];
-}
+int PipePosix::GetReadFileDescriptor() const { return m_fds[READ]; }
-int
-PipePosix::ReleaseReadFileDescriptor()
-{
- const int fd = m_fds[READ];
- m_fds[READ] = PipePosix::kInvalidDescriptor;
- return fd;
+int PipePosix::GetWriteFileDescriptor() const { return m_fds[WRITE]; }
+
+int PipePosix::ReleaseReadFileDescriptor() {
+ const int fd = m_fds[READ];
+ m_fds[READ] = PipePosix::kInvalidDescriptor;
+ return fd;
}
-int
-PipePosix::ReleaseWriteFileDescriptor()
-{
- const int fd = m_fds[WRITE];
- m_fds[WRITE] = PipePosix::kInvalidDescriptor;
- return fd;
+int PipePosix::ReleaseWriteFileDescriptor() {
+ const int fd = m_fds[WRITE];
+ m_fds[WRITE] = PipePosix::kInvalidDescriptor;
+ return fd;
}
-void
-PipePosix::Close()
-{
- CloseReadFileDescriptor();
- CloseWriteFileDescriptor();
+void PipePosix::Close() {
+ CloseReadFileDescriptor();
+ CloseWriteFileDescriptor();
}
-Error
-PipePosix::Delete(llvm::StringRef name)
-{
- return FileSystem::Unlink(FileSpec{name.data(), true});
+Error PipePosix::Delete(llvm::StringRef name) {
+ return FileSystem::Unlink(FileSpec{name.data(), true});
}
-bool
-PipePosix::CanRead() const
-{
- return m_fds[READ] != PipePosix::kInvalidDescriptor;
+bool PipePosix::CanRead() const {
+ return m_fds[READ] != PipePosix::kInvalidDescriptor;
}
-bool
-PipePosix::CanWrite() const
-{
- return m_fds[WRITE] != PipePosix::kInvalidDescriptor;
+bool PipePosix::CanWrite() const {
+ return m_fds[WRITE] != PipePosix::kInvalidDescriptor;
}
-void
-PipePosix::CloseReadFileDescriptor()
-{
- if (CanRead())
- {
- close(m_fds[READ]);
- m_fds[READ] = PipePosix::kInvalidDescriptor;
- }
+void PipePosix::CloseReadFileDescriptor() {
+ if (CanRead()) {
+ close(m_fds[READ]);
+ m_fds[READ] = PipePosix::kInvalidDescriptor;
+ }
}
-void
-PipePosix::CloseWriteFileDescriptor()
-{
- if (CanWrite())
- {
- close(m_fds[WRITE]);
- m_fds[WRITE] = PipePosix::kInvalidDescriptor;
- }
+void PipePosix::CloseWriteFileDescriptor() {
+ if (CanWrite()) {
+ close(m_fds[WRITE]);
+ m_fds[WRITE] = PipePosix::kInvalidDescriptor;
+ }
}
-Error
-PipePosix::ReadWithTimeout(void *buf, size_t size, const std::chrono::microseconds &timeout, size_t &bytes_read)
-{
- bytes_read = 0;
- if (!CanRead())
- return Error(EINVAL, eErrorTypePOSIX);
-
- auto handle = GetReadFileDescriptor();
- return SelectIO(handle,
- true,
- [=, &bytes_read](bool &done)
- {
- Error error;
- auto result = ::read(handle,
- reinterpret_cast<char*>(buf) + bytes_read,
- size - bytes_read);
- if (result != -1)
- {
- bytes_read += result;
- if (bytes_read == size || result == 0)
- done = true;
- }
- else
- error.SetErrorToErrno();
-
- return error;
- },
- timeout);
+Error PipePosix::ReadWithTimeout(void *buf, size_t size,
+ const std::chrono::microseconds &timeout,
+ size_t &bytes_read) {
+ bytes_read = 0;
+ if (!CanRead())
+ return Error(EINVAL, eErrorTypePOSIX);
+
+ const int fd = GetReadFileDescriptor();
+
+ SelectHelper select_helper;
+ select_helper.SetTimeout(timeout);
+ select_helper.FDSetRead(fd);
+
+ Error error;
+ while (error.Success()) {
+ error = select_helper.Select();
+ if (error.Success()) {
+ auto result = ::read(fd, reinterpret_cast<char *>(buf) + bytes_read,
+ size - bytes_read);
+ if (result != -1) {
+ bytes_read += result;
+ if (bytes_read == size || result == 0)
+ break;
+ } else {
+ error.SetErrorToErrno();
+ break;
+ }
+ }
+ }
+ return error;
}
-Error
-PipePosix::Write(const void *buf, size_t size, size_t &bytes_written)
-{
- bytes_written = 0;
- if (!CanWrite())
- return Error(EINVAL, eErrorTypePOSIX);
-
- auto handle = GetWriteFileDescriptor();
- return SelectIO(handle,
- false,
- [=, &bytes_written](bool &done)
- {
- Error error;
- auto result = ::write(handle,
- reinterpret_cast<const char*>(buf) + bytes_written,
- size - bytes_written);
- if (result != -1)
- {
- bytes_written += result;
- if (bytes_written == size)
- done = true;
- }
- else
- error.SetErrorToErrno();
-
- return error;
- },
- std::chrono::microseconds::zero());
+Error PipePosix::Write(const void *buf, size_t size, size_t &bytes_written) {
+ bytes_written = 0;
+ if (!CanWrite())
+ return Error(EINVAL, eErrorTypePOSIX);
+
+ const int fd = GetWriteFileDescriptor();
+ SelectHelper select_helper;
+ select_helper.SetTimeout(std::chrono::seconds(0));
+ select_helper.FDSetWrite(fd);
+
+ Error error;
+ while (error.Success()) {
+ error = select_helper.Select();
+ if (error.Success()) {
+ auto result =
+ ::write(fd, reinterpret_cast<const char *>(buf) + bytes_written,
+ size - bytes_written);
+ if (result != -1) {
+ bytes_written += result;
+ if (bytes_written == size)
+ break;
+ } else {
+ error.SetErrorToErrno();
+ }
+ }
+ }
+ return error;
}