[Tom Christiansen <tchrist@jhereg.perl.com>] Linux has a broken shutdown syscall!

Ben Gertzfield (che@debian.org)
24 Apr 1998 12:23:08 -0700


Tom usually knows what he's talking about; is this really a problem
with Linux? What's going on here? :)

Ben

-- 
Brought to you by the letters X and J and the number 6.
"Disobeying me?" "No, I don't." -- Final Fantasy II
Ben Gertzfield <http://www.imsa.edu/~wilwonka/> Finger me for my public
PGP key. I'm on FurryMUCK as Che, and EFNet and YiffNet IRC as Che_Fox.
------- Start of forwarded message -------
Message-Id: <199804241237.GAA32529@jhereg.perl.com>
To: The Perl Porters Mailing List <perl5-porters@perl.org>
cc: Nathan Torkington <gnat@frii.com>
Subject: Linux has a broken shutdown syscall!
Reply-to: tchrist@perl.com
Date: Fri, 24 Apr 1998 06:37:38 -0600
From: Tom Christiansen <tchrist@jhereg.perl.com>

Normally, one can exchange

pipe(READER, WRITER)

for

socketpair(READER, WRITER, AF_UNIX, SOCK_STREAM, PF_UNIX); shutdown(READER, 1); # no more writing for reader shutdown(WRITER, 0); # no more reading for writer

But guess what -- that doesn't work without fiddling!

1) The call to PF_UNIX must be PF_UNSPEC (or 0) on SunOS and BSD, even though it claims otherwise. There's some talk of PF_LOCAL, but that's not even documented outside BSD. Linux will accept either PF_UNIX or PF_UNSPEC there.

2) On Linux, shutdown is broken! You have to give it the opposite argument! You must perversely do this: shutdown(READER, 0); shutdown(WRITER, 1);

Here's a suite that demonstrates this. Notice 1a and 1c, 2a and 2c. If you're on Linux, you'll have shutdown tell the reader not to read and the writer not to write. Very bizarre. On SunOS and BSD, you do the sane thing.

Anybody have any clues about this?

--tom

Linux jhereg.perl.com 2.0.33 #3 Sat Feb 7 12:02:26 MST 1998 i686

