delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin/2000/11/29/22:22:07

Mailing-List: contact cygwin-help AT sourceware DOT cygnus DOT com; run by ezmlm
List-Subscribe: <mailto:cygwin-subscribe AT sources DOT redhat DOT com>
List-Archive: <http://sources.redhat.com/ml/cygwin/>
List-Post: <mailto:cygwin AT sources DOT redhat DOT com>
List-Help: <mailto:cygwin-help AT sources DOT redhat DOT com>, <http://sources.redhat.com/ml/#faqs>
Sender: cygwin-owner AT sources DOT redhat DOT com
Delivered-To: mailing list cygwin AT sources DOT redhat DOT com
Message-ID: <3A25C7DA.6F76C8DA@delcomsys.com>
Date: Wed, 29 Nov 2000 22:22:03 -0500
From: Patrick Doyle <wpd AT delcomsys DOT com>
X-Mailer: Mozilla 4.76 [en] (Win98; U)
X-Accept-Language: en,zh,zh-CN,zh-TW
MIME-Version: 1.0
To: cygwin <cygwin AT sources DOT redhat DOT com>
Subject: Re: Why does scp leave ssh running? -- select() never returns
References: <3A22C383 DOT 5C16BBC8 AT delcomsys DOT com>

Patrick Doyle wrote:
> 
> When I run
> 
> scp somefile host:.
> 
> I am left with a copy of SSH running.  ...

I believe that have traced this problem down to the call to select() in
ssh.  Basically, it appears that ssh calls select() on a pipe.  If the
writer of that pipe closes it, select() never returns.  I have attached
code to the end of this email demonstrating this phenomenon.

I believe that I have traced this down to the call to PeekNamedPipe() in
"select.cc".  For some reason, on my W98 box, PeekNamedPipe() does not
return an error when the other end of the pipe is closed.

So, a few questions...
1) Is this behavior (of PeekNamedPipe()) a W9x bug?  (That is, does it
work correctly on NT/2K?)

2) What is the expected behavior of select() on a pipe when the writer
closes the pipe?  The code in ssh seems to imply that it should return,
probably with the "read" bit set for the closed pipe.

3) Does anybody have any ideas of how I might work around this problem,
preferably in cygwin?  (Otherwise, I could change the call to select()
"clientloop.c" to include a timeout).

4) Would folks mind trying this code and confirming if I am on the right
track or not?

Thanks for any help and/or advice...

--wpd

code follows... sorry about the leftover #ifdef debug stuff.

/************************************************************************
 * Simple program that demonstrates the "problem" with select(). 
Basically,
 * when a process is blocked on a select() call to read from a pipe, and
the
 * writer for the pipe closes it, the select call never returns (unless,
 * presumably, the timeout is set.
 *
 * This code demonstrats this phenomenon by creating a pipe, forking
 * a subprocess, closing the write side of the pipe (in the parent
process)
 * and performing a select() on the read side of the pipe.  Meanwhile,
the
 * child process closes the pipe, either after a timeout, or upon
receipt
 * if a SIGHUP.

************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/select.h>
#include <signal.h>

void
sighup(int x)
{
  /* do nothing */
}

int
main(int argc, char *argv[])
{
  int pid;
  int timeout;
  int pipe_fd[2];
  char buf[256];
  int bytes_read;
  int input_fd;
  fd_set readset;

  if (argc < 2) {
    timeout = 5;
  } else {
    if (sscanf(argv[1], "%d", &timeout) != 1 || timeout < 0) {
      fprintf(stderr, "usage: test1 [timeout]\n");
      exit(1);
    }
  }

  if (pipe(pipe_fd) < 0) {
    perror("pipe");
    exit(1);
  }
  if ((pid = fork()) == 0) {
    /* We are the child -- wait the specified timeout, write something
     * to the pipe, wait again, then close the pipe.
     */
    if (timeout == 0) {
      signal(SIGHUP, sighup);
      printf("Waiting for signal\n");
      sigpause(0);
    } else {
      sleep(timeout);
    }
#if 0
    printf("child: about to write to pipe\n");
    if (write(pipe_fd[1], "hello", sizeof("hello")) != sizeof("hello"))
{
      perror("child: write");
      exit(1);
    }
    if (timeout == 0) {
      signal(SIGHUP, sighup);
      printf("Waiting for signal\n");
      sigpause(0);
    } else {
      sleep(timeout);
    }
#endif
    if (close(pipe_fd[1]) < 0) {
      perror("child: close: pipe");
      exit(1);
    }
    printf("child: pipe closed, exiting\n");
    /* Exit successfully */
    exit(0);
  } else if (pid < 0) {
    /* The fork failed for some reason */
    perror("fork");
    exit(1);
  }
  /* We are the parent */
  close(pipe_fd[1]);
#if 1
  input_fd = pipe_fd[0];
#else
  input_fd = 0; /* Read from stdin */
#endif

  printf("parent: about to select on fd %d for reading\n", input_fd);
  FD_ZERO(&readset);
  FD_SET(input_fd, &readset);
  if (select(pipe_fd[0] + 1, &readset, 0, 0, 0) < 0) {
    perror("select");
    exit(1);
  }

  printf("parent: About to read from fd %d\n", input_fd);
  if ((bytes_read = read(input_fd, buf, sizeof(buf))) < 0) {
    perror("parent: read");
    exit(1);
  }
  buf[bytes_read] = 0;

  printf("read buffer of length %d: %s\n", bytes_read, buf);
  close(pipe_fd[0]);
  exit(0);
}

--
Want to unsubscribe from this list?
Send a message to cygwin-unsubscribe AT sourceware DOT cygnus DOT com

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019