[comp.lang.perl] Perl 3.0 PL28 problems with pipe

gorpong@math-cs.kent.edu (Gordon C. Galligher) (09/05/90)

There is some synchronization problems when dealing with pipes via the
pipe() call in Perl.  Below are code examples first in PERL and then one
in C.  The one in C works just like you would expect:
	IN THE PARENT:  PID == ...
	IN THE CHILD:  PID == 0
	CHILD-SEND:  25
	PARENT REC'd <25>
	PARENT-SEND:  255
	CHILD REC'd <255>
The Perl example, on the other hand, does this:
	IN THE CHILD:  PID == 0
	CHILD-SEND:  25
	IN THE PARENT:  PID == ...
And just sits there.

I do get some output when I change the $val = <DESC?_0> calls below to
read() calls, but I need to know exactly how many bytes are coming down
the pipe in order to not hang.  What is so drastically different between
the C program and Perl that makes it not work?  Any help would be greatly
appreciated.  Is there a way to specially treat descriptors created with
pipe() to be non-buffered?  (I even tried $| = 1 on a read descriptor,
and it had no effect (but it did not fail).)

In order to totally emulate the effect of C, I would need to pack a variable
with an integer, and force that down the pipe first, and then unpack it to
get the number of bytes coming, and so on.  That is a lot of work.  Granted,
if it needs to be done, it needs to be done, but it would make me think 
twice before choosing Perl as the tool to use.

		-- Gordon.
=========================snip here--PERL--====================================

pipe(DESC1_0, DESC1_1);
pipe(DESC2_0, DESC2_1);
$id = fork();
$| = 1;
if ( $id == 0 )
{
	sleep(1);
	close(DESC1_0);
	close(DESC2_1);
	select(DESC1_1); $| = 1; select(STDOUT);
	print "IN THE CHILD:  PID == $id\n";
	$mval = 25;
	print "CHILD-SEND:  $mval\n";
	print DESC1_1 $mval;
	$mval = <DESC2_0>;
	print "CHILD REC'd  <$mval>\n";
	exit(0);
}
else
{
	close(DESC1_1);
	close(DESC2_0);
	select(DESC2_1); $| = 1; select(STDOUT);
	print "IN THE PARENT:  PID == $id\n";
	$val = <DESC1_0>;
	print "PARENT REC'd <$val>\n";
	$val = 255;
	print "PARENT-SEND:  $val\n";
	print DESC2_1 $val;
	exit(0);
}
=========================snip here--C--=======================================
#include        <stdio.h>

main()
{
	int desc1[2], desc2[2];
	int pid, msg1, msg2;
	char buf[256];

	pipe(desc1);
	pipe(desc2);
	switch(pid = fork())
	{
		case 0:
			close(desc1[0]);
			close(desc2[1]);
			printf("IN THE CHILD:  PID == %d\n", pid);
			msg1 = 25;
			printf("CHILD-SEND:  %d\n", msg1);
			write(desc1[1], & msg1, sizeof(int));
			read(desc2[0], & msg2, sizeof(int));
			printf("CHILD REC'd <%d>\n", msg2);
			exit(0);

		default:
			close(desc1[1]);
			close(desc2[0]);
			printf("IN THE PARENT:  PID == %d\n", pid);
			read(desc1[0], & msg1, sizeof(int));
			printf("PARENT REC'd <%d>\n", msg1);
			msg2 = 255;
			printf("PARENT-SEND:  %d\n", msg2);
			write(desc2[1], & msg2, sizeof(int));
			exit(0);
	} /* SWITCH */
} /* MAIN */
===================================done snip==============================

gorpong@math-cs.kent.edu (Gordon C. Galligher) (09/05/90)

Here is another wierdness in the code.  I changed it slightly to remove the
two pipes, and just the one pipe, had the child close the read and the parent
close the write, and then had the child send first a 25 and then a 250
and then sleep 20 seconds before exiting.  The parent just did a read with
a print, and another read and print.  The parent hung until the child had
died (thus flushing the pipe (even though it was set to be unbuffered by the
child)) and the parent read both numbers in as one "25250".  Is there something
which I am missing terribly?  I really do not understand this behavior and
why it differs so from C.  

Even if I $| = 1 in the parent before closing it, it still does not work.  If
I put the select(DESC1_1); $| = 1; select(STDOUT); before the fork, the
exact same results occur.  Larry, I seek your infinite wisdom in the manner 
of this behavior.

		-- Gordon.

merlyn@iwarp.intel.com (Randal Schwartz) (09/05/90)

In article <1990Sep4.205514.13088@math-cs.kent.edu>, gorpong@math-cs (Gordon C. Galligher) writes:
| There is some synchronization problems when dealing with pipes via the
| pipe() call in Perl.  Below are code examples first in PERL and then one
| in C.  The one in C works just like you would expect:
| 	$mval = 25;
| 	print "CHILD-SEND:  $mval\n";
| 	print DESC1_1 $mval;

Well, there's your problem.  You're not printing a newline, so the
read on the otherside hangs until it sees a newline.  Use getc() [ugh]
or append a \n, or write fixed-size goodies (as you did in C) with
pack/unpack and then use read.

pipe(R,W);fork?close(R)&&print W "Just another Perl hacker,":close(W)&&print<R>
-- 
/=Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095 ==========\
| on contract to Intel's iWarp project, Beaverton, Oregon, USA, Sol III      |
| merlyn@iwarp.intel.com ...!any-MX-mailer-like-uunet!iwarp.intel.com!merlyn |
\=Cute Quote: "Welcome to Portland, Oregon, home of the California Raisins!"=/