12#include "llvm/ADT/SmallString.h"
13#include "llvm/Support/Errno.h"
14#include "llvm/Support/FileSystem.h"
28int PipePosix::kInvalidDescriptor = -1;
34#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 10) || \
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();
57 : m_fds{PipePosix::kInvalidDescriptor, PipePosix::kInvalidDescriptor} {}
60 : m_fds{read, write} {}
62PipePosix::PipePosix(PipePosix &&pipe_posix)
64 m_fds{pipe_posix.ReleaseReadFileDescriptor(),
65 pipe_posix.ReleaseWriteFileDescriptor()} {}
67PipePosix &PipePosix::operator=(PipePosix &&pipe_posix) {
68 PipeBase::operator=(std::move(pipe_posix));
69 m_fds[
READ] = pipe_posix.ReleaseReadFileDescriptor();
70 m_fds[
WRITE] = pipe_posix.ReleaseWriteFileDescriptor();
74PipePosix::~PipePosix() { Close(); }
76Status PipePosix::CreateNew(
bool child_processes_inherit) {
77 if (CanRead() || CanWrite())
82 if (::pipe2(m_fds, (child_processes_inherit) ? 0 : O_CLOEXEC) == 0)
85 if (::pipe(m_fds) == 0) {
87 if (!child_processes_inherit) {
89 error.SetErrorToErrno();
99 error.SetErrorToErrno();
100 m_fds[
READ] = PipePosix::kInvalidDescriptor;
101 m_fds[
WRITE] = PipePosix::kInvalidDescriptor;
105Status PipePosix::CreateNew(llvm::StringRef name,
bool child_process_inherit) {
106 if (CanRead() || CanWrite())
107 return Status(
"Pipe is already opened");
110 if (::mkfifo(name.str().c_str(), 0660) != 0)
111 error.SetErrorToErrno();
116Status PipePosix::CreateWithUniqueName(llvm::StringRef prefix,
117 bool child_process_inherit,
119 llvm::SmallString<128> named_pipe_path;
120 llvm::SmallString<128> pipe_spec((prefix +
".%%%%%%").str());
121 FileSpec tmpdir_file_spec = HostInfo::GetProcessTempDir();
122 if (!tmpdir_file_spec)
131 llvm::sys::fs::createUniquePath(tmpdir_file_spec.
GetPath(), named_pipe_path,
133 error = CreateNew(named_pipe_path, child_process_inherit);
134 }
while (
error.GetError() == EEXIST);
137 name = named_pipe_path;
141Status PipePosix::OpenAsReader(llvm::StringRef name,
142 bool child_process_inherit) {
143 if (CanRead() || CanWrite())
144 return Status(
"Pipe is already opened");
147 if (!child_process_inherit)
151 int fd = llvm::sys::RetryAfterSignal(-1, ::open, name.str().c_str(), flags);
155 error.SetErrorToErrno();
161PipePosix::OpenAsWriterWithTimeout(llvm::StringRef name,
162 bool child_process_inherit,
163 const std::chrono::microseconds &timeout) {
164 if (CanRead() || CanWrite())
165 return Status(
"Pipe is already opened");
168 if (!child_process_inherit)
171 using namespace std::chrono;
172 const auto finish_time =
Now() + timeout;
174 while (!CanWrite()) {
175 if (timeout != microseconds::zero()) {
176 const auto dur = duration_cast<microseconds>(finish_time -
Now()).count();
178 return Status(
"timeout exceeded - reader hasn't opened so far");
182 int fd = ::open(name.str().c_str(), flags);
184 const auto errno_copy = errno;
186 if (errno_copy != ENXIO && errno_copy != EINTR)
189 std::this_thread::sleep_for(
199int PipePosix::GetReadFileDescriptor()
const {
return m_fds[
READ]; }
201int PipePosix::GetWriteFileDescriptor()
const {
return m_fds[
WRITE]; }
203int PipePosix::ReleaseReadFileDescriptor() {
204 const int fd = m_fds[
READ];
205 m_fds[
READ] = PipePosix::kInvalidDescriptor;
209int PipePosix::ReleaseWriteFileDescriptor() {
210 const int fd = m_fds[
WRITE];
211 m_fds[
WRITE] = PipePosix::kInvalidDescriptor;
215void PipePosix::Close() {
216 CloseReadFileDescriptor();
217 CloseWriteFileDescriptor();
220Status PipePosix::Delete(llvm::StringRef name) {
221 return llvm::sys::fs::remove(name);
224bool PipePosix::CanRead()
const {
225 return m_fds[
READ] != PipePosix::kInvalidDescriptor;
228bool PipePosix::CanWrite()
const {
229 return m_fds[
WRITE] != PipePosix::kInvalidDescriptor;
232void PipePosix::CloseReadFileDescriptor() {
235 m_fds[
READ] = PipePosix::kInvalidDescriptor;
239void PipePosix::CloseWriteFileDescriptor() {
242 m_fds[
WRITE] = PipePosix::kInvalidDescriptor;
246Status PipePosix::ReadWithTimeout(
void *buf,
size_t size,
247 const std::chrono::microseconds &timeout,
248 size_t &bytes_read) {
253 const int fd = GetReadFileDescriptor();
260 while (
error.Success()) {
262 if (
error.Success()) {
264 ::read(fd,
static_cast<char *
>(buf) + bytes_read, size - bytes_read);
266 bytes_read += result;
267 if (bytes_read == size || result == 0)
269 }
else if (errno == EINTR) {
272 error.SetErrorToErrno();
280Status PipePosix::Write(
const void *buf,
size_t size,
size_t &bytes_written) {
285 const int fd = GetWriteFileDescriptor();
287 select_helper.
SetTimeout(std::chrono::seconds(0));
291 while (
error.Success()) {
293 if (
error.Success()) {
294 auto result = ::write(fd,
static_cast<const char *
>(buf) + bytes_written,
295 size - bytes_written);
297 bytes_written += result;
298 if (bytes_written == size)
300 }
else if (errno == EINTR) {
303 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.
A class that represents a running process on the host machine.
@ eErrorTypePOSIX
POSIX error codes.