#!/bin/sh # This is a shell archive (produced by GNU sharutils 4.2). # To extract the files from this archive, save it to some FILE, remove # everything before the `!/bin/sh' line above, then type `sh FILE'. # # Made on 1998-04-24 06:35 MDT by <tchrist@jhereg.perl.com>. # Source directory was `/home/tchrist/writings/cookbook'. # # Existing files will *not* be overwritten unless `-c' is specified. # This format requires very little intelligence at unshar time. # "if test", "echo", "mkdir", and "sed" may be needed. # # This shar contains: # length mode name # ------ ---------- ------------------------------------------ # 478 -rwxr-xr-x pipe1a # 366 -rwxr-xr-x pipe1b # 719 -rwxr-xr-x pipe1c # 478 -rwxr-xr-x pipe2a # 368 -rwxr-xr-x pipe2b # 723 -rwxr-xr-x pipe2c # 877 -rwxr-xr-x pipe3a # 796 -rwxr-xr-x pipe3b # echo=echo if mkdir _sh32489; then $echo 'x -' 'creating lock directory' else $echo 'failed to create lock directory' exit 1 fi # ============= pipe1a ============== if test -f 'pipe1a' && test "$first_param" != -c; then $echo 'x -' SKIPPING 'pipe1a' '(file already exists)' else shar: Saving pipe1a (text) $echo 'x -' extracting 'pipe1a' '(text)' sed 's/^X//' << 'SHAR_EOF' > 'pipe1a' && X#!/usr/bin/perl -w X# pipe1a - use pipe and fork so parent can send to child X Xuse IO::Handle; Xpipe(READER, WRITER); XWRITER->autoflush(1); X Xif ($pid = fork) { X close READER; X print WRITER "Parent Pid $$ is sending this\n"; X close WRITER; X waitpid($pid,0); X} else { X die "cannot fork: $!" unless defined $pid; X close WRITER; X chomp($line = <READER>); X print "Child Pid $$ just read this: `$line'\n"; X close READER; # this will happen anyway X exit; X} SHAR_EOF : || $echo 'restore of' 'pipe1a' 'failed' fi # ============= pipe1b ============== if test -f 'pipe1b' && test "$first_param" != -c; then $echo 'x -' SKIPPING 'pipe1b' '(file already exists)' else shar: Saving pipe1b (text) $echo 'x -' extracting 'pipe1b' '(text)' sed 's/^X//' << 'SHAR_EOF' > 'pipe1b' && X#!/usr/bin/perl -w X# pipe1b - use forking open so parent can send to child X Xuse IO::Handle; Xif ($pid = open(CHILD, "|-")) { X CHILD->autoflush(1); X print CHILD "Parent Pid $$ is sending this\n"; X close(CHILD); X} else { X die "cannot fork: $!" unless defined $pid; X chomp($line = <STDIN>); X print "Child Pid $$ just read this: `$line'\n"; X exit; X} SHAR_EOF : || $echo 'restore of' 'pipe1b' 'failed' fi # ============= pipe1c ============== if test -f 'pipe1c' && test "$first_param" != -c; then $echo 'x -' SKIPPING 'pipe1c' '(file already exists)' else shar: Saving pipe1c (text) $echo 'x -' extracting 'pipe1c' '(text)' sed 's/^X//' << 'SHAR_EOF' > 'pipe1c' && X#!/usr/bin/perl -w X# pipe1c - socketpair emulating pipe X Xuse Socket; Xuse IO::Handle; X Xsocketpair(READER, WRITER, AF_UNIX, SOCK_STREAM, PF_UNSPEC) X || die "socketpair: $!"; X X# Linux shutdown is broken! You must switch 0 and 1 in the X# next two calls X Xshutdown(READER, 1); # no more writing for reader Xshutdown(WRITER, 0); # no more reading for writer X XWRITER->autoflush(1); X Xif ($pid = fork) { X close READER; X print WRITER "Parent Pid $$ is sending this\n"; X close WRITER; X waitpid($pid,0); X} else { X die "cannot fork: $!" unless defined $pid; X close WRITER; X chomp($line = <READER>); X print "Child Pid $$ just read this: `$line'\n"; X close READER; # this will happen anyway X exit; X} SHAR_EOF : || $echo 'restore of' 'pipe1c' 'failed' fi # ============= pipe2a ============== if test -f 'pipe2a' && test "$first_param" != -c; then $echo 'x -' SKIPPING 'pipe2a' '(file already exists)' else shar: Saving pipe2a (text) $echo 'x -' extracting 'pipe2a' '(text)' sed 's/^X//' << 'SHAR_EOF' > 'pipe2a' && X#!/usr/bin/perl -w X# pipe2a - use pipe and fork so child can send to parent X Xuse IO::Handle; Xpipe(READER, WRITER); XWRITER->autoflush(1); X Xif ($pid = fork) { X close WRITER; X chomp($line = <READER>); X print "Parent Pid $$ just read this: `$line'\n"; X close READER; X waitpid($pid,0); X} else { X die "cannot fork: $!" unless defined $pid; X close READER; X print WRITER "Child Pid $$ is sending this\n"; X close WRITER; # this will happen anyway X exit; X} SHAR_EOF : || $echo 'restore of' 'pipe2a' 'failed' fi # ============= pipe2b ============== if test -f 'pipe2b' && test "$first_param" != -c; then $echo 'x -' SKIPPING 'pipe2b' '(file already exists)' else shar: Saving pipe2b (text) $echo 'x -' extracting 'pipe2b' '(text)' sed 's/^X//' << 'SHAR_EOF' > 'pipe2b' && X#!/usr/bin/perl -w X# pipe2b - use forking open so child can send to parent X Xuse IO::Handle; Xif ($pid = open(CHILD, "-|")) { X chomp($line = <CHILD>); X print "Parent Pid $$ just read this: `$line'\n"; X close(CHILD); X} else { X die "cannot fork: $!" unless defined $pid; X STDOUT->autoflush(1); X print STDOUT "Child Pid $$ is sending this\n"; X exit; X} SHAR_EOF : || $echo 'restore of' 'pipe2b' 'failed' fi # ============= pipe2c ============== if test -f 'pipe2c' && test "$first_param" != -c; then $echo 'x -' SKIPPING 'pipe2c' '(file already exists)' else shar: Saving pipe2c (text) $echo 'x -' extracting 'pipe2c' '(text)' sed 's/^X//' << 'SHAR_EOF' > 'pipe2c' && X#!/usr/bin/perl -w X# pipe2c - emulate pipe with socketpair X Xuse Socket; Xuse IO::Handle; X Xsocketpair(READER, WRITER, AF_UNIX, SOCK_STREAM, PF_UNSPEC) X || die "socketpair: $!"; X X X# Linux shutdown is broken! You must switch 0 and 1 in the X# next two calls X Xshutdown(READER, 1); # no more writing for reader Xshutdown(WRITER, 0); # no more reading for writer X XWRITER->autoflush(1); X Xif ($pid = fork) { X close WRITER; X chomp($line = <READER>); X print "Parent Pid $$ just read this: `$line'\n"; X close READER; X waitpid($pid,0); X} else { X die "cannot fork: $!" unless defined $pid; X close READER; X print WRITER "Child Pid $$ is sending this\n"; X close WRITER; # this will happen anyway X exit; X} SHAR_EOF : || $echo 'restore of' 'pipe2c' 'failed' fi # ============= pipe3a ============== if test -f 'pipe3a' && test "$first_param" != -c; then $echo 'x -' SKIPPING 'pipe3a' '(file already exists)' else shar: Saving pipe3a (text) $echo 'x -' extracting 'pipe3a' '(text)' sed 's/^X//' << 'SHAR_EOF' > 'pipe3a' && X#!/usr/bin/perl -w X# pipe3a - bidirectional communication using two pipe pairs X# designed for the socketpair-challenged X Xuse IO::Handle; X Xpipe(READ_PARENT, WRITE_CHILD); Xpipe(READ_CHILD, WRITE_PARENT); X XWRITE_CHILD->autoflush(1); XWRITE_PARENT->autoflush(1); X Xif ($pid = fork) { X close READ_PARENT; X close WRITE_PARENT; X X print WRITE_CHILD "Parent Pid $$ is sending this\n"; X chomp($line = <READ_CHILD>); X print "Parent Pid $$ just read this: `$line'\n"; X X close READ_CHILD; X close WRITE_CHILD; X waitpid($pid,0); X X} else { X X die "cannot fork: $!" unless defined $pid; X close READ_CHILD; X close WRITE_CHILD; X X chomp($line = <READ_PARENT>); X print "Child Pid $$ just read this: `$line'\n"; X print WRITE_PARENT "Child Pid $$ is sending this\n"; X X close READ_PARENT; X close WRITE_PARENT; X exit; X} SHAR_EOF : || $echo 'restore of' 'pipe3a' 'failed' fi # ============= pipe3b ============== if test -f 'pipe3b' && test "$first_param" != -c; then $echo 'x -' SKIPPING 'pipe3b' '(file already exists)' else shar: Saving pipe3b (text) $echo 'x -' extracting 'pipe3b' '(text)' sed 's/^X//' << 'SHAR_EOF' > 'pipe3b' && X#!/usr/bin/perl -w X# pipe3b - bidirectional communication using socketpair X# "the best ones always go both ways" X X Xuse Socket; Xuse IO::Handle; X X# last arg should be PF_UNIX, but BSD complains Xsocketpair(CHILD, PARENT, AF_UNIX, SOCK_STREAM, PF_UNSPEC) X || die "socketpair: $!"; X XCHILD->autoflush(1); XPARENT->autoflush(1); X Xif ($pid = fork) { X close PARENT; X print CHILD "Parent Pid $$ is sending this\n"; X chomp($line = <CHILD>); X print "Parent Pid $$ just read this: `$line'\n"; X close CHILD; X waitpid($pid,0); X} else { X die "cannot fork: $!" unless defined $pid; X close CHILD; X chomp($line = <PARENT>); X print "Child Pid $$ just read this: `$line'\n"; X print PARENT "Child Pid $$ is sending this\n"; X close PARENT; X exit; X} SHAR_EOF : || $echo 'restore of' 'pipe3b' 'failed' fi rm -fr _sh32489 exit 0

------- End of forwarded message -------

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu