From ee394c311e493ba8e23516a2ba72cadf3d9eaf9a Mon Sep 17 00:00:00 2001 From: Ken Brown Date: Fri, 22 Mar 2019 19:30:41 +0000 Subject: [PATCH] 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. --- winsup/cygwin/fhandler.h | 4 + winsup/cygwin/select.cc | 161 +++++++++++++++++++++++++++++++++++---- winsup/cygwin/select.h | 7 ++ 3 files changed, 157 insertions(+), 15 deletions(-) diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 0ebc44e0d..f6982f0ba 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -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 (); } diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc index 59325860d..991494aa8 100644 --- a/winsup/cygwin/select.cc +++ b/winsup/cygwin/select.cc @@ -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; diff --git a/winsup/cygwin/select.h b/winsup/cygwin/select.h index 71821f76c..19f9d7dc2 100644 --- a/winsup/cygwin/select.h +++ b/winsup/cygwin/select.h @@ -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) {} -- 2.43.5