blob: 4e0810c1a9b382567b62e94c5ded03cbbed6732a [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>
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +000029#include <sys/stat.h>
Kate Stoneb9c1b512016-09-06 20:57:50 +000030#include <sys/types.h>
31#include <unistd.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.
Kate Stoneb9c1b512016-09-06 20:57:50 +000042#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 10) || \
43 defined(__NetBSD__)
Zachary Turner0b9d3ee2014-12-17 18:02:19 +000044#define PIPE2_SUPPORTED 1
45#else
46#define PIPE2_SUPPORTED 0
47#endif
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +000048
Kate Stoneb9c1b512016-09-06 20:57:50 +000049namespace {
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +000050
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
Kate Stoneb9c1b512016-09-06 20:57:50 +000054bool SetCloexecFlag(int fd) {
55 int flags = ::fcntl(fd, F_GETFD);
56 if (flags == -1)
57 return false;
58 return (::fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == 0);
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +000059}
60#endif
61
Kate Stoneb9c1b512016-09-06 20:57:50 +000062std::chrono::time_point<std::chrono::steady_clock> Now() {
63 return std::chrono::steady_clock::now();
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +000064}
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +000065}
66
Zachary Turner0b9d3ee2014-12-17 18:02:19 +000067PipePosix::PipePosix()
Kate Stoneb9c1b512016-09-06 20:57:50 +000068 : m_fds{PipePosix::kInvalidDescriptor, PipePosix::kInvalidDescriptor} {}
Chaoren Lina52f4842015-04-29 17:36:58 +000069
Kate Stoneb9c1b512016-09-06 20:57:50 +000070PipePosix::PipePosix(int read_fd, int write_fd) : m_fds{read_fd, write_fd} {}
Greg Clayton100eb932014-07-02 21:10:39 +000071
Chaoren Linec534822015-05-01 16:49:23 +000072PipePosix::PipePosix(PipePosix &&pipe_posix)
73 : PipeBase{std::move(pipe_posix)},
Kate Stoneb9c1b512016-09-06 20:57:50 +000074 m_fds{pipe_posix.ReleaseReadFileDescriptor(),
75 pipe_posix.ReleaseWriteFileDescriptor()} {}
Chaoren Linec534822015-05-01 16:49:23 +000076
Kate Stoneb9c1b512016-09-06 20:57:50 +000077PipePosix &PipePosix::operator=(PipePosix &&pipe_posix) {
78 PipeBase::operator=(std::move(pipe_posix));
79 m_fds[READ] = pipe_posix.ReleaseReadFileDescriptor();
80 m_fds[WRITE] = pipe_posix.ReleaseWriteFileDescriptor();
81 return *this;
Chaoren Linec534822015-05-01 16:49:23 +000082}
83
Kate Stoneb9c1b512016-09-06 20:57:50 +000084PipePosix::~PipePosix() { Close(); }
Greg Clayton100eb932014-07-02 21:10:39 +000085
Kate Stoneb9c1b512016-09-06 20:57:50 +000086Error PipePosix::CreateNew(bool child_processes_inherit) {
87 if (CanRead() || CanWrite())
88 return Error(EINVAL, eErrorTypePOSIX);
Greg Clayton100eb932014-07-02 21:10:39 +000089
Kate Stoneb9c1b512016-09-06 20:57:50 +000090 Error error;
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +000091#if PIPE2_SUPPORTED
Kate Stoneb9c1b512016-09-06 20:57:50 +000092 if (::pipe2(m_fds, (child_processes_inherit) ? 0 : O_CLOEXEC) == 0)
93 return error;
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +000094#else
Kate Stoneb9c1b512016-09-06 20:57:50 +000095 if (::pipe(m_fds) == 0) {
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +000096#ifdef FD_CLOEXEC
Kate Stoneb9c1b512016-09-06 20:57:50 +000097 if (!child_processes_inherit) {
98 if (!SetCloexecFlag(m_fds[0]) || !SetCloexecFlag(m_fds[1])) {
99 error.SetErrorToErrno();
100 Close();
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000101 return error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000102 }
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +0000103 }
104#endif
Kate Stoneb9c1b512016-09-06 20:57:50 +0000105 return error;
106 }
107#endif
Zachary Turnerb2df30d2014-10-08 20:38:41 +0000108
Kate Stoneb9c1b512016-09-06 20:57:50 +0000109 error.SetErrorToErrno();
110 m_fds[READ] = PipePosix::kInvalidDescriptor;
111 m_fds[WRITE] = PipePosix::kInvalidDescriptor;
112 return error;
113}
114
115Error PipePosix::CreateNew(llvm::StringRef name, bool child_process_inherit) {
116 if (CanRead() || CanWrite())
117 return Error("Pipe is already opened");
118
119 Error error;
120 if (::mkfifo(name.data(), 0660) != 0)
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000121 error.SetErrorToErrno();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000122
123 return error;
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000124}
125
Kate Stoneb9c1b512016-09-06 20:57:50 +0000126Error PipePosix::CreateWithUniqueName(llvm::StringRef prefix,
127 bool child_process_inherit,
128 llvm::SmallVectorImpl<char> &name) {
129 llvm::SmallString<PATH_MAX> named_pipe_path;
130 llvm::SmallString<PATH_MAX> pipe_spec((prefix + ".%%%%%%").str());
131 FileSpec tmpdir_file_spec;
132 tmpdir_file_spec.Clear();
133 if (HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) {
134 tmpdir_file_spec.AppendPathComponent(pipe_spec.c_str());
135 } else {
136 tmpdir_file_spec.AppendPathComponent("/tmp");
137 tmpdir_file_spec.AppendPathComponent(pipe_spec.c_str());
138 }
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000139
Kate Stoneb9c1b512016-09-06 20:57:50 +0000140 // It's possible that another process creates the target path after we've
141 // verified it's available but before we create it, in which case we
142 // should try again.
143 Error error;
144 do {
Malcolm Parsons771ef6d2016-11-02 20:34:10 +0000145 llvm::sys::fs::createUniqueFile(tmpdir_file_spec.GetPath(),
Kate Stoneb9c1b512016-09-06 20:57:50 +0000146 named_pipe_path);
147 error = CreateNew(named_pipe_path, child_process_inherit);
148 } while (error.GetError() == EEXIST);
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000149
Kate Stoneb9c1b512016-09-06 20:57:50 +0000150 if (error.Success())
151 name = named_pipe_path;
152 return error;
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000153}
154
Kate Stoneb9c1b512016-09-06 20:57:50 +0000155Error PipePosix::OpenAsReader(llvm::StringRef name,
156 bool child_process_inherit) {
157 if (CanRead() || CanWrite())
158 return Error("Pipe is already opened");
159
160 int flags = O_RDONLY | O_NONBLOCK;
161 if (!child_process_inherit)
162 flags |= O_CLOEXEC;
163
164 Error error;
165 int fd = ::open(name.data(), flags);
166 if (fd != -1)
167 m_fds[READ] = fd;
168 else
169 error.SetErrorToErrno();
170
171 return error;
172}
173
174Error PipePosix::OpenAsWriterWithTimeout(
175 llvm::StringRef name, bool child_process_inherit,
176 const std::chrono::microseconds &timeout) {
177 if (CanRead() || CanWrite())
178 return Error("Pipe is already opened");
179
180 int flags = O_WRONLY | O_NONBLOCK;
181 if (!child_process_inherit)
182 flags |= O_CLOEXEC;
183
184 using namespace std::chrono;
185 const auto finish_time = Now() + timeout;
186
187 while (!CanWrite()) {
188 if (timeout != microseconds::zero()) {
189 const auto dur = duration_cast<microseconds>(finish_time - Now()).count();
190 if (dur <= 0)
191 return Error("timeout exceeded - reader hasn't opened so far");
Oleksiy Vyalov4536c452015-02-05 16:29:12 +0000192 }
193
Kate Stoneb9c1b512016-09-06 20:57:50 +0000194 errno = 0;
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000195 int fd = ::open(name.data(), flags);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000196 if (fd == -1) {
197 const auto errno_copy = errno;
198 // We may get ENXIO if a reader side of the pipe hasn't opened yet.
199 if (errno_copy != ENXIO)
200 return Error(errno_copy, eErrorTypePOSIX);
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000201
Kate Stoneb9c1b512016-09-06 20:57:50 +0000202 std::this_thread::sleep_for(
203 milliseconds(OPEN_WRITER_SLEEP_TIMEOUT_MSECS));
204 } else {
205 m_fds[WRITE] = fd;
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000206 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000207 }
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000208
Mehdi Aminic1edf562016-11-11 04:29:25 +0000209 return Error();
Greg Clayton100eb932014-07-02 21:10:39 +0000210}
211
Kate Stoneb9c1b512016-09-06 20:57:50 +0000212int PipePosix::GetReadFileDescriptor() const { return m_fds[READ]; }
213
214int PipePosix::GetWriteFileDescriptor() const { return m_fds[WRITE]; }
215
216int PipePosix::ReleaseReadFileDescriptor() {
217 const int fd = m_fds[READ];
218 m_fds[READ] = PipePosix::kInvalidDescriptor;
219 return fd;
Greg Clayton100eb932014-07-02 21:10:39 +0000220}
221
Kate Stoneb9c1b512016-09-06 20:57:50 +0000222int PipePosix::ReleaseWriteFileDescriptor() {
223 const int fd = m_fds[WRITE];
224 m_fds[WRITE] = PipePosix::kInvalidDescriptor;
225 return fd;
Greg Clayton100eb932014-07-02 21:10:39 +0000226}
227
Kate Stoneb9c1b512016-09-06 20:57:50 +0000228void PipePosix::Close() {
229 CloseReadFileDescriptor();
230 CloseWriteFileDescriptor();
231}
232
233Error PipePosix::Delete(llvm::StringRef name) {
234 return FileSystem::Unlink(FileSpec{name.data(), true});
235}
236
237bool PipePosix::CanRead() const {
238 return m_fds[READ] != PipePosix::kInvalidDescriptor;
239}
240
241bool PipePosix::CanWrite() const {
242 return m_fds[WRITE] != PipePosix::kInvalidDescriptor;
243}
244
245void PipePosix::CloseReadFileDescriptor() {
246 if (CanRead()) {
247 close(m_fds[READ]);
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000248 m_fds[READ] = PipePosix::kInvalidDescriptor;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000249 }
Greg Clayton100eb932014-07-02 21:10:39 +0000250}
251
Kate Stoneb9c1b512016-09-06 20:57:50 +0000252void PipePosix::CloseWriteFileDescriptor() {
253 if (CanWrite()) {
254 close(m_fds[WRITE]);
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000255 m_fds[WRITE] = PipePosix::kInvalidDescriptor;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000256 }
Greg Clayton100eb932014-07-02 21:10:39 +0000257}
258
Kate Stoneb9c1b512016-09-06 20:57:50 +0000259Error PipePosix::ReadWithTimeout(void *buf, size_t size,
260 const std::chrono::microseconds &timeout,
261 size_t &bytes_read) {
262 bytes_read = 0;
263 if (!CanRead())
264 return Error(EINVAL, eErrorTypePOSIX);
Greg Clayton100eb932014-07-02 21:10:39 +0000265
Kate Stoneb9c1b512016-09-06 20:57:50 +0000266 const int fd = GetReadFileDescriptor();
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000267
Kate Stoneb9c1b512016-09-06 20:57:50 +0000268 SelectHelper select_helper;
269 select_helper.SetTimeout(timeout);
270 select_helper.FDSetRead(fd);
Greg Clayton100eb932014-07-02 21:10:39 +0000271
Kate Stoneb9c1b512016-09-06 20:57:50 +0000272 Error error;
273 while (error.Success()) {
274 error = select_helper.Select();
275 if (error.Success()) {
276 auto result = ::read(fd, reinterpret_cast<char *>(buf) + bytes_read,
277 size - bytes_read);
278 if (result != -1) {
279 bytes_read += result;
280 if (bytes_read == size || result == 0)
281 break;
282 } else {
283 error.SetErrorToErrno();
284 break;
285 }
Greg Clayton100eb932014-07-02 21:10:39 +0000286 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000287 }
288 return error;
Greg Clayton100eb932014-07-02 21:10:39 +0000289}
290
Kate Stoneb9c1b512016-09-06 20:57:50 +0000291Error PipePosix::Write(const void *buf, size_t size, size_t &bytes_written) {
292 bytes_written = 0;
293 if (!CanWrite())
294 return Error(EINVAL, eErrorTypePOSIX);
295
296 const int fd = GetWriteFileDescriptor();
297 SelectHelper select_helper;
298 select_helper.SetTimeout(std::chrono::seconds(0));
299 select_helper.FDSetWrite(fd);
300
301 Error error;
302 while (error.Success()) {
303 error = select_helper.Select();
304 if (error.Success()) {
305 auto result =
306 ::write(fd, reinterpret_cast<const char *>(buf) + bytes_written,
307 size - bytes_written);
308 if (result != -1) {
309 bytes_written += result;
310 if (bytes_written == size)
311 break;
312 } else {
313 error.SetErrorToErrno();
314 }
Greg Clayton100eb932014-07-02 21:10:39 +0000315 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000316 }
317 return error;
Greg Clayton100eb932014-07-02 21:10:39 +0000318}