blob: b321cad642758cbeaba24e75d527466f255e1c67 [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 Vyalov4536c452015-02-05 16:29:12 +000011#include "lldb/Host/HostInfo.h"
Greg Claytonee1f5782016-08-10 22:43:48 +000012#include "lldb/Utility/SelectHelper.h"
Oleksiy Vyalov4536c452015-02-05 16:29:12 +000013#include "llvm/ADT/SmallString.h"
14#include "llvm/Support/FileSystem.h"
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +000015
Omair Javaid20405482015-08-09 19:04:41 +000016#if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8))
Stephane Sezer4d640f22015-09-09 01:17:24 +000017#ifndef _GLIBCXX_USE_NANOSLEEP
Omair Javaid20405482015-08-09 19:04:41 +000018#define _GLIBCXX_USE_NANOSLEEP
19#endif
Stephane Sezer4d640f22015-09-09 01:17:24 +000020#endif
Omair Javaid20405482015-08-09 19:04:41 +000021
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +000022#include <functional>
23#include <thread>
Greg Clayton100eb932014-07-02 21:10:39 +000024
Zachary Turner0b9d3ee2014-12-17 18:02:19 +000025#include <errno.h>
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +000026#include <fcntl.h>
Oleksiy Vyalov4536c452015-02-05 16:29:12 +000027#include <limits.h>
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +000028#include <sys/stat.h>
Kate Stoneb9c1b512016-09-06 20:57:50 +000029#include <sys/types.h>
30#include <unistd.h>
Greg Clayton100eb932014-07-02 21:10:39 +000031
Zachary Turner0b9d3ee2014-12-17 18:02:19 +000032using namespace lldb;
Greg Clayton100eb932014-07-02 21:10:39 +000033using namespace lldb_private;
34
Zachary Turner0b9d3ee2014-12-17 18:02:19 +000035int PipePosix::kInvalidDescriptor = -1;
Greg Clayton100eb932014-07-02 21:10:39 +000036
37enum PIPES { READ, WRITE }; // Constants 0 and 1 for READ and WRITE
38
Ed Maste37366e52015-09-14 15:12:49 +000039// pipe2 is supported by a limited set of platforms
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +000040// TODO: Add more platforms that support pipe2.
Kate Stoneb9c1b512016-09-06 20:57:50 +000041#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 10) || \
42 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
Kate Stoneb9c1b512016-09-06 20:57:50 +000048namespace {
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +000049
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +000050constexpr auto OPEN_WRITER_SLEEP_TIMEOUT_MSECS = 100;
51
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +000052#if defined(FD_CLOEXEC) && !PIPE2_SUPPORTED
Kate Stoneb9c1b512016-09-06 20:57:50 +000053bool SetCloexecFlag(int fd) {
54 int flags = ::fcntl(fd, F_GETFD);
55 if (flags == -1)
56 return false;
57 return (::fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == 0);
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +000058}
59#endif
60
Kate Stoneb9c1b512016-09-06 20:57:50 +000061std::chrono::time_point<std::chrono::steady_clock> Now() {
62 return std::chrono::steady_clock::now();
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +000063}
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +000064}
65
Zachary Turner0b9d3ee2014-12-17 18:02:19 +000066PipePosix::PipePosix()
Kate Stoneb9c1b512016-09-06 20:57:50 +000067 : m_fds{PipePosix::kInvalidDescriptor, PipePosix::kInvalidDescriptor} {}
Chaoren Lina52f4842015-04-29 17:36:58 +000068
Kate Stoneb9c1b512016-09-06 20:57:50 +000069PipePosix::PipePosix(int read_fd, int write_fd) : m_fds{read_fd, write_fd} {}
Greg Clayton100eb932014-07-02 21:10:39 +000070
Chaoren Linec534822015-05-01 16:49:23 +000071PipePosix::PipePosix(PipePosix &&pipe_posix)
72 : PipeBase{std::move(pipe_posix)},
Kate Stoneb9c1b512016-09-06 20:57:50 +000073 m_fds{pipe_posix.ReleaseReadFileDescriptor(),
74 pipe_posix.ReleaseWriteFileDescriptor()} {}
Chaoren Linec534822015-05-01 16:49:23 +000075
Kate Stoneb9c1b512016-09-06 20:57:50 +000076PipePosix &PipePosix::operator=(PipePosix &&pipe_posix) {
77 PipeBase::operator=(std::move(pipe_posix));
78 m_fds[READ] = pipe_posix.ReleaseReadFileDescriptor();
79 m_fds[WRITE] = pipe_posix.ReleaseWriteFileDescriptor();
80 return *this;
Chaoren Linec534822015-05-01 16:49:23 +000081}
82
Kate Stoneb9c1b512016-09-06 20:57:50 +000083PipePosix::~PipePosix() { Close(); }
Greg Clayton100eb932014-07-02 21:10:39 +000084
Zachary Turner97206d52017-05-12 04:51:55 +000085Status PipePosix::CreateNew(bool child_processes_inherit) {
Kate Stoneb9c1b512016-09-06 20:57:50 +000086 if (CanRead() || CanWrite())
Zachary Turner97206d52017-05-12 04:51:55 +000087 return Status(EINVAL, eErrorTypePOSIX);
Greg Clayton100eb932014-07-02 21:10:39 +000088
Zachary Turner97206d52017-05-12 04:51:55 +000089 Status error;
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +000090#if PIPE2_SUPPORTED
Kate Stoneb9c1b512016-09-06 20:57:50 +000091 if (::pipe2(m_fds, (child_processes_inherit) ? 0 : O_CLOEXEC) == 0)
92 return error;
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +000093#else
Kate Stoneb9c1b512016-09-06 20:57:50 +000094 if (::pipe(m_fds) == 0) {
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +000095#ifdef FD_CLOEXEC
Kate Stoneb9c1b512016-09-06 20:57:50 +000096 if (!child_processes_inherit) {
97 if (!SetCloexecFlag(m_fds[0]) || !SetCloexecFlag(m_fds[1])) {
98 error.SetErrorToErrno();
99 Close();
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000100 return error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000101 }
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +0000102 }
103#endif
Kate Stoneb9c1b512016-09-06 20:57:50 +0000104 return error;
105 }
106#endif
Zachary Turnerb2df30d2014-10-08 20:38:41 +0000107
Kate Stoneb9c1b512016-09-06 20:57:50 +0000108 error.SetErrorToErrno();
109 m_fds[READ] = PipePosix::kInvalidDescriptor;
110 m_fds[WRITE] = PipePosix::kInvalidDescriptor;
111 return error;
112}
113
Zachary Turner97206d52017-05-12 04:51:55 +0000114Status PipePosix::CreateNew(llvm::StringRef name, bool child_process_inherit) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000115 if (CanRead() || CanWrite())
Zachary Turner97206d52017-05-12 04:51:55 +0000116 return Status("Pipe is already opened");
Kate Stoneb9c1b512016-09-06 20:57:50 +0000117
Zachary Turner97206d52017-05-12 04:51:55 +0000118 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000119 if (::mkfifo(name.data(), 0660) != 0)
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000120 error.SetErrorToErrno();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000121
122 return error;
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000123}
124
Zachary Turner97206d52017-05-12 04:51:55 +0000125Status PipePosix::CreateWithUniqueName(llvm::StringRef prefix,
126 bool child_process_inherit,
127 llvm::SmallVectorImpl<char> &name) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000128 llvm::SmallString<PATH_MAX> named_pipe_path;
129 llvm::SmallString<PATH_MAX> pipe_spec((prefix + ".%%%%%%").str());
Pavel Labath60f028f2018-06-19 15:09:07 +0000130 FileSpec tmpdir_file_spec = HostInfo::GetProcessTempDir();
131 if (!tmpdir_file_spec)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000132 tmpdir_file_spec.AppendPathComponent("/tmp");
Pavel Labath60f028f2018-06-19 15:09:07 +0000133 tmpdir_file_spec.AppendPathComponent(pipe_spec);
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000134
Kate Stoneb9c1b512016-09-06 20:57:50 +0000135 // It's possible that another process creates the target path after we've
Adrian Prantl05097242018-04-30 16:49:04 +0000136 // verified it's available but before we create it, in which case we should
137 // try again.
Zachary Turner97206d52017-05-12 04:51:55 +0000138 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000139 do {
Malcolm Parsons771ef6d2016-11-02 20:34:10 +0000140 llvm::sys::fs::createUniqueFile(tmpdir_file_spec.GetPath(),
Kate Stoneb9c1b512016-09-06 20:57:50 +0000141 named_pipe_path);
142 error = CreateNew(named_pipe_path, child_process_inherit);
143 } while (error.GetError() == EEXIST);
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000144
Kate Stoneb9c1b512016-09-06 20:57:50 +0000145 if (error.Success())
146 name = named_pipe_path;
147 return error;
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000148}
149
Zachary Turner97206d52017-05-12 04:51:55 +0000150Status PipePosix::OpenAsReader(llvm::StringRef name,
151 bool child_process_inherit) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000152 if (CanRead() || CanWrite())
Zachary Turner97206d52017-05-12 04:51:55 +0000153 return Status("Pipe is already opened");
Kate Stoneb9c1b512016-09-06 20:57:50 +0000154
155 int flags = O_RDONLY | O_NONBLOCK;
156 if (!child_process_inherit)
157 flags |= O_CLOEXEC;
158
Zachary Turner97206d52017-05-12 04:51:55 +0000159 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000160 int fd = ::open(name.data(), flags);
161 if (fd != -1)
162 m_fds[READ] = fd;
163 else
164 error.SetErrorToErrno();
165
166 return error;
167}
168
Zachary Turner97206d52017-05-12 04:51:55 +0000169Status
170PipePosix::OpenAsWriterWithTimeout(llvm::StringRef name,
171 bool child_process_inherit,
172 const std::chrono::microseconds &timeout) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000173 if (CanRead() || CanWrite())
Zachary Turner97206d52017-05-12 04:51:55 +0000174 return Status("Pipe is already opened");
Kate Stoneb9c1b512016-09-06 20:57:50 +0000175
176 int flags = O_WRONLY | O_NONBLOCK;
177 if (!child_process_inherit)
178 flags |= O_CLOEXEC;
179
180 using namespace std::chrono;
181 const auto finish_time = Now() + timeout;
182
183 while (!CanWrite()) {
184 if (timeout != microseconds::zero()) {
185 const auto dur = duration_cast<microseconds>(finish_time - Now()).count();
186 if (dur <= 0)
Zachary Turner97206d52017-05-12 04:51:55 +0000187 return Status("timeout exceeded - reader hasn't opened so far");
Oleksiy Vyalov4536c452015-02-05 16:29:12 +0000188 }
189
Kate Stoneb9c1b512016-09-06 20:57:50 +0000190 errno = 0;
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000191 int fd = ::open(name.data(), flags);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000192 if (fd == -1) {
193 const auto errno_copy = errno;
194 // We may get ENXIO if a reader side of the pipe hasn't opened yet.
195 if (errno_copy != ENXIO)
Zachary Turner97206d52017-05-12 04:51:55 +0000196 return Status(errno_copy, eErrorTypePOSIX);
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000197
Kate Stoneb9c1b512016-09-06 20:57:50 +0000198 std::this_thread::sleep_for(
199 milliseconds(OPEN_WRITER_SLEEP_TIMEOUT_MSECS));
200 } else {
201 m_fds[WRITE] = fd;
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000202 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000203 }
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000204
Zachary Turner97206d52017-05-12 04:51:55 +0000205 return Status();
Greg Clayton100eb932014-07-02 21:10:39 +0000206}
207
Kate Stoneb9c1b512016-09-06 20:57:50 +0000208int PipePosix::GetReadFileDescriptor() const { return m_fds[READ]; }
209
210int PipePosix::GetWriteFileDescriptor() const { return m_fds[WRITE]; }
211
212int PipePosix::ReleaseReadFileDescriptor() {
213 const int fd = m_fds[READ];
214 m_fds[READ] = PipePosix::kInvalidDescriptor;
215 return fd;
Greg Clayton100eb932014-07-02 21:10:39 +0000216}
217
Kate Stoneb9c1b512016-09-06 20:57:50 +0000218int PipePosix::ReleaseWriteFileDescriptor() {
219 const int fd = m_fds[WRITE];
220 m_fds[WRITE] = PipePosix::kInvalidDescriptor;
221 return fd;
Greg Clayton100eb932014-07-02 21:10:39 +0000222}
223
Kate Stoneb9c1b512016-09-06 20:57:50 +0000224void PipePosix::Close() {
225 CloseReadFileDescriptor();
226 CloseWriteFileDescriptor();
227}
228
Zachary Turner97206d52017-05-12 04:51:55 +0000229Status PipePosix::Delete(llvm::StringRef name) {
Zachary Turner07db3f72017-03-21 05:47:57 +0000230 return llvm::sys::fs::remove(name);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000231}
232
233bool PipePosix::CanRead() const {
234 return m_fds[READ] != PipePosix::kInvalidDescriptor;
235}
236
237bool PipePosix::CanWrite() const {
238 return m_fds[WRITE] != PipePosix::kInvalidDescriptor;
239}
240
241void PipePosix::CloseReadFileDescriptor() {
242 if (CanRead()) {
243 close(m_fds[READ]);
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000244 m_fds[READ] = PipePosix::kInvalidDescriptor;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000245 }
Greg Clayton100eb932014-07-02 21:10:39 +0000246}
247
Kate Stoneb9c1b512016-09-06 20:57:50 +0000248void PipePosix::CloseWriteFileDescriptor() {
249 if (CanWrite()) {
250 close(m_fds[WRITE]);
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000251 m_fds[WRITE] = PipePosix::kInvalidDescriptor;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000252 }
Greg Clayton100eb932014-07-02 21:10:39 +0000253}
254
Zachary Turner97206d52017-05-12 04:51:55 +0000255Status PipePosix::ReadWithTimeout(void *buf, size_t size,
256 const std::chrono::microseconds &timeout,
257 size_t &bytes_read) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000258 bytes_read = 0;
259 if (!CanRead())
Zachary Turner97206d52017-05-12 04:51:55 +0000260 return Status(EINVAL, eErrorTypePOSIX);
Greg Clayton100eb932014-07-02 21:10:39 +0000261
Kate Stoneb9c1b512016-09-06 20:57:50 +0000262 const int fd = GetReadFileDescriptor();
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000263
Kate Stoneb9c1b512016-09-06 20:57:50 +0000264 SelectHelper select_helper;
265 select_helper.SetTimeout(timeout);
266 select_helper.FDSetRead(fd);
Greg Clayton100eb932014-07-02 21:10:39 +0000267
Zachary Turner97206d52017-05-12 04:51:55 +0000268 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000269 while (error.Success()) {
270 error = select_helper.Select();
271 if (error.Success()) {
272 auto result = ::read(fd, reinterpret_cast<char *>(buf) + bytes_read,
273 size - bytes_read);
274 if (result != -1) {
275 bytes_read += result;
276 if (bytes_read == size || result == 0)
277 break;
278 } else {
279 error.SetErrorToErrno();
280 break;
281 }
Greg Clayton100eb932014-07-02 21:10:39 +0000282 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000283 }
284 return error;
Greg Clayton100eb932014-07-02 21:10:39 +0000285}
286
Zachary Turner97206d52017-05-12 04:51:55 +0000287Status PipePosix::Write(const void *buf, size_t size, size_t &bytes_written) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000288 bytes_written = 0;
289 if (!CanWrite())
Zachary Turner97206d52017-05-12 04:51:55 +0000290 return Status(EINVAL, eErrorTypePOSIX);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000291
292 const int fd = GetWriteFileDescriptor();
293 SelectHelper select_helper;
294 select_helper.SetTimeout(std::chrono::seconds(0));
295 select_helper.FDSetWrite(fd);
296
Zachary Turner97206d52017-05-12 04:51:55 +0000297 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000298 while (error.Success()) {
299 error = select_helper.Select();
300 if (error.Success()) {
301 auto result =
302 ::write(fd, reinterpret_cast<const char *>(buf) + bytes_written,
303 size - bytes_written);
304 if (result != -1) {
305 bytes_written += result;
306 if (bytes_written == size)
307 break;
308 } else {
309 error.SetErrorToErrno();
310 }
Greg Clayton100eb932014-07-02 21:10:39 +0000311 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000312 }
313 return error;
Greg Clayton100eb932014-07-02 21:10:39 +0000314}