13#include "llvm/ADT/SmallString.h"
14#include "llvm/Support/Errno.h"
34#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
36#define PIPE2_SUPPORTED 1
38#define PIPE2_SUPPORTED 0
43#if defined(FD_CLOEXEC) && !PIPE2_SUPPORTED
45 int flags = ::fcntl(fd, F_GETFD);
48 return (::fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == 0);
52static std::chrono::time_point<std::chrono::steady_clock>
Now() {
53 return std::chrono::steady_clock::now();
60 : m_fds{read, write} {}
64 m_fds{pipe_posix.ReleaseReadFileDescriptor(),
65 pipe_posix.ReleaseWriteFileDescriptor()} {}
68 std::scoped_lock<std::mutex, std::mutex, std::mutex, std::mutex> guard(
70 pipe_posix.m_write_mutex);
72 PipeBase::operator=(std::move(pipe_posix));
73 m_fds[
READ] = pipe_posix.ReleaseReadFileDescriptorUnlocked();
74 m_fds[
WRITE] = pipe_posix.ReleaseWriteFileDescriptorUnlocked();
87 if (::pipe2(
m_fds, (child_processes_inherit) ? 0 : O_CLOEXEC) == 0)
90 if (::pipe(
m_fds) == 0) {
92 if (!child_processes_inherit) {
94 error.SetErrorToErrno();
104 error.SetErrorToErrno();
113 return Status(
"Pipe is already opened");
116 if (::mkfifo(name.str().c_str(), 0660) != 0)
117 error.SetErrorToErrno();
123 bool child_process_inherit,
125 llvm::SmallString<128> named_pipe_path;
126 llvm::SmallString<128> pipe_spec((prefix +
".%%%%%%").str());
127 FileSpec tmpdir_file_spec = HostInfo::GetProcessTempDir();
128 if (!tmpdir_file_spec)
137 llvm::sys::fs::createUniquePath(tmpdir_file_spec.
GetPath(), named_pipe_path,
140 }
while (
error.GetError() == EEXIST);
143 name = named_pipe_path;
148 bool child_process_inherit) {
152 return Status(
"Pipe is already opened");
155 if (!child_process_inherit)
163 error.SetErrorToErrno();
170 bool child_process_inherit,
171 const std::chrono::microseconds &timeout) {
174 return Status(
"Pipe is already opened");
177 if (!child_process_inherit)
180 using namespace std::chrono;
181 const auto finish_time =
Now() + timeout;
184 if (timeout != microseconds::zero()) {
185 const auto dur = duration_cast<microseconds>(finish_time -
Now()).count();
187 return Status(
"timeout exceeded - reader hasn't opened so far");
191 int fd = ::open(name.str().c_str(), flags);
193 const auto errno_copy = errno;
195 if (errno_copy != ENXIO && errno_copy != EINTR)
198 std::this_thread::sleep_for(
259 return llvm::sys::fs::remove(name);
304 const std::chrono::microseconds &timeout,
305 size_t &bytes_read) {
318 while (
error.Success()) {
320 if (
error.Success()) {
322 ::read(fd,
static_cast<char *
>(buf) + bytes_read, size - bytes_read);
324 bytes_read += result;
325 if (bytes_read == size || result == 0)
327 }
else if (errno == EINTR) {
330 error.SetErrorToErrno();
339 const std::chrono::microseconds &timeout,
340 size_t &bytes_written) {
352 while (
error.Success()) {
354 if (
error.Success()) {
355 auto result = ::write(fd,
static_cast<const char *
>(buf) + bytes_written,
356 size - bytes_written);
358 bytes_written += result;
359 if (bytes_written == size)
361 }
else if (errno == EINTR) {
364 error.SetErrorToErrno();
static llvm::raw_ostream & error(Stream &strm)
static std::chrono::time_point< std::chrono::steady_clock > Now()
static constexpr auto OPEN_WRITER_SLEEP_TIMEOUT_MSECS
static bool SetCloexecFlag(int fd)
lldb_private::Status Select()
void FDSetRead(lldb::socket_t fd)
void SetTimeout(const std::chrono::microseconds &timeout)
void FDSetWrite(lldb::socket_t fd)
void AppendPathComponent(llvm::StringRef component)
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
int Open(const char *path, int flags, int mode=0600)
Wraps ::open in a platform-independent way.
static FileSystem & Instance()
A posix-based implementation of Pipe, a class that abtracts unix style pipes.
Status OpenAsReader(llvm::StringRef name, bool child_process_inherit) override
int ReleaseWriteFileDescriptorUnlocked()
int GetReadFileDescriptor() const override
Status OpenAsWriterWithTimeout(llvm::StringRef name, bool child_process_inherit, const std::chrono::microseconds &timeout) override
void CloseWriteFileDescriptor() override
bool CanWrite() const override
bool CanRead() const override
static int kInvalidDescriptor
Status ReadWithTimeout(void *buf, size_t size, const std::chrono::microseconds &timeout, size_t &bytes_read) override
std::mutex m_read_mutex
Mutexes for m_fds;.
int ReleaseReadFileDescriptor() override
Status Delete(llvm::StringRef name) override
int ReleaseReadFileDescriptorUnlocked()
void CloseWriteFileDescriptorUnlocked()
int GetReadFileDescriptorUnlocked() const
Status CreateWithUniqueName(llvm::StringRef prefix, bool child_process_inherit, llvm::SmallVectorImpl< char > &name) override
bool CanWriteUnlocked() const
PipePosix & operator=(const PipePosix &)=delete
int ReleaseWriteFileDescriptor() override
void CloseReadFileDescriptorUnlocked()
Status WriteWithTimeout(const void *buf, size_t size, const std::chrono::microseconds &timeout, size_t &bytes_written) override
void CloseReadFileDescriptor() override
Status CreateNew(bool child_process_inherit) override
bool CanReadUnlocked() const
int GetWriteFileDescriptor() const override
int GetWriteFileDescriptorUnlocked() const
A class that represents a running process on the host machine.
@ eErrorTypePOSIX
POSIX error codes.