cygrunsrv + sshd + rsync = 20 times too slow -- throttled?

Takashi Yano takashi.yano@nifty.ne.jp
Sat Sep 4 23:15:23 GMT 2021


Hi Ken,

On Sat, 4 Sep 2021 10:04:12 -0400
Ken Brown wrote:
> On 9/4/2021 8:37 AM, Takashi Yano wrote:
> > On Sat, 4 Sep 2021 21:02:58 +0900
> > Takashi Yano wrote:
> >> Hi Corinna, Ken,
> >>
> >> On Fri, 3 Sep 2021 09:27:37 -0400
> >> Ken Brown wrote:
> >>> On 9/3/2021 8:22 AM, Takashi Yano wrote:
> >>>> POSIX says:
> >>>>       The value returned may be less than nbyte if the number of bytes left
> >>>>       in the file is less than nbyte, if the read() request was interrupted
> >>>>       by a signal, or if the file is a pipe or FIFO or special file and has
> >>>>                                                                         ~~~
> >>>>       fewer than nbyte bytes immediately available for reading.
> >>>>       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> >>>>
> >>>> https://pubs.opengroup.org/onlinepubs/009604599/functions/read.html
> >>>>
> >>>> If it is turned over, read() should read all data immediately available,
> >>>> I think.
> >>>
> >>> I understand the reasoning now, but I think your patch isn't quite right.  As it
> >>> stands, if the call to NtQueryInformationFile fails but total_length != 0,
> >>> you're trying to read again without knowing that there's data in the pipe.
> >>>
> >>> Also, I think you need the following:
> >>>
> >>> diff --git a/winsup/cygwin/fhandler_pipe.cc b/winsup/cygwin/fhandler_pipe.cc
> >>> index ef7823ae5..46bb96961 100644
> >>> --- a/winsup/cygwin/fhandler_pipe.cc
> >>> +++ b/winsup/cygwin/fhandler_pipe.cc
> >>> @@ -348,8 +348,13 @@ fhandler_pipe::raw_read (void *ptr, size_t& len)
> >>>        CloseHandle (evt);
> >>>      if (status == STATUS_THREAD_SIGNALED)
> >>>        {
> >>> -      set_errno (EINTR);
> >>> -      len = (size_t) -1;
> >>> +      if (total_len == 0)
> >>> +       {
> >>> +         set_errno (EINTR);
> >>> +         len = (size_t) -1;
> >>> +       }
> >>> +      else
> >>> +       len = total_len;
> >>>        }
> >>>      else if (status == STATUS_THREAD_CANCELED)
> >>>        pthread::static_cancel_self ();
> >>
> >> Thanks for your advice. I fixed the issue and attached new patch.
> >>
> >> On Fri, 3 Sep 2021 17:37:13 +0200
> >> Corinna Vinschen wrote:
> >>> Hmm, I see the point, but we might have another problem with that.
> >>>
> >>> We can't keep the mutex while waiting on the pending read, and there
> >>> could be more than one pending read running at the time.  if so,
> >>> chances are extremly high, that the data written to the buffer gets
> >>> split like this:
> >>>
> >>>     reader 1		               reader 2
> >>>
> >>>     calls read(65536)                   calls read(65536)
> >>>
> >>>     calls NtReadFile(16384 bytes)
> >>>                                         calls NtReadFile(16384 bytes)
> >>>
> >>> writer writes 65536 bytes
> >>>
> >>>     wakes up and gets 16384 bytes
> >>>                                         wakes up and gets 16384 bytes
> >>>     gets the mutex, calls
> >>>     NtReadFile(32768) which
> >>>     returns immediately with
> >>>     32768 bytes added to the
> >>>     caller's buffer.
> >>>
> >>> so the buffer returned to reader 1 is 49152 bytes, with 16384 bytes
> >>> missing in the middle of it, *without* the reader knowing about that
> >>> fact.  If reader 1 gets the first 16384 bytes, the 16384 bytes have
> >>> been read in a single call, at least, so the byte order is not
> >>> unknowingly broken on the application level.
> >>>
> >>> Does that make sense?
> >>
> >> Why can't we keep the mutex while waiting on the pending read?
> >> If we can keep the mutex, the issue above mentioned does not
> >> happen, right?
> >>
> >> What about the patch attached? This keeps the mutex while read()
> >> but I do not see any defects so far.
> 
> LGTM.
> 
> If Corinna agrees, I have a couple of suggestions.
> 
> 1. With this patch, we can no longer have more than one pending ReadFile.  So 
> there's no longer a need to count read handles, and the problem with select is 
> completely fixed as long as the number of bytes requested is less than the pipe 
> buffer size.
> 
> 2. raw_read is now reading in chunks, like raw_write.  For readability of the 
> code, I think it would be better to make the two functions as similar as 
> possible.  For example, you could replace the do/while loop by a 
> while(total_len<orig_len) loop.  And you could even use similar names for the 
> variables, e.g., nbytes instead of total_len, or vice versa.

Thanks for the suggestion. I have rebuilt the patch.
Please see the patch attached.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-Cygwin-pipe-Stop-counting-reader-and-read-all-availa.patch
Type: application/octet-stream
Size: 5079 bytes
Desc: not available
URL: <https://cygwin.com/pipermail/cygwin-developers/attachments/20210905/7312189b/attachment.obj>


More information about the Cygwin-developers mailing list