diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 1f0f28077..38390848f 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -1172,6 +1172,7 @@ class fhandler_pipe: public fhandler_base
 {
 private:
   HANDLE query_hdl;
+  HANDLE reader_evt;
   pid_t popen_pid;
   size_t max_atomic_write;
   void set_pipe_non_blocking (bool nonblocking);
@@ -1181,6 +1182,7 @@ public:
   bool ispipe() const { return true; }
 
   HANDLE get_query_handle () const { return query_hdl; }
+  bool reader_closed ();
 
   void set_popen_pid (pid_t pid) {popen_pid = pid;}
   pid_t get_popen_pid () const {return popen_pid;}
diff --git a/winsup/cygwin/fhandler_pipe.cc b/winsup/cygwin/fhandler_pipe.cc
index 2d9e87bb3..4773d04da 100644
--- a/winsup/cygwin/fhandler_pipe.cc
+++ b/winsup/cygwin/fhandler_pipe.cc
@@ -51,6 +51,8 @@ fhandler_pipe::set_pipe_non_blocking (bool nonblocking)
   fpi.ReadMode = FILE_PIPE_BYTE_STREAM_MODE;
   fpi.CompletionMode = nonblocking ? FILE_PIPE_COMPLETE_OPERATION
     : FILE_PIPE_QUEUE_OPERATION;
+  if (get_device () == FH_PIPEW)
+    fpi.CompletionMode = FILE_PIPE_COMPLETE_OPERATION;
   status = NtSetInformationFile (get_handle (), &io, &fpi, sizeof fpi,
 				 FilePipeInformation);
   if (!NT_SUCCESS (status))
@@ -308,6 +310,22 @@ fhandler_pipe::raw_read (void *ptr, size_t& len)
     }
   else if (status == STATUS_THREAD_CANCELED)
     pthread::static_cancel_self ();
+
+  if ((ssize_t)len > 0)
+    SetEvent (reader_evt);
+}
+
+bool
+fhandler_pipe::reader_closed (void)
+{
+  if (get_device () == FH_PIPER)
+    return false;
+  OBJECT_BASIC_INFORMATION obi;
+  NtQueryObject (get_handle (), ObjectBasicInformation, &obi, sizeof obi, NULL);
+  int n_writer = obi.HandleCount;
+  NtQueryObject (query_hdl, ObjectBasicInformation, &obi, sizeof obi, NULL);
+  int n_reader = obi.HandleCount;
+  return n_writer == n_reader;
 }
 
 ssize_t __reg3
@@ -323,6 +341,13 @@ fhandler_pipe::raw_write (const void *ptr, size_t len)
   if (!len)
     return 0;
 
+  if (reader_closed ())
+    {
+      set_errno(EPIPE);
+      raise(SIGPIPE);
+      return -1;
+    }
+
   if (len <= max_atomic_write)
     chunk = len;
   else if (is_nonblocking ())
@@ -400,10 +425,24 @@ fhandler_pipe::raw_write (const void *ptr, size_t len)
 	  /* NtWriteFile returns success with # of bytes written == 0
 	     if writing on a non-blocking pipe fails because the pipe
 	     buffer doesn't have sufficient space. */
-	  if (nbytes_now == 0 && nbytes == 0)
+	  if (nbytes_now == 0 && nbytes == 0 && is_nonblocking ())
 	    set_errno (EAGAIN);
-	  ptr = ((char *) ptr) + chunk;
+	  ptr = ((char *) ptr) + nbytes_now;
 	  nbytes += nbytes_now;
+	  if (reader_closed () && nbytes == 0)
+	    {
+	      set_errno(EPIPE);
+	      raise(SIGPIPE);
+	    }
+	  if (!is_nonblocking () && nbytes < len)
+	    {
+	      if (nbytes_now == 0)
+		{
+		  cygwait (reader_evt);
+		  ResetEvent (reader_evt);
+		}
+	      continue;
+	    }
 	}
       else if (STATUS_PIPE_IS_CLOSED (status))
 	{
@@ -430,9 +469,14 @@ fhandler_pipe::raw_write (const void *ptr, size_t len)
 void
 fhandler_pipe::fixup_after_fork (HANDLE parent)
 {
+  if (close_on_exec() && query_hdl)
+    CloseHandle (query_hdl);
   if (query_hdl)
     fork_fixup (parent, query_hdl, "query_hdl");
   fhandler_base::fixup_after_fork (parent);
+  if (!close_on_exec ())
+    DuplicateHandle (parent, reader_evt, GetCurrentProcess (), &reader_evt,
+		     0, 1, DUPLICATE_SAME_ACCESS);
 }
 
 int
@@ -453,6 +497,9 @@ fhandler_pipe::dup (fhandler_base *child, int flags)
       ftp->close ();
       res = -1;
     }
+  DuplicateHandle (GetCurrentProcess (), reader_evt,
+		   GetCurrentProcess (), &ftp->reader_evt,
+		   0, 1, DUPLICATE_SAME_ACCESS);
 
   debug_printf ("res %d", res);
   return res;
@@ -463,7 +510,11 @@ fhandler_pipe::close ()
 {
   if (query_hdl)
     NtClose (query_hdl);
-  return fhandler_base::close ();
+  int ret = fhandler_base::close ();
+  if (get_device () == FH_PIPER)
+    SetEvent (reader_evt);
+  CloseHandle (reader_evt);
+  return ret;
 }
 
 #define PIPE_INTRO "\\\\.\\pipe\\cygwin-"
@@ -678,6 +729,10 @@ fhandler_pipe::create (fhandler_pipe *fhs[2], unsigned psize, int mode)
       else
 	res = 0;
     }
+  fhs[0]->reader_evt = CreateEvent (NULL, true, false, NULL);
+  DuplicateHandle (GetCurrentProcess (), fhs[0]->reader_evt,
+		   GetCurrentProcess (), &fhs[1]->reader_evt,
+		   0, 1, DUPLICATE_SAME_ACCESS);
 
   debug_printf ("%R = pipe(%d, %y)", res, psize, mode);
   return res;
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index dc1f79613..0905b3d38 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -741,6 +741,13 @@ out:
     }
   if (s->write_selected && dev != FH_PIPER)
     {
+      if (dev == FH_PIPEW && ((fhandler_pipe *) fh)->reader_closed ())
+	{
+	  gotone += s->write_ready = true;
+	  if (s->except_selected)
+	    gotone += s->except_ready = true;
+	  return gotone;
+	}
       /* For the write side of a pipe, fetch the handle to the read side.
 	 See the longish comment in pipe_data_available for the reasoning. */
       if (dev == FH_PIPEW)
