Cygwin: pipe: Handle STATUS_PENDING even for nonblocking mode.
- NtReadFile() and NtWriteFile() seems to return STATUS_PENDING occasionally even in nonblocking mode. This patch adds handling for STATUS_PENDING in nonblocking mode. Addresses: https://cygwin.com/pipermail/cygwin/2021-November/249910.html
This commit is contained in:
parent
19955359c7
commit
6ac73b36c8
|
@ -279,13 +279,12 @@ fhandler_pipe::raw_read (void *ptr, size_t& len)
|
||||||
size_t nbytes = 0;
|
size_t nbytes = 0;
|
||||||
NTSTATUS status = STATUS_SUCCESS;
|
NTSTATUS status = STATUS_SUCCESS;
|
||||||
IO_STATUS_BLOCK io;
|
IO_STATUS_BLOCK io;
|
||||||
HANDLE evt = NULL;
|
HANDLE evt;
|
||||||
|
|
||||||
if (!len)
|
if (!len)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Create a wait event if we're in blocking mode. */
|
if (!(evt = CreateEvent (NULL, false, false, NULL)))
|
||||||
if (!is_nonblocking () && !(evt = CreateEvent (NULL, false, false, NULL)))
|
|
||||||
{
|
{
|
||||||
__seterrno ();
|
__seterrno ();
|
||||||
len = (size_t) -1;
|
len = (size_t) -1;
|
||||||
|
@ -321,8 +320,7 @@ fhandler_pipe::raw_read (void *ptr, size_t& len)
|
||||||
ULONG len1 = (ULONG) (len - nbytes);
|
ULONG len1 = (ULONG) (len - nbytes);
|
||||||
waitret = WAIT_OBJECT_0;
|
waitret = WAIT_OBJECT_0;
|
||||||
|
|
||||||
if (evt)
|
ResetEvent (evt);
|
||||||
ResetEvent (evt);
|
|
||||||
FILE_PIPE_LOCAL_INFORMATION fpli;
|
FILE_PIPE_LOCAL_INFORMATION fpli;
|
||||||
status = NtQueryInformationFile (get_handle (), &io,
|
status = NtQueryInformationFile (get_handle (), &io,
|
||||||
&fpli, sizeof (fpli),
|
&fpli, sizeof (fpli),
|
||||||
|
@ -336,7 +334,7 @@ fhandler_pipe::raw_read (void *ptr, size_t& len)
|
||||||
break;
|
break;
|
||||||
status = NtReadFile (get_handle (), evt, NULL, NULL, &io, ptr,
|
status = NtReadFile (get_handle (), evt, NULL, NULL, &io, ptr,
|
||||||
len1, NULL, NULL);
|
len1, NULL, NULL);
|
||||||
if (evt && status == STATUS_PENDING)
|
if (status == STATUS_PENDING)
|
||||||
{
|
{
|
||||||
waitret = cygwait (evt, INFINITE, cw_cancel | cw_sig);
|
waitret = cygwait (evt, INFINITE, cw_cancel | cw_sig);
|
||||||
/* If io.Status is STATUS_CANCELLED after CancelIo, IO has actually
|
/* If io.Status is STATUS_CANCELLED after CancelIo, IO has actually
|
||||||
|
@ -406,8 +404,7 @@ fhandler_pipe::raw_read (void *ptr, size_t& len)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ReleaseMutex (read_mtx);
|
ReleaseMutex (read_mtx);
|
||||||
if (evt)
|
CloseHandle (evt);
|
||||||
CloseHandle (evt);
|
|
||||||
if (status == STATUS_THREAD_SIGNALED && nbytes == 0)
|
if (status == STATUS_THREAD_SIGNALED && nbytes == 0)
|
||||||
{
|
{
|
||||||
set_errno (EINTR);
|
set_errno (EINTR);
|
||||||
|
@ -437,7 +434,7 @@ fhandler_pipe_fifo::raw_write (const void *ptr, size_t len)
|
||||||
ULONG chunk;
|
ULONG chunk;
|
||||||
NTSTATUS status = STATUS_SUCCESS;
|
NTSTATUS status = STATUS_SUCCESS;
|
||||||
IO_STATUS_BLOCK io;
|
IO_STATUS_BLOCK io;
|
||||||
HANDLE evt = NULL;
|
HANDLE evt;
|
||||||
|
|
||||||
if (!len)
|
if (!len)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -456,8 +453,7 @@ fhandler_pipe_fifo::raw_write (const void *ptr, size_t len)
|
||||||
else
|
else
|
||||||
chunk = pipe_buf_size;
|
chunk = pipe_buf_size;
|
||||||
|
|
||||||
/* Create a wait event if the pipe or fifo is in blocking mode. */
|
if (!(evt = CreateEvent (NULL, false, false, NULL)))
|
||||||
if (!is_nonblocking () && !(evt = CreateEvent (NULL, false, false, NULL)))
|
|
||||||
{
|
{
|
||||||
__seterrno ();
|
__seterrno ();
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -502,42 +498,42 @@ fhandler_pipe_fifo::raw_write (const void *ptr, size_t len)
|
||||||
{
|
{
|
||||||
status = NtWriteFile (get_handle (), evt, NULL, NULL, &io,
|
status = NtWriteFile (get_handle (), evt, NULL, NULL, &io,
|
||||||
(PVOID) ptr, len1, NULL, NULL);
|
(PVOID) ptr, len1, NULL, NULL);
|
||||||
if (evt || !NT_SUCCESS (status) || io.Information > 0
|
if (status == STATUS_PENDING)
|
||||||
|
{
|
||||||
|
while (WAIT_TIMEOUT ==
|
||||||
|
(waitret = cygwait (evt, (DWORD) 0, cw_cancel | cw_sig)))
|
||||||
|
{
|
||||||
|
if (reader_closed ())
|
||||||
|
{
|
||||||
|
CancelIo (get_handle ());
|
||||||
|
set_errno (EPIPE);
|
||||||
|
raise (SIGPIPE);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cygwait (select_sem, 10);
|
||||||
|
}
|
||||||
|
/* If io.Status is STATUS_CANCELLED after CancelIo, IO has
|
||||||
|
actually been cancelled and io.Information contains the
|
||||||
|
number of bytes processed so far.
|
||||||
|
Otherwise IO has been finished regulary and io.Status
|
||||||
|
contains valid success or error information. */
|
||||||
|
CancelIo (get_handle ());
|
||||||
|
if (waitret == WAIT_SIGNALED && io.Status != STATUS_CANCELLED)
|
||||||
|
waitret = WAIT_OBJECT_0;
|
||||||
|
|
||||||
|
if (waitret == WAIT_CANCELED)
|
||||||
|
status = STATUS_THREAD_CANCELED;
|
||||||
|
else if (waitret == WAIT_SIGNALED)
|
||||||
|
status = STATUS_THREAD_SIGNALED;
|
||||||
|
else
|
||||||
|
status = io.Status;
|
||||||
|
}
|
||||||
|
if (!is_nonblocking () || !NT_SUCCESS (status) || io.Information > 0
|
||||||
|| len <= PIPE_BUF)
|
|| len <= PIPE_BUF)
|
||||||
break;
|
break;
|
||||||
len1 >>= 1;
|
len1 >>= 1;
|
||||||
}
|
}
|
||||||
if (evt && status == STATUS_PENDING)
|
|
||||||
{
|
|
||||||
while (WAIT_TIMEOUT ==
|
|
||||||
(waitret = cygwait (evt, (DWORD) 0, cw_cancel | cw_sig)))
|
|
||||||
{
|
|
||||||
if (reader_closed ())
|
|
||||||
{
|
|
||||||
CancelIo (get_handle ());
|
|
||||||
set_errno (EPIPE);
|
|
||||||
raise (SIGPIPE);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
cygwait (select_sem, 10);
|
|
||||||
}
|
|
||||||
/* If io.Status is STATUS_CANCELLED after CancelIo, IO has actually
|
|
||||||
been cancelled and io.Information contains the number of bytes
|
|
||||||
processed so far.
|
|
||||||
Otherwise IO has been finished regulary and io.Status contains
|
|
||||||
valid success or error information. */
|
|
||||||
CancelIo (get_handle ());
|
|
||||||
if (waitret == WAIT_SIGNALED && io.Status != STATUS_CANCELLED)
|
|
||||||
waitret = WAIT_OBJECT_0;
|
|
||||||
|
|
||||||
if (waitret == WAIT_CANCELED)
|
|
||||||
status = STATUS_THREAD_CANCELED;
|
|
||||||
else if (waitret == WAIT_SIGNALED)
|
|
||||||
status = STATUS_THREAD_SIGNALED;
|
|
||||||
else
|
|
||||||
status = io.Status;
|
|
||||||
}
|
|
||||||
if (isclosed ()) /* A signal handler might have closed the fd. */
|
if (isclosed ()) /* A signal handler might have closed the fd. */
|
||||||
{
|
{
|
||||||
if (waitret == WAIT_OBJECT_0)
|
if (waitret == WAIT_OBJECT_0)
|
||||||
|
@ -570,8 +566,7 @@ fhandler_pipe_fifo::raw_write (const void *ptr, size_t len)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
if (evt)
|
CloseHandle (evt);
|
||||||
CloseHandle (evt);
|
|
||||||
if (status == STATUS_THREAD_SIGNALED && nbytes == 0)
|
if (status == STATUS_THREAD_SIGNALED && nbytes == 0)
|
||||||
set_errno (EINTR);
|
set_errno (EINTR);
|
||||||
else if (status == STATUS_THREAD_CANCELED)
|
else if (status == STATUS_THREAD_CANCELED)
|
||||||
|
|
|
@ -22,3 +22,8 @@ Bug Fixes
|
||||||
- Fix long-standing problem that fchmod or facl on newly created files
|
- Fix long-standing problem that fchmod or facl on newly created files
|
||||||
screw up the DOS file attributes.
|
screw up the DOS file attributes.
|
||||||
Addresses: https://cygwin.com/pipermail/cygwin/2021-November/249909.html
|
Addresses: https://cygwin.com/pipermail/cygwin/2021-November/249909.html
|
||||||
|
|
||||||
|
- Fix issue that pipe read()/write() occasionally returns a garbage
|
||||||
|
length when NtReadFile/NtWriteFile returns STATUS_PENDING in non-
|
||||||
|
blocking mode.
|
||||||
|
Addresses: https://cygwin.com/pipermail/cygwin/2021-November/249910.html
|
||||||
|
|
Loading…
Reference in New Issue