blob: 6695bbfbac7ebf08c1703793458d213195f688b0 [file] [log] [blame]
Zachary Turnerb2df30d2014-10-08 20:38:41 +00001//===-- PipePosix.cpp -------------------------------------------*- C++ -*-===//
Greg Clayton100eb932014-07-02 21:10:39 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Zachary Turnerb2df30d2014-10-08 20:38:41 +000010#include "lldb/Host/posix/PipePosix.h"
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +000011#include "lldb/Host/FileSystem.h"
Oleksiy Vyalov4536c452015-02-05 16:29:12 +000012#include "lldb/Host/HostInfo.h"
Greg Claytonee1f5782016-08-10 22:43:48 +000013#include "lldb/Utility/SelectHelper.h"
Oleksiy Vyalov4536c452015-02-05 16:29:12 +000014#include "llvm/ADT/SmallString.h"
15#include "llvm/Support/FileSystem.h"
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +000016
Omair Javaid20405482015-08-09 19:04:41 +000017#if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8))
Stephane Sezer4d640f22015-09-09 01:17:24 +000018#ifndef _GLIBCXX_USE_NANOSLEEP
Omair Javaid20405482015-08-09 19:04:41 +000019#define _GLIBCXX_USE_NANOSLEEP
20#endif
Stephane Sezer4d640f22015-09-09 01:17:24 +000021#endif
Omair Javaid20405482015-08-09 19:04:41 +000022
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +000023#include <functional>
24#include <thread>
Greg Clayton100eb932014-07-02 21:10:39 +000025
Zachary Turner0b9d3ee2014-12-17 18:02:19 +000026#include <errno.h>
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +000027#include <fcntl.h>
Oleksiy Vyalov4536c452015-02-05 16:29:12 +000028#include <limits.h>
Zachary Turner0b9d3ee2014-12-17 18:02:19 +000029#include <unistd.h>
30#include <sys/types.h>
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +000031#include <sys/stat.h>
Greg Clayton100eb932014-07-02 21:10:39 +000032
Zachary Turner0b9d3ee2014-12-17 18:02:19 +000033using namespace lldb;
Greg Clayton100eb932014-07-02 21:10:39 +000034using namespace lldb_private;
35
Zachary Turner0b9d3ee2014-12-17 18:02:19 +000036int PipePosix::kInvalidDescriptor = -1;
Greg Clayton100eb932014-07-02 21:10:39 +000037
38enum PIPES { READ, WRITE }; // Constants 0 and 1 for READ and WRITE
39
Ed Maste37366e52015-09-14 15:12:49 +000040// pipe2 is supported by a limited set of platforms
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +000041// TODO: Add more platforms that support pipe2.
Ed Maste37366e52015-09-14 15:12:49 +000042#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__NetBSD__)
Zachary Turner0b9d3ee2014-12-17 18:02:19 +000043#define PIPE2_SUPPORTED 1
44#else
45#define PIPE2_SUPPORTED 0
46#endif
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +000047
48namespace
49{
50
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +000051constexpr auto OPEN_WRITER_SLEEP_TIMEOUT_MSECS = 100;
52
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +000053#if defined(FD_CLOEXEC) && !PIPE2_SUPPORTED
54bool SetCloexecFlag(int fd)
55{
56 int flags = ::fcntl(fd, F_GETFD);
57 if (flags == -1)
58 return false;
59 return (::fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == 0);
60}
61#endif
62
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +000063std::chrono::time_point<std::chrono::steady_clock>
64Now()
65{
66 return std::chrono::steady_clock::now();
67}
68
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +000069}
70
Zachary Turner0b9d3ee2014-12-17 18:02:19 +000071PipePosix::PipePosix()
Chaoren Linec534822015-05-01 16:49:23 +000072 : m_fds{
73 PipePosix::kInvalidDescriptor,
74 PipePosix::kInvalidDescriptor
75 } {}
Chaoren Lina52f4842015-04-29 17:36:58 +000076
77PipePosix::PipePosix(int read_fd, int write_fd)
78 : m_fds{read_fd, write_fd} {}
Greg Clayton100eb932014-07-02 21:10:39 +000079
Chaoren Linec534822015-05-01 16:49:23 +000080PipePosix::PipePosix(PipePosix &&pipe_posix)
81 : PipeBase{std::move(pipe_posix)},
82 m_fds{
83 pipe_posix.ReleaseReadFileDescriptor(),
84 pipe_posix.ReleaseWriteFileDescriptor()
85 } {}
86
87PipePosix &PipePosix::operator=(PipePosix &&pipe_posix)
88{
89 PipeBase::operator=(std::move(pipe_posix));
90 m_fds[READ] = pipe_posix.ReleaseReadFileDescriptor();
91 m_fds[WRITE] = pipe_posix.ReleaseWriteFileDescriptor();
92 return *this;
93}
94
Zachary Turner0b9d3ee2014-12-17 18:02:19 +000095PipePosix::~PipePosix()
Greg Clayton100eb932014-07-02 21:10:39 +000096{
97 Close();
98}
99
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000100Error
101PipePosix::CreateNew(bool child_processes_inherit)
Greg Clayton100eb932014-07-02 21:10:39 +0000102{
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000103 if (CanRead() || CanWrite())
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000104 return Error(EINVAL, eErrorTypePOSIX);
Greg Clayton100eb932014-07-02 21:10:39 +0000105
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000106 Error error;
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +0000107#if PIPE2_SUPPORTED
108 if (::pipe2(m_fds, (child_processes_inherit) ? 0 : O_CLOEXEC) == 0)
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000109 return error;
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +0000110#else
111 if (::pipe(m_fds) == 0)
112 {
113#ifdef FD_CLOEXEC
114 if (!child_processes_inherit)
115 {
116 if (!SetCloexecFlag(m_fds[0]) || !SetCloexecFlag(m_fds[1]))
117 {
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000118 error.SetErrorToErrno();
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +0000119 Close();
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000120 return error;
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +0000121 }
122 }
123#endif
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000124 return error;
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +0000125 }
126#endif
Zachary Turnerb2df30d2014-10-08 20:38:41 +0000127
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000128 error.SetErrorToErrno();
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000129 m_fds[READ] = PipePosix::kInvalidDescriptor;
130 m_fds[WRITE] = PipePosix::kInvalidDescriptor;
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000131 return error;
132}
133
134Error
135PipePosix::CreateNew(llvm::StringRef name, bool child_process_inherit)
136{
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000137 if (CanRead() || CanWrite())
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000138 return Error("Pipe is already opened");
139
140 Error error;
141 if (::mkfifo(name.data(), 0660) != 0)
142 error.SetErrorToErrno();
143
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000144 return error;
145}
146
147Error
Oleksiy Vyalov4536c452015-02-05 16:29:12 +0000148PipePosix::CreateWithUniqueName(llvm::StringRef prefix, bool child_process_inherit, llvm::SmallVectorImpl<char>& name)
149{
150 llvm::SmallString<PATH_MAX> named_pipe_path;
151 llvm::SmallString<PATH_MAX> pipe_spec((prefix + ".%%%%%%").str());
152 FileSpec tmpdir_file_spec;
153 tmpdir_file_spec.Clear();
154 if (HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
155 {
156 tmpdir_file_spec.AppendPathComponent(pipe_spec.c_str());
157 }
158 else
159 {
160 tmpdir_file_spec.AppendPathComponent("/tmp");
161 tmpdir_file_spec.AppendPathComponent(pipe_spec.c_str());
162 }
163
164 // It's possible that another process creates the target path after we've
165 // verified it's available but before we create it, in which case we
166 // should try again.
167 Error error;
168 do {
169 llvm::sys::fs::createUniqueFile(tmpdir_file_spec.GetPath().c_str(), named_pipe_path);
170 error = CreateNew(named_pipe_path, child_process_inherit);
171 } while (error.GetError() == EEXIST);
172
173 if (error.Success())
174 name = named_pipe_path;
175 return error;
176}
177
178Error
Oleksiy Vyalov47718292015-01-14 01:31:27 +0000179PipePosix::OpenAsReader(llvm::StringRef name, bool child_process_inherit)
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000180{
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000181 if (CanRead() || CanWrite())
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000182 return Error("Pipe is already opened");
183
184 int flags = O_RDONLY | O_NONBLOCK;
185 if (!child_process_inherit)
186 flags |= O_CLOEXEC;
187
188 Error error;
189 int fd = ::open(name.data(), flags);
190 if (fd != -1)
191 m_fds[READ] = fd;
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000192 else
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000193 error.SetErrorToErrno();
194
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000195 return error;
196}
197
198Error
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000199PipePosix::OpenAsWriterWithTimeout(llvm::StringRef name, bool child_process_inherit, const std::chrono::microseconds &timeout)
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000200{
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000201 if (CanRead() || CanWrite())
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000202 return Error("Pipe is already opened");
203
204 int flags = O_WRONLY | O_NONBLOCK;
205 if (!child_process_inherit)
206 flags |= O_CLOEXEC;
207
208 using namespace std::chrono;
209 const auto finish_time = Now() + timeout;
210
211 while (!CanWrite())
212 {
Pavel Labath7c52f852015-07-21 11:04:52 +0000213 if (timeout != microseconds::zero())
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000214 {
215 const auto dur = duration_cast<microseconds>(finish_time - Now()).count();
216 if (dur <= 0)
217 return Error("timeout exceeded - reader hasn't opened so far");
218 }
219
220 errno = 0;
221 int fd = ::open(name.data(), flags);
222 if (fd == -1)
223 {
224 const auto errno_copy = errno;
225 // We may get ENXIO if a reader side of the pipe hasn't opened yet.
226 if (errno_copy != ENXIO)
227 return Error(errno_copy, eErrorTypePOSIX);
228
229 std::this_thread::sleep_for(milliseconds(OPEN_WRITER_SLEEP_TIMEOUT_MSECS));
230 }
231 else
232 {
233 m_fds[WRITE] = fd;
234 }
235 }
236
237 return Error();
Greg Clayton100eb932014-07-02 21:10:39 +0000238}
239
240int
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000241PipePosix::GetReadFileDescriptor() const
Greg Clayton100eb932014-07-02 21:10:39 +0000242{
243 return m_fds[READ];
244}
245
246int
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000247PipePosix::GetWriteFileDescriptor() const
Greg Clayton100eb932014-07-02 21:10:39 +0000248{
249 return m_fds[WRITE];
250}
251
252int
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000253PipePosix::ReleaseReadFileDescriptor()
Greg Clayton100eb932014-07-02 21:10:39 +0000254{
255 const int fd = m_fds[READ];
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000256 m_fds[READ] = PipePosix::kInvalidDescriptor;
Greg Clayton100eb932014-07-02 21:10:39 +0000257 return fd;
258}
259
260int
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000261PipePosix::ReleaseWriteFileDescriptor()
Greg Clayton100eb932014-07-02 21:10:39 +0000262{
263 const int fd = m_fds[WRITE];
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000264 m_fds[WRITE] = PipePosix::kInvalidDescriptor;
Greg Clayton100eb932014-07-02 21:10:39 +0000265 return fd;
266}
267
268void
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000269PipePosix::Close()
Greg Clayton100eb932014-07-02 21:10:39 +0000270{
271 CloseReadFileDescriptor();
272 CloseWriteFileDescriptor();
273}
274
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000275Error
276PipePosix::Delete(llvm::StringRef name)
277{
Chaoren Lind3173f32015-05-29 19:52:29 +0000278 return FileSystem::Unlink(FileSpec{name.data(), true});
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000279}
280
Greg Clayton100eb932014-07-02 21:10:39 +0000281bool
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000282PipePosix::CanRead() const
Greg Clayton100eb932014-07-02 21:10:39 +0000283{
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000284 return m_fds[READ] != PipePosix::kInvalidDescriptor;
Greg Clayton100eb932014-07-02 21:10:39 +0000285}
286
287bool
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000288PipePosix::CanWrite() const
Greg Clayton100eb932014-07-02 21:10:39 +0000289{
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000290 return m_fds[WRITE] != PipePosix::kInvalidDescriptor;
Greg Clayton100eb932014-07-02 21:10:39 +0000291}
292
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000293void
294PipePosix::CloseReadFileDescriptor()
Greg Clayton100eb932014-07-02 21:10:39 +0000295{
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000296 if (CanRead())
Greg Clayton100eb932014-07-02 21:10:39 +0000297 {
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000298 close(m_fds[READ]);
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000299 m_fds[READ] = PipePosix::kInvalidDescriptor;
Greg Clayton100eb932014-07-02 21:10:39 +0000300 }
Greg Clayton100eb932014-07-02 21:10:39 +0000301}
302
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000303void
304PipePosix::CloseWriteFileDescriptor()
Greg Clayton100eb932014-07-02 21:10:39 +0000305{
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000306 if (CanWrite())
Greg Clayton100eb932014-07-02 21:10:39 +0000307 {
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000308 close(m_fds[WRITE]);
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000309 m_fds[WRITE] = PipePosix::kInvalidDescriptor;
Greg Clayton100eb932014-07-02 21:10:39 +0000310 }
Greg Clayton100eb932014-07-02 21:10:39 +0000311}
312
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000313Error
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000314PipePosix::ReadWithTimeout(void *buf, size_t size, const std::chrono::microseconds &timeout, size_t &bytes_read)
Greg Clayton100eb932014-07-02 21:10:39 +0000315{
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000316 bytes_read = 0;
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000317 if (!CanRead())
318 return Error(EINVAL, eErrorTypePOSIX);
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000319
Greg Claytonee1f5782016-08-10 22:43:48 +0000320 const int fd = GetReadFileDescriptor();
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000321
Greg Claytonee1f5782016-08-10 22:43:48 +0000322 SelectHelper select_helper;
323 select_helper.SetTimeout(timeout);
324 select_helper.FDSetRead(fd);
325
326 Error error;
327 while (error.Success())
328 {
329 error = select_helper.Select();
330 if (error.Success())
331 {
332 auto result = ::read(fd, reinterpret_cast<char*>(buf) + bytes_read, size - bytes_read);
333 if (result != -1)
334 {
335 bytes_read += result;
336 if (bytes_read == size || result == 0)
337 break;
338 }
339 else
340 {
341 error.SetErrorToErrno();
342 break;
343 }
344 }
345 }
346 return error;
Greg Clayton100eb932014-07-02 21:10:39 +0000347}
348
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000349Error
Pavel Labath7c52f852015-07-21 11:04:52 +0000350PipePosix::Write(const void *buf, size_t size, size_t &bytes_written)
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000351{
352 bytes_written = 0;
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000353 if (!CanWrite())
354 return Error(EINVAL, eErrorTypePOSIX);
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000355
Greg Claytonee1f5782016-08-10 22:43:48 +0000356 const int fd = GetWriteFileDescriptor();
357 SelectHelper select_helper;
358 select_helper.SetTimeout(std::chrono::seconds(0));
359 select_helper.FDSetWrite(fd);
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000360
Greg Claytonee1f5782016-08-10 22:43:48 +0000361 Error error;
362 while (error.Success())
363 {
364 error = select_helper.Select();
365 if (error.Success())
366 {
367 auto result = ::write(fd, reinterpret_cast<const char*>(buf) + bytes_written, size - bytes_written);
368 if (result != -1)
369 {
370 bytes_written += result;
371 if (bytes_written == size)
372 break;
373 }
374 else
375 {
376 error.SetErrorToErrno();
377 }
378 }
379 }
380 return error;
Greg Clayton100eb932014-07-02 21:10:39 +0000381}