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_private;
21 
22 namespace
23 {
24 std::atomic<uint32_t> g_pipe_serial(0);
25 }
26 
27 Pipe::Pipe()
28 {
29     m_read = INVALID_HANDLE_VALUE;
30     m_write = INVALID_HANDLE_VALUE;
31 
32     m_read_fd = -1;
33     m_write_fd = -1;
34 
35     m_read_overlapped = nullptr;
36     m_write_overlapped = nullptr;
37 }
38 
39 Pipe::~Pipe()
40 {
41     Close();
42 }
43 
44 bool
45 Pipe::Open(bool read_overlapped, bool write_overlapped)
46 {
47     if (IsValid())
48         return true;
49 
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 << "\\\\.\\Pipe\\lldb.pipe." << ::GetCurrentProcessId() << "." << serial;
54     pipe_name_stream.flush();
55 
56     DWORD read_mode = 0;
57     DWORD write_mode = 0;
58     if (read_overlapped)
59         read_mode |= FILE_FLAG_OVERLAPPED;
60     if (write_overlapped)
61         write_mode |= FILE_FLAG_OVERLAPPED;
62     m_read =
63         ::CreateNamedPipe(pipe_name.c_str(), PIPE_ACCESS_INBOUND | read_mode, PIPE_TYPE_BYTE | PIPE_WAIT, 1, 1024, 1024, 120 * 1000, NULL);
64     if (INVALID_HANDLE_VALUE == m_read)
65         return false;
66     m_write = ::CreateFile(pipe_name.c_str(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, write_mode, NULL);
67     if (INVALID_HANDLE_VALUE == m_write)
68     {
69         ::CloseHandle(m_read);
70         m_read = INVALID_HANDLE_VALUE;
71         return false;
72     }
73 
74     m_read_fd = _open_osfhandle((intptr_t)m_read, _O_RDONLY);
75     m_write_fd = _open_osfhandle((intptr_t)m_write, _O_WRONLY);
76 
77     if (read_overlapped)
78     {
79         m_read_overlapped = new OVERLAPPED;
80         ZeroMemory(m_read_overlapped, sizeof(OVERLAPPED));
81     }
82     if (write_overlapped)
83     {
84         m_write_overlapped = new OVERLAPPED;
85         ZeroMemory(m_write_overlapped, sizeof(OVERLAPPED));
86     }
87     return true;
88 }
89 
90 int
91 Pipe::GetReadFileDescriptor() const
92 {
93     return m_read_fd;
94 }
95 
96 int
97 Pipe::GetWriteFileDescriptor() const
98 {
99     return m_write_fd;
100 }
101 
102 int
103 Pipe::ReleaseReadFileDescriptor()
104 {
105     int result = m_read_fd;
106     m_read_fd = -1;
107     m_read = INVALID_HANDLE_VALUE;
108     if (m_read_overlapped)
109     {
110         delete m_read_overlapped;
111         m_read_overlapped = nullptr;
112     }
113     return result;
114 }
115 
116 int
117 Pipe::ReleaseWriteFileDescriptor()
118 {
119     int result = m_write_fd;
120     m_write_fd = -1;
121     m_write = INVALID_HANDLE_VALUE;
122     if (m_write_overlapped)
123     {
124         delete m_write_overlapped;
125         m_write_overlapped = nullptr;
126     }
127     return result;
128 }
129 
130 void
131 Pipe::Close()
132 {
133     CloseReadFileDescriptor();
134     CloseWriteFileDescriptor();
135 }
136 
137 bool
138 Pipe::ReadDescriptorIsValid() const
139 {
140     return m_read_fd != -1;
141 }
142 
143 bool
144 Pipe::WriteDescriptorIsValid() const
145 {
146     return m_write_fd != -1;
147 }
148 
149 bool
150 Pipe::IsValid() const
151 {
152     return ReadDescriptorIsValid() && WriteDescriptorIsValid();
153 }
154 
155 bool
156 Pipe::CloseReadFileDescriptor()
157 {
158     if (ReadDescriptorIsValid())
159     {
160         int err;
161         err = _close(m_read_fd);
162         m_read_fd = -1;
163         m_read = INVALID_HANDLE_VALUE;
164         if (m_read_overlapped)
165         {
166             delete m_read_overlapped;
167             m_read_overlapped = nullptr;
168         }
169         return err == 0;
170     }
171     return true;
172 }
173 
174 bool
175 Pipe::CloseWriteFileDescriptor()
176 {
177     if (WriteDescriptorIsValid())
178     {
179         int err;
180         err = _close(m_write_fd);
181         m_write_fd = -1;
182         m_write = INVALID_HANDLE_VALUE;
183         if (m_write_overlapped)
184         {
185             delete m_write_overlapped;
186             m_write_overlapped = nullptr;
187         }
188         return err == 0;
189     }
190     return true;
191 }
192 
193 HANDLE
194 Pipe::GetReadNativeHandle()
195 {
196     return m_read;
197 }
198 
199 HANDLE
200 Pipe::GetWriteNativeHandle()
201 {
202     return m_write;
203 }
204 
205 size_t
206 Pipe::Read(void *buf, size_t num_bytes)
207 {
208     if (ReadDescriptorIsValid())
209     {
210         DWORD bytes_read = 0;
211         ::ReadFile(m_read, buf, num_bytes, &bytes_read, m_read_overlapped);
212         if (m_read_overlapped)
213             GetOverlappedResult(m_read, m_read_overlapped, &bytes_read, TRUE);
214         return bytes_read;
215     }
216     return 0; // Return 0 since errno won't be set if we didn't call read
217 }
218 
219 size_t
220 Pipe::Write(const void *buf, size_t num_bytes)
221 {
222     if (WriteDescriptorIsValid())
223     {
224         DWORD bytes_written = 0;
225         ::WriteFile(m_write, buf, num_bytes, &bytes_written, m_read_overlapped);
226         if (m_write_overlapped)
227             GetOverlappedResult(m_write, m_write_overlapped, &bytes_written, TRUE);
228         return bytes_written;
229     }
230     return 0; // Return 0 since errno won't be set if we didn't call write
231 }
232