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!"=/