On Mon, 2 Sep 2024 20:49:28 +0900
Takashi Yano wrote:
> On Mon, 2 Sep 2024 13:10:31 +0200
> Corinna Vinschen wrote:
> > On Aug 30 23:15, Takashi Yano wrote:
> > > If a cygwin app is executed from a non-cygwin app and the cygwin
> > > app exits, read pipe remains on non-blocking mode because of the
> > > commit fc691d0246b9. Due to this behaviour, the non-cygwin app
> > > cannot read the pipe correctly after that. With this patch, the
> > > blocking mode of the read pipe is stored into was_blocking_read_pipe
> > > on set_pipe_non_blocking() when the cygwin app starts and restored
> > > on close().
> > 
> > Looks ok to me, but it would be helpful if Johannes could test this as
> > well.
> > 
> > I just wonder if the whole code could be simplified, if we set
> > the pipe to non-blocking only temporarily while reading or writing,
> > while the pipe is blocking all the time otherwise:
> > 
> > - Create pipe blocking
> > 
> > - set_pipe_non_blocking(true);
> >   NtReadFile() or NtWriteFile();
> >   set_pipe_non_blocking(false)
> > 
> > How costly is it to call NtSetInformationFile(FilePipeInformation)
> > for each read/write?
> 
> Good point. I'll try performance test for that idea.

I did perfomance test using dd command:
dd if=/dev/zero ibs=1M count=1K obs=WB | dd ibs=RB obs=1M of=/dev/null 
status=none
with the patch attached.

[Current master]
WB=1M,RB=1M: 1.6GB/s
WB=1K,RB=1M: 200MB/s
WB=1M,RB=1K: 245MB/s
WB=1K,RB=1K: 170MB/s

[With experimental patch]
WB=1M,RB=1M: 1.5GB/s
WB=1K,RB=1M: 110MB/s
WB=1M,RB=1K: 125MB/s
WB=1K,RB=1K:  95MB/s

With the experimental implementation, the performance degraded quite a bit,
expecially small read/write block size.

-- 
Takashi Yano <takashi.y...@nifty.ne.jp>
From 02d4498de1805118ff2989d9e6251a39578cfe7b Mon Sep 17 00:00:00 2001
From: Takashi Yano <takashi.y...@nifty.ne.jp>
Date: Mon, 2 Sep 2024 21:46:45 +0900
Subject: [PATCH] Cygwin: pipe: [Experimental] Set the default pipe mode
 blocking

With this patch, pipe mode is set to blocking when the pipe is created
for compatibility with non-cygwin apps. Instead, raw_read()/raw_write()
set the pipe mode appropriate and restore it blocking mode on return.
This makes the code simpler than before.

Addresses: https://github.com/git-for-windows/git/issues/5115
Fixes: fc691d0246b9 ("Cygwin: pipe: Make sure to set read pipe non-blocking for 
cygwin apps.");
Reported-by: isaacag, Johannes Schindelin <johannes.schinde...@gmx.de>
Reviewed-by:
Signed-off-by:
---
 winsup/cygwin/dtable.cc                 |  3 --
 winsup/cygwin/fhandler/pipe.cc          | 55 ++++++++-----------------
 winsup/cygwin/local_includes/fhandler.h |  2 -
 3 files changed, 18 insertions(+), 42 deletions(-)

diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc
index 9508f3e0b..4bfc4c46f 100644
--- a/winsup/cygwin/dtable.cc
+++ b/winsup/cygwin/dtable.cc
@@ -410,9 +410,6 @@ dtable::init_std_file_from_handle (int fd, HANDLE handle)
        {
          fhandler_pipe *fhp = (fhandler_pipe *) fh;
          fhp->set_pipe_buf_size ();
-         /* Set read pipe always to nonblocking */
-         fhp->set_pipe_non_blocking (fhp->get_device () == FH_PIPER ?
-                                     true : fhp->is_nonblocking ());
        }
 
       if (!fh->open_setup (openflags))
diff --git a/winsup/cygwin/fhandler/pipe.cc b/winsup/cygwin/fhandler/pipe.cc
index c686df650..12858507c 100644
--- a/winsup/cygwin/fhandler/pipe.cc
+++ b/winsup/cygwin/fhandler/pipe.cc
@@ -91,10 +91,8 @@ fhandler_pipe::init (HANDLE f, DWORD a, mode_t mode, int64_t 
uniq_id)
   set_ino (uniq_id);
   set_unique_id (uniq_id | !!(mode & GENERIC_WRITE));
   if (opened_properly)
-    /* Set read pipe always nonblocking to allow signal handling
-       even with FILE_SYNCHRONOUS_IO_NONALERT. */
-    set_pipe_non_blocking (get_device () == FH_PIPER ?
-                          true : is_nonblocking ());
+    /* Set the pipe blocking mode for compatibility with non-cygwin apps. */
+    set_pipe_non_blocking (false);
 
   /* Store pipe name to path_conv pc for query_hdl check */
   if (get_dev () == FH_PIPEW)
@@ -327,6 +325,9 @@ fhandler_pipe::raw_read (void *ptr, size_t& len)
       len = (size_t) -1;
       return;
     }
