Cygwin: FIFO: update select

Add static functions peek_fifo, thread_fifo, start_thread_fifo, and
fifo_cleanup to select.cc.  These are based on the corresponding pipe
functions, the main difference being that peek_fifo loops through the
connected clients to see if any of them have data available for
reading.

Add the fhandler_fifo methods select_read, select_write, and
select_except.

Add accessor methods get_nclients, get_handle, and is_connected that
are needed by peek_fifo.
This commit is contained in:
Ken Brown 2019-03-22 19:30:41 +00:00 committed by Corinna Vinschen
parent 1aa438a94c
commit ee394c311e
3 changed files with 157 additions and 15 deletions

View File

@ -1278,6 +1278,10 @@ class fhandler_fifo: public fhandler_base
public:
fhandler_fifo ();
bool hit_eof ();
int get_nclients () const { return nclients; }
HANDLE& get_handle () { return fhandler_base::get_handle (); }
HANDLE get_handle (int i) const { return client[i].fh->get_handle (); }
bool is_connected (int i) const { return client[i].state == fc_connected; }
PUNICODE_STRING get_pipe_name ();
DWORD listen_client_thread ();
void fifo_client_lock () { _fifo_client_lock.lock (); }

View File

@ -822,17 +822,148 @@ fhandler_pipe::select_except (select_stuff *ss)
return s;
}
static int
peek_fifo (select_record *s, bool from_select)
{
if (cygheap->fdtab.not_open (s->fd))
{
s->thread_errno = EBADF;
return -1;
}
int gotone = 0;
fhandler_fifo *fh = (fhandler_fifo *) s->fh;
if (s->read_selected)
{
if (s->read_ready)
{
select_printf ("%s, already ready for read", fh->get_name ());
gotone = 1;
goto out;
}
if (fh->get_readahead_valid ())
{
select_printf ("readahead");
gotone = s->read_ready = true;
goto out;
}
if (fh->hit_eof ())
{
select_printf ("read: %s, saw EOF", fh->get_name ());
gotone = s->read_ready = true;
if (s->except_selected)
gotone += s->except_ready = true;
goto out;
}
fh->fifo_client_lock ();
for (int i = 0; i < fh->get_nclients (); i++)
if (fh->is_connected (i))
{
int n = pipe_data_available (s->fd, fh, fh->get_handle (i),
false);
if (n > 0)
{
select_printf ("read: %s, ready for read: avail %d, client %d",
fh->get_name (), n, i);
fh->fifo_client_unlock ();
gotone += s->read_ready = true;
goto out;
}
}
fh->fifo_client_unlock ();
}
out:
if (s->write_selected)
{
gotone += s->write_ready
= pipe_data_available (s->fd, fh, fh->get_handle (), true);
select_printf ("write: %s, gotone %d", fh->get_name (), gotone);
}
return gotone;
}
static int start_thread_fifo (select_record *me, select_stuff *stuff);
static DWORD WINAPI
thread_fifo (void *arg)
{
select_fifo_info *pi = (select_fifo_info *) arg;
DWORD sleep_time = 0;
bool looping = true;
while (looping)
{
for (select_record *s = pi->start; (s = s->next); )
if (s->startup == start_thread_fifo)
{
if (peek_fifo (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
start_thread_fifo (select_record *me, select_stuff *stuff)
{
select_fifo_info *pi = stuff->device_specific_fifo;
if (pi->start)
me->h = *((select_fifo_info *) stuff->device_specific_fifo)->thread;
else
{
pi->start = &stuff->start;
pi->stop_thread = false;
pi->thread = new cygthread (thread_fifo, pi, "fifosel");
me->h = *pi->thread;
if (!me->h)
return 0;
}
return 1;
}
static void
fifo_cleanup (select_record *, select_stuff *stuff)
{
select_fifo_info *pi = (select_fifo_info *) stuff->device_specific_fifo;
if (!pi)
return;
if (pi->thread)
{
pi->stop_thread = true;
pi->thread->detach ();
}
delete pi;
stuff->device_specific_fifo = NULL;
}
select_record *
fhandler_fifo::select_read (select_stuff *ss)
{
if (!ss->device_specific_pipe
&& (ss->device_specific_pipe = new select_pipe_info) == NULL)
if (!ss->device_specific_fifo
&& (ss->device_specific_fifo = new select_fifo_info) == NULL)
return NULL;
select_record *s = ss->start.next;
s->startup = start_thread_pipe;
s->peek = peek_pipe;
s->startup = start_thread_fifo;
s->peek = peek_fifo;
s->verify = verify_ok;
s->cleanup = pipe_cleanup;
s->cleanup = fifo_cleanup;
s->read_selected = true;
s->read_ready = false;
return s;
@ -841,14 +972,14 @@ fhandler_fifo::select_read (select_stuff *ss)
select_record *
fhandler_fifo::select_write (select_stuff *ss)
{
if (!ss->device_specific_pipe
&& (ss->device_specific_pipe = new select_pipe_info) == NULL)
if (!ss->device_specific_fifo
&& (ss->device_specific_fifo = new select_fifo_info) == NULL)
return NULL;
select_record *s = ss->start.next;
s->startup = start_thread_pipe;
s->peek = peek_pipe;
s->startup = start_thread_fifo;
s->peek = peek_fifo;
s->verify = verify_ok;
s->cleanup = pipe_cleanup;
s->cleanup = fifo_cleanup;
s->write_selected = true;
s->write_ready = false;
return s;
@ -857,14 +988,14 @@ fhandler_fifo::select_write (select_stuff *ss)
select_record *
fhandler_fifo::select_except (select_stuff *ss)
{
if (!ss->device_specific_pipe
&& (ss->device_specific_pipe = new select_pipe_info) == NULL)
if (!ss->device_specific_fifo
&& (ss->device_specific_fifo = new select_fifo_info) == NULL)
return NULL;
select_record *s = ss->start.next;
s->startup = start_thread_pipe;
s->peek = peek_pipe;
s->startup = start_thread_fifo;
s->peek = peek_fifo;
s->verify = verify_ok;
s->cleanup = pipe_cleanup;
s->cleanup = fifo_cleanup;
s->except_selected = true;
s->except_ready = false;
return s;

View File

@ -53,6 +53,11 @@ struct select_pipe_info: public select_info
select_pipe_info (): select_info () {}
};
struct select_fifo_info: public select_info
{
select_fifo_info (): select_info () {}
};
struct select_socket_info: public select_info
{
int num_w4;
@ -89,6 +94,7 @@ public:
select_record start;
select_pipe_info *device_specific_pipe;
select_fifo_info *device_specific_fifo;
select_socket_info *device_specific_socket;
select_serial_info *device_specific_serial;
select_signalfd_info *device_specific_signalfd;
@ -102,6 +108,7 @@ public:
select_stuff (): return_on_signal (false), always_ready (false),
windows_used (false), start (),
device_specific_pipe (NULL),
device_specific_fifo (NULL),
device_specific_socket (NULL),
device_specific_serial (NULL),
device_specific_signalfd (NULL) {}