diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 28099d78c..30b075d32 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,31 @@
+2011-12-09  Christopher Faylor  <me.cygwin2011@cgf.cx>
+
+	Rename cygWFMO to cygwait throughout and use the magic of polymorphism
+	to "wait for stuff".
+	* fhandler.cc (fhandler_base_overlapped::wait_overlapped): Use
+	simplified arg form of cygwait.
+	* fhandler_console.cc (fhandler_console::read): Ditto.
+	* fhandler_audio.cc (fhandler_dev_dsp::Audio_out::waitforspac): Ditto.
+	(fhandler_dev_dsp::Audio_in::waitfordata): Ditto.
+	* fhandler_fifo.cc (fhandler_fifo::wait): Ditto.
+	* fhandler_serial.cc (fhandler_serial::raw_read): Ditto.
+	(fhandler_serial::raw_write): Ditto.
+	* select.cc (cygwin_select): Ditto.
+	* sigproc.h (cygwait): Rename from cygWFMO.  Define two argument and
+	single argument forms of this function.
+
+	* fhandler_tty.cc (fhandler_pty_slave::open): Use method to query if
+	tty is open.
+	(fhandler_pty_slave::read): Send SIGHUP when master is detected as
+	closed.
+	(fhandler_pty_common::close): Close input_available_event in callers
+	since master may need to signal it first.
+	(fhandler_pty_master::close): Lie and set input_available_event when
+	closing, then close input_available_event.
+	(fhandler_pty_slave::close): Close input_available_event explicitly
+	here.
+	* tty.h (tty::is_master_closed): Declare new method.
+
 2011-12-09  Christopher Faylor  <me.cygwin2011@cgf.cx>
 
 	* sigproc.cc (signal_exit): Revert reversion of 2011-12-04 change
diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc
index a29b1f235..48e114f28 100644
--- a/winsup/cygwin/fhandler.cc
+++ b/winsup/cygwin/fhandler.cc
@@ -1926,7 +1926,7 @@ fhandler_base_overlapped::wait_overlapped (bool inres, bool writing, DWORD *byte
   if (res == overlapped_unknown)
     {
       HANDLE h = writing ? get_output_handle () : get_handle ();
-      DWORD wfres = cygWFMO (1, INFINITE, get_overlapped ()->hEvent);
+      DWORD wfres = cygwait (get_overlapped ()->hEvent);
       /* Cancelling here to prevent races.  It's possible that the I/O has
 	 completed already, in which case this is a no-op.  Otherwise,
 	 WFMO returned because 1) This is a non-blocking call, 2) a signal
diff --git a/winsup/cygwin/fhandler_console.cc b/winsup/cygwin/fhandler_console.cc
index e8a8d6a08..e04e0aad1 100644
--- a/winsup/cygwin/fhandler_console.cc
+++ b/winsup/cygwin/fhandler_console.cc
@@ -348,7 +348,7 @@ fhandler_console::read (void *pv, size_t& buflen)
 
       set_cursor_maybe ();	/* to make cursor appear on the screen immediately */
 restart:
-      switch (cygWFMO (1, timeout, h))
+      switch (cygwait (h, timeout))
 	{
 	case WAIT_OBJECT_0:
 	  break;
diff --git a/winsup/cygwin/fhandler_dsp.cc b/winsup/cygwin/fhandler_dsp.cc
index e46214fe5..4d7ddcd2a 100644
--- a/winsup/cygwin/fhandler_dsp.cc
+++ b/winsup/cygwin/fhandler_dsp.cc
@@ -541,7 +541,7 @@ fhandler_dev_dsp::Audio_out::waitforspace ()
 	  return false;
 	}
       debug_printf ("100ms");
-      switch (cygWFMO (0, 100))
+      switch (cygwait (100))
 	{
 	case WAIT_OBJECT_0:
 	  if (!_my_tls.call_signal_handler ())
@@ -919,7 +919,7 @@ fhandler_dev_dsp::Audio_in::waitfordata ()
 	  return false;
 	}
       debug_printf ("100ms");
-      switch (cygWFMO (0, 100))
+      switch (cygwait (100))
 	{
 	case WAIT_OBJECT_0:
 	  if (!_my_tls.call_signal_handler ())
diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index c0aaf1e82..d34628660 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -216,7 +216,7 @@ fhandler_fifo::wait (HANDLE h)
 
   debug_only_printf ("waiting for %s", what);
   /* Wait for the event.  Set errno, as appropriate if something goes wrong. */
-  switch (cygWFMO (1, wait, h))
+  switch (cygwait (h, wait))
     {
     case WAIT_OBJECT_0:
       debug_only_printf ("successfully waited for %s", what);
diff --git a/winsup/cygwin/fhandler_serial.cc b/winsup/cygwin/fhandler_serial.cc
index 1503cdc75..4c33d5e83 100644
--- a/winsup/cygwin/fhandler_serial.cc
+++ b/winsup/cygwin/fhandler_serial.cc
@@ -96,7 +96,7 @@ fhandler_serial::raw_read (void *ptr, size_t& ulen)
 	    {
 	      overlapped_armed = 1;
 restart:
-	      switch (cygWFMO (1, INFINITE, io_status.hEvent))
+	      switch (cygwait (io_status.hEvent))
 		{
 		case WAIT_OBJECT_0:
 		  if (!GetOverlappedResult (get_handle (), &io_status, &n,
@@ -203,7 +203,7 @@ fhandler_serial::raw_write (const void *ptr, size_t len)
       if (!is_nonblocking ())
 	{
     restart:
-	  switch (cygWFMO (1, INFINITE, write_status.hEvent))
+	  switch (cygwait (write_status.hEvent))
 	    {
 	    case WAIT_OBJECT_0:
 	      break;
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 1906b06b2..d8927cf9d 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -428,7 +428,7 @@ fhandler_pty_slave::open (int flags, mode_t)
       goto err_no_errno;
     }
 
-  if (get_ttyp ()->master_pid < 0)
+  if (get_ttyp ()->is_master_closed ())
     {
       errmsg = "*** master is closed";
       set_errno (EAGAIN);
@@ -562,6 +562,8 @@ fhandler_pty_slave::close ()
   termios_printf ("closing last open %s handle", ttyname ());
   if (inuse && !CloseHandle (inuse))
     termios_printf ("CloseHandle (inuse), %E");
+  if (!ForceCloseHandle (input_available_event))
+    termios_printf ("CloseHandle (input_available_event<%p>), %E", input_available_event);
   return fhandler_pty_common::close ();
 }
 
@@ -702,9 +704,15 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
 
   while (len)
     {
-      switch (cygWFMO (1, time_to_wait, input_available_event))
+      switch (cygwait (input_available_event, time_to_wait))
 	{
 	case WAIT_OBJECT_0:
+	  if (get_ttyp ()->is_master_closed ())
+	    {
+	      raise (SIGHUP);
+	      totalread = 0;
+	      goto out;
+	    }
 	  break;
 	case WAIT_OBJECT_0 + 1:
 	  if (totalread > 0)
@@ -738,7 +746,7 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
 	}
       /* Now that we know that input is available we have to grab the
 	 input mutex. */
-      switch (cygWFMO (1, 1000, input_mutex))
+      switch (cygwait (input_mutex, 1000))
 	{
 	case WAIT_OBJECT_0:
 	case WAIT_ABANDONED_0:
@@ -811,26 +819,32 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
 	  if (!ReadFile (get_handle (), buf, readlen, &n, NULL))
 	    {
 	      termios_printf ("read failed, %E");
-	      raise (SIGHUP);
-	    }
-	  /* MSDN states that 5th prameter can be used to determine total
-	     number of bytes in pipe, but for some reason this number doesn't
-	     change after successful read. So we have to peek into the pipe
-	     again to see if input is still available */
-	  if (!PeekNamedPipe (get_handle (), peek_buf, 1, &bytes_in_pipe, NULL, NULL))
-	    {
-	      termios_printf ("PeekNamedPipe failed, %E");
+	      bytes_in_pipe = 0;
 	      raise (SIGHUP);
 	      bytes_in_pipe = 0;
+	      ptr = NULL;
 	    }
-	  if (n)
+	  else
 	    {
-	      len -= n;
-	      totalread += n;
-	      if (ptr)
+	      /* MSDN states that 5th prameter can be used to determine total
+		 number of bytes in pipe, but for some reason this number doesn't
+		 change after successful read. So we have to peek into the pipe
+		 again to see if input is still available */
+	      if (!PeekNamedPipe (get_handle (), peek_buf, 1, &bytes_in_pipe, NULL, NULL))
 		{
-		  memcpy (ptr, buf, n);
-		  ptr = (char *) ptr + n;
+		  termios_printf ("PeekNamedPipe failed, %E");
+		  raise (SIGHUP);
+		  bytes_in_pipe = 0;
+		}
+	      if (n)
+		{
+		  len -= n;
+		  totalread += n;
+		  if (ptr)
+		    {
+		      memcpy (ptr, buf, n);
+		      ptr = (char *) ptr + n;
+		    }
 		}
 	    }
 	}
@@ -1233,9 +1247,6 @@ fhandler_pty_common::close ()
   if (!ForceCloseHandle1 (get_output_handle (), to_pty))
     termios_printf ("CloseHandle (get_output_handle ()<%p>), %E", get_output_handle ());
 
-  if (!ForceCloseHandle (input_available_event))
-    termios_printf ("CloseHandle (input_available_event<%p>), %E", input_available_event);
-
   return 0;
 }
 
@@ -1285,7 +1296,12 @@ fhandler_pty_master::close ()
   if (have_execed || get_ttyp ()->master_pid != myself->pid)
     termios_printf ("not clearing: %d, master_pid %d", have_execed, get_ttyp ()->master_pid);
   else
-    get_ttyp ()->set_master_closed ();
+    {
+      get_ttyp ()->set_master_closed ();
+      SetEvent (input_available_event);
+    }
+  if (!ForceCloseHandle (input_available_event))
+    termios_printf ("CloseHandle (input_available_event<%p>), %E", input_available_event);
 
   return 0;
 }
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index f409c6c5a..261f004b2 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -132,7 +132,7 @@ cygwin_select (int maxfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
   int res = 1;
   /* Degenerate case.  No fds to wait for.  Just wait. */
   if (sel.start.next == NULL)
-    switch (cygWFMO (0, ms))
+    switch (cygwait (ms))
       {
       case WAIT_OBJECT_0:
 	select_printf ("signal received");
diff --git a/winsup/cygwin/sigproc.h b/winsup/cygwin/sigproc.h
index 21293ccb9..66507e6e0 100644
--- a/winsup/cygwin/sigproc.h
+++ b/winsup/cygwin/sigproc.h
@@ -81,8 +81,8 @@ void __stdcall sigproc_init ();
 #ifdef __INSIDE_CYGWIN__
 void __stdcall sigproc_terminate (enum exit_states);
 
-static inline
-DWORD cygWFMO (DWORD n, DWORD howlong, ...)
+static inline DWORD
+cygwait (DWORD n, DWORD howlong, ...)
 {
   va_list ap;
   va_start (ap, howlong);
@@ -96,6 +96,18 @@ DWORD cygWFMO (DWORD n, DWORD howlong, ...)
     n--;
   return WaitForMultipleObjects (n, w4, FALSE, howlong);
 }
+
+static inline DWORD
+cygwait (HANDLE h, DWORD wait = INFINITE)
+{
+  return cygwait (1, wait, h);
+}
+
+static inline DWORD
+cygwait (DWORD wait)
+{
+  return cygwait ((DWORD) 0, wait);
+}
 #endif
 bool __stdcall pid_exists (pid_t) __attribute__ ((regparm(1)));
 int __stdcall sig_send (_pinfo *, siginfo_t&, class _cygtls *tls = NULL) __attribute__ ((regparm (3)));
diff --git a/winsup/cygwin/tty.h b/winsup/cygwin/tty.h
index 38e57caba..4dc0395f5 100644
--- a/winsup/cygwin/tty.h
+++ b/winsup/cygwin/tty.h
@@ -109,6 +109,7 @@ public:
   bool exists ();
   bool not_allocated (HANDLE&, HANDLE&);
   void set_master_closed () {master_pid = -1;}
+  bool is_master_closed () const {return master_pid == -1;}
   static void __stdcall create_master (int);
   static void __stdcall init_session ();
   friend class fhandler_pty_master;