blob: 3ac5d480de89933abadd4bb2670e7a33be08ac93 [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
Kate Stoneb9c1b512016-09-06 20:57:50 +000085Error PipePosix::CreateNew(bool child_processes_inherit) {
86 if (CanRead() || CanWrite())
87 return Error(EINVAL, eErrorTypePOSIX);
Greg Clayton100eb932014-07-02 21:10:39 +000088
Kate Stoneb9c1b512016-09-06 20:57:50 +000089 Error 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
114Error PipePosix::CreateNew(llvm::StringRef name, bool child_process_inherit) {
115 if (CanRead() || CanWrite())
116 return Error("Pipe is already opened");
117
118 Error error;
119 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
Kate Stoneb9c1b512016-09-06 20:57:50 +0000125Error PipePosix::CreateWithUniqueName(llvm::StringRef prefix,
126 bool child_process_inherit,
127 llvm::SmallVectorImpl<char> &name) {
128 llvm::SmallString<PATH_MAX> named_pipe_path;
129 llvm::SmallString<PATH_MAX> pipe_spec((prefix + ".%%%%%%").str());
130 FileSpec tmpdir_file_spec;
131 tmpdir_file_spec.Clear();
132 if (HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) {
133 tmpdir_file_spec.AppendPathComponent(pipe_spec.c_str());
134 } else {
135 tmpdir_file_spec.AppendPathComponent("/tmp");
136 tmpdir_file_spec.AppendPathComponent(pipe_spec.c_str());
137 }
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000138
Kate Stoneb9c1b512016-09-06 20:57:50 +0000139 // It's possible that another process creates the target path after we've
140 // verified it's available but before we create it, in which case we
141 // should try again.
142 Error error;
143 do {
Malcolm Parsons771ef6d2016-11-02 20:34:10 +0000144 llvm::sys::fs::createUniqueFile(tmpdir_file_spec.GetPath(),
Kate Stoneb9c1b512016-09-06 20:57:50 +0000145 named_pipe_path);
146 error = CreateNew(named_pipe_path, child_process_inherit);
147 } while (error.GetError() == EEXIST);
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000148
Kate Stoneb9c1b512016-09-06 20:57:50 +0000149 if (error.Success())
150 name = named_pipe_path;
151 return error;
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000152}
153
Kate Stoneb9c1b512016-09-06 20:57:50 +0000154Error PipePosix::OpenAsReader(llvm::StringRef name,
155 bool child_process_inherit) {
156 if (CanRead() || CanWrite())
157 return Error("Pipe is already opened");
158
159 int flags = O_RDONLY | O_NONBLOCK;
160 if (!child_process_inherit)
161 flags |= O_CLOEXEC;
162
163 Error error;
164 int fd = ::open(name.data(), flags);
165 if (fd != -1)
166 m_fds[READ] = fd;
167 else
168 error.SetErrorToErrno();
169
170 return error;
171}
172
173Error PipePosix::OpenAsWriterWithTimeout(
174 llvm::StringRef name, bool child_process_inherit,
175 const std::chrono::microseconds &timeout) {
176 if (CanRead() || CanWrite())
177 return Error("Pipe is already opened");
178
179 int flags = O_WRONLY | O_NONBLOCK;
180 if (!child_process_inherit)
181 flags |= O_CLOEXEC;
182
183 using namespace std::chrono;
184 const auto finish_time = Now() + timeout;
185
186 while (!CanWrite()) {
187 if (timeout != microseconds::zero()) {
188 const auto dur = duration_cast<microseconds>(finish_time - Now()).count();
189 if (dur <= 0)
190 return Error("timeout exceeded - reader hasn't opened so far");
Oleksiy Vyalov4536c452015-02-05 16:29:12 +0000191 }
192
Kate Stoneb9c1b512016-09-06 20:57:50 +0000193 errno = 0;
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000194 int fd = ::open(name.data(), flags);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000195 if (fd == -1) {
196 const auto errno_copy = errno;
197 // We may get ENXIO if a reader side of the pipe hasn't opened yet.
198 if (errno_copy != ENXIO)
199 return Error(errno_copy, eErrorTypePOSIX);
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000200
Kate Stoneb9c1b512016-09-06 20:57:50 +0000201 std::this_thread::sleep_for(
202 milliseconds(OPEN_WRITER_SLEEP_TIMEOUT_MSECS));
203 } else {
204 m_fds[WRITE] = fd;
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000205 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000206 }
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000207
Mehdi Aminic1edf562016-11-11 04:29:25 +0000208 return Error();
Greg Clayton100eb932014-07-02 21:10:39 +0000209}
210
Kate Stoneb9c1b512016-09-06 20:57:50 +0000211int PipePosix::GetReadFileDescriptor() const { return m_fds[READ]; }
212
213int PipePosix::GetWriteFileDescriptor() const { return m_fds[WRITE]; }
214
215int PipePosix::ReleaseReadFileDescriptor() {
216 const int fd = m_fds[READ];
217 m_fds[READ] = PipePosix::kInvalidDescriptor;
218 return fd;
Greg Clayton100eb932014-07-02 21:10:39 +0000219}
220
Kate Stoneb9c1b512016-09-06 20:57:50 +0000221int PipePosix::ReleaseWriteFileDescriptor() {
222 const int fd = m_fds[WRITE];
223 m_fds[WRITE] = PipePosix::kInvalidDescriptor;
224 return fd;
Greg Clayton100eb932014-07-02 21:10:39 +0000225}
226
Kate Stoneb9c1b512016-09-06 20:57:50 +0000227void PipePosix::Close() {
228 CloseReadFileDescriptor();
229 CloseWriteFileDescriptor();
230}
231
232Error PipePosix::Delete(llvm::StringRef name) {
Zachary Turner07db3f72017-03-21 05:47:57 +0000233 return llvm::sys::fs::remove(name);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000234}
235
236bool PipePosix::CanRead() const {
237 return m_fds[READ] != PipePosix::kInvalidDescriptor;
238}
239
240bool PipePosix::CanWrite() const {
241 return m_fds[WRITE] != PipePosix::kInvalidDescriptor;
242}
243
244void PipePosix::CloseReadFileDescriptor() {
245 if (CanRead()) {
246 close(m_fds[READ]);
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000247 m_fds[READ] = PipePosix::kInvalidDescriptor;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000248 }
Greg Clayton100eb932014-07-02 21:10:39 +0000249}
250
Kate Stoneb9c1b512016-09-06 20:57:50 +0000251void PipePosix::CloseWriteFileDescriptor() {
252 if (CanWrite()) {
253 close(m_fds[WRITE]);
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000254 m_fds[WRITE] = PipePosix::kInvalidDescriptor;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000255 }
Greg Clayton100eb932014-07-02 21:10:39 +0000256}
257
Kate Stoneb9c1b512016-09-06 20:57:50 +0000258Error PipePosix::ReadWithTimeout(void *buf, size_t size,
259 const std::chrono::microseconds &timeout,
260 size_t &bytes_read) {
261 bytes_read = 0;
262 if (!CanRead())
263 return Error(EINVAL, eErrorTypePOSIX);
Greg Clayton100eb932014-07-02 21:10:39 +0000264
Kate Stoneb9c1b512016-09-06 20:57:50 +0000265 const int fd = GetReadFileDescriptor();
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000266
Kate Stoneb9c1b512016-09-06 20:57:50 +0000267 SelectHelper select_helper;
268 select_helper.SetTimeout(timeout);
269 select_helper.FDSetRead(fd);
Greg Clayton100eb932014-07-02 21:10:39 +0000270
Kate Stoneb9c1b512016-09-06 20:57:50 +0000271 Error error;
272 while (error.Success()) {
273 error = select_helper.Select();
274 if (error.Success()) {
275 auto result = ::read(fd, reinterpret_cast<char *>(buf) + bytes_read,
276 size - bytes_read);
277 if (result != -1) {
278 bytes_read += result;
279 if (bytes_read == size || result == 0)
280 break;
281 } else {
282 error.SetErrorToErrno();
283 break;
284 }
Greg Clayton100eb932014-07-02 21:10:39 +0000285 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000286 }
287 return error;
Greg Clayton100eb932014-07-02 21:10:39 +0000288}
289
Kate Stoneb9c1b512016-09-06 20:57:50 +0000290Error PipePosix::Write(const void *buf, size_t size, size_t &bytes_written) {
291 bytes_written = 0;
292 if (!CanWrite())
293 return Error(EINVAL, eErrorTypePOSIX);
294
295 const int fd = GetWriteFileDescriptor();
296 SelectHelper select_helper;
297 select_helper.SetTimeout(std::chrono::seconds(0));
298 select_helper.FDSetWrite(fd);
299
300 Error error;
301 while (error.Success()) {
302 error = select_helper.Select();
303 if (error.Success()) {
304 auto result =
305 ::write(fd, reinterpret_cast<const char *>(buf) + bytes_written,
306 size - bytes_written);
307 if (result != -1) {
308 bytes_written += result;
309 if (bytes_written == size)
310 break;
311 } else {
312 error.SetErrorToErrno();
313 }
Greg Clayton100eb932014-07-02 21:10:39 +0000314 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000315 }
316 return error;
Greg Clayton100eb932014-07-02 21:10:39 +0000317}