diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 3e6b8b351..35b7fa5df 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,22 @@ +2001-03-04 Egor Duda + + * fhandler.h (class fhandler_tty_common): New mutex and event to + syncronize input on master tty with slave tty. + * fhandler_tty.cc (fhandler_pty_master::accept_input): Use them to + syncronize with slave. + * fhandler_tty.cc (fhandler_tty_slave::read): Use input mutex and + event to syncronize with master. Do not limit amount of data read + from master to vmin value. Interrupt on signal and return already + read data, if any. + * fhandler_tty.cc (fhandler_tty_slave::open): Handle input mutex and + event. + * fhandler_tty.cc (fhandler_tty_common::close): Ditto. + * fhandler_tty.cc (fhandler_tty_common::set_close_on_exec): Ditto. + * fhandler_tty.cc (fhandler_tty_common::fixup_after_fork): Ditto. + * fhandler_tty.cc (fhandler_tty_common::dup): Ditto. + * tty.h (tty::open_input_mutex): New function. + * tty.cc (tty::common_init): Create input mutex and event. + Fri Mar 2 13:32:00 2001 Corinna Vinschen * dir.cc (readdir): Fix creating path in symlink check. diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 3607b3b28..73aa294a6 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -707,7 +707,8 @@ public: // Ioctl() request in tty::cmd/arg. HANDLE ioctl_done_event; // Raised by master on ioctl() completion. // Ioctl() status in tty::ioctl_retval. - HANDLE output_mutex; + HANDLE output_mutex, input_mutex; + HANDLE input_available_event; HANDLE inuse; // used to indicate that a tty is in use diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc index 01a5a9691..c3165285e 100644 --- a/winsup/cygwin/fhandler_tty.cc +++ b/winsup/cygwin/fhandler_tty.cc @@ -167,22 +167,21 @@ fhandler_pty_master::accept_input () { DWORD written; DWORD n; - const char dummy[1] = {'X'}; - const char *buf; + DWORD rc; + + rc = WaitForSingleObject (input_mutex, INFINITE); n = get_ttyp ()->read_retval = eat_readahead (-1); - if (n != 0) - buf = rabuf; - else + if ( n != 0 ) { - n = 1; - buf = dummy; - termios_printf ("sending EOF to slave"); + termios_printf ("about to write %d chars to slave", n); + rc = WriteFile (get_output_handle (), rabuf, n, &written, NULL); } - termios_printf ("about to write %d chars to slave", n); - if (!WriteFile (get_output_handle (), buf, n, &written, NULL)) - return -1; + else + termios_printf ("sending EOF to slave"); + SetEvent (input_available_event); + ReleaseMutex (input_mutex); return get_ttyp ()->read_retval; } @@ -459,6 +458,19 @@ fhandler_tty_slave::open (const char *, int flags, mode_t) __seterrno (); return 0; } + if (!(input_mutex = get_ttyp()->open_input_mutex (TRUE))) + { + termios_printf ("open input mutex failed, %E"); + __seterrno (); + return 0; + } + __small_sprintf (buf, INPUT_AVAILABLE_EVENT, ttynum); + if (!(input_available_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf))) + { + termios_printf ("open input event failed, %E"); + __seterrno (); + return 0; + } /* The ioctl events may or may not exist. See output_done_event, above. */ @@ -599,29 +611,90 @@ fhandler_tty_slave::read (void *ptr, size_t len) int totalread = 0; int vmin = INT_MAX; int vtime = 0; /* Initialized to prevent -Wuninitialized warning */ + size_t readlen; + DWORD bytes_in_pipe; char buf[INP_BUFFER_SIZE]; + DWORD time_to_wait; + DWORD rc; + HANDLE w4[2]; - termios_printf("read(%x, %d) handle %d", ptr, len, get_handle ()); + termios_printf ("read(%x, %d) handle %d", ptr, len, get_handle ()); if (!(get_ttyp ()->ti.c_lflag & ICANON)) { - vmin = get_ttyp ()->ti.c_cc[VMIN]; + vmin = min (INP_BUFFER_SIZE, get_ttyp ()->ti.c_cc[VMIN]); vtime = get_ttyp ()->ti.c_cc[VTIME]; + if (vmin < 0) vmin = 0; + if (vtime < 0) vtime = 0; + if (vmin == 0) + time_to_wait = INFINITE; + else + time_to_wait = (vtime == 0 ? INFINITE : 10 * vtime); } + else + time_to_wait = INFINITE; + + w4[0] = signal_arrived; + w4[1] = input_available_event; while (len) { - size_t readlen = min ((unsigned) vmin, min (len, sizeof (buf))); - termios_printf ("reading %d bytes (vtime %d)", - min ((unsigned) vmin, min (len, sizeof (buf))), vtime); - - n = get_readahead_into_buffer (buf, readlen); - - if (!n && ReadFile (get_handle (), buf, readlen, &n, NULL) == FALSE) + rc = WaitForMultipleObjects (2, w4, FALSE, time_to_wait); + if (rc == WAIT_OBJECT_0) + { + /* if we've recieved signal after successfully reading some data, + just return all data successfully read */ + if (totalread > 0) + break; + set_sig_errno (EINTR); + return -1; + } + else if (rc == WAIT_FAILED) + { + termios_printf ("wait for input event failed, %E"); + break; + } + else if (rc == WAIT_TIMEOUT) + break; + rc = WaitForSingleObject (input_mutex, 1000); + if (rc == WAIT_FAILED) + { + termios_printf ("wait for input mutex failed, %E"); + break; + } + else if (rc == WAIT_TIMEOUT) + { + termios_printf ("failed to acquire input mutex after input event arrived"); + break; + } + if (!PeekNamedPipe (get_handle (), NULL, 0, NULL, &bytes_in_pipe, NULL)) { - termios_printf ("read failed, %E"); - _raise (SIGHUP); + termios_printf ("PeekNamedPipe failed, %E"); + _raise (SIGHUP); + bytes_in_pipe = 0; } + readlen = min (bytes_in_pipe, min (len, sizeof (buf))); + if ( readlen ) + { + termios_printf ("reading %d bytes (vtime %d)", readlen, vtime); + if (ReadFile (get_handle (), buf, readlen, &n, NULL) == FALSE) + { + termios_printf ("read failed, %E"); + _raise (SIGHUP); + } + if (n) + { + len -= n; + totalread += n; + memcpy (ptr, buf, n); + ptr = (char *) ptr + n; + } + } + + if (readlen != bytes_in_pipe) + SetEvent (input_available_event); + + ReleaseMutex (input_mutex); if (get_ttyp ()->read_retval < 0) // read error { @@ -634,48 +707,28 @@ fhandler_tty_slave::read (void *ptr, size_t len) termios_printf ("saw EOF"); break; } - len -= n; - totalread += n; - memcpy (ptr, buf, n); - ptr = (char *) ptr + n; - if (get_ttyp ()->ti.c_lflag & ICANON) - break; - else if (totalread >= vmin) + if ( get_ttyp ()->ti.c_lflag & ICANON || + get_flags () & (O_NONBLOCK | O_NDELAY)) break; + if (totalread >= vmin && (vmin > 0 || totalread > 0)) + break; - if (!PeekNamedPipe (get_handle (), NULL, 0, NULL, &n, NULL)) - { - termios_printf("PeekNamedPipe failed, %E"); - break; - } - if (n == 0) - { - if (get_flags () & (O_NONBLOCK | O_NDELAY)) - break; + /* vmin == 0 && vtime == 0: + * we've already read all input, if any, so return immediately + * vmin == 0 && vtime > 0: + * we've waited for input 10*vtime ms in WFSO(input_available_event), + * no matter whether any input arrived, we shouldn't wait any longer, + * so return immediately + * vmin > 0 && vtime == 0: + * here, totalread < vmin, so continue waiting until more data + * arrive + * vmin > 0 && vtime > 0: + * similar to the previous here, totalread < vmin, and timer + * hadn't expired -- WFSO(input_available_event) != WAIT_TIMEOUT, + * so "restart timer" and wait until more data arrive + */ - /* We can't enter the blocking Readfile as signals will be lost. - * So, poll the pipe for data. - * FIXME: try to avoid polling... - * FIXME: Current EINTR scheme does not take vmin/vtime into account. - */ - if (!(get_ttyp ()->ti.c_lflag & ICANON)) - { - termios_printf("vmin %d vtime %d", vmin, vtime); - if (vmin == 0 && vtime == 0) - return 0; // min = 0, time = 0 - if (vtime == 0) - continue; // min > 0, time = 0 - while (vtime--) - { - PeekNamedPipe (get_handle (), NULL, 0, NULL, &n, NULL); - if (n) - break; - Sleep(10); - } - if (vtime == 0) - return totalread; - } - } + if (vmin == 0) break; } termios_printf ("%d=read(%x, %d)", totalread, ptr, len); return totalread; @@ -721,18 +774,32 @@ fhandler_tty_common::dup (fhandler_base *child) errind = 3; goto err; } + if (!DuplicateHandle (hMainProc, input_available_event, hMainProc, + &fts->input_available_event, 0, 1, + DUPLICATE_SAME_ACCESS)) + { + errind = 4; + goto err; + } if (!DuplicateHandle (hMainProc, output_mutex, hMainProc, &fts->output_mutex, 0, 1, DUPLICATE_SAME_ACCESS)) { - errind = 4; + errind = 5; + goto err; + } + if (!DuplicateHandle (hMainProc, input_mutex, hMainProc, + &fts->input_mutex, 0, 1, + DUPLICATE_SAME_ACCESS)) + { + errind = 6; goto err; } if (!DuplicateHandle (hMainProc, get_handle (), hMainProc, &nh, 0, 1, DUPLICATE_SAME_ACCESS)) { - errind = 5; + errind = 7; goto err; } fts->set_io_handle (nh); @@ -741,7 +808,7 @@ fhandler_tty_common::dup (fhandler_base *child) &nh, 0, 1, DUPLICATE_SAME_ACCESS)) { - errind = 6; + errind = 8; goto err; } fts->set_output_handle (nh); @@ -752,7 +819,7 @@ fhandler_tty_common::dup (fhandler_base *child) &fts->inuse, 0, 1, DUPLICATE_SAME_ACCESS)) { - errind = 7; + errind = 9; goto err; } return 0; @@ -888,6 +955,10 @@ fhandler_tty_common::close () termios_printf ("CloseHandle (inuse), %E"); if (!ForceCloseHandle (output_mutex)) termios_printf ("CloseHandle (output_mutex<%p>), %E", output_mutex); + if (!ForceCloseHandle (input_mutex)) + termios_printf ("CloseHandle (input_mutex<%p>), %E", input_mutex); + if (!ForceCloseHandle (input_available_event)) + termios_printf ("CloseHandle (input_available_event<%p>), %E", input_available_event); if (!ForceCloseHandle1 (get_handle (), from_pty)) termios_printf ("CloseHandle (get_handle ()<%p>), %E", get_handle ()); if (!ForceCloseHandle1 (get_output_handle (), to_pty)) @@ -1009,6 +1080,8 @@ fhandler_tty_common::set_close_on_exec (int val) if (inuse) set_inheritance (inuse, val); set_inheritance (output_mutex, val, "output_mutex"); + set_inheritance (input_mutex, val, "input_mutex"); + set_inheritance (input_available_event, val); set_inheritance (output_handle, val); } @@ -1027,6 +1100,13 @@ fhandler_tty_common::fixup_after_fork (HANDLE parent) fork_fixup (parent, output_mutex, "output_mutex"); ProtectHandle (output_mutex); } + if (input_mutex) + { + fork_fixup (parent, input_mutex, "input_mutex"); + ProtectHandle (input_mutex); + } + if (input_available_event) + fork_fixup (parent, input_available_event, "input_available_event"); fork_fixup (parent, output_handle, "output_handle"); fork_fixup (parent, inuse, "inuse"); } diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc index baff0a4c2..070fa3e28 100644 --- a/winsup/cygwin/tty.cc +++ b/winsup/cygwin/tty.cc @@ -408,6 +408,9 @@ tty::common_init (fhandler_pty_master *ptym) return FALSE; } + if (!(ptym->input_available_event = get_event (INPUT_AVAILABLE_EVENT, FALSE))) + return FALSE; + char buf[40]; __small_sprintf (buf, OUTPUT_MUTEX, ntty); if (!(ptym->output_mutex = CreateMutex (&sec_all, FALSE, buf))) @@ -417,7 +420,16 @@ tty::common_init (fhandler_pty_master *ptym) return FALSE; } + __small_sprintf (buf, INPUT_MUTEX, ntty); + if (!(ptym->input_mutex = CreateMutex (&sec_all, FALSE, buf))) + { + termios_printf ("can't create %s", buf); + set_errno (ENOENT); + return FALSE; + } + ProtectHandle1 (ptym->output_mutex, output_mutex); + ProtectHandle1 (ptym->input_mutex, input_mutex); winsize.ws_col = 80; winsize.ws_row = 25; diff --git a/winsup/cygwin/tty.h b/winsup/cygwin/tty.h index bdd6eaedf..36f7ae19d 100644 --- a/winsup/cygwin/tty.h +++ b/winsup/cygwin/tty.h @@ -23,7 +23,9 @@ details. */ #define IOCTL_REQUEST_EVENT "cygtty%d.ioctl.request" #define IOCTL_DONE_EVENT "cygtty%d.ioctl.done" #define RESTART_OUTPUT_EVENT "cygtty%d.output.restart" +#define INPUT_AVAILABLE_EVENT "cygtty%d.input.avail" #define OUTPUT_MUTEX "cygtty%d.output.mutex" +#define INPUT_MUTEX "cygtty%d.input.mutex" #define TTY_SLAVE_ALIVE "cygtty%x.slave_alive" #define TTY_MASTER_ALIVE "cygtty%x.master_alive" @@ -111,6 +113,12 @@ public: __small_sprintf (buf, OUTPUT_MUTEX, ntty); return OpenMutex (MUTEX_ALL_ACCESS, inherit, buf); } + HANDLE open_input_mutex (BOOL inherit = FALSE) + { + char buf[80]; + __small_sprintf (buf, INPUT_MUTEX, ntty); + return OpenMutex (MUTEX_ALL_ACCESS, inherit, buf); + } BOOL exists () { HANDLE h = open_output_mutex ();