1 //===-- PipeWindows.cpp -----------------------------------------*- C++ -*-===//
2 //
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 
10 #include "lldb/Host/windows/PipeWindows.h"
11 
12 #include "llvm/Support/raw_ostream.h"
13 
14 #include <fcntl.h>
15 #include <io.h>
16 
17 #include <atomic>
18 #include <string>
19 
20 using namespace lldb;
21 using namespace lldb_private;
22 
23 namespace
24 {
25 std::atomic<uint32_t> g_pipe_serial(0);
26 }
27 
28 PipeWindows::PipeWindows()
29 {
30     m_read = INVALID_HANDLE_VALUE;
31     m_write = INVALID_HANDLE_VALUE;
32 
33     m_read_fd = -1;
34     m_write_fd = -1;
35     ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));
36     ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));
37 }
38 
39 PipeWindows::~PipeWindows()
40 {
41     Close();
42 }
43 
44 Error
45 PipeWindows::CreateNew(bool child_process_inherit)
46 {
47     // Even for anonymous pipes, we open a named pipe.  This is because you cannot get
48     // overlapped i/o on Windows without using a named pipe.  So we synthesize a unique
49     // name.
50     uint32_t serial = g_pipe_serial.fetch_add(1);
51     std::string pipe_name;
52     llvm::raw_string_ostream pipe_name_stream(pipe_name);
53     pipe_name_stream << "lldb.pipe." << ::GetCurrentProcessId() << "." << serial;
54     pipe_name_stream.flush();
55 
56     return CreateNew(pipe_name.c_str(), child_process_inherit);
57 }
58 
59 Error
60 PipeWindows::CreateNew(llvm::StringRef name, bool child_process_inherit)
61 {
62     if (name.empty())
63         return Error(ERROR_INVALID_PARAMETER, eErrorTypeWin32);
64 
65     if (CanRead() || CanWrite())
66         return Error(ERROR_ALREADY_EXISTS, eErrorTypeWin32);
67 
68     std::string pipe_path = "\\\\.\\Pipe\\";
69     pipe_path.append(name);
70 
71     // Always open for overlapped i/o.  We implement blocking manually in Read and Write.
72     DWORD read_mode = FILE_FLAG_OVERLAPPED;
73     m_read =
74         ::CreateNamedPipe(pipe_path.c_str(), PIPE_ACCESS_INBOUND | read_mode, PIPE_TYPE_BYTE | PIPE_WAIT, 1, 1024, 1024, 120 * 1000, NULL);
75     if (INVALID_HANDLE_VALUE == m_read)
76         return Error(::GetLastError(), eErrorTypeWin32);
77     m_read_fd = _open_osfhandle((intptr_t)m_read, _O_RDONLY);
78     ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));
79     m_read_overlapped.hEvent = ::CreateEvent(nullptr, TRUE, FALSE, nullptr);
80 
81     // Open the write end of the pipe.
82     Error result = OpenNamedPipe(name, child_process_inherit, false);
83     if (!result.Success())
84     {
85         CloseReadEndpoint();
86         return result;
87     }
88 
89     return result;
90 }
91 
92 Error
93 PipeWindows::OpenAsReader(llvm::StringRef name, bool child_process_inherit)
94 {
95     if (CanRead() || CanWrite())
96         return Error(ERROR_ALREADY_EXISTS, eErrorTypeWin32);
97 
98     return OpenNamedPipe(name, child_process_inherit, true);
99 }
100 
101 Error
102 PipeWindows::OpenAsWriterWithTimeout(llvm::StringRef name, bool child_process_inherit, const std::chrono::microseconds &timeout)
103 {
104     if (CanRead() || CanWrite())
105         return Error(ERROR_ALREADY_EXISTS, eErrorTypeWin32);
106 
107     return OpenNamedPipe(name, child_process_inherit, false);
108 }
109 
110 Error
111 PipeWindows::OpenNamedPipe(llvm::StringRef name, bool child_process_inherit, bool is_read)
112 {
113     if (name.empty())
114         return Error(ERROR_INVALID_PARAMETER, eErrorTypeWin32);
115 
116     assert(is_read ? !CanRead() : !CanWrite());
117 
118     SECURITY_ATTRIBUTES attributes = {0};
119     attributes.bInheritHandle = child_process_inherit;
120 
121     std::string pipe_path = "\\\\.\\Pipe\\";
122     pipe_path.append(name);
123 
124     if (is_read)
125     {
126         m_read = ::CreateFile(pipe_path.c_str(), GENERIC_READ, 0, &attributes, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
127         if (INVALID_HANDLE_VALUE == m_read)
128             return Error(::GetLastError(), eErrorTypeWin32);
129 
130         m_read_fd = _open_osfhandle((intptr_t)m_read, _O_RDONLY);
131 
132         ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));
133         m_read_overlapped.hEvent = ::CreateEvent(nullptr, TRUE, FALSE, nullptr);
134     }
135     else
136     {
137         m_write = ::CreateFile(pipe_path.c_str(), GENERIC_WRITE, 0, &attributes, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
138         if (INVALID_HANDLE_VALUE == m_write)
139             return Error(::GetLastError(), eErrorTypeWin32);
140 
141         m_write_fd = _open_osfhandle((intptr_t)m_write, _O_WRONLY);
142 
143         ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));
144     }
145 
146     return Error();
147 }
148 
149 int
150 PipeWindows::GetReadFileDescriptor() const
151 {
152     return m_read_fd;
153 }
154 
155 int
156 PipeWindows::GetWriteFileDescriptor() const
157 {
158     return m_write_fd;
159 }
160 
161 int
162 PipeWindows::ReleaseReadFileDescriptor()
163 {
164     if (!CanRead())
165         return -1;
166     int result = m_read_fd;
167     m_read_fd = -1;
168     if (m_read_overlapped.hEvent)
169         ::CloseHandle(m_read_overlapped.hEvent);
170     m_read = INVALID_HANDLE_VALUE;
171     ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));
172     return result;
173 }
174 
175 int
176 PipeWindows::ReleaseWriteFileDescriptor()
177 {
178     if (!CanWrite())
179         return -1;
180     int result = m_write_fd;
181     m_write_fd = -1;
182     m_write = INVALID_HANDLE_VALUE;
183     ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));
184     return result;
185 }
186 
187 void
188 PipeWindows::CloseReadEndpoint()
189 {
190     if (!CanRead())
191         return;
192 
193     if (m_read_overlapped.hEvent)
194         ::CloseHandle(m_read_overlapped.hEvent);
195     _close(m_read_fd);
196     m_read = INVALID_HANDLE_VALUE;
197     m_read_fd = -1;
198     ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));
199 }
200 
201 void
202 PipeWindows::CloseWriteEndpoint()
203 {
204     if (!CanWrite())
205         return;
206 
207     _close(m_write_fd);
208     m_write = INVALID_HANDLE_VALUE;
209     m_write_fd = -1;
210     ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));
211 }
212 
213 void
214 PipeWindows::Close()
215 {
216     CloseReadEndpoint();
217     CloseWriteEndpoint();
218 }
219 
220 Error
221 PipeWindows::Delete(llvm::StringRef name)
222 {
223     return Error();
224 }
225 
226 bool
227 PipeWindows::CanRead() const
228 {
229     return (m_read != INVALID_HANDLE_VALUE);
230 }
231 
232 bool
233 PipeWindows::CanWrite() const
234 {
235     return (m_write != INVALID_HANDLE_VALUE);
236 }
237 
238 HANDLE
239 PipeWindows::GetReadNativeHandle()
240 {
241     return m_read;
242 }
243 
244 HANDLE
245 PipeWindows::GetWriteNativeHandle()
246 {
247     return m_write;
248 }
249 
250 Error
251 PipeWindows::ReadWithTimeout(void *buf, size_t size, const std::chrono::microseconds &duration, size_t &bytes_read)
252 {
253     if (!CanRead())
254         return Error(ERROR_INVALID_HANDLE, eErrorTypeWin32);
255 
256     bytes_read = 0;
257     DWORD sys_bytes_read = size;
258     BOOL result = ::ReadFile(m_read, buf, sys_bytes_read, &sys_bytes_read, &m_read_overlapped);
259     if (!result && GetLastError() != ERROR_IO_PENDING)
260         return Error(::GetLastError(), eErrorTypeWin32);
261 
262     DWORD timeout = (duration == std::chrono::microseconds::zero()) ? INFINITE : duration.count() * 1000;
263     DWORD wait_result = ::WaitForSingleObject(m_read_overlapped.hEvent, timeout);
264     if (wait_result != WAIT_OBJECT_0)
265     {
266         // The operation probably failed.  However, if it timed out, we need to cancel the I/O.
267         // Between the time we returned from WaitForSingleObject and the time we call CancelIoEx,
268         // the operation may complete.  If that hapens, CancelIoEx will fail and return ERROR_NOT_FOUND.
269         // If that happens, the original operation should be considered to have been successful.
270         bool failed = true;
271         DWORD failure_error = ::GetLastError();
272         if (wait_result == WAIT_TIMEOUT)
273         {
274             BOOL cancel_result = CancelIoEx(m_read, &m_read_overlapped);
275             if (!cancel_result && GetLastError() == ERROR_NOT_FOUND)
276                 failed = false;
277         }
278         if (failed)
279             return Error(failure_error, eErrorTypeWin32);
280     }
281 
282     // Now we call GetOverlappedResult setting bWait to false, since we've already waited
283     // as long as we're willing to.
284     if (!GetOverlappedResult(m_read, &m_read_overlapped, &sys_bytes_read, FALSE))
285         return Error(::GetLastError(), eErrorTypeWin32);
286 
287     bytes_read = sys_bytes_read;
288     return Error();
289 }
290 
291 Error
292 PipeWindows::Write(const void *buf, size_t num_bytes, size_t &bytes_written)
293 {
294     if (!CanWrite())
295         return Error(ERROR_INVALID_HANDLE, eErrorTypeWin32);
296 
297     DWORD sys_bytes_written = 0;
298     BOOL write_result = ::WriteFile(m_write, buf, num_bytes, &sys_bytes_written, &m_write_overlapped);
299     if (!write_result && GetLastError() != ERROR_IO_PENDING)
300         return Error(::GetLastError(), eErrorTypeWin32);
301 
302     BOOL result = GetOverlappedResult(m_write, &m_write_overlapped, &sys_bytes_written, TRUE);
303     if (!result)
304         return Error(::GetLastError(), eErrorTypeWin32);
305     return Error();
306 }
307