@@ -214,17 +214,25 @@ final class AsyncIO: @unchecked Sendable {
214214
215215 // Windows Documentation: The function returns the handle
216216 // of the existing I/O completion port if successful
217- guard
218- CreateIoCompletionPort (
219- handle, ioPort, completionKey, 0
220- ) == ioPort
221- else {
222- let error = SubprocessError (
223- code: . init( . asyncIOFailed( " CreateIoCompletionPort failed " ) ) ,
224- underlyingError: . init( rawValue: GetLastError ( ) )
225- )
226- continuation. finish ( throwing: error)
227- return
217+ if CreateIoCompletionPort (
218+ handle, ioPort, completionKey, 0
219+ ) != ioPort {
220+ let lastError = GetLastError ( )
221+ if lastError != ERROR_INVALID_PARAMETER {
222+ let error = SubprocessError (
223+ code: . init( . asyncIOFailed( " CreateIoCompletionPort failed " ) ) ,
224+ underlyingError: . init( rawValue: GetLastError ( ) )
225+ )
226+ continuation. finish ( throwing: error)
227+ return
228+ } else {
229+ // Special Case:
230+ //
231+ // * ERROR_INVALID_PARAMETER - The handle likely doesn't have FILE_FLAG_OVERLAPPED, which might indicate that it isn't a pipe
232+ // so we can just signal that it is ready for reading right away.
233+ //
234+ continuation. yield ( UInt32 . max)
235+ }
228236 }
229237 // Now save the continuation
230238 _registration. withLock { storage in
@@ -271,6 +279,7 @@ final class AsyncIO: @unchecked Sendable {
271279 // We use an empty `_OVERLAPPED()` here because `ReadFile` below
272280 // only reads non-seekable files, aka pipes.
273281 var overlapped = _OVERLAPPED ( )
282+ var bytesReadIfSynchronous = UInt32 ( 0 )
274283 let succeed = try resultBuffer. withUnsafeMutableBufferPointer { bufferPointer in
275284 // Get a pointer to the memory at the specified offset
276285 // Windows ReadFile uses DWORD for target count, which means we can only
@@ -286,7 +295,7 @@ final class AsyncIO: @unchecked Sendable {
286295 handle,
287296 offsetAddress,
288297 targetCount,
289- nil ,
298+ & bytesReadIfSynchronous ,
290299 & overlapped
291300 )
292301 }
@@ -312,8 +321,18 @@ final class AsyncIO: @unchecked Sendable {
312321 }
313322
314323 }
315- // Now wait for read to finish
316- let bytesRead = try await signalStream. next ( ) ?? 0
324+
325+ let bytesRead =
326+ if bytesReadIfSynchronous == 0 {
327+ try await signalStream. next ( ) ?? 0
328+ } else {
329+ bytesReadIfSynchronous
330+ }
331+
332+ // This handle doesn't support overlapped (asynchronous) I/O, so we must have read it synchronously above
333+ if bytesRead == UInt32 . max {
334+ bytesRead = bytesReadIfSynchronous
335+ }
317336
318337 if bytesRead == 0 {
319338 // We reached EOF. Return whatever's left
0 commit comments