@@ -1432,9 +1432,30 @@ _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+ } else {
1440+ // Try to make writing nonblocking, although pipes not coming
1441+ // from Foundation.Pipe may not have FILE_WRITE_ATTRIBUTES.
1442+ DWORD dwPipeMode = 0 ;
1443+ if (GetNamedPipeHandleState ((HANDLE )fd , & dwPipeMode , NULL ,
1444+ NULL , NULL , NULL , 0 ) && !(dwPipeMode & PIPE_NOWAIT )) {
1445+ dwPipeMode |= PIPE_NOWAIT ;
1446+ if (!SetNamedPipeHandleState ((HANDLE )fd , & dwPipeMode ,
1447+ NULL , NULL )) {
1448+ // We may end up blocking on subsequent writes, but we
1449+ // don't have a good alternative.
1450+ // The WriteQuotaAvailable from NtQueryInformationFile
1451+ // erroneously returns 0 when there is a blocking read
1452+ // on the other end of the pipe.
1453+ _dispatch_fd_entry_debug ("failed to set PIPE_NOWAIT" ,
1454+ fd_entry );
1455+ }
1456+ }
1457+ }
1458+
14381459 _dispatch_stream_init (fd_entry ,
14391460 _dispatch_get_default_queue (false));
14401461 } else {
@@ -2489,24 +2510,6 @@ _dispatch_operation_perform(dispatch_operation_t op)
24892510 }
24902511 bSuccess = TRUE;
24912512 } 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- }
25102513 OVERLAPPED ovlOverlapped = {};
25112514 bSuccess = WriteFile (hFile , buf , (DWORD )len ,
25122515 (LPDWORD )& processed , & ovlOverlapped );
@@ -2523,6 +2526,10 @@ _dispatch_operation_perform(dispatch_operation_t op)
25232526 processed = 0 ;
25242527 }
25252528 }
2529+ if (bSuccess && processed == 0 ) {
2530+ err = EAGAIN ;
2531+ goto error ;
2532+ }
25262533 } else {
25272534 bSuccess = WriteFile (hFile , buf , (DWORD )len ,
25282535 (LPDWORD )& processed , NULL );
0 commit comments