diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index d07638cd0..7bfdc5d80 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,16 @@
+2011-12-17  Christopher Faylor  <me.cygwin2011@cgf.cx>
+
+	* fhandler.cc (fhandler_base::close): Move setting isclosed() from here
+	to closed().
+	(fhandler_base_overlapped::close): Correct comment.
+	(fhandler_base_overlapped::destroy_overlapped): Signal overlapped event
+	before closing it to potentially wake up a waiting thread.
+	(fhandler_base_overlapped::wait_overlapped): Expand setting of err when
+	closed to encompass non-signal event.  Test for a cancel event before
+	making nonblocking decisions.
+	* syscalls.cc (close): Set closed flag here so that any concurrently
+	executing functions will be notified ASAP.
+
 2011-12-17  Corinna Vinschen  <vinschen@redhat.com>
 
 	* dcrt0.cc (_dll_crt0): Fix formatting.
diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc
index 6624bc7da..a93b45436 100644
--- a/winsup/cygwin/fhandler.cc
+++ b/winsup/cygwin/fhandler.cc
@@ -1148,7 +1148,6 @@ fhandler_base::close ()
       paranoid_printf ("CloseHandle failed, %E");
       __seterrno ();
     }
-  isclosed (true);
   return res;
 }
 
@@ -1219,9 +1218,8 @@ fhandler_base_overlapped::close ()
     }
   else
     {
-      /* Cancelling seems to be necessary for cases where a reader is
-	 still executing either in another thread or when a signal handler
-	 performs a close.  */
+     /* Cancelling seems to be necessary for cases where a reader is
+         still executing when a signal handler performs a close.  */
       CancelIo (get_io_handle ());
       destroy_overlapped ();
       res = fhandler_base::close ();
@@ -1882,6 +1880,7 @@ fhandler_base_overlapped::destroy_overlapped ()
   OVERLAPPED *ov = get_overlapped ();
   if (ov && ov->hEvent)
     {
+      SetEvent (ov->hEvent);
       CloseHandle (ov->hEvent);
       ov->hEvent = NULL;
     }
@@ -1931,7 +1930,21 @@ fhandler_base_overlapped::wait_overlapped (bool inres, bool writing, DWORD *byte
       HANDLE h = writing ? get_output_handle () : get_handle ();
       BOOL wores;
       if (isclosed ())
-	wores = 0;	/* closed in another thread or via signal handler */
+	{
+	  switch (err)
+	    {
+	    case WAIT_OBJECT_0:
+	      err = ERROR_INVALID_HANDLE;
+	      break;
+	    case WAIT_OBJECT_0 + 1:
+	      err = ERROR_INVALID_AT_INTERRUPT_TIME;
+	      break;
+	    default:
+	      err = GetLastError ();
+	      break;
+	    }
+	  res = overlapped_error;
+	}
       else
 	{
 	  /* Cancelling here to prevent races.  It's possible that the I/O has
@@ -1945,23 +1958,23 @@ fhandler_base_overlapped::wait_overlapped (bool inres, bool writing, DWORD *byte
 	  err = GetLastError ();
 	  ResetEvent (get_overlapped ()->hEvent);	/* Probably not needed but CYA */
 	  debug_printf ("wfres %d, wores %d, bytes %u", wfres, wores, *bytes);
-	}
-      if (wores)
-	res = overlapped_success;	/* operation succeeded */
-      else if (wfres == WAIT_OBJECT_0 + 1)
-	{
-	  err = ERROR_INVALID_AT_INTERRUPT_TIME; /* forces an EINTR below */
-	  debug_printf ("signal");
-	  res = overlapped_error;
-	}
-      else if (nonblocking)
-	res = overlapped_nonblocking_no_data;	/* more handling below */
-      else if (wfres == WAIT_OBJECT_0 + 2)
-	pthread::static_cancel_self ();		/* never returns */
-      else
-	{
-	  debug_printf ("GetOverLappedResult failed, h %p, bytes %u, %E", h, *bytes);
-	  res = overlapped_error;
+	  if (wores)
+	    res = overlapped_success;	/* operation succeeded */
+	  else if (wfres == WAIT_OBJECT_0 + 1)
+	    {
+	      err = ERROR_INVALID_AT_INTERRUPT_TIME; /* forces an EINTR below */
+	      debug_printf ("signal");
+	      res = overlapped_error;
+	    }
+	  else if (wfres == WAIT_OBJECT_0 + 2)
+	    pthread::static_cancel_self ();		/* never returns */
+	  else if (nonblocking)
+	    res = overlapped_nonblocking_no_data;	/* more handling below */
+	  else
+	    {
+	      debug_printf ("GetOverLappedResult failed, h %p, bytes %u, %E", h, *bytes);
+	      res = overlapped_error;
+	    }
 	}
     }
 
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index ea0c23d0b..f86e0442a 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -1373,6 +1373,7 @@ close (int fd)
     res = -1;
   else
     {
+      cfd->isclosed (true);
       res = cfd->close_with_arch ();
       cfd.release ();
     }