From: Dr.Ruud on
David Resnick wrote:

> I've been poking at a script that loses the ability to ready from
> <STDIN> after doing a system() call.
>
> I located this
> http://perldoc.perl.org/perlfaq8.html#Why-can%27t-my-script-read-from-STDIN-after-I-gave-it-EOF-%28^D-on-Unix,-^Z-on-MS-DOS%29?
> which seemed to be the obvious answer to my questions.
>
> But after doing this:
> STDIN->clearerr();
>
> or this:
>
> seek STDIN, 0, SEEK_SET

Here I decided that you need to read `perldoc -f open`.
Look for "perlipc".

--
Ruud
From: David Resnick on
On May 10, 2:45 pm, Ben Morrow <b...(a)morrow.me.uk> wrote:
> Quoth David Resnick <lndresn...(a)gmail.com>:
>
>
>
> > On May 10, 12:56 pm, Ben Morrow <b...(a)morrow.me.uk> wrote:
> > > Quoth David Resnick <lndresn...(a)gmail.com>:
>
> > > > I've been poking at a script that loses the ability to ready from
> > > > <STDIN> after doing a system() call.
>
> > > Please post your code, and also your OS and version of perl. Something
> > > like
>
> > >     perl -E'system "cat"; say scalar <STDIN>;'
>
> > > works just fine for me here. (The first ^D sends EOF to cat, and any
> > > subsequent lines are happily read by perl.)
>
> > As I mentioned in the follow up, closing stdin on the system command
> > fixed it.
>
> > It does not apply to any command, I discovered that early on.  Once I
> > saw that the "system" command is what seemed to mess up my STDIN, I
> > tried the "date" run via system, didn't cause the issue.
>
> > The relevant part of the code is here.  Note sipp is an open source
> > tool to handle SIP traffic.  When run normally it does look for input
> > in STDIN.
>
> >         getline("hit return when ready to execute test $testName\n");
>
> >         my $sippCommand = "$vobBase/thparty3/sipp/sipp -sf " ..
> >             "$sippFile $remoteIpAddress -trace_msg -m 1 -l 1 -key
> > testname $testName -key testdir $outputDirRoot/$testName" .
> >             " > /dev/null 2> /dev/null 0<&-";
>
> It's generally safer to redirect stdin from /dev/null rather than
> closing it. Closing it means the first file sipp opens will appear on
> its fd 0, which may have unfortunate consequences.
>
> > If I don't do the 0<&- in the system call, all future calls to <STDIN>
> > return eof. But that seems to fix my problem, so I'm now merely just
> > curious as to why this happens.  I'm still mystified as to why, as I
> > thought that system would create an independent process that couldn't
> > alter its parents file descriptor state in any way.
>
> It does create a separate process, but the two filehandles are still
> somewhat connected. I can't see, off the top of my head, what sipp could
> be doing to cause your STDIN to return EOF, but if you're interested you
> could run the whole thing under strace to find out what it actually does
> to fd 0.
>
> Ben

I was still a bit curious, so I examined the sipp source code for how
they mucked with stdin. Here is a minimal perl script and C program
that allows reproduction of the problem.

temp(1726)$ cat foo.pl
#!/usr/bin/perl -w

use strict;

my $line = <STDIN>;

print "got: $line";

if ( ! $line )
{
die("STDIN returns undef before system call");
}

system("foo");

$line = <STDIN>;

if ( ! $line )
{
die("STDIN returns undef before system call");
}

print "got: $line";


***********

temp(1727)$ cat foo.c
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
int main(void)
{
printf("about to fcntl\n");
fcntl(fileno(stdin), F_SETFL, fcntl(fileno(stdin), F_GETFL) |
O_NONBLOCK);
return 0;
}


Hmmm. Apparently this fcntl crocks the parent perl scripts STDIN.
OK, I have a work around, guess I'm done with this issue. Thanks for
your help!

-David
From: Uri Guttman on
>>>>> "DR" == David Resnick <lndresnick(a)gmail.com> writes:

DR> I was still a bit curious, so I examined the sipp source code for how
DR> they mucked with stdin. Here is a minimal perl script and C program
DR> that allows reproduction of the problem.

and it is now obvious what the cause of the problem is.

DR> system("foo");

stdin is no in nonblocking mode (what foo does). so since you haven't
typed anything quickly, <> will return immediately and be
undef. sipp/foo are doing async stdio, likely some form of terminal
screen stuff or whatever. clean programs will return stdin to the normal
blocking mode when they exit. you can do that in your perl easily with
IO::Handle's nonblocking method. something like this should do:

