@@ -58,7 +58,10 @@ 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 (); }
@@ -77,6 +80,7 @@ Status PipeWindows::CreateNew(bool child_process_inherit) {
77
80
78
81
m_write_fd = _open_osfhandle ((intptr_t )m_write, _O_WRONLY);
79
82
ZeroMemory (&m_write_overlapped, sizeof (m_write_overlapped));
83
+ m_write_overlapped.hEvent = ::CreateEventA (nullptr , TRUE , FALSE , nullptr );
80
84
81
85
return Status ();
82
86
}
@@ -202,6 +206,7 @@ Status PipeWindows::OpenNamedPipe(llvm::StringRef name,
202
206
m_write_fd = _open_osfhandle ((intptr_t )m_write, _O_WRONLY);
203
207
204
208
ZeroMemory (&m_write_overlapped, sizeof (m_write_overlapped));
209
+ m_write_overlapped.hEvent = ::CreateEventA (nullptr , TRUE , FALSE , nullptr );
205
210
}
206
211
207
212
return Status ();
@@ -228,6 +233,8 @@ int PipeWindows::ReleaseWriteFileDescriptor() {
228
233
return PipeWindows::kInvalidDescriptor ;
229
234
int result = m_write_fd;
230
235
m_write_fd = PipeWindows::kInvalidDescriptor ;
236
+ if (m_write_overlapped.hEvent )
237
+ ::CloseHandle (m_write_overlapped.hEvent);
231
238
m_write = INVALID_HANDLE_VALUE;
232
239
ZeroMemory (&m_write_overlapped, sizeof (m_write_overlapped));
233
240
return result;
@@ -250,6 +257,9 @@ void PipeWindows::CloseWriteFileDescriptor() {
250
257
if (!CanWrite ())
251
258
return ;
252
259
260
+ if (m_write_overlapped.hEvent )
261
+ ::CloseHandle (m_write_overlapped.hEvent);
262
+
253
263
_close (m_write_fd);
254
264
m_write = INVALID_HANDLE_VALUE;
255
265
m_write_fd = PipeWindows::kInvalidDescriptor ;
@@ -283,7 +293,12 @@ Status PipeWindows::ReadWithTimeout(void *buf, size_t size,
283
293
DWORD sys_bytes_read = size;
284
294
BOOL result = ::ReadFile (m_read, buf, sys_bytes_read, &sys_bytes_read,
285
295
&m_read_overlapped);
286
- if (!result && GetLastError () != ERROR_IO_PENDING)
296
+ if (result) {
297
+ bytes_read = sys_bytes_read;
298
+ return Status ();
299
+ }
300
+
301
+ if (GetLastError () != ERROR_IO_PENDING)
287
302
return Status (::GetLastError (), eErrorTypeWin32);
288
303
289
304
DWORD timeout = (duration == std::chrono::microseconds::zero ())
@@ -319,18 +334,56 @@ Status PipeWindows::ReadWithTimeout(void *buf, size_t size,
319
334
320
335
Status PipeWindows::Write (const void *buf, size_t num_bytes,
321
336
size_t &bytes_written) {
337
+ return WriteWithTimeout (buf, num_bytes, std::chrono::microseconds::zero (),
338
+ bytes_written);
339
+ }
340
+
341
+ Status PipeWindows::WriteWithTimeout (const void *buf, size_t size,
342
+ const std::chrono::microseconds &duration,
343
+ size_t &bytes_written) {
322
344
if (!CanWrite ())
323
345
return Status (ERROR_INVALID_HANDLE, eErrorTypeWin32);
324
346
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)
347
+ bytes_written = 0 ;
348
+ DWORD sys_bytes_write = size;
349
+ BOOL result = ::WriteFile (m_write, buf, sys_bytes_write, &sys_bytes_write,
350
+ &m_write_overlapped);
351
+ if (result) {
352
+ bytes_written = sys_bytes_write;
353
+ return Status ();
354
+ }
355
+
356
+ if (GetLastError () != ERROR_IO_PENDING)
329
357
return Status (::GetLastError (), eErrorTypeWin32);
330
358
331
- BOOL result = GetOverlappedResult (m_write, &m_write_overlapped,
332
- &sys_bytes_written, TRUE );
333
- if (!result)
359
+ DWORD timeout = (duration == std::chrono::microseconds::zero ())
360
+ ? INFINITE
361
+ : duration.count () * 1000 ;
362
+ DWORD wait_result = ::WaitForSingleObject (m_write_overlapped.hEvent , timeout);
363
+ if (wait_result != WAIT_OBJECT_0) {
364
+ // The operation probably failed. However, if it timed out, we need to
365
+ // cancel the I/O. Between the time we returned from WaitForSingleObject
366
+ // and the time we call CancelIoEx, the operation may complete. If that
367
+ // hapens, CancelIoEx will fail and return ERROR_NOT_FOUND. If that
368
+ // happens, the original operation should be considered to have been
369
+ // successful.
370
+ bool failed = true ;
371
+ DWORD failure_error = ::GetLastError ();
372
+ if (wait_result == WAIT_TIMEOUT) {
373
+ BOOL cancel_result = CancelIoEx (m_write, &m_write_overlapped);
374
+ if (!cancel_result && GetLastError () == ERROR_NOT_FOUND)
375
+ failed = false ;
376
+ }
377
+ if (failed)
378
+ return Status (failure_error, eErrorTypeWin32);
379
+ }
380
+
381
+ // Now we call GetOverlappedResult setting bWait to false, since we've
382
+ // already waited as long as we're willing to.
383
+ if (!GetOverlappedResult (m_write, &m_write_overlapped, &sys_bytes_write,
384
+ FALSE ))
334
385
return Status (::GetLastError (), eErrorTypeWin32);
386
+
387
+ bytes_written = sys_bytes_write;
335
388
return Status ();
336
389
}
0 commit comments