summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/lldb/source/Host/posix/PipePosix.cpp
diff options
context:
space:
mode:
authorpatrick <patrick@openbsd.org>2020-08-03 14:33:06 +0000
committerpatrick <patrick@openbsd.org>2020-08-03 14:33:06 +0000
commit061da546b983eb767bad15e67af1174fb0bcf31c (patch)
tree83c78b820819d70aa40c36d90447978b300078c5 /gnu/llvm/lldb/source/Host/posix/PipePosix.cpp
parentImport LLVM 10.0.0 release including clang, lld and lldb. (diff)
downloadwireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.tar.xz
wireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.zip
Import LLVM 10.0.0 release including clang, lld and lldb.
ok hackroom tested by plenty
Diffstat (limited to 'gnu/llvm/lldb/source/Host/posix/PipePosix.cpp')
-rw-r--r--gnu/llvm/lldb/source/Host/posix/PipePosix.cpp318
1 files changed, 318 insertions, 0 deletions
diff --git a/gnu/llvm/lldb/source/Host/posix/PipePosix.cpp b/gnu/llvm/lldb/source/Host/posix/PipePosix.cpp
new file mode 100644
index 00000000000..3558ebcdc96
--- /dev/null
+++ b/gnu/llvm/lldb/source/Host/posix/PipePosix.cpp
@@ -0,0 +1,318 @@
+//===-- PipePosix.cpp -------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/posix/PipePosix.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Utility/SelectHelper.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Errno.h"
+#include "llvm/Support/FileSystem.h"
+
+#if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8))
+#ifndef _GLIBCXX_USE_NANOSLEEP
+#define _GLIBCXX_USE_NANOSLEEP
+#endif
+#endif
+
+#include <functional>
+#include <thread>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+int PipePosix::kInvalidDescriptor = -1;
+
+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__) || defined(__OpenBSD__)
+#define PIPE2_SUPPORTED 1
+#else
+#define PIPE2_SUPPORTED 0
+#endif
+
+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);
+}
+#endif
+
+std::chrono::time_point<std::chrono::steady_clock> Now() {
+ return std::chrono::steady_clock::now();
+}
+} // namespace
+
+PipePosix::PipePosix()
+ : m_fds{PipePosix::kInvalidDescriptor, PipePosix::kInvalidDescriptor} {}
+
+PipePosix::PipePosix(lldb::pipe_t read, lldb::pipe_t write)
+ : m_fds{read, write} {}
+
+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;
+}
+
+PipePosix::~PipePosix() { Close(); }
+
+Status PipePosix::CreateNew(bool child_processes_inherit) {
+ if (CanRead() || CanWrite())
+ return Status(EINVAL, eErrorTypePOSIX);
+
+ Status error;
+#if PIPE2_SUPPORTED
+ if (::pipe2(m_fds, (child_processes_inherit) ? 0 : O_CLOEXEC) == 0)
+ return error;
+#else
+ 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
+ return error;
+ }
+#endif
+
+ error.SetErrorToErrno();
+ m_fds[READ] = PipePosix::kInvalidDescriptor;
+ m_fds[WRITE] = PipePosix::kInvalidDescriptor;
+ return error;
+}
+
+Status PipePosix::CreateNew(llvm::StringRef name, bool child_process_inherit) {
+ if (CanRead() || CanWrite())
+ return Status("Pipe is already opened");
+
+ Status error;
+ if (::mkfifo(name.data(), 0660) != 0)
+ error.SetErrorToErrno();
+
+ return error;
+}
+
+Status PipePosix::CreateWithUniqueName(llvm::StringRef prefix,
+ bool child_process_inherit,
+ llvm::SmallVectorImpl<char> &name) {
+ llvm::SmallString<128> named_pipe_path;
+ llvm::SmallString<128> pipe_spec((prefix + ".%%%%%%").str());
+ FileSpec tmpdir_file_spec = HostInfo::GetProcessTempDir();
+ if (!tmpdir_file_spec)
+ tmpdir_file_spec.AppendPathComponent("/tmp");
+ tmpdir_file_spec.AppendPathComponent(pipe_spec);
+
+ // 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.
+ Status 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;
+}
+
+Status PipePosix::OpenAsReader(llvm::StringRef name,
+ bool child_process_inherit) {
+ if (CanRead() || CanWrite())
+ return Status("Pipe is already opened");
+
+ int flags = O_RDONLY | O_NONBLOCK;
+ if (!child_process_inherit)
+ flags |= O_CLOEXEC;
+
+ Status error;
+ int fd = llvm::sys::RetryAfterSignal(-1, ::open, name.data(), flags);
+ if (fd != -1)
+ m_fds[READ] = fd;
+ else
+ error.SetErrorToErrno();
+
+ return error;
+}
+
+Status
+PipePosix::OpenAsWriterWithTimeout(llvm::StringRef name,
+ bool child_process_inherit,
+ const std::chrono::microseconds &timeout) {
+ if (CanRead() || CanWrite())
+ return Status("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 Status("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 && errno_copy != EINTR)
+ return Status(errno_copy, eErrorTypePOSIX);
+
+ std::this_thread::sleep_for(
+ milliseconds(OPEN_WRITER_SLEEP_TIMEOUT_MSECS));
+ } else {
+ m_fds[WRITE] = fd;
+ }
+ }
+
+ return Status();
+}
+
+int PipePosix::GetReadFileDescriptor() const { return m_fds[READ]; }
+
+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;
+}
+
+void PipePosix::Close() {
+ CloseReadFileDescriptor();
+ CloseWriteFileDescriptor();
+}
+
+Status PipePosix::Delete(llvm::StringRef name) {
+ return llvm::sys::fs::remove(name);
+}
+
+bool PipePosix::CanRead() const {
+ return m_fds[READ] != 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::CloseWriteFileDescriptor() {
+ if (CanWrite()) {
+ close(m_fds[WRITE]);
+ m_fds[WRITE] = PipePosix::kInvalidDescriptor;
+ }
+}
+
+Status PipePosix::ReadWithTimeout(void *buf, size_t size,
+ const std::chrono::microseconds &timeout,
+ size_t &bytes_read) {
+ bytes_read = 0;
+ if (!CanRead())
+ return Status(EINVAL, eErrorTypePOSIX);
+
+ const int fd = GetReadFileDescriptor();
+
+ SelectHelper select_helper;
+ select_helper.SetTimeout(timeout);
+ select_helper.FDSetRead(fd);
+
+ Status error;
+ while (error.Success()) {
+ error = select_helper.Select();
+ if (error.Success()) {
+ auto result =
+ ::read(fd, static_cast<char *>(buf) + bytes_read, size - bytes_read);
+ if (result != -1) {
+ bytes_read += result;
+ if (bytes_read == size || result == 0)
+ break;
+ } else if (errno == EINTR) {
+ continue;
+ } else {
+ error.SetErrorToErrno();
+ break;
+ }
+ }
+ }
+ return error;
+}
+
+Status PipePosix::Write(const void *buf, size_t size, size_t &bytes_written) {
+ bytes_written = 0;
+ if (!CanWrite())
+ return Status(EINVAL, eErrorTypePOSIX);
+
+ const int fd = GetWriteFileDescriptor();
+ SelectHelper select_helper;
+ select_helper.SetTimeout(std::chrono::seconds(0));
+ select_helper.FDSetWrite(fd);
+
+ Status error;
+ while (error.Success()) {
+ error = select_helper.Select();
+ if (error.Success()) {
+ auto result = ::write(fd, static_cast<const char *>(buf) + bytes_written,
+ size - bytes_written);
+ if (result != -1) {
+ bytes_written += result;
+ if (bytes_written == size)
+ break;
+ } else if (errno == EINTR) {
+ continue;
+ } else {
+ error.SetErrorToErrno();
+ }
+ }
+ }
+ return error;
+}