This is the mail archive of the cygwin@sources.redhat.com mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: Why does scp leave ssh running? -- select() never returns


Status update...

First, to refresh the memory of those who are interested in following
this thread:

1) cygwin implements pipes (i.e. the 'pipe()' system call) using Windows
"anonymous pipes".

2) cygwin implements the 'select()' system call by creating a thread
which wakes up every 10 ms and calls 'PeekNamedPipe()' to see if any
data are available in the pipe.

3) On Windows 9x machines, 'PeekNamedPipe()' gives no indication when
the writer of a pipe closes the pipe.  It simply indicates that there
are 0 bytes available to be read from the pipe.  The only way to know
that the writer has closed the pipe is to call 'ReadFile()'.  On Windows
NT/2K, 'PeekNamedPipe()' returns an indication that the pipe has been
closed.

4) SSH uses 'select()' to determine when it is time to read from stdin. 
If stdin is a pipe and the writer closes the pipe, SSH does not detect
this and is left waiting for more input.  This happens when using "scp"
and when using SSH with "cvs".

5) I have been racking my brain trying to figure out a way to solve this
problem.  (I posted a simple program to the list a couple of weeks ago
that demonstrates this problem).

So far, the most elegant solution I have come up with is to reimplement
'select()' so that it calls 'ReadFileEx()' with a suitable 'OVERLAPPED'
structure, thus eliminating the separate thread that wakes up every 10
ms.  Of course, if I read a byte from the pipe, I would have to buffer
it somewhere and fix 'read()' so that it checks for the "readahead" byte
first, but that is basically solvable.  If the call to 'select()'
returned for some other reason (i.e. another fd was made ready), then
call 'CancelIo()' to terminate the asynchronous read.

The problem with this approach is that the documentation on the MSDN web
site states that, for Windows 95/98, "You cannot perform asynchronous
read operations on mailslots, named pipes, or disk files", leaving the
possibility that it might work on anonymous pipes.

Before I expend a lot of effort on this, does anybody know if
asynchronous reads of anonymous pipes are supported on 9x?  If there is
documentation that says that it is not supported, but experimentation
indicates that it works anyway, would such an approach be incorporated
into cygwin?  (In other words, is cygwin willing to depend on code
behavior that is unsupported by MS, specifically, behavior of 9x code --
if the answer is no, then I won't waste any effort trying to figure out
if it would work).

The only other viable alternative I have come up with is to open a
second anonymous pipe in parallel with the first and use it to send OOB
messages such as "dup occured" or "closing pipe" to the reader.  I would
bracket all of this code with:

if (win9x) {
  anonymous_pipe_hack();
}

so that it would not impact NT/2K users.  It would not work with
non-cygwin apps (on 9x machines) and could suffer from being fooled
somehow.

I am reminded that I meant to look into how the TTY code works, since
Christopher said that it has some similar issues (and has problems
working with non-cygwin apps).

I have come to appreciate Christopher's statement "I hate Windows 9x."
more and more as each idea I have come up with to address this problem
has been shot down when I check the MSDN website and find words to the
effect of "this is unsupported on Windows 95/98" in the middle of the
function that I think might solve the problem.

As a final note, I wondered why RSH didn't suffer from this problem. 
It's because it forks a separate process just to read from stdin, and
doesn't call 'select()'.  I keep toying with the idea of modifying SSH
to do something similar, but it seems like too much work, and too much
modification to SSH, to be a "good" solution.  (I would fork a process
that just read from stdin and wrote to stdout and then use SIGCHILD to
notify the parent process that it should no longer attempt to read from
stdin.  If we were willing to tolerate an additional process-per-pipe on
9x machines, I could look into doing something like this automatically
in cygwin, but I think I'll try my "second anonymous pipe" approach
first).

If anybody has bothered to continue reading this far, I just want to say
that I truly appreciate the work that has gone into cygwin and that I
especially like the fact that I can compile, test, and debug
modifications to cygwin1.dll myself (i.e. on my W98 box).  I remember
the days when cygwin1.dll had to be compiled on a Linux box and then
copied to the Windows box, and I am very grateful for all the work that
has gone into making the tools self-hosting.  Thanks again folks!

--wpd

--
Want to unsubscribe from this list?
Send a message to cygwin-unsubscribe@sourceware.cygnus.com


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]