Cygwin: fhandler_fifo::raw_read: handle STATUS_PENDING

NtReadFile can return STATUS_PENDING occasionally even in non-blocking
mode.  Check for this and wait for NtReadFile to complete.  To avoid
code repetition, do this in a static helper function nt_read.
This commit is contained in:
Ken Brown 2021-11-23 11:40:56 -05:00
parent 384c78e8a7
commit da32bafaac
1 changed files with 47 additions and 23 deletions

View File

@ -1201,12 +1201,39 @@ fhandler_fifo::release_select_sem (const char *from)
ReleaseSemaphore (select_sem, n_release, NULL); ReleaseSemaphore (select_sem, n_release, NULL);
} }
/* Read from a non-blocking pipe and wait for completion. */
static NTSTATUS
nt_read (HANDLE h, HANDLE evt, PIO_STATUS_BLOCK pio, void *in_ptr, size_t& len)
{
NTSTATUS status;
ResetEvent (evt);
status = NtReadFile (h, evt, NULL, NULL, pio, in_ptr, len, NULL, NULL);
if (status == STATUS_PENDING)
{
/* Very short-lived */
status = NtWaitForSingleObject (evt, FALSE, NULL);
if (NT_SUCCESS (status))
status = pio->Status;
}
return status;
}
void __reg3 void __reg3
fhandler_fifo::raw_read (void *in_ptr, size_t& len) fhandler_fifo::raw_read (void *in_ptr, size_t& len)
{ {
HANDLE evt;
if (!len) if (!len)
return; return;
if (!(evt = CreateEvent (NULL, false, false, NULL)))
{
__seterrno ();
len = (size_t) -1;
return;
}
while (1) while (1)
{ {
int nconnected = 0; int nconnected = 0;
@ -1244,17 +1271,15 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
NTSTATUS status; NTSTATUS status;
IO_STATUS_BLOCK io; IO_STATUS_BLOCK io;
status = NtReadFile (fc_handler[j].h, NULL, NULL, NULL, status = nt_read (fc_handler[j].h, evt, &io, in_ptr, len);
&io, in_ptr, len, NULL, NULL);
switch (status) switch (status)
{ {
case STATUS_SUCCESS: case STATUS_SUCCESS:
case STATUS_BUFFER_OVERFLOW: case STATUS_BUFFER_OVERFLOW:
/* io.Information is supposedly valid in latter case. */
if (io.Information > 0) if (io.Information > 0)
{ {
len = io.Information; len = io.Information;
goto out; goto unlock_out;
} }
break; break;
case STATUS_PIPE_EMPTY: case STATUS_PIPE_EMPTY:
@ -1265,7 +1290,7 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
fc_handler[j].set_state (fc_disconnected); fc_handler[j].set_state (fc_disconnected);
break; break;
default: default:
debug_printf ("NtReadFile status %y", status); debug_printf ("nt_read status %y", status);
fc_handler[j].set_state (fc_error); fc_handler[j].set_state (fc_error);
break; break;
} }
@ -1278,8 +1303,7 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
NTSTATUS status; NTSTATUS status;
IO_STATUS_BLOCK io; IO_STATUS_BLOCK io;
status = NtReadFile (fc_handler[i].h, NULL, NULL, NULL, status = nt_read (fc_handler[i].h, evt, &io, in_ptr, len);
&io, in_ptr, len, NULL, NULL);
switch (status) switch (status)
{ {
case STATUS_SUCCESS: case STATUS_SUCCESS:
@ -1290,7 +1314,7 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
if (j < nhandlers) if (j < nhandlers)
fc_handler[j].last_read = false; fc_handler[j].last_read = false;
fc_handler[i].last_read = true; fc_handler[i].last_read = true;
goto out; goto unlock_out;
} }
break; break;
case STATUS_PIPE_EMPTY: case STATUS_PIPE_EMPTY:
@ -1301,7 +1325,7 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
fc_handler[i].set_state (fc_disconnected); fc_handler[i].set_state (fc_disconnected);
break; break;
default: default:
debug_printf ("NtReadFile status %y", status); debug_printf ("nt_read status %y", status);
fc_handler[i].set_state (fc_error); fc_handler[i].set_state (fc_error);
break; break;
} }
@ -1315,8 +1339,7 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
IO_STATUS_BLOCK io; IO_STATUS_BLOCK io;
nconnected++; nconnected++;
status = NtReadFile (fc_handler[i].h, NULL, NULL, NULL, status = nt_read (fc_handler[i].h, evt, &io, in_ptr, len);
&io, in_ptr, len, NULL, NULL);
switch (status) switch (status)
{ {
case STATUS_SUCCESS: case STATUS_SUCCESS:
@ -1327,7 +1350,7 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
if (j < nhandlers) if (j < nhandlers)
fc_handler[j].last_read = false; fc_handler[j].last_read = false;
fc_handler[i].last_read = true; fc_handler[i].last_read = true;
goto out; goto unlock_out;
} }
break; break;
case STATUS_PIPE_EMPTY: case STATUS_PIPE_EMPTY:
@ -1337,25 +1360,25 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
nconnected--; nconnected--;
break; break;
default: default:
debug_printf ("NtReadFile status %y", status); debug_printf ("nt_read status %y", status);
fc_handler[i].set_state (fc_error); fc_handler[i].set_state (fc_error);
nconnected--; nconnected--;
break; break;
} }
} }
fifo_client_unlock ();
if (!nconnected && hit_eof ()) if (!nconnected && hit_eof ())
{ {
reading_unlock ();
len = 0; len = 0;
return; goto unlock_out;
} }
fifo_client_unlock ();
maybe_retry: maybe_retry:
reading_unlock (); reading_unlock ();
if (is_nonblocking ()) if (is_nonblocking ())
{ {
set_errno (EAGAIN); set_errno (EAGAIN);
goto errout; len = (size_t) -1;
goto out;
} }
else else
{ {
@ -1370,7 +1393,8 @@ maybe_retry:
else else
{ {
set_errno (EINTR); set_errno (EINTR);
goto errout; len = (size_t) -1;
goto out;
} }
} }
} }
@ -1378,17 +1402,17 @@ maybe_retry:
if (isclosed ()) if (isclosed ())
{ {
set_errno (EBADF); set_errno (EBADF);
goto errout; len = (size_t) -1;
goto out;
} }
} }
errout: unlock_out:
len = (size_t) -1;
return;
out:
fifo_client_unlock (); fifo_client_unlock ();
reading_unlock (); reading_unlock ();
out:
if (select_sem) if (select_sem)
release_select_sem ("raw_read"); release_select_sem ("raw_read");
CloseHandle (evt);
} }
int __reg2 int __reg2