use IO::Handle ;

STDIN->nonblocking(0) ;

DR> ***********
DR> printf("about to fcntl\n");
DR> fcntl(fileno(stdin), F_SETFL, fcntl(fileno(stdin), F_GETFL) |
DR> O_NONBLOCK);


DR> Hmmm. Apparently this fcntl crocks the parent perl scripts STDIN.
DR> OK, I have a work around, guess I'm done with this issue. Thanks for
DR> your help!

if your workaround is anything more complex than mine, switch it. all
you need to do is set clear the nonblocking flag after you run sipp.

uri

--
Uri Guttman ------ uri(a)stemsystems.com -------- http://www.sysarch.com --
----- Perl Code Review , Architecture, Development, Training, Support ------
--------- Gourmet Hot Cocoa Mix ---- http://bestfriendscocoa.com ---------
From: David Resnick on
On May 11, 2:46 pm, "Uri Guttman" <u...(a)StemSystems.com> wrote:
> >>>>> "DR" == David Resnick <lndresn...(a)gmail.com> writes:
>
>   DR> I was still a bit curious, so I examined the sipp source code for how
>   DR> they mucked with stdin.  Here is a minimal perl script and C program
>   DR> that allows reproduction of the problem.
>
> and it is now obvious what the cause of the problem is.
>
>   DR> system("foo");
>
> stdin is no in nonblocking mode (what foo does). so since you haven't
> typed anything quickly, <>  will return immediately and be
> undef. sipp/foo are doing async stdio, likely some form of terminal
> screen stuff or whatever. clean programs will return stdin to the normal
> blocking mode when they exit. you can do that in your perl easily with
> IO::Handle's nonblocking method. something like this should do:
>
>         use IO::Handle ;
>
>         STDIN->nonblocking(0) ;
>
>   DR> ***********
>   DR>     printf("about to fcntl\n");
>   DR>     fcntl(fileno(stdin), F_SETFL, fcntl(fileno(stdin), F_GETFL) |
>   DR> O_NONBLOCK);
>
>   DR> Hmmm.  Apparently this fcntl crocks the parent perl scripts STDIN.
>   DR> OK, I have a work around, guess I'm done with this issue.  Thanks for
>   DR> your help!
>
> if your workaround is anything more complex than mine, switch it. all
> you need to do is set clear the nonblocking flag after you run sipp.
> -----
Thanks for the comments.

My work around is simple, in the system() invocation I redirect stdin
to take input from /dev/null (closing stdin in the system call also
works). I think (and you suggest above) that it is a bug in sipp --
it should put stdin back to how it found it prior to exiting. I may
suggest that to the sipp devs.

The part that surprised me and made this a bit painful was that I had
no idea the process launched by the system command could muck with the
parents i/o. I guess I had an understanding that after system fork
and execs the new command the new process was basically independent.
Apparently not completely...

-David
From: Uri Guttman on
>>>>> "DR" == David Resnick <lndresnick(a)gmail.com> writes:

DR> My work around is simple, in the system() invocation I redirect stdin
DR> to take input from /dev/null (closing stdin in the system call also
DR> works). I think (and you suggest above) that it is a bug in sipp --
DR> it should put stdin back to how it found it prior to exiting. I may
DR> suggest that to the sipp devs.

normally the shell will return the terminal to a sane mode (it didn't in
the old days) and the sipp dev team may not have noticed for that reason.

DR> The part that surprised me and made this a bit painful was that I
DR> had no idea the process launched by the system command could muck
DR> with the parents i/o. I guess I had an understanding that after
DR> system fork and execs the new command the new process was
DR> basically independent. Apparently not completely...

forked processes have their own memory and many private things but they
can share stdio and usually do. that is how sipp even gets to use stdio
from the terminal after you fork it. otherwise it wouldn't be able to
get any terminal i/o. this has always been the case for unix
forking. the shell opens (or rather init does) the terminal one time and
the 3 fds (0,1,2) are share with forked children so they can do stdio
and not need to know which terminal to open. the other side of this is
when you want a child not to deal with the terminal it will usually
close stdio. in your case redirectling stdin from /dev/null did it.

uri

--
Uri Guttman ------ uri(a)stemsystems.com -------- http://www.sysarch.com --
----- Perl Code Review , Architecture, Development, Training, Support ------
--------- Gourmet Hot Cocoa Mix ---- http://bestfriendscocoa.com ---------