[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index][Thread Index][Top&Search][Original]

Re: [ID 19991215.008] perl hangs when two files are redirected into a pipe



On Thu, 16 Dec 1999 18:25:15 GMT, "M.J.T. Guy" wrote:
>Ronald J Kimball <rjk@linguist.dartmouth.edu> wrote
>> I see the same behavior here in 5.005_03.  Stepping through with the
>> debugger, Perl hangs on close(STDOUT).  Switching the order of the close()
>> statements, so that STDERR is closed before STDOUT, avoids the problem.
>
>Yes  -  that's because Perl doesn't "know" that STDERR is thr result of a
>pipe open.    So it doesn't wait in close(STDERR);.

I don't think waiting in close(STDERR) is the problem.  It's the close(STOUT)
that hangs when it waits.  The subprocess won't get EOF until all the dup-ed
handles are closed too, so the parent waits indefinitely for the child to
quit, and the child waits indefinitely for the parent to close all the
handles, which it never will, because it is waiting for the child to quit.
Deadlock ensues.

>The prpoblem is a more general one, and will hit if the file descriptor
>is copied in any way.    For example, this code digs you into a similar
>hole (and I assume perl_clone would be an equally efficient spade):
>
>% perl -w
>open FH, "| cat >temp.foo" or die "open: $!\n";
>my $pid = fork or sleep 1000000, exit;
>print "Forked $pid\n";
>close FH;
>print "Closed\n";
>__END__
>Forked 5516
>
>   ... then silence.

As John noticed correctly, that doesn't hang; it merely sleeps a great long
while, because you asked for it.  Here's a better example:

    open(A, "| cat >foo.out") or die;
    open(B, ">&A") or die;
    print A "foo\n";

    close(A);		# hangs...
    close(B);		# ...unless you flip this line with the one above

The problem really originates in the old fclose/pclose duplicity.  This
has the same issue:

    #include <stdio.h>
    int
    main(int argc, char **argv)
    {
	FILE *f = popen("cat > foo.out", "w");
	if (f) {
	    FILE *d = fdopen(dup(fileno(f)), "w");
	    fprintf(f, "foo\n");
	    pclose(f);  /* hangs... */
	    fclose(d);  /* ...unless you flip this line with the one above */
	}
    }

Chalk up another reason to rewrite stdio.


Sarathy
gsar@ActiveState.com


[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index][Thread Index][Top&Search][Original]