Cygwin: pty: Fix select() with pseudo console support.

- select() did not work correctly when both read and except are
  polled simultaneously for the same fd and the r/w pipe is switched
  to pseudo console side. This patch fixes this isseu.
This commit is contained in:
Takashi Yano
2019-09-05 13:22:54 +09:00
committed by Corinna Vinschen
parent 433c6b8e0a
commit 915fcd0ae8
4 changed files with 207 additions and 15 deletions

View File

@@ -667,9 +667,6 @@ peek_pipe (select_record *s, bool from_select)
fhm->flush_to_slave ();
}
break;
case DEV_PTYS_MAJOR:
((fhandler_pty_slave *) fh)->reset_switch_to_pcon ();
break;
default:
if (fh->get_readahead_valid ())
{
@@ -713,6 +710,7 @@ peek_pipe (select_record *s, bool from_select)
}
out:
h = fh->get_output_handle_cyg ();
if (s->write_selected && dev != FH_PIPER)
{
gotone += s->write_ready = pipe_data_available (s->fd, fh, h, true);
@@ -1176,33 +1174,173 @@ static int
verify_tty_slave (select_record *me, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds)
{
if (IsEventSignalled (me->h))
fhandler_pty_slave *ptys = (fhandler_pty_slave *) me->fh;
if (me->read_selected && !ptys->to_be_read_from_pcon () &&
IsEventSignalled (ptys->input_available_event))
me->read_ready = true;
return set_bits (me, readfds, writefds, exceptfds);
}
static int
pty_slave_startup (select_record *s, select_stuff *)
peek_pty_slave (select_record *s, bool from_select)
{
int gotone = 0;
fhandler_base *fh = (fhandler_base *) s->fh;
((fhandler_pty_slave *) fh)->mask_switch_to_pcon (true);
fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
ptys->reset_switch_to_pcon ();
if (s->read_selected)
{
if (s->read_ready)
{
select_printf ("%s, already ready for read", fh->get_name ());
gotone = 1;
goto out;
}
if (fh->bg_check (SIGTTIN, true) <= bg_eof)
{
gotone = s->read_ready = true;
goto out;
}
if (ptys->to_be_read_from_pcon ())
{
if (ptys->is_line_input ())
{
#define INREC_SIZE (65536 / sizeof (INPUT_RECORD))
INPUT_RECORD inp[INREC_SIZE];
DWORD n;
PeekConsoleInput (ptys->get_handle (), inp, INREC_SIZE, &n);
bool end_of_line = false;
while (n-- > 0)
if (inp[n].EventType == KEY_EVENT &&
inp[n].Event.KeyEvent.bKeyDown &&
inp[n].Event.KeyEvent.uChar.AsciiChar == '\r')
end_of_line = true;
if (end_of_line)
{
gotone = s->read_ready = true;
goto out;
}
else
goto out;
}
}
if (IsEventSignalled (ptys->input_available_event))
{
gotone = s->read_ready = true;
goto out;
}
if (!gotone && s->fh->hit_eof ())
{
select_printf ("read: %s, saw EOF", fh->get_name ());
if (s->except_selected)
gotone += s->except_ready = true;
if (s->read_selected)
gotone += s->read_ready = true;
}
}
out:
HANDLE h = ptys->get_output_handle_cyg ();
if (s->write_selected)
{
gotone += s->write_ready = pipe_data_available (s->fd, fh, h, true);
select_printf ("write: %s, gotone %d", fh->get_name (), gotone);
}
return gotone;
}
static int pty_slave_startup (select_record *me, select_stuff *stuff);
static DWORD WINAPI
thread_pty_slave (void *arg)
{
select_pipe_info *pi = (select_pipe_info *) arg;
DWORD sleep_time = 0;
bool looping = true;
while (looping)
{
for (select_record *s = pi->start; (s = s->next); )
if (s->startup == pty_slave_startup)
{
if (peek_pty_slave (s, true))
looping = false;
if (pi->stop_thread)
{
select_printf ("stopping");
looping = false;
break;
}
}
if (!looping)
break;
Sleep (sleep_time >> 3);
if (sleep_time < 80)
++sleep_time;
if (pi->stop_thread)
break;
}
return 0;
}
static int
pty_slave_startup (select_record *me, select_stuff *stuff)
{
fhandler_base *fh = (fhandler_base *) me->fh;
fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
if (me->read_selected && ptys->get_pcon_pid () != myself->pid)
ptys->mask_switch_to_pcon (true);
select_pipe_info *pi = stuff->device_specific_ptys;
if (pi->start)
me->h = *((select_pipe_info *) stuff->device_specific_ptys)->thread;
else
{
pi->start = &stuff->start;
pi->stop_thread = false;
pi->thread = new cygthread (thread_pty_slave, pi, "ptyssel");
me->h = *pi->thread;
if (!me->h)
return 0;
}
return 1;
}
static void
pty_slave_cleanup (select_record *s, select_stuff *)
pty_slave_cleanup (select_record *me, select_stuff *stuff)
{
fhandler_base *fh = (fhandler_base *) s->fh;
((fhandler_pty_slave *) fh)->mask_switch_to_pcon (false);
fhandler_base *fh = (fhandler_base *) me->fh;
fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
if (me->read_selected)
ptys->mask_switch_to_pcon (false);
select_pipe_info *pi = (select_pipe_info *) stuff->device_specific_ptys;
if (!pi)
return;
if (pi->thread)
{
pi->stop_thread = true;
pi->thread->detach ();
}
delete pi;
stuff->device_specific_ptys = NULL;
}
select_record *
fhandler_pty_slave::select_read (select_stuff *ss)
{
if (!ss->device_specific_ptys
&& (ss->device_specific_ptys = new select_pipe_info) == NULL)
return NULL;
select_record *s = ss->start.next;
s->h = input_available_event;
s->startup = pty_slave_startup;
s->peek = peek_pipe;
s->peek = peek_pty_slave;
s->verify = verify_tty_slave;
s->read_selected = true;
s->read_ready = false;
@@ -1210,6 +1348,38 @@ fhandler_pty_slave::select_read (select_stuff *ss)
return s;
}
select_record *
fhandler_pty_slave::select_write (select_stuff *ss)
{
if (!ss->device_specific_ptys
&& (ss->device_specific_ptys = new select_pipe_info) == NULL)
return NULL;
select_record *s = ss->start.next;
s->startup = pty_slave_startup;
s->peek = peek_pty_slave;
s->verify = verify_tty_slave;
s->write_selected = true;
s->write_ready = false;
s->cleanup = pty_slave_cleanup;
return s;
}
select_record *
fhandler_pty_slave::select_except (select_stuff *ss)
{
if (!ss->device_specific_ptys
&& (ss->device_specific_ptys = new select_pipe_info) == NULL)
return NULL;
select_record *s = ss->start.next;
s->startup = pty_slave_startup;
s->peek = peek_pty_slave;
s->verify = verify_tty_slave;
s->except_selected = true;
s->except_ready = false;
s->cleanup = pty_slave_cleanup;
return s;
}
select_record *
fhandler_dev_null::select_read (select_stuff *ss)
{