Index: fhandler.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/fhandler.h,v
retrieving revision 1.41
diff -u -p -2 -r1.41 fhandler.h
--- fhandler.h	2001/02/27 09:14:35	1.41
+++ fhandler.h	2001/02/28 14:10:42
@@ -707,5 +707,6 @@ public:
   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
 
Index: fhandler_tty.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/fhandler_tty.cc,v
retrieving revision 1.23
diff -u -p -2 -r1.23 fhandler_tty.cc
--- fhandler_tty.cc	2000/10/17 01:42:04	1.23
+++ fhandler_tty.cc	2001/02/28 14:10:44
@@ -168,20 +168,19 @@ 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;
 }
@@ -460,4 +459,17 @@ fhandler_tty_slave::open (const char *, 
       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,
@@ -600,5 +612,10 @@ fhandler_tty_slave::read (void *ptr, siz
   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 ());
@@ -606,21 +623,77 @@ fhandler_tty_slave::read (void *ptr, siz
   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
@@ -635,46 +708,26 @@ fhandler_tty_slave::read (void *ptr, siz
 	  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);
@@ -722,9 +775,23 @@ fhandler_tty_common::dup (fhandler_base 
       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;
     }
@@ -733,5 +800,5 @@ fhandler_tty_common::dup (fhandler_base 
 			DUPLICATE_SAME_ACCESS))
     {
-      errind = 5;
+      errind = 7;
       goto err;
     }
@@ -742,5 +809,5 @@ fhandler_tty_common::dup (fhandler_base 
 			DUPLICATE_SAME_ACCESS))
     {
-      errind = 6;
+      errind = 8;
       goto err;
     }
@@ -753,5 +820,5 @@ fhandler_tty_common::dup (fhandler_base 
 			     DUPLICATE_SAME_ACCESS))
     {
-      errind = 7;
+      errind = 9;
       goto err;
     }
@@ -889,4 +956,8 @@ fhandler_tty_common::close ()
   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 ());
@@ -1010,4 +1081,6 @@ fhandler_tty_common::set_close_on_exec (
     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);
 }
@@ -1028,4 +1101,11 @@ fhandler_tty_common::fixup_after_fork (H
       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");
Index: tty.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/tty.cc,v
retrieving revision 1.13
diff -u -p -2 -r1.13 tty.cc
--- tty.cc	2000/10/17 01:42:04	1.13
+++ tty.cc	2001/02/28 14:10:44
@@ -409,4 +409,7 @@ tty::common_init (fhandler_pty_master *p
     }
 
+  if (!(ptym->input_available_event = get_event (INPUT_AVAILABLE_EVENT, FALSE)))
+    return FALSE;
+
   char buf[40];
   __small_sprintf (buf, OUTPUT_MUTEX, ntty);
@@ -418,5 +421,14 @@ tty::common_init (fhandler_pty_master *p
     }
 
+  __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;
Index: tty.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/tty.h,v
retrieving revision 1.2
diff -u -p -2 -r1.2 tty.h
--- tty.h	2000/10/27 15:38:32	1.2
+++ tty.h	2001/02/28 14:10:44
@@ -24,5 +24,7 @@ details. */
 #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"
@@ -110,4 +112,10 @@ public:
     char buf[80];
     __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);
   }
