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

Ken Brown kbrown@cornell.edu
Fri Sep 3 13:27:37 GMT 2021


On 9/3/2021 8:22 AM, Takashi Yano wrote:
> On Fri, 3 Sep 2021 13:41:45 +0200
> Corinna Vinschen wrote:
>> On Sep  3 13:31, Corinna Vinschen wrote:
>>> On Sep  3 19:13, Takashi Yano wrote:
>>>> On Fri, 3 Sep 2021 19:00:46 +0900
>>>> Takashi Yano wrote:
>>>>> On Thu, 2 Sep 2021 21:35:21 +0200
>>>>> Corinna Vinschen wrote:
>>>>>> On Sep  2 21:00, Corinna Vinschen wrote:
>>>>>> It's getting too late again.  I drop off for tonight, but I attached
>>>>>> my POC code I have so far.  It also adds the snippets from my previous
>>>>>> patch which fixes stuff Takashi found during testing.  It also fixes
>>>>>> something which looks like a bug in raw_write:
>>>>>>
>>>>>> -	  ptr = ((char *) ptr) + chunk;
>>>>>> +	  ptr = ((char *) ptr) + nbytes_now;
>>>>>>
>>>>>> Incrementing ptr by chunk bytes while only nbytes_now have been written
>>>>>> looks incorrect.
>>>>>>
>>>>>> As for the reader, it makes the # of bytes to read dependent on the
>>>>>> number of reader handles.  I don't know if that's such a bright idea,
>>>>>> but this can be changed easily.
>>>>>>
>>>>>> Anyway, this runs all my testcases successfully but they are anything
>>>>>> but thorough.
>>>>>>
>>>>>> Patch relativ to topic/pipe attached.  Would you both mind to take a
>>>>>> scrutinizing look?
>>>>>
>>>>> Thanks.
>>>>>
>>>>> Your code seems that read() returns only the partial data even
>>>>> if the pipe stil has more data. Is this by design?
>>>>>
>>>>> This happes in both blocking and non-blocking case.
>>>>
>>>> The patch attached seems to fix the issue.
>>>
>>> I'm sorry, but I don't see what your patch is supposed to do in the
>>> first place.  What I see is that it now calls NtQueryInformationFile
>>> even in the non-blocking case, which is not supposed to happen.
>>>
>>> I'm a bit puzzled what the actual bug is.
>>>
>>> The code changing len is only called if there's no data in the pipe.
>>> In that case we only request a partial buffer so as not to block
>>> the writer on select.
>>>
>>> If there *is* data in the pipe, it will just go straight to the
>>> NtReadFile code without changing len.
>>>
>>> Where's the mistake?
>>
>> Oh, wait.  Do you mean, if we only request less than len bytes, but
>> after NtReadFile there's still data in the buffer, we should try to
>> deplete the buffer up to len bytes in a subsequent NtReadFile?
> 
> Yes. I am sorry, my intent was not clear because I did more than
> necessary in the previous patch. Please see attached patch revised.
> 
>> I thought this is unnecessary, actually, because of POSIX:
>>
>>     The standard developers considered adding atomicity requirements  to  a
>>     pipe  or FIFO, but recognized that due to the nature of pipes and FIFOs
>>     there could be no guarantee of atomicity of reads of {PIPE_BUF} or  any
>>     other size that would be an aid to applications portability.
> 
> 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 ();

Ken


More information about the Cygwin-developers mailing list