* select.cc (pipe_data_available): New function - uses NtQueryInformationFile
to return information about pipes. (peek_pipe): Rewrite to use pipe_data_available for both read and write tests.
This commit is contained in:
parent
2ec2d00e1b
commit
a7a1247770
@ -1,3 +1,10 @@
|
|||||||
|
2011-05-31 Christopher Faylor <me.cygwin2011@cgf.cx>
|
||||||
|
|
||||||
|
* select.cc (pipe_data_available): New function - uses
|
||||||
|
NtQueryInformationFile to return information about pipes.
|
||||||
|
(peek_pipe): Rewrite to use pipe_data_available for both read and write
|
||||||
|
tests.
|
||||||
|
|
||||||
2011-05-30 Christopher Faylor <me.cygwin2011@cgf.cx>
|
2011-05-30 Christopher Faylor <me.cygwin2011@cgf.cx>
|
||||||
|
|
||||||
* dtable.cc (dtable::select_write): Add missing argument to
|
* dtable.cc (dtable::select_write): Add missing argument to
|
||||||
|
@ -473,26 +473,71 @@ no_verify (select_record *, fd_set *, fd_set *, fd_set *)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
pipe_data_available (int fd, fhandler_base *fh, HANDLE h, bool writing)
|
||||||
|
{
|
||||||
|
IO_STATUS_BLOCK iosb = {0};
|
||||||
|
FILE_PIPE_LOCAL_INFORMATION fpli = {0};
|
||||||
|
|
||||||
|
bool res = false;
|
||||||
|
if (NtQueryInformationFile (h,
|
||||||
|
&iosb,
|
||||||
|
&fpli,
|
||||||
|
sizeof (fpli),
|
||||||
|
FilePipeLocalInformation))
|
||||||
|
{
|
||||||
|
/* If NtQueryInformationFile fails, optimistically assume the
|
||||||
|
pipe is writable. This could happen if we somehow
|
||||||
|
inherit a pipe that doesn't permit FILE_READ_ATTRIBUTES
|
||||||
|
access on the write end. */
|
||||||
|
select_printf ("fd %d, %s, NtQueryInformationFile failed",
|
||||||
|
fd, fh->get_name ());
|
||||||
|
res = writing ? true : -1;
|
||||||
|
}
|
||||||
|
else if (!writing)
|
||||||
|
{
|
||||||
|
res = !!fpli.ReadDataAvailable;
|
||||||
|
select_printf ("fd %d, %s, read avail %u", fd, fh->get_name (), fpli.ReadDataAvailable);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* 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(). */
|
||||||
|
if ((fpli.WriteQuotaAvailable = (fpli.OutboundQuota - fpli.ReadDataAvailable)))
|
||||||
|
{
|
||||||
|
select_printf ("fd %d, %s, write: size %lu, avail %lu", fd,
|
||||||
|
fh->get_name (), fpli.OutboundQuota,
|
||||||
|
fpli.WriteQuotaAvailable);
|
||||||
|
res = true;
|
||||||
|
}
|
||||||
|
/* If we somehow inherit a tiny pipe (size < PIPE_BUF), then consider
|
||||||
|
the pipe writable only if it is completely empty, to minimize the
|
||||||
|
probability that a subsequent write will block. */
|
||||||
|
else if (fpli.OutboundQuota < PIPE_BUF &&
|
||||||
|
fpli.WriteQuotaAvailable == fpli.OutboundQuota)
|
||||||
|
{
|
||||||
|
select_printf ("fd, %s, write tiny pipe: size %lu, avail %lu",
|
||||||
|
fd, fh->get_name (), fpli.OutboundQuota,
|
||||||
|
fpli.WriteQuotaAvailable);
|
||||||
|
res = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
peek_pipe (select_record *s, bool from_select)
|
peek_pipe (select_record *s, bool from_select)
|
||||||
{
|
{
|
||||||
HANDLE h;
|
HANDLE h;
|
||||||
set_handle_or_return_if_not_open (h, s);
|
set_handle_or_return_if_not_open (h, s);
|
||||||
|
|
||||||
int n = 0;
|
|
||||||
int gotone = 0;
|
int gotone = 0;
|
||||||
fhandler_base *fh = (fhandler_base *) s->fh;
|
fhandler_base *fh = (fhandler_base *) s->fh;
|
||||||
|
|
||||||
/* Don't check if this is a non-blocking fd and I/O is still active.
|
DWORD dev = fh->get_device ();
|
||||||
That could give a false-positive with peek_pipe and friends. */
|
if (s->read_selected && dev != FH_PIPEW)
|
||||||
if (fh->has_ongoing_io ())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Don't perform complicated tests if we don't need to. */
|
|
||||||
if (!s->read_selected && !s->except_selected)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (s->read_selected)
|
|
||||||
{
|
{
|
||||||
if (s->read_ready)
|
if (s->read_ready)
|
||||||
{
|
{
|
||||||
@ -524,106 +569,37 @@ peek_pipe (select_record *s, bool from_select)
|
|||||||
gotone = s->read_ready = true;
|
gotone = s->read_ready = true;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
int n = pipe_data_available (s->fd, fh, h, false);
|
||||||
|
|
||||||
if (fh->get_device () == FH_PIPEW)
|
|
||||||
select_printf ("%s, select for read/except on write end of pipe",
|
|
||||||
fh->get_name ());
|
|
||||||
else if (!PeekNamedPipe (h, NULL, 0, NULL, (DWORD *) &n, NULL))
|
|
||||||
switch (GetLastError ())
|
|
||||||
{
|
|
||||||
case ERROR_BAD_PIPE:
|
|
||||||
case ERROR_PIPE_BUSY:
|
|
||||||
case ERROR_NO_DATA:
|
|
||||||
case ERROR_PIPE_NOT_CONNECTED:
|
|
||||||
n = 0;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
select_printf ("%s, PeekNamedPipe failed, %E", fh->get_name ());
|
|
||||||
n = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
{
|
{
|
||||||
select_printf ("%s, n %d", fh->get_name (), n);
|
select_printf ("read: %s, n %d", fh->get_name (), n);
|
||||||
if (s->except_selected)
|
if (s->except_selected)
|
||||||
gotone += s->except_ready = true;
|
gotone += s->except_ready = true;
|
||||||
if (s->read_selected)
|
if (s->read_selected)
|
||||||
gotone += s->read_ready = true;
|
gotone += s->read_ready = true;
|
||||||
}
|
}
|
||||||
if (n > 0 && s->read_selected)
|
else if (n > 0)
|
||||||
{
|
{
|
||||||
select_printf ("%s, ready for read: avail %d", fh->get_name (), n);
|
select_printf ("read: %s, ready for read: avail %d", fh->get_name (), n);
|
||||||
gotone += s->read_ready = true;
|
gotone += s->read_ready = true;
|
||||||
}
|
}
|
||||||
if (!gotone && s->fh->hit_eof ())
|
if (!gotone && s->fh->hit_eof ())
|
||||||
{
|
{
|
||||||
select_printf ("%s, saw EOF", fh->get_name ());
|
select_printf ("read: %s, saw EOF", fh->get_name ());
|
||||||
if (s->except_selected)
|
if (s->except_selected)
|
||||||
gotone += s->except_ready = true;
|
gotone += s->except_ready = true;
|
||||||
if (s->read_selected)
|
if (s->read_selected)
|
||||||
gotone += s->read_ready = true;
|
gotone += s->read_ready = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (s->write_selected)
|
if (s->write_selected && dev != FH_PIPER)
|
||||||
{
|
{
|
||||||
if (s->write_ready)
|
gotone += s->write_ready = pipe_data_available (s->fd, fh, h, true);
|
||||||
{
|
select_printf ("write: %s, gotone %d", fh->get_name (), gotone);
|
||||||
select_printf ("%s, already ready for write", fh->get_name ());
|
|
||||||
gotone++;
|
|
||||||
}
|
}
|
||||||
/* Do we need to do anything about SIGTTOU here? */
|
|
||||||
else if (fh->get_device () == FH_PIPER)
|
|
||||||
select_printf ("%s, select for write on read end of pipe",
|
|
||||||
fh->get_name ());
|
|
||||||
else
|
|
||||||
{
|
|
||||||
IO_STATUS_BLOCK iosb = {0};
|
|
||||||
FILE_PIPE_LOCAL_INFORMATION fpli = {0};
|
|
||||||
|
|
||||||
if (NtQueryInformationFile (h,
|
|
||||||
&iosb,
|
|
||||||
&fpli,
|
|
||||||
sizeof (fpli),
|
|
||||||
FilePipeLocalInformation))
|
|
||||||
{
|
|
||||||
/* If NtQueryInformationFile fails, optimistically assume the
|
|
||||||
pipe is writable. This could happen if we somehow
|
|
||||||
inherit a pipe that doesn't permit FILE_READ_ATTRIBUTES
|
|
||||||
access on the write end. */
|
|
||||||
select_printf ("%s, NtQueryInformationFile failed",
|
|
||||||
fh->get_name ());
|
|
||||||
gotone += s->write_ready = true;
|
|
||||||
}
|
|
||||||
/* 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(). */
|
|
||||||
else if ((fpli.WriteQuotaAvailable = (fpli.OutboundQuota - fpli.ReadDataAvailable)))
|
|
||||||
{
|
|
||||||
select_printf ("%s, ready for write: size %lu, avail %lu",
|
|
||||||
fh->get_name (),
|
|
||||||
fpli.OutboundQuota,
|
|
||||||
fpli.WriteQuotaAvailable);
|
|
||||||
gotone += s->write_ready = true;
|
|
||||||
}
|
|
||||||
/* If we somehow inherit a tiny pipe (size < PIPE_BUF), then consider
|
|
||||||
the pipe writable only if it is completely empty, to minimize the
|
|
||||||
probability that a subsequent write will block. */
|
|
||||||
else if (fpli.OutboundQuota < PIPE_BUF &&
|
|
||||||
fpli.WriteQuotaAvailable == fpli.OutboundQuota)
|
|
||||||
{
|
|
||||||
select_printf ("%s, tiny pipe: size %lu, avail %lu",
|
|
||||||
fh->get_name (),
|
|
||||||
fpli.OutboundQuota,
|
|
||||||
fpli.WriteQuotaAvailable);
|
|
||||||
gotone += s->write_ready = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return gotone;
|
return gotone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user