Kate Stone b9c1b51e45 *** This commit represents a complete reformatting of the LLDB source code
*** to conform to clang-format’s LLVM style.  This kind of mass change has
*** two obvious implications:

Firstly, merging this particular commit into a downstream fork may be a huge
effort.  Alternatively, it may be worth merging all changes up to this commit,
performing the same reformatting operation locally, and then discarding the
merge for this particular commit.  The commands used to accomplish this
reformatting were as follows (with current working directory as the root of
the repository):

    find . \( -iname "*.c" -or -iname "*.cpp" -or -iname "*.h" -or -iname "*.mm" \) -exec clang-format -i {} +
    find . -iname "*.py" -exec autopep8 --in-place --aggressive --aggressive {} + ;

The version of clang-format used was 3.9.0, and autopep8 was 1.2.4.

Secondly, “blame” style tools will generally point to this commit instead of
a meaningful prior commit.  There are alternatives available that will attempt
to look through this change and find the appropriate prior commit.  YMMV.

llvm-svn: 280751
2016-09-06 20:57:50 +00:00

319 lines
8.4 KiB
C++

//===-- PipePosix.cpp -------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#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"
#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__)
#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();
}
}
PipePosix::PipePosix()
: m_fds{PipePosix::kInvalidDescriptor, PipePosix::kInvalidDescriptor} {}
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;
}
PipePosix::~PipePosix() { Close(); }
Error PipePosix::CreateNew(bool child_processes_inherit) {
if (CanRead() || CanWrite())
return Error(EINVAL, eErrorTypePOSIX);
Error 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;
}
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();
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::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;
Error error;
int fd = ::open(name.data(), flags);
if (fd != -1)
m_fds[READ] = fd;
else
error.SetErrorToErrno();
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;
}
}
return Error();
}
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();
}
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::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;
}
}
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);
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;
}