diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 0e7c859b8..5ed168267 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,17 @@
+Sun Mar 12 01:14:33 2000  Christopher Faylor <cgf@cygnus.com>
+
+	* fhandler.cc (fhandler_base::get_readahead_into_buffer): New function.
+	* fhandler.h: Declare new function.  Add extra argument to
+	process_slave_output.
+	* fhandler_console.cc (fhandler_console::read): Move read ahead code to
+	new function.
+	* fhandler_tty.cc (fhandler_pty_master::process_slave_output): Move
+	common code here.
+	(fhandler_tty_slave::read): Understand readahead.
+	(fhandler_pty_master::read): Move code to process_slave_output.
+	* select.cc (peek_pipe): Avoid performing certain checks when non-read
+	and on inappropriate fh types.
+
 Sat Mar 11 22:47:43 2000  Christopher Faylor <cgf@cygnus.com>
 
 	* fhandler_console.cc (fhandler_console::read): Don't even think about
diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc
index c9a493fc0..4fbe8d33a 100644
--- a/winsup/cygwin/fhandler.cc
+++ b/winsup/cygwin/fhandler.cc
@@ -96,6 +96,24 @@ fhandler_base::eat_readahead (int n)
   return oralen;
 }
 
+int
+fhandler_base::get_readahead_into_buffer (char *buf, size_t buflen)
+{
+  int ch;
+  int copied_chars = 0;
+
+  while (buflen)
+    if ((ch = get_readahead ()) < 0)
+      break;
+    else
+      {
+	buf[copied_chars++] = (unsigned char)(ch & 0xff);
+	buflen--;
+      }
+
+  return copied_chars;
+}
+
 uid_t __stdcall
 get_file_owner (int use_ntsec, const char *filename)
 {
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 94a4bdbb6..9ebfa104e 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -222,6 +222,8 @@ public:
 
   void set_readahead_valid (int val, int ch = -1);
 
+  int get_readahead_into_buffer (char *buf, size_t buflen);
+
   int has_acls () { return FHISSETF (HASACLS); }
   void set_has_acls (int val) { FHCONDSETF (val, HASACLS); }
 
@@ -663,12 +665,12 @@ class fhandler_pty_master: public fhandler_tty_common
 {
   int pktmode;			// non-zero if pty in a packet mode.
 public:
-  int neednl_;			// Next read should start with \n
+  int need_nl;			// Next read should start with \n
 
   /* Constructor */
   fhandler_pty_master (const char *name, DWORD devtype = FH_PTYM, int unit = -1);
 
-  int process_slave_output (char *buf, size_t len);
+  int process_slave_output (char *buf, size_t len, int pktmode_on);
   void doecho (const void *str, DWORD len);
   int accept_input ();
   int open (const char *path, int flags, mode_t mode = 0);
diff --git a/winsup/cygwin/fhandler_console.cc b/winsup/cygwin/fhandler_console.cc
index 54d8da618..c7b9a6ec3 100644
--- a/winsup/cygwin/fhandler_console.cc
+++ b/winsup/cygwin/fhandler_console.cc
@@ -115,20 +115,13 @@ fhandler_console::read (void *pv, size_t buflen)
     return 0;
 
   HANDLE h = get_io_handle ();
-  int copied_chars = 0;
 
 #define buf ((char *) pv)
 
   int ch;
   set_input_state ();
-  while (buflen)
-    if ((ch = get_readahead ()) < 0)
-      break;
-    else
-      {
-	buf[copied_chars++] = (unsigned char)(ch & 0xff);
-	buflen--;
-      }
+
+  int copied_chars = get_readahead_into_buffer (buf, buflen);
 
   if (copied_chars)
     return copied_chars;
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 14da2bbbd..0cc9b5284 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -214,10 +214,10 @@ fhandler_pty_master::hit_eof ()
 /* Process tty output requests */
 
 int
-fhandler_pty_master::process_slave_output (char *buf, size_t len)
+fhandler_pty_master::process_slave_output (char *buf, size_t len, int pktmode_on)
 {
   size_t rlen;
-  char outbuf[OUT_BUFFER_SIZE];
+  char outbuf[OUT_BUFFER_SIZE + 1];
   DWORD n;
   int column = 0;
   int rc = 0;
@@ -225,20 +225,20 @@ fhandler_pty_master::process_slave_output (char *buf, size_t len)
   if (len == 0)
     goto out;
 
+  if (need_nl)
+    {
+      /* We need to return a left over \n character, resulting from
+	 \r\n conversion.  Note that we already checked for FLUSHO and
+	 OutputStopped at the time that we read the character, so we
+	 don't check again here.  */
+      buf[0] = '\n';
+      need_nl = 0;
+      goto out;
+    }
+
+
   for (;;)
     {
-      if (neednl_)
-	{
-	  /* We need to return a left over \n character, resulting from
-	     \r\n conversion.  Note that we already checked for FLUSHO and
-	     OutputStopped at the time that we read the character, so we
-	     don't check again here.  */
-	  buf[0] = '\n';
-	  neednl_ = 0;
-	  rc = 1;
-	  break;
-	}
-
       /* Set RLEN to the number of bytes to read from the pipe.  */
       rlen = len;
       if (get_ttyp ()->ti.c_oflag & OPOST && get_ttyp ()->ti.c_oflag & ONLCR)
@@ -254,25 +254,35 @@ fhandler_pty_master::process_slave_output (char *buf, size_t len)
 
       HANDLE handle = get_io_handle ();
 
-      /* Doing a busy wait like this is quite inefficient, but nothing
-	 else seems to work completely.  Windows should provide some sort
-	 of overlapped I/O for pipes, or something, but it doesn't.  */
-      while (1)
+      n = 0; // get_readahead_into_buffer (outbuf, len);
+      if (!n)
 	{
-	  DWORD avail;
-	  if (!PeekNamedPipe (handle, NULL, 0, NULL, &avail, NULL))
+	  /* Doing a busy wait like this is quite inefficient, but nothing
+	     else seems to work completely.  Windows should provide some sort
+	     of overlapped I/O for pipes, or something, but it doesn't.  */
+	  while (1)
+	    {
+	      if (!PeekNamedPipe (handle, NULL, 0, NULL, &n, NULL))
+		goto err;
+	      if (n > 0)
+		break;
+	      if (hit_eof ())
+		goto out;
+	      if (n == 0 && (get_flags () & (O_NONBLOCK | O_NDELAY)) != 0)
+		{
+		  set_errno (EAGAIN);
+		  rc = -1;
+		  break;
+		}
+
+	      Sleep (10);
+	    }
+
+	  if (ReadFile (handle, outbuf, rlen, &n, NULL) == FALSE)
 	    goto err;
-	  if (avail > 0)
-	    break;
-	  if (hit_eof ())
-	    goto out;
-	  Sleep (10);
 	}
 
-      if (ReadFile (handle, outbuf, rlen, &n, NULL) == FALSE)
-	goto err;
-
-      termios_printf ("rlen %u", n);
+      termios_printf ("bytes read %u", n);
 
       if (get_ttyp ()->ti.c_lflag & FLUSHO)
 	{
@@ -289,14 +299,19 @@ fhandler_pty_master::process_slave_output (char *buf, size_t len)
 	  termios_printf ("done waiting for restart_output_event");
 	}
 
+      char *optr;
+      optr = buf;
+      if (pktmode_on)
+	*optr++ = TIOCPKT_DATA;
+
       if (!(get_ttyp ()->ti.c_oflag & OPOST))	// post-process output
 	{
-	  memcpy (buf, outbuf, n);
-	  rc = n;
+	  memcpy (optr, outbuf, n);
+	  optr += n;
 	}
       else					// raw output mode
 	{
-	  char *iptr = outbuf, *optr = buf;
+	  char *iptr = outbuf;
 
 	  while (n--)
 	    {
@@ -332,16 +347,16 @@ fhandler_pty_master::process_slave_output (char *buf, size_t len)
 		 doing \r\n expansion.  */
 	      if (optr - buf >= (int) len)
 		{
-		  neednl_ = 1;
 		  if (*iptr != '\n' || n != 0)
 		    system_printf ("internal error: %d unexpected characters", n);
+		  need_nl = 1;
 		  break;
 		}
 
 	      *optr++ = *iptr++;
 	    }
-	  rc = optr - buf;
 	}
+      rc = optr - buf;
       break;
 
     err:
@@ -364,11 +379,10 @@ static DWORD WINAPI
 process_output (void *)
 {
   char buf[OUT_BUFFER_SIZE*2];
-  int n;
 
-  while (1)
+  for (;;)
     {
-      n = tty_master->process_slave_output (buf, OUT_BUFFER_SIZE);
+      int n = tty_master->process_slave_output (buf, OUT_BUFFER_SIZE, 0);
       if (n < 0)
 	{
 	  termios_printf ("ReadFile %E");
@@ -592,14 +606,18 @@ fhandler_tty_slave::read (void *ptr, size_t len)
 
   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);
-      if (ReadFile (get_handle (), (unsigned *) buf,
-		 min ((unsigned) vmin, min (len, sizeof (buf))), &n, NULL) == FALSE)
+
+      n = get_readahead_into_buffer (buf, readlen);
+
+      if (!n && ReadFile (get_handle (), buf, readlen, &n, NULL) == FALSE)
 	{
 	  termios_printf ("read failed, %E");
 	  _raise (SIGHUP);
 	}
+
       if (get_ttyp ()->read_retval < 0)	// read error
 	{
 	  set_errno (-get_ttyp ()->read_retval);
@@ -827,7 +845,7 @@ fhandler_pty_master::fhandler_pty_master (const char *name, DWORD devtype, int u
   ioctl_request_event = NULL;
   ioctl_done_event = NULL;
   restart_output_event = NULL;
-  pktmode = neednl_ = 0;
+  pktmode = need_nl = 0;
   inuse = NULL;
 }
 
@@ -908,39 +926,11 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 int
 fhandler_pty_master::read (void *ptr, size_t len)
 {
-  DWORD n;
-  char *cptr = (char *) ptr;
+  int x = process_slave_output ((char *) ptr, len, pktmode);
 
-  if (!PeekNamedPipe (get_handle (), NULL, 0, NULL, &n, NULL))
-    {
-      if (GetLastError () == ERROR_BROKEN_PIPE)
-	{
-	  /* On Unix, a read from a broken pipe returns EOF.  */
-	  return 0;
-	}
-      __seterrno ();
-      return -1;
-    }
-  if (n == 0
-      && (get_flags () & (O_NONBLOCK | O_NDELAY)) != 0)
-    {
-      set_errno (EAGAIN);
-      return -1;
-    }
-  if (pktmode)
-    {
-      *cptr++ = TIOCPKT_DATA;
-      len--;
-    }
-
-  int x;
-  x = process_slave_output (cptr, len);
-  if (x < 0)
-    return -1;
   if (output_done_event != NULL)
     SetEvent (output_done_event);
-  if (pktmode && x > 0)
-    x++;
+
   return x;
 }
 
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index b3d35606e..5067006fa 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -409,20 +409,24 @@ peek_pipe (select_record *s, int ignra)
   if (!s->read_selected && !s->except_selected)
     goto out;
 
-  if (s->read_selected && fh->bg_check (SIGTTIN) <= 0)
+  if (s->read_selected)
     {
-      gotone = s->read_ready = 1;
-      goto out;
+      if (fh->bg_check (SIGTTIN) <= 0)
+	{
+	  gotone = s->read_ready = 1;
+	  goto out;
+	}
+
+      if (!ignra && fh->get_device () != FH_PTYM && fh->get_device () != FH_TTYM &&
+	  fh->get_readahead_valid ())
+	{
+	  select_printf ("readahead");
+	  gotone = s->read_ready = 1;
+	  goto out;
+	}
     }
 
-  if (!ignra && fh->get_readahead_valid ())
-    {
-      select_printf ("readahead");
-      gotone = s->read_ready = 1;
-      goto out;
-    }
-
-  else if (!PeekNamedPipe (h, NULL, 0, NULL, (DWORD *) &n, NULL))
+  if (!PeekNamedPipe (h, NULL, 0, NULL, (DWORD *) &n, NULL))
     {
       select_printf ("%s, PeekNamedPipe failed, %E", fh->get_name ());
       n = -1;
diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc
index ef9bec5a3..ec020b184 100644
--- a/winsup/cygwin/tty.cc
+++ b/winsup/cygwin/tty.cc
@@ -366,7 +366,7 @@ tty::common_init (fhandler_pty_master *ptym)
 
   if (!make_pipes (ptym))
     return FALSE;
-  ptym->neednl_ = 0;
+  ptym->need_nl = 0;
 
   /* Save our pid  */