aboutsummaryrefslogtreecommitdiff
path: root/winsup/cygwin
diff options
context:
space:
mode:
authorKen Brown <kbrown@cornell.edu>2019-06-08 11:05:39 -0400
committerKen Brown <kbrown@cornell.edu>2019-06-23 10:16:33 -0400
commit724c18ff7e05545555689854571ea27ed73e8f0b (patch)
tree24a7c99de093ddf41d41275a2d5b4e824b459c16 /winsup/cygwin
parentad101bcb0f55f0eb1a9f60187f949c3decd855e4 (diff)
downloadnewlib-724c18ff7e05545555689854571ea27ed73e8f0b.zip
newlib-724c18ff7e05545555689854571ea27ed73e8f0b.tar.gz
newlib-724c18ff7e05545555689854571ea27ed73e8f0b.tar.bz2
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.
Diffstat (limited to 'winsup/cygwin')
-rw-r--r--winsup/cygwin/fhandler_fifo.cc85
1 files changed, 54 insertions, 31 deletions
diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index c9ff0a3..f63787f 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -640,11 +640,15 @@ ssize_t __reg3
fhandler_fifo::raw_write (const void *ptr, size_t len)
{
ssize_t ret = -1;
- size_t nbytes = 0, chunk;
+ size_t nbytes = 0;
+ ULONG chunk;
NTSTATUS status = STATUS_SUCCESS;
IO_STATUS_BLOCK io;
HANDLE evt = NULL;
+ if (!len)
+ return 0;
+
if (len <= max_atomic_write)
chunk = len;
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. */
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
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;
size_t left = len - nbytes;
- size_t len1;
+ ULONG len1;
+ DWORD waitret = WAIT_OBJECT_0;
+
if (left > chunk)
len1 = chunk;
else
- len1 = left;
+ len1 = (ULONG) left;
nbytes_now = 0;
status = NtWriteFile (get_handle (), evt, NULL, NULL, &io,
(PVOID) ptr, len1, NULL, NULL);
if (evt && status == STATUS_PENDING)
{
- DWORD waitret = cygwait (evt, cw_infinite, cw_cancel | cw_sig_eintr);
- switch (waitret)
- {
- 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;
- }
+ waitret = cygwait (evt);
+ if (waitret == WAIT_OBJECT_0)
+ status = io.Status;
}
- 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;
/* NtWriteFile returns success with # of bytes written == 0
@@ -714,7 +723,7 @@ fhandler_fifo::raw_write (const void *ptr, size_t len)
}
if (evt)
CloseHandle (evt);
- if (status == STATUS_THREAD_SIGNALED && !_my_tls.call_signal_handler ())
+ if (status == STATUS_THREAD_SIGNALED && ret < 0)
set_errno (EINTR);
else if (status == STATUS_THREAD_CANCELED)
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 ()))
goto errout;
+ if (!len)
+ return;
+
while (1)
{
if (hit_eof ())
@@ -827,21 +839,32 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
}
else
{
- /* Allow interruption. Copied from
- fhandler_socket_unix::open_reparse_point. */
- pthread_testcancel ();
- if (cygwait (NULL, cw_nowait, cw_sig_eintr) == WAIT_SIGNALED
- && !_my_tls.call_signal_handler ())
+ /* Allow interruption. */
+ DWORD waitret = cygwait (NULL, cw_nowait, cw_cancel | cw_sig_eintr);
+ if (waitret == WAIT_CANCELED)
+ pthread::static_cancel_self ();
+ else if (waitret == WAIT_SIGNALED)
{
- set_errno (EINTR);
- goto errout;
+ if (_my_tls.call_signal_handler ())
+ 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:
- len = -1;
+ len = (size_t) -1;
}
int __reg2