Cygwin: FIFO: fix signal handling in raw_read and raw_write

cygwait wasn't being called correctly.

Also do some minor cleanup in raw_read and raw_write.
This commit is contained in:
Ken Brown 2019-06-08 11:05:39 -04:00
parent ad101bcb0f
commit 724c18ff7e
1 changed files with 54 additions and 31 deletions

View File

@ -640,11 +640,15 @@ ssize_t __reg3
fhandler_fifo::raw_write (const void *ptr, size_t len) fhandler_fifo::raw_write (const void *ptr, size_t len)
{ {
ssize_t ret = -1; ssize_t ret = -1;
size_t nbytes = 0, chunk; size_t nbytes = 0;
ULONG chunk;
NTSTATUS status = STATUS_SUCCESS; NTSTATUS status = STATUS_SUCCESS;
IO_STATUS_BLOCK io; IO_STATUS_BLOCK io;
HANDLE evt = NULL; HANDLE evt = NULL;
if (!len)
return 0;
if (len <= max_atomic_write) if (len <= max_atomic_write)
chunk = len; chunk = len;
else if (is_nonblocking ()) else if (is_nonblocking ())
@ -654,7 +658,10 @@ fhandler_fifo::raw_write (const void *ptr, size_t len)
/* Create a wait event if the FIFO is in blocking mode. */ /* Create a wait event if the FIFO is in blocking mode. */
if (!is_nonblocking () && !(evt = CreateEvent (NULL, false, false, NULL))) if (!is_nonblocking () && !(evt = CreateEvent (NULL, false, false, NULL)))
return -1; {
__seterrno ();
return -1;
}
/* Write in chunks, accumulating a total. If there's an error, just /* Write in chunks, accumulating a total. If there's an error, just
return the accumulated total unless the first write fails, in return the accumulated total unless the first write fails, in
@ -663,33 +670,35 @@ fhandler_fifo::raw_write (const void *ptr, size_t len)
{ {
ULONG_PTR nbytes_now = 0; ULONG_PTR nbytes_now = 0;
size_t left = len - nbytes; size_t left = len - nbytes;
size_t len1; ULONG len1;
DWORD waitret = WAIT_OBJECT_0;
if (left > chunk) if (left > chunk)
len1 = chunk; len1 = chunk;
else else
len1 = left; len1 = (ULONG) left;
nbytes_now = 0; nbytes_now = 0;
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 && status == STATUS_PENDING) if (evt && status == STATUS_PENDING)
{ {
DWORD waitret = cygwait (evt, cw_infinite, cw_cancel | cw_sig_eintr); waitret = cygwait (evt);
switch (waitret) if (waitret == WAIT_OBJECT_0)
{ status = io.Status;
case WAIT_OBJECT_0:
status = io.Status;
break;
case WAIT_SIGNALED:
status = STATUS_THREAD_SIGNALED;
break;
case WAIT_CANCELED:
status = STATUS_THREAD_CANCELED;
break;
default:
break;
}
} }
if (NT_SUCCESS (status)) if (waitret == WAIT_CANCELED)
status = STATUS_THREAD_CANCELED;
else if (waitret == WAIT_SIGNALED)
status = STATUS_THREAD_SIGNALED;
else if (isclosed ()) /* A signal handler might have closed the fd. */
{
if (waitret == WAIT_OBJECT_0)
set_errno (EBADF);
else
__seterrno ();
len = (size_t) -1;
}
else if (NT_SUCCESS (status))
{ {
nbytes_now = io.Information; nbytes_now = io.Information;
/* NtWriteFile returns success with # of bytes written == 0 /* NtWriteFile returns success with # of bytes written == 0
@ -714,7 +723,7 @@ fhandler_fifo::raw_write (const void *ptr, size_t len)
} }
if (evt) if (evt)
CloseHandle (evt); CloseHandle (evt);
if (status == STATUS_THREAD_SIGNALED && !_my_tls.call_signal_handler ()) if (status == STATUS_THREAD_SIGNALED && ret < 0)
set_errno (EINTR); set_errno (EINTR);
else if (status == STATUS_THREAD_CANCELED) else if (status == STATUS_THREAD_CANCELED)
pthread::static_cancel_self (); pthread::static_cancel_self ();
@ -784,6 +793,9 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
if (res < 0 || (res == 0 && !listen_client ())) if (res < 0 || (res == 0 && !listen_client ()))
goto errout; goto errout;
if (!len)
return;
while (1) while (1)
{ {
if (hit_eof ()) if (hit_eof ())
@ -827,21 +839,32 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
} }
else else
{ {
/* Allow interruption. Copied from /* Allow interruption. */
fhandler_socket_unix::open_reparse_point. */ DWORD waitret = cygwait (NULL, cw_nowait, cw_cancel | cw_sig_eintr);
pthread_testcancel (); if (waitret == WAIT_CANCELED)
if (cygwait (NULL, cw_nowait, cw_sig_eintr) == WAIT_SIGNALED pthread::static_cancel_self ();
&& !_my_tls.call_signal_handler ()) else if (waitret == WAIT_SIGNALED)
{ {
set_errno (EINTR); if (_my_tls.call_signal_handler ())
goto errout; continue;
else
{
set_errno (EINTR);
goto errout;
}
} }
/* Don't hog the CPU. */
Sleep (1);
} }
/* We might have been closed by a signal handler or another thread. */
if (isclosed ())
{
set_errno (EBADF);
goto errout;
}
/* Don't hog the CPU. */
Sleep (1);
} }
errout: errout:
len = -1; len = (size_t) -1;
} }
int __reg2 int __reg2