+  /* Set read pipe always nonblocking to allow signal handling
+     even with FILE_SYNCHRONOUS_IO_NONALERT. */
+  set_pipe_non_blocking (true);
   while (nbytes < len)
     {
       ULONG_PTR nbytes_now = 0;
@@ -410,6 +411,8 @@ fhandler_pipe::raw_read (void *ptr, size_t& len)
          || status == STATUS_BUFFER_OVERFLOW)
        break;
     }
+  /* Set the pipe blocking mode for compatibility with non-cygwin apps. */
+  set_pipe_non_blocking (false);
   ReleaseMutex (read_mtx);
   len = nbytes;
 }
@@ -459,6 +462,11 @@ fhandler_pipe_fifo::raw_write (const void *ptr, size_t len)
       return -1;
     }
 
+  if (get_device () == FH_PIPEW)
+    {
+      fhandler_pipe *fh = (fhandler_pipe *) this;
+      fh->set_pipe_non_blocking (is_nonblocking ());
+    }
   /* Write in chunks, accumulating a total.  If there's an error, just
      return the accumulated total unless the first write fails, in
      which case return -1. */
@@ -610,6 +618,12 @@ fhandler_pipe_fifo::raw_write (const void *ptr, size_t len)
        break;
     }
 out:
+  if (get_device () == FH_PIPEW)
+    {
+      /* Set the pipe blocking mode for compatibility with non-cygwin apps. */
+      fhandler_pipe *fh = (fhandler_pipe *) this;
+      fh->set_pipe_non_blocking (false);
+    }
   CloseHandle (evt);
   if (status == STATUS_THREAD_SIGNALED && nbytes == 0)
     set_errno (EINTR);
@@ -649,17 +663,6 @@ fhandler_pipe::fixup_after_fork (HANDLE parent)
   ReleaseMutex (hdl_cnt_mtx);
 }
 
-void
-fhandler_pipe::fixup_after_exec ()
-{
-  /* Set read pipe itself always non-blocking for cygwin process.
-     Blocking/non-blocking is simulated in raw_read(). For write
-     pipe, follow is_nonblocking(). */
-  bool mode = get_device () == FH_PIPEW ? is_nonblocking () : true;
-  set_pipe_non_blocking (mode);
-  fhandler_base::fixup_after_exec ();
-}
-
 int
 fhandler_pipe::dup (fhandler_base *child, int flags)
 {
@@ -1174,22 +1177,6 @@ fhandler_pipe::ioctl (unsigned int cmd, void *p)
   return 0;
 }
 
-int
-fhandler_pipe::fcntl (int cmd, intptr_t arg)
-{
-  if (cmd != F_SETFL)
-    return fhandler_base::fcntl (cmd, arg);
-
-  const bool was_nonblocking = is_nonblocking ();
-  int res = fhandler_base::fcntl (cmd, arg);
-  const bool now_nonblocking = is_nonblocking ();
-  /* Do not set blocking mode for read pipe to allow signal handling
-     even with FILE_SYNCHRONOUS_IO_NONALERT. */
-  if (now_nonblocking != was_nonblocking && get_device () != FH_PIPER)
-    set_pipe_non_blocking (now_nonblocking);
-  return res;
-}
-
 int
 fhandler_pipe::fstat (struct stat *buf)
 {
@@ -1362,17 +1349,11 @@ fhandler_pipe::spawn_worker (int fileno_stdin, int 
fileno_stdout,
        && (fd == fileno_stdout || fd == fileno_stderr))
       {
        fhandler_pipe *pipe = (fhandler_pipe *)(fhandler_base *) cfd;
-       pipe->set_pipe_non_blocking (false);
 
        /* Setup for query_ndl stuff. Read the comment below. */
        if (pipe->request_close_query_hdl ())
          need_send_noncygchld_sig = true;
       }
-    else if (cfd->get_dev () == FH_PIPER && fd == fileno_stdin)
-      {
-       fhandler_pipe *pipe = (fhandler_pipe *)(fhandler_base *) cfd;
-       pipe->set_pipe_non_blocking (false);
-      }
 
   /* If multiple writers including non-cygwin app exist, the non-cygwin
      app cannot detect pipe closure on the read side when the pipe is
diff --git a/winsup/cygwin/local_includes/fhandler.h 
b/winsup/cygwin/local_includes/fhandler.h
index 1c339cfbc..e972c6700 100644
--- a/winsup/cygwin/local_includes/fhandler.h
+++ b/winsup/cygwin/local_includes/fhandler.h
@@ -1234,13 +1234,11 @@ public:
   int open (int flags, mode_t mode = 0);
   bool open_setup (int flags);
   void fixup_after_fork (HANDLE);
-  void fixup_after_exec ();
   int dup (fhandler_base *child, int);
   void set_close_on_exec (bool val);
   int close ();
   void raw_read (void *ptr, size_t& len);
   int ioctl (unsigned int cmd, void *);
-  int fcntl (int cmd, intptr_t);
   int fstat (struct stat *buf);
   int fstatvfs (struct statvfs *buf);
   int fadvise (off_t, off_t, int);
-- 
2.45.1

Reply via email to