@@ -58,30 +58,15 @@ PipeWindows::PipeWindows(pipe_t read, pipe_t write)
58
58
}
59
59
60
60
ZeroMemory (&m_read_overlapped, sizeof (m_read_overlapped));
61
+ m_read_overlapped.hEvent = ::CreateEventA (nullptr , TRUE , FALSE , nullptr );
62
+
61
63
ZeroMemory (&m_write_overlapped, sizeof (m_write_overlapped));
64
+ m_write_overlapped.hEvent = ::CreateEventA (nullptr , TRUE , FALSE , nullptr );
62
65
}
63
66
64
67
PipeWindows::~PipeWindows () { Close (); }
65
68
66
69
Status PipeWindows::CreateNew (bool child_process_inherit) {
67
- // Create an anonymous pipe with the specified inheritance.
68
- SECURITY_ATTRIBUTES sa{sizeof (SECURITY_ATTRIBUTES), 0 ,
69
- child_process_inherit ? TRUE : FALSE };
70
- BOOL result = ::CreatePipe (&m_read, &m_write, &sa, 1024 );
71
- if (result == FALSE )
72
- return Status (::GetLastError (), eErrorTypeWin32);
73
-
74
- m_read_fd = _open_osfhandle ((intptr_t )m_read, _O_RDONLY);
75
- ZeroMemory (&m_read_overlapped, sizeof (m_read_overlapped));
76
- m_read_overlapped.hEvent = ::CreateEventA (nullptr , TRUE , FALSE , nullptr );
77
-
78
- m_write_fd = _open_osfhandle ((intptr_t )m_write, _O_WRONLY);
79
- ZeroMemory (&m_write_overlapped, sizeof (m_write_overlapped));
80
-
81
- return Status ();
82
- }
83
-
84
- Status PipeWindows::CreateNewNamed (bool child_process_inherit) {
85
70
// Even for anonymous pipes, we open a named pipe. This is because you
86
71
// cannot get overlapped i/o on Windows without using a named pipe. So we
87
72
// synthesize a unique name.
@@ -105,12 +90,19 @@ Status PipeWindows::CreateNew(llvm::StringRef name,
105
90
std::string pipe_path = g_pipe_name_prefix.str ();
106
91
pipe_path.append (name.str ());
107
92
93
+ SECURITY_ATTRIBUTES sa{sizeof (SECURITY_ATTRIBUTES), 0 ,
94
+ child_process_inherit ? TRUE : FALSE };
95
+
108
96
// Always open for overlapped i/o. We implement blocking manually in Read
109
97
// and Write.
110
98
DWORD read_mode = FILE_FLAG_OVERLAPPED;
111
- m_read = ::CreateNamedPipeA (
112
- pipe_path.c_str (), PIPE_ACCESS_INBOUND | read_mode,
113
- PIPE_TYPE_BYTE | PIPE_WAIT, 1 , 1024 , 1024 , 120 * 1000 , NULL );
99
+ m_read =
100
+ ::CreateNamedPipeA (pipe_path.c_str(), PIPE_ACCESS_INBOUND | read_mode,
101
+ PIPE_TYPE_BYTE | PIPE_WAIT, 1,
102
+ 1024, // Out buffer size
103
+ 1024, // In buffer size
104
+ 0, // Default timeout in ms, 0 means 50ms
105
+ &sa);
114
106
if (INVALID_HANDLE_VALUE == m_read)
115
107
return Status (::GetLastError (), eErrorTypeWin32);
116
108
m_read_fd = _open_osfhandle ((intptr_t )m_read, _O_RDONLY);
@@ -155,7 +147,7 @@ Status PipeWindows::CreateWithUniqueName(llvm::StringRef prefix,
155
147
Status PipeWindows::OpenAsReader (llvm::StringRef name,
156
148
bool child_process_inherit) {
157
149
if (CanRead ())
158
- return Status (ERROR_ALREADY_EXISTS, eErrorTypeWin32);
150
+ return Status (); // Note the name is ignored.
159
151
160
152
return OpenNamedPipe (name, child_process_inherit, true );
161
153
}
@@ -165,7 +157,7 @@ PipeWindows::OpenAsWriterWithTimeout(llvm::StringRef name,
165
157
bool child_process_inherit,
166
158
const std::chrono::microseconds &timeout) {
167
159
if (CanWrite ())
168
- return Status (ERROR_ALREADY_EXISTS, eErrorTypeWin32);
160
+ return Status (); // Note the name is ignored.
169
161
170
162
return OpenNamedPipe (name, child_process_inherit, false );
171
163
}
@@ -177,8 +169,8 @@ Status PipeWindows::OpenNamedPipe(llvm::StringRef name,
177
169
178
170
assert (is_read ? !CanRead () : !CanWrite ());
179
171
180
- SECURITY_ATTRIBUTES attributes = {};
181
- attributes. bInheritHandle = child_process_inherit;
172
+ SECURITY_ATTRIBUTES attributes{ sizeof (SECURITY_ATTRIBUTES), 0 ,
173
+ child_process_inherit ? TRUE : FALSE } ;
182
174
183
175
std::string pipe_path = g_pipe_name_prefix.str ();
184
176
pipe_path.append (name.str ());
@@ -202,6 +194,7 @@ Status PipeWindows::OpenNamedPipe(llvm::StringRef name,
202
194
m_write_fd = _open_osfhandle ((intptr_t )m_write, _O_WRONLY);
203
195
204
196
ZeroMemory (&m_write_overlapped, sizeof (m_write_overlapped));
197
+ m_write_overlapped.hEvent = ::CreateEventA (nullptr , TRUE , FALSE , nullptr );
205
198
}
206
199
207
200
return Status ();
@@ -228,6 +221,8 @@ int PipeWindows::ReleaseWriteFileDescriptor() {
228
221
return PipeWindows::kInvalidDescriptor ;
229
222
int result = m_write_fd;
230
223
m_write_fd = PipeWindows::kInvalidDescriptor ;
224
+ if (m_write_overlapped.hEvent )
225
+ ::CloseHandle (m_write_overlapped.hEvent);
231
226
m_write = INVALID_HANDLE_VALUE;
232
227
ZeroMemory (&m_write_overlapped, sizeof (m_write_overlapped));
233
228
return result;
@@ -250,6 +245,9 @@ void PipeWindows::CloseWriteFileDescriptor() {
250
245
if (!CanWrite ())
251
246
return ;
252
247
248
+ if (m_write_overlapped.hEvent )
249
+ ::CloseHandle (m_write_overlapped.hEvent);
250
+
253
251
_close (m_write_fd);
254
252
m_write = INVALID_HANDLE_VALUE;
255
253
m_write_fd = PipeWindows::kInvalidDescriptor ;
@@ -280,15 +278,21 @@ Status PipeWindows::ReadWithTimeout(void *buf, size_t size,
280
278
return Status (ERROR_INVALID_HANDLE, eErrorTypeWin32);
281
279
282
280
bytes_read = 0 ;
283
- DWORD sys_bytes_read = size;
284
- BOOL result = ::ReadFile (m_read, buf, sys_bytes_read, &sys_bytes_read,
285
- &m_read_overlapped);
286
- if (!result && GetLastError () != ERROR_IO_PENDING)
287
- return Status (::GetLastError (), eErrorTypeWin32);
281
+ DWORD sys_bytes_read = 0 ;
282
+ BOOL result =
283
+ ::ReadFile (m_read, buf, size, &sys_bytes_read, &m_read_overlapped);
284
+ if (result) {
285
+ bytes_read = sys_bytes_read;
286
+ return Status ();
287
+ }
288
+
289
+ DWORD failure_error = ::GetLastError ();
290
+ if (failure_error != ERROR_IO_PENDING)
291
+ return Status (failure_error, eErrorTypeWin32);
288
292
289
293
DWORD timeout = (duration == std::chrono::microseconds::zero ())
290
294
? INFINITE
291
- : duration.count () * 1000 ;
295
+ : duration.count () / 1000 ;
292
296
DWORD wait_result = ::WaitForSingleObject (m_read_overlapped.hEvent , timeout);
293
297
if (wait_result != WAIT_OBJECT_0) {
294
298
// The operation probably failed. However, if it timed out, we need to
@@ -298,10 +302,10 @@ Status PipeWindows::ReadWithTimeout(void *buf, size_t size,
298
302
// happens, the original operation should be considered to have been
299
303
// successful.
300
304
bool failed = true ;
301
- DWORD failure_error = ::GetLastError ();
305
+ failure_error = ::GetLastError ();
302
306
if (wait_result == WAIT_TIMEOUT) {
303
- BOOL cancel_result = CancelIoEx (m_read, &m_read_overlapped);
304
- if (!cancel_result && GetLastError () == ERROR_NOT_FOUND)
307
+ BOOL cancel_result = :: CancelIoEx (m_read, &m_read_overlapped);
308
+ if (!cancel_result && :: GetLastError () == ERROR_NOT_FOUND)
305
309
failed = false ;
306
310
}
307
311
if (failed)
@@ -310,27 +314,61 @@ Status PipeWindows::ReadWithTimeout(void *buf, size_t size,
310
314
311
315
// Now we call GetOverlappedResult setting bWait to false, since we've
312
316
// already waited as long as we're willing to.
313
- if (!GetOverlappedResult (m_read, &m_read_overlapped, &sys_bytes_read, FALSE ))
317
+ if (!::GetOverlappedResult (m_read, &m_read_overlapped, &sys_bytes_read,
318
+ FALSE ))
314
319
return Status (::GetLastError (), eErrorTypeWin32);
315
320
316
321
bytes_read = sys_bytes_read;
317
322
return Status ();
318
323
}
319
324
320
- Status PipeWindows::Write (const void *buf, size_t num_bytes,
321
- size_t &bytes_written) {
325
+ Status PipeWindows::WriteWithTimeout (const void *buf, size_t size,
326
+ const std::chrono::microseconds &duration,
327
+ size_t &bytes_written) {
322
328
if (!CanWrite ())
323
329
return Status (ERROR_INVALID_HANDLE, eErrorTypeWin32);
324
330
325
- DWORD sys_bytes_written = 0 ;
326
- BOOL write_result = ::WriteFile (m_write, buf, num_bytes, &sys_bytes_written,
327
- &m_write_overlapped);
328
- if (!write_result && GetLastError () != ERROR_IO_PENDING)
329
- return Status (::GetLastError (), eErrorTypeWin32);
331
+ bytes_written = 0 ;
332
+ DWORD sys_bytes_write = 0 ;
333
+ BOOL result =
334
+ ::WriteFile (m_write, buf, size, &sys_bytes_write, &m_write_overlapped);
335
+ if (result) {
336
+ bytes_written = sys_bytes_write;
337
+ return Status ();
338
+ }
339
+
340
+ DWORD failure_error = ::GetLastError ();
341
+ if (failure_error != ERROR_IO_PENDING)
342
+ return Status (failure_error, eErrorTypeWin32);
330
343
331
- BOOL result = GetOverlappedResult (m_write, &m_write_overlapped,
332
- &sys_bytes_written, TRUE );
333
- if (!result)
344
+ DWORD timeout = (duration == std::chrono::microseconds::zero ())
345
+ ? INFINITE
346
+ : duration.count () / 1000 ;
347
+ DWORD wait_result = ::WaitForSingleObject (m_write_overlapped.hEvent , timeout);
348
+ if (wait_result != WAIT_OBJECT_0) {
349
+ // The operation probably failed. However, if it timed out, we need to
350
+ // cancel the I/O. Between the time we returned from WaitForSingleObject
351
+ // and the time we call CancelIoEx, the operation may complete. If that
352
+ // hapens, CancelIoEx will fail and return ERROR_NOT_FOUND. If that
353
+ // happens, the original operation should be considered to have been
354
+ // successful.
355
+ bool failed = true ;
356
+ failure_error = ::GetLastError ();
357
+ if (wait_result == WAIT_TIMEOUT) {
358
+ BOOL cancel_result = ::CancelIoEx (m_write, &m_write_overlapped);
359
+ if (!cancel_result && ::GetLastError () == ERROR_NOT_FOUND)
360
+ failed = false ;
361
+ }
362
+ if (failed)
363
+ return Status (failure_error, eErrorTypeWin32);
364
+ }
365
+
366
+ // Now we call GetOverlappedResult setting bWait to false, since we've
367
+ // already waited as long as we're willing to.
368
+ if (!::GetOverlappedResult (m_write, &m_write_overlapped, &sys_bytes_write,
369
+ FALSE ))
334
370
return Status (::GetLastError (), eErrorTypeWin32);
371
+
372
+ bytes_written = sys_bytes_write;
335
373
return Status ();
336
374
}
0 commit comments