aboutsummaryrefslogtreecommitdiff
path: root/winsup/cygwin/select.cc
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin/select.cc')
-rw-r--r--winsup/cygwin/select.cc88
1 files changed, 47 insertions, 41 deletions
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index 422c8e8..a7e82a0 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -601,7 +601,7 @@ pipe_data_available (int fd, fhandler_base *fh, HANDLE h, int mode)
if (mode == PDA_READ
&& PeekNamedPipe (h, NULL, 0, NULL, &nbytes_in_pipe, NULL))
return nbytes_in_pipe;
- return -1;
+ return PDA_ERROR;
}
IO_STATUS_BLOCK iosb = {{0}, 0};
@@ -618,48 +618,52 @@ pipe_data_available (int fd, fhandler_base *fh, HANDLE h, int mode)
access on the write end. */
select_printf ("fd %d, %s, NtQueryInformationFile failed, status %y",
fd, fh->get_name (), status);
- return (mode == PDA_WRITE) ? 1 : -1;
+ return (mode == PDA_WRITE) ? PDA_UNKNOWN : PDA_ERROR;
}
if (mode == PDA_WRITE)
{
/* If there is anything available in the pipe buffer then signal
- that. This means that a pipe could still block since you could
- be trying to write more to the pipe than is available in the
- buffer but that is the hazard of select().
-
- Note that WriteQuotaAvailable is unreliable.
-
- Usually WriteQuotaAvailable on the write side reflects the space
- available in the inbound buffer on the read side. However, if a
- pipe read is currently pending, WriteQuotaAvailable on the write side
- is decremented by the number of bytes the read side is requesting.
- So it's possible (even likely) that WriteQuotaAvailable is 0, even
- if the inbound buffer on the read side is not full. This can lead to
- a deadlock situation: The reader is waiting for data, but select
- on the writer side assumes that no space is available in the read
- side inbound buffer.
-
- Consequentially, there are two possibilities when WriteQuotaAvailable
- is 0. One is that the buffer is really full. The other is that the
- reader is currently trying to read the pipe and it is pending.
- In the latter case, the fact that the reader cannot read the data
- immediately means that the pipe is empty. In the former case,
- NtSetInformationFile() in set_pipe_non_blocking(true) will fail
- with STATUS_PIPE_BUSY, while it succeeds in the latter case.
- Therefore, we can distinguish these cases by calling set_pipe_non_
- blocking(true). If it returns success, the pipe is empty, so we
- return the pipe buffer size. Otherwise, we return 0. */
- if (fh->get_device () == FH_PIPEW && fpli.WriteQuotaAvailable == 0)
+ that. This means that a pipe could still block since you could
+ be trying to write more to the pipe than is available in the
+ buffer but that is the hazard of select().
+
+ Note that WriteQuotaAvailable is unreliable.
+
+ Usually WriteQuotaAvailable on the write side reflects the space
+ available in the inbound buffer on the read side. However, if a
+ pipe read is currently pending, WriteQuotaAvailable on the write side
+ is decremented by the number of bytes the read side is requesting.
+ So it's possible (even likely) that WriteQuotaAvailable is less than
+ actual space available in the pipe, even if the inbound buffer is
+ empty. This can lead to a deadlock situation: The reader is waiting
+ for data, but select on the writer side assumes that no space is
+ available in the read side inbound buffer.
+
+ Consequentially, there are two possibilities when WriteQuotaAvailable
+ is less than pipe size. One is that the buffer is really not empty.
+ The other is that the reader is currently trying to read the pipe
+ and it is pending.
+ In the latter case, the fact that the reader cannot read the data
+ immediately means that the pipe is empty. In the former case,
+ NtSetInformationFile() in set_pipe_non_blocking(!orig_mode) will
+ fail with STATUS_PIPE_BUSY, while it succeeds in the latter case.
+ Therefore, we can distinguish these cases by calling set_pipe_non_
+ blocking(true). If it returns success, the pipe is empty, so we
+ return the pipe buffer size. Otherwise, we return the value of
+ WriteQuotaAvailable as is. */
+ if (fh->get_device () == FH_PIPEW
+ && fpli.WriteQuotaAvailable < fpli.InboundQuota)
{
+ bool orig_mode = ((fhandler_pipe *) fh)->real_non_blocking_mode;
NTSTATUS status =
- ((fhandler_pipe *) fh)->set_pipe_non_blocking (true);
+ ((fhandler_pipe *) fh)->set_pipe_non_blocking (!orig_mode);
if (status == STATUS_PIPE_BUSY)
- return 0; /* Full */
+ return fpli.WriteQuotaAvailable; /* Not empty */
else if (!NT_SUCCESS (status))
/* We cannot know actual write pipe space. */
- return 1;
- /* Restore pipe mode to blocking mode */
- ((fhandler_pipe *) fh)->set_pipe_non_blocking (false);
+ return PDA_UNKNOWN;
+ /* Restore pipe mode to original blocking mode */
+ ((fhandler_pipe *) fh)->set_pipe_non_blocking (orig_mode);
/* Empty */
fpli.WriteQuotaAvailable = fpli.InboundQuota;
}
@@ -670,7 +674,9 @@ pipe_data_available (int fd, fhandler_base *fh, HANDLE h, int mode)
fpli.WriteQuotaAvailable);
return fpli.WriteQuotaAvailable;
}
- /* TODO: Buffer really full or non-Cygwin reader? */
+ return PIPE_BUF; /* Workaround for native ninja. Native ninja creates
+ pipe with size == 0, and starts cygwin process
+ with that pipe. */
}
else if (fpli.ReadDataAvailable)
{
@@ -679,7 +685,7 @@ pipe_data_available (int fd, fhandler_base *fh, HANDLE h, int mode)
return fpli.ReadDataAvailable;
}
if (fpli.NamedPipeState & FILE_PIPE_CLOSING_STATE)
- return -1;
+ return PDA_ERROR;
return 0;
}
@@ -729,7 +735,7 @@ peek_pipe (select_record *s, bool from_select)
if (n == 0 && fh->get_echo_handle ())
n = pipe_data_available (s->fd, fh, fh->get_echo_handle (), PDA_READ);
- if (n < 0)
+ if (n == PDA_ERROR)
{
select_printf ("read: %s, n %d", fh->get_name (), n);
if (s->except_selected)
@@ -770,8 +776,8 @@ out:
}
ssize_t n = pipe_data_available (s->fd, fh, h, PDA_WRITE);
select_printf ("write: %s, n %d", fh->get_name (), n);
- gotone += s->write_ready = (n > 0);
- if (n < 0 && s->except_selected)
+ gotone += s->write_ready = (n > 0 || n == PDA_UNKNOWN);
+ if (n == PDA_ERROR && s->except_selected)
gotone += s->except_ready = true;
}
return gotone;
@@ -984,7 +990,7 @@ out:
ssize_t n = pipe_data_available (s->fd, fh, fh->get_handle (), PDA_WRITE);
select_printf ("write: %s, n %d", fh->get_name (), n);
gotone += s->write_ready = (n > 0);
- if (n < 0 && s->except_selected)
+ if (n == PDA_ERROR && s->except_selected)
gotone += s->except_ready = true;
}
return gotone;
@@ -1410,7 +1416,7 @@ out:
ssize_t n = pipe_data_available (s->fd, fh, h, PDA_WRITE);
select_printf ("write: %s, n %d", fh->get_name (), n);
gotone += s->write_ready = (n > 0);
- if (n < 0 && s->except_selected)
+ if (n == PDA_ERROR && s->except_selected)
gotone += s->except_ready = true;
}
return gotone;