Christopher Faylor <cgf@timesys.com>

* autoload.cc (NtQueryInformationFile): Return nonzero on error.
* ntdll.h (FILE_PIPE_LOCAL_INFORMATION): Add.
(NtQueryInformationFile): Fix types for last two arguments.
* pipe.cc: Include stdlib.h, limits.h, and ntdll.h.
(create_selectable_pipe): New function to create a pipe that can be used with
NtQueryInformationFile for select.
(fhandler_pipe::create): Call create_selectable_pipe instead of CreatePipe.
(pipe): Use DEFAULT_PIPEBUFSIZE as argument to create_pipe.
* select.cc: Include limits.h and ntdll.h.
(peek_pipe): Add select_printf output.  Call NtQueryInformationFile to
implement select for write on pipes.
(fhandler_pipe::select_read): Reorder field assignments to be consistent with
fhandler_pipe::select_write.
(fhandler_pipe::select_write): Initialize startup, verify, cleanup, and
write_ready fields for select_record.
(fhandler_pipe::select_except): Tweak indentation to be consistent with
fhandler_pipe::select_write.
This commit is contained in:
Christopher Faylor
2004-09-03 01:32:02 +00:00
parent 79eebb79a6
commit 6644c628f5
5 changed files with 250 additions and 21 deletions

View File

@@ -28,7 +28,7 @@ details. */
#include <winuser.h>
#include <netdb.h>
#include <unistd.h>
#include <stdio.h>
#include <limits.h>
#define USE_SYS_TYPES_FD_SET
#include <winsock.h>
#include "select.h"
@@ -42,6 +42,7 @@ details. */
#include "perthread.h"
#include "tty.h"
#include "cygthread.h"
#include "ntdll.h"
/*
* All these defines below should be in sys/types.h
@@ -419,7 +420,7 @@ peek_pipe (select_record *s, bool from_select)
{
if (s->read_ready)
{
select_printf ("already ready");
select_printf ("%s, already ready for read", fh->get_name ());
gotone = 1;
goto out;
}
@@ -451,7 +452,8 @@ peek_pipe (select_record *s, bool from_select)
}
if (fh->get_device () == FH_PIPEW)
/* nothing */;
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))
{
select_printf ("%s, PeekNamedPipe failed, %E", fh->get_name ());
@@ -489,21 +491,82 @@ peek_pipe (select_record *s, bool from_select)
}
if (n > 0 && s->read_selected)
{
select_printf ("%s, ready for read", fh->get_name ());
select_printf ("%s, ready for read: avail %d", fh->get_name (), n);
gotone += s->read_ready = true;
}
if (!gotone && s->fh->hit_eof ())
{
select_printf ("%s, saw EOF", fh->get_name ());
if (s->except_selected)
gotone = s->except_ready = true;
gotone += s->except_ready = true;
if (s->read_selected)
gotone += s->read_ready = true;
select_printf ("saw eof on '%s'", fh->get_name ());
}
out:
return gotone || s->write_ready;
if (s->write_selected)
{
if (s->write_ready)
{
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
{
/* We don't worry about the guard mutex, because that only applies
when from_select is false, and peek_pipe is never called that
way for writes. */
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 on Win9x, because
NtQueryInformationFile is not available, or 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;
}
/* Ensure that enough space is available for atomic writes,
as required by POSIX. Subsequent writes with size > PIPE_BUF
can still block, but most (all?) UNIX variants seem to work
this way (e.g., BSD, Linux, Solaris). */
else if (fpli.WriteQuotaAvailable >= PIPE_BUF)
{
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;
}
static int start_thread_pipe (select_record *me, select_stuff *stuff);
@@ -603,9 +666,9 @@ fhandler_pipe::select_read (select_record *s)
s->startup = start_thread_pipe;
s->peek = peek_pipe;
s->verify = verify_ok;
s->cleanup = pipe_cleanup;
s->read_selected = true;
s->read_ready = false;
s->cleanup = pipe_cleanup;
return s;
}
@@ -613,14 +676,13 @@ select_record *
fhandler_pipe::select_write (select_record *s)
{
if (!s)
{
s = new select_record;
s->startup = no_startup;
s->verify = no_verify;
}
s = new select_record;
s->startup = start_thread_pipe;
s->peek = peek_pipe;
s->verify = verify_ok;
s->cleanup = pipe_cleanup;
s->write_selected = true;
s->write_ready = true;
s->write_ready = false;
return s;
}
@@ -628,7 +690,7 @@ select_record *
fhandler_pipe::select_except (select_record *s)
{
if (!s)
s = new select_record;
s = new select_record;
s->startup = start_thread_pipe;
s->peek = peek_pipe;
s->verify = verify_ok;