Skip to content

Commit 2084def

Browse files
Use PIPE_NOWAIT on Windows to avoid blocking on writes
1 parent 6242e80 commit 2084def

File tree

1 file changed

+23
-21
lines changed

1 file changed

+23
-21
lines changed

src/io.c

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1432,9 +1432,26 @@ _dispatch_fd_entry_create_with_fd(dispatch_fd_t fd, uintptr_t hash)
14321432
#if defined(_WIN32)
14331433
DWORD dwType = GetFileType((HANDLE)fd);
14341434
if (dwType == FILE_TYPE_PIPE) {
1435-
unsigned long value = 1;
1436-
int result = ioctlsocket((SOCKET)fd, (long)FIONBIO, &value);
1437-
(void)dispatch_assume_zero(result);
1435+
if (_dispatch_handle_is_socket((HANDLE)fd)) {
1436+
unsigned long value = 1;
1437+
int result = ioctlsocket((SOCKET)fd, (long)FIONBIO, &value);
1438+
(void)dispatch_assume_zero(result);
1439+
}
1440+
else {
1441+
// Try to make writing nonblocking, although pipes not coming
1442+
// from Foundation.Pipe may not have FILE_WRITE_ATTRIBUTES.
1443+
DWORD pipe_mode = PIPE_NOWAIT;
1444+
if (!SetNamedPipeHandleState((HANDLE)fd, &pipe_mode, NULL,
1445+
NULL)) {
1446+
// We may end up blocking on subsequent writes, but we
1447+
// don't have a good alternative. The WriteQuotaAvailable
1448+
// from NtQueryInformationFile erroneously returns 0 when
1449+
// there is a blocking read on the other end of the pipe.
1450+
_dispatch_fd_entry_debug("failed to set PIPE_NOWAIT",
1451+
fd_entry);
1452+
}
1453+
}
1454+
14381455
_dispatch_stream_init(fd_entry,
14391456
_dispatch_get_default_queue(false));
14401457
} else {
@@ -2489,24 +2506,6 @@ _dispatch_operation_perform(dispatch_operation_t op)
24892506
}
24902507
bSuccess = TRUE;
24912508
} else if (GetFileType(hFile) == FILE_TYPE_PIPE) {
2492-
// Unfortunately there isn't a good way to achieve O_NONBLOCK
2493-
// semantics when writing to a pipe. SetNamedPipeHandleState()
2494-
// can allow pipes to be switched into a "no wait" mode, but
2495-
// that doesn't work on most pipe handles because Windows
2496-
// doesn't consistently create pipes with FILE_WRITE_ATTRIBUTES
2497-
// access. The best we can do is to try to query the write quota
2498-
// and then write as much as we can.
2499-
IO_STATUS_BLOCK iosb;
2500-
FILE_PIPE_LOCAL_INFORMATION fpli;
2501-
NTSTATUS status = _dispatch_NtQueryInformationFile(hFile, &iosb,
2502-
&fpli, sizeof(fpli), FilePipeLocalInformation);
2503-
if (NT_SUCCESS(status)) {
2504-
if (fpli.WriteQuotaAvailable == 0) {
2505-
err = EAGAIN;
2506-
goto error;
2507-
}
2508-
len = MIN(len, fpli.WriteQuotaAvailable);
2509-
}
25102509
OVERLAPPED ovlOverlapped = {};
25112510
bSuccess = WriteFile(hFile, buf, (DWORD)len,
25122511
(LPDWORD)&processed, &ovlOverlapped);
@@ -2523,6 +2522,9 @@ _dispatch_operation_perform(dispatch_operation_t op)
25232522
processed = 0;
25242523
}
25252524
}
2525+
if (bSuccess && processed == 0) {
2526+
err = EAGAIN;
2527+
}
25262528
} else {
25272529
bSuccess = WriteFile(hFile, buf, (DWORD)len,
25282530
(LPDWORD)&processed, NULL);

0 commit comments

Comments
 (0)