blob: 0ed319facf93facb5e0fc96492992d797d3ac506 [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"
13#include "llvm/ADT/SmallString.h"
14#include "llvm/Support/FileSystem.h"
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +000015
16#include <functional>
17#include <thread>
Greg Clayton100eb932014-07-02 21:10:39 +000018
Zachary Turner0b9d3ee2014-12-17 18:02:19 +000019#include <errno.h>
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +000020#include <fcntl.h>
Oleksiy Vyalov4536c452015-02-05 16:29:12 +000021#include <limits.h>
Zachary Turner0b9d3ee2014-12-17 18:02:19 +000022#include <unistd.h>
23#include <sys/types.h>
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +000024#include <sys/stat.h>
Greg Clayton100eb932014-07-02 21:10:39 +000025
Zachary Turner0b9d3ee2014-12-17 18:02:19 +000026using namespace lldb;
Greg Clayton100eb932014-07-02 21:10:39 +000027using namespace lldb_private;
28
Zachary Turner0b9d3ee2014-12-17 18:02:19 +000029int PipePosix::kInvalidDescriptor = -1;
Greg Clayton100eb932014-07-02 21:10:39 +000030
31enum PIPES { READ, WRITE }; // Constants 0 and 1 for READ and WRITE
32
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +000033// pipe2 is supported by Linux, FreeBSD v10 and higher.
34// TODO: Add more platforms that support pipe2.
Zachary Turner0b9d3ee2014-12-17 18:02:19 +000035#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 10)
36#define PIPE2_SUPPORTED 1
37#else
38#define PIPE2_SUPPORTED 0
39#endif
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +000040
41namespace
42{
43
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +000044constexpr auto OPEN_WRITER_SLEEP_TIMEOUT_MSECS = 100;
45
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +000046#if defined(FD_CLOEXEC) && !PIPE2_SUPPORTED
47bool SetCloexecFlag(int fd)
48{
49 int flags = ::fcntl(fd, F_GETFD);
50 if (flags == -1)
51 return false;
52 return (::fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == 0);
53}
54#endif
55
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +000056std::chrono::time_point<std::chrono::steady_clock>
57Now()
58{
59 return std::chrono::steady_clock::now();
60}
61
62Error
63SelectIO(int handle, bool is_read, const std::function<Error(bool&)> &io_handler, const std::chrono::microseconds &timeout)
64{
65 Error error;
66 fd_set fds;
67 bool done = false;
68
69 using namespace std::chrono;
70
71 const auto finish_time = Now() + timeout;
72
73 while (!done)
74 {
75 struct timeval tv = {0, 0};
76 if (timeout != microseconds::zero())
77 {
78 const auto remaining_dur = duration_cast<microseconds>(finish_time - Now());
79 if (remaining_dur.count() <= 0)
80 {
81 error.SetErrorString("timeout exceeded");
82 break;
83 }
84 const auto dur_secs = duration_cast<seconds>(remaining_dur);
85 const auto dur_usecs = remaining_dur % seconds(1);
86
87 tv.tv_sec = dur_secs.count();
88 tv.tv_usec = dur_usecs.count();
89 }
90 else
91 tv.tv_sec = 1;
92
93 FD_ZERO(&fds);
94 FD_SET(handle, &fds);
95
96 const auto retval = ::select(handle + 1,
97 (is_read) ? &fds : nullptr,
98 (is_read) ? nullptr : &fds,
99 nullptr, &tv);
100 if (retval == -1)
101 {
102 if (errno == EINTR)
103 continue;
104 error.SetErrorToErrno();
105 break;
106 }
107 if (retval == 0)
108 {
109 error.SetErrorString("timeout exceeded");
110 break;
111 }
112 if (!FD_ISSET(handle, &fds))
113 {
114 error.SetErrorString("invalid state");
115 break;
116 }
117
118 error = io_handler(done);
119 if (error.Fail())
120 {
121 if (error.GetError() == EINTR)
122 continue;
123 break;
124 }
125 }
126 return error;
127}
128
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +0000129}
130
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000131PipePosix::PipePosix()
Chaoren Linec534822015-05-01 16:49:23 +0000132 : m_fds{
133 PipePosix::kInvalidDescriptor,
134 PipePosix::kInvalidDescriptor
135 } {}
Chaoren Lina52f4842015-04-29 17:36:58 +0000136
137PipePosix::PipePosix(int read_fd, int write_fd)
138 : m_fds{read_fd, write_fd} {}
Greg Clayton100eb932014-07-02 21:10:39 +0000139
Chaoren Linec534822015-05-01 16:49:23 +0000140PipePosix::PipePosix(PipePosix &&pipe_posix)
141 : PipeBase{std::move(pipe_posix)},
142 m_fds{
143 pipe_posix.ReleaseReadFileDescriptor(),
144 pipe_posix.ReleaseWriteFileDescriptor()
145 } {}
146
147PipePosix &PipePosix::operator=(PipePosix &&pipe_posix)
148{
149 PipeBase::operator=(std::move(pipe_posix));
150 m_fds[READ] = pipe_posix.ReleaseReadFileDescriptor();
151 m_fds[WRITE] = pipe_posix.ReleaseWriteFileDescriptor();
152 return *this;
153}
154
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000155PipePosix::~PipePosix()
Greg Clayton100eb932014-07-02 21:10:39 +0000156{
157 Close();
158}
159
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000160Error
161PipePosix::CreateNew(bool child_processes_inherit)
Greg Clayton100eb932014-07-02 21:10:39 +0000162{
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000163 if (CanRead() || CanWrite())
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000164 return Error(EINVAL, eErrorTypePOSIX);
Greg Clayton100eb932014-07-02 21:10:39 +0000165
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000166 Error error;
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +0000167#if PIPE2_SUPPORTED
168 if (::pipe2(m_fds, (child_processes_inherit) ? 0 : O_CLOEXEC) == 0)
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000169 return error;
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +0000170#else
171 if (::pipe(m_fds) == 0)
172 {
173#ifdef FD_CLOEXEC
174 if (!child_processes_inherit)
175 {
176 if (!SetCloexecFlag(m_fds[0]) || !SetCloexecFlag(m_fds[1]))
177 {
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000178 error.SetErrorToErrno();
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +0000179 Close();
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000180 return error;
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +0000181 }
182 }
183#endif
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000184 return error;
Oleksiy Vyalovff9a0722014-11-21 16:18:57 +0000185 }
186#endif
Zachary Turnerb2df30d2014-10-08 20:38:41 +0000187
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000188 error.SetErrorToErrno();
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000189 m_fds[READ] = PipePosix::kInvalidDescriptor;
190 m_fds[WRITE] = PipePosix::kInvalidDescriptor;
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000191 return error;
192}
193
194Error
195PipePosix::CreateNew(llvm::StringRef name, bool child_process_inherit)
196{
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000197 if (CanRead() || CanWrite())
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000198 return Error("Pipe is already opened");
199
200 Error error;
201 if (::mkfifo(name.data(), 0660) != 0)
202 error.SetErrorToErrno();
203
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000204 return error;
205}
206
207Error
Oleksiy Vyalov4536c452015-02-05 16:29:12 +0000208PipePosix::CreateWithUniqueName(llvm::StringRef prefix, bool child_process_inherit, llvm::SmallVectorImpl<char>& name)
209{
210 llvm::SmallString<PATH_MAX> named_pipe_path;
211 llvm::SmallString<PATH_MAX> pipe_spec((prefix + ".%%%%%%").str());
212 FileSpec tmpdir_file_spec;
213 tmpdir_file_spec.Clear();
214 if (HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
215 {
216 tmpdir_file_spec.AppendPathComponent(pipe_spec.c_str());
217 }
218 else
219 {
220 tmpdir_file_spec.AppendPathComponent("/tmp");
221 tmpdir_file_spec.AppendPathComponent(pipe_spec.c_str());
222 }
223
224 // It's possible that another process creates the target path after we've
225 // verified it's available but before we create it, in which case we
226 // should try again.
227 Error error;
228 do {
229 llvm::sys::fs::createUniqueFile(tmpdir_file_spec.GetPath().c_str(), named_pipe_path);
230 error = CreateNew(named_pipe_path, child_process_inherit);
231 } while (error.GetError() == EEXIST);
232
233 if (error.Success())
234 name = named_pipe_path;
235 return error;
236}
237
238Error
Oleksiy Vyalov47718292015-01-14 01:31:27 +0000239PipePosix::OpenAsReader(llvm::StringRef name, bool child_process_inherit)
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000240{
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000241 if (CanRead() || CanWrite())
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000242 return Error("Pipe is already opened");
243
244 int flags = O_RDONLY | O_NONBLOCK;
245 if (!child_process_inherit)
246 flags |= O_CLOEXEC;
247
248 Error error;
249 int fd = ::open(name.data(), flags);
250 if (fd != -1)
251 m_fds[READ] = fd;
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000252 else
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000253 error.SetErrorToErrno();
254
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000255 return error;
256}
257
258Error
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000259PipePosix::OpenAsWriterWithTimeout(llvm::StringRef name, bool child_process_inherit, const std::chrono::microseconds &timeout)
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000260{
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000261 if (CanRead() || CanWrite())
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000262 return Error("Pipe is already opened");
263
264 int flags = O_WRONLY | O_NONBLOCK;
265 if (!child_process_inherit)
266 flags |= O_CLOEXEC;
267
268 using namespace std::chrono;
269 const auto finish_time = Now() + timeout;
270
271 while (!CanWrite())
272 {
273 if (timeout != microseconds::zero())
274 {
275 const auto dur = duration_cast<microseconds>(finish_time - Now()).count();
276 if (dur <= 0)
277 return Error("timeout exceeded - reader hasn't opened so far");
278 }
279
280 errno = 0;
281 int fd = ::open(name.data(), flags);
282 if (fd == -1)
283 {
284 const auto errno_copy = errno;
285 // We may get ENXIO if a reader side of the pipe hasn't opened yet.
286 if (errno_copy != ENXIO)
287 return Error(errno_copy, eErrorTypePOSIX);
288
289 std::this_thread::sleep_for(milliseconds(OPEN_WRITER_SLEEP_TIMEOUT_MSECS));
290 }
291 else
292 {
293 m_fds[WRITE] = fd;
294 }
295 }
296
297 return Error();
Greg Clayton100eb932014-07-02 21:10:39 +0000298}
299
300int
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000301PipePosix::GetReadFileDescriptor() const
Greg Clayton100eb932014-07-02 21:10:39 +0000302{
303 return m_fds[READ];
304}
305
306int
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000307PipePosix::GetWriteFileDescriptor() const
Greg Clayton100eb932014-07-02 21:10:39 +0000308{
309 return m_fds[WRITE];
310}
311
312int
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000313PipePosix::ReleaseReadFileDescriptor()
Greg Clayton100eb932014-07-02 21:10:39 +0000314{
315 const int fd = m_fds[READ];
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000316 m_fds[READ] = PipePosix::kInvalidDescriptor;
Greg Clayton100eb932014-07-02 21:10:39 +0000317 return fd;
318}
319
320int
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000321PipePosix::ReleaseWriteFileDescriptor()
Greg Clayton100eb932014-07-02 21:10:39 +0000322{
323 const int fd = m_fds[WRITE];
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000324 m_fds[WRITE] = PipePosix::kInvalidDescriptor;
Greg Clayton100eb932014-07-02 21:10:39 +0000325 return fd;
326}
327
328void
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000329PipePosix::Close()
Greg Clayton100eb932014-07-02 21:10:39 +0000330{
331 CloseReadFileDescriptor();
332 CloseWriteFileDescriptor();
333}
334
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000335Error
336PipePosix::Delete(llvm::StringRef name)
337{
Chaoren Lind3173f32015-05-29 19:52:29 +0000338 return FileSystem::Unlink(FileSpec{name.data(), true});
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000339}
340
Greg Clayton100eb932014-07-02 21:10:39 +0000341bool
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000342PipePosix::CanRead() const
Greg Clayton100eb932014-07-02 21:10:39 +0000343{
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000344 return m_fds[READ] != PipePosix::kInvalidDescriptor;
Greg Clayton100eb932014-07-02 21:10:39 +0000345}
346
347bool
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000348PipePosix::CanWrite() const
Greg Clayton100eb932014-07-02 21:10:39 +0000349{
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000350 return m_fds[WRITE] != PipePosix::kInvalidDescriptor;
Greg Clayton100eb932014-07-02 21:10:39 +0000351}
352
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000353void
354PipePosix::CloseReadFileDescriptor()
Greg Clayton100eb932014-07-02 21:10:39 +0000355{
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000356 if (CanRead())
Greg Clayton100eb932014-07-02 21:10:39 +0000357 {
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000358 close(m_fds[READ]);
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000359 m_fds[READ] = PipePosix::kInvalidDescriptor;
Greg Clayton100eb932014-07-02 21:10:39 +0000360 }
Greg Clayton100eb932014-07-02 21:10:39 +0000361}
362
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000363void
364PipePosix::CloseWriteFileDescriptor()
Greg Clayton100eb932014-07-02 21:10:39 +0000365{
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000366 if (CanWrite())
Greg Clayton100eb932014-07-02 21:10:39 +0000367 {
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000368 close(m_fds[WRITE]);
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000369 m_fds[WRITE] = PipePosix::kInvalidDescriptor;
Greg Clayton100eb932014-07-02 21:10:39 +0000370 }
Greg Clayton100eb932014-07-02 21:10:39 +0000371}
372
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000373Error
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000374PipePosix::ReadWithTimeout(void *buf, size_t size, const std::chrono::microseconds &timeout, size_t &bytes_read)
Greg Clayton100eb932014-07-02 21:10:39 +0000375{
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000376 bytes_read = 0;
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000377 if (!CanRead())
378 return Error(EINVAL, eErrorTypePOSIX);
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000379
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000380 auto handle = GetReadFileDescriptor();
381 return SelectIO(handle,
382 true,
383 [=, &bytes_read](bool &done)
384 {
385 Error error;
386 auto result = ::read(handle,
387 reinterpret_cast<char*>(buf) + bytes_read,
388 size - bytes_read);
389 if (result != -1)
390 {
391 bytes_read += result;
392 if (bytes_read == size || result == 0)
393 done = true;
394 }
395 else
396 error.SetErrorToErrno();
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000397
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000398 return error;
399 },
400 timeout);
Greg Clayton100eb932014-07-02 21:10:39 +0000401}
402
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000403Error
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000404PipePosix::Write(const void *buf, size_t size, size_t &bytes_written)
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000405{
406 bytes_written = 0;
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000407 if (!CanWrite())
408 return Error(EINVAL, eErrorTypePOSIX);
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000409
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000410 auto handle = GetWriteFileDescriptor();
411 return SelectIO(handle,
412 false,
413 [=, &bytes_written](bool &done)
414 {
415 Error error;
416 auto result = ::write(handle,
417 reinterpret_cast<const char*>(buf) + bytes_written,
418 size - bytes_written);
419 if (result != -1)
420 {
421 bytes_written += result;
422 if (bytes_written == size)
423 done = true;
424 }
425 else
426 error.SetErrorToErrno();
Zachary Turner0b9d3ee2014-12-17 18:02:19 +0000427
Oleksiy Vyalovd5f8b6a2015-01-13 23:19:40 +0000428 return error;
429 },
430 std::chrono::microseconds::zero());
Greg Clayton100eb932014-07-02 21:10:39 +0000431}