[bug:trunk] GNU/Linux select hang on a socket which TCP state is CLOSED

GNU/Linux e$B$G!"0J2<$N%W%m%0%i%`$,%O%s%0$7$^$9!#e(B

% uname -mrsv
Linux 2.6.26-2-486 #1 Sat Dec 26 08:37:39 UTC 2009 i686
% ./ruby -rsocket -ve ’
BasicSocket.do_not_reverse_lookup = true
serv = TCPServer.open(“127.0.0.1”, 0)
s1 = TCPSocket.open(“127.0.0.1”, serv.addr[1])
s2 = serv.accept
s2.close
s1.write(“a”) rescue p $!
s1.write(“a”) rescue p $!
Thread.new {
s1.write(“a”)
}.join’
ruby 1.9.3dev (2010-07-06 trunk 28554) [i686-linux]
#<Errno::EPIPE: Broken pipe>
e$B$3$3$G%O%s%0e(B

FreeBSD e$B$G$O%O%s%0$7$^$;$s!#e(B

% ./ruby -rsocket -ve ’
BasicSocket.do_not_reverse_lookup = true
serv = TCPServer.open(“127.0.0.1”, 0)
s1 = TCPSocket.open(“127.0.0.1”, serv.addr[1])
s2 = serv.accept
s2.close
s1.write(“a”) rescue p $!
s1.write(“a”) rescue p $!
Thread.new {
s1.write(“a”)
}.join’
ruby 1.9.3dev (2010-07-06 trunk 28554) [i386-freebsd8.0]
#<Errno::EPIPE: Broken pipe>
-e:10:in write': Broken pipe (Errno::EPIPE) from -e:10:inblock in ’

e$B$^$!!"e(B[ruby-core:31065], [ruby-core:31068] e$B$NOC$J$s$G$9$,!#e(B

e$B$=$&$$$($P!“e(B[ruby-dev:34567]
e$B$H$$$&$N$b$”$j$^$7$?$,F1$8$+$J!#e(B

e$B$^$D$b$He(B e$B$f$-$R$m$G$9e(B

In message “Re: [ruby-dev:41833] [bug:trunk] GNU/Linux select hang on a
socket which TCP state is CLOSED”
on Tue, 6 Jul 2010 22:21:26 +0900, Tanaka A. [email protected]
writes:

|GNU/Linux e$B$G!"0J2<$N%W%m%0%i%`$,%O%s%0$7$^$9!#e(B

|e$B$^$!!"e(B[ruby-core:31065], [ruby-core:31068] e$B$NOC$J$s$G$9$,!#e(B

e$B;vBV$,$h$/M}2r$G$-$F$J$$$s$G$9$,!“$3$l$Oe(BLinuxe$B$Ne(Bselecte$B$N5sF0e(B
e$B$,$*$+$7$$$H$$$&$3$H$J$s$G$7$g$&$+!#$=$l$H$be(BRubye$B$Ne(Bselecte$B$N<he(B
e$B$j07$$$KLdBj$,$”$k$H$$$&$3$H$J$s$G$7$g$&$+!#e(B

e$B$^$?!"e(B[ruby-core:31065]e$B$Ge(B

I think select should notify writability when write would not block.
Cleary write doesn’t block on disconnected socket.

e$B$H$$C$7$c$C$F$$$k$N$O!"!V$H$$$&5sF0$rK~$?$5$J$$e(BLinuxe$B$Ne(B
selecte$B$O$
$+$7$$!W$H$$$&Iw$K$bFI$a$k$N$G$9$,!"$=$l$G@5$7$$$Ge(B
e$B$9$+!#e(B

e$B$3$l$,e(BLinuxe$B$Ne(Bselecte$B$N%P%0$@$H$9$k$H!"$=$A$i$rD>$7$F$b$i$&$Ye(B
e$B$/%l%]!<%H$9$k$Y$-$J$s$G$7$g$&$+!#e(B

                            e$B$^$D$b$He(B e$B$f$-$R$me(B /:|)

kosakie$B$G$9e(B

e$B$$$D$bC&@~$P$+$j$G62=L$G$9e(B

e$B$/%l%]!<%H$9$k$Y$-$J$s$G$7$g$&$+!#e(B
SUSe$B$_$k$He(B

If the writefds argument is not a null pointer, it points to an object
of type fd_set that on input specifies the file descriptors to be
checked for being ready to write, and on output indicates which file
descriptors are ready to write.

e$B$H!"e(Bready to
writee$B$H$$$&I=8=$J$N$G!"e(BEPIPEe$B$K$J$C$A$c$&$h$&$Je(Bfde$B$Oe(Breadye$B$A$c$&$o$$!#$H$$$&$N$b2r<a$H$7$FA4A3IT<+A3$G$O$J$$$h$&$J!#!#!#e(B
e$B2?$+8+Mn$H$7$F$$$k$@$m$&$+!)e(B

linuxe$B$N<BAu8+$k$He(B

linux/net/ipv4/tcp.c

unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table
*wait)
{
(snip)
if (!(sk->sk_shutdown & SEND_SHUTDOWN)) {
if (sk_stream_wspace(sk) >=
sk_stream_min_wspace(sk)) {
mask |= POLLOUT | POLLWRNORM;

e$B$N$h$&$K!";W$$$C$-$j0U?^E*$J%A%’%C%/$,$"$C$F!"$+$D$3$N%3!<%I$,F~$C$?$N$,e(B
Bitkeepere$BF3F~e(B(2002e$BG/!K$h$j$bA0$J$N$G7P0^$,A4A3J,$+$i$J$$$H$$$&!&!&!&e(B

e$B$H$O$$$(!"%M%C%H%o!<%/$^$o$j$K$OA4A3>$7$/$J$$$N$H!“L@F|5HF#$5$se(B(Linuxe$B$Ne(Bnetwork
subsysteme$B$N%a%s%F%J!K$K2q$&M=Dj$,$”$k$N$GK:$l$F$J$+$C$?$i8+2rJ9$$$F$_$h$&$+$H;W$$$^$9!#e(B

2010e$BG/e(B7e$B7ne(B6e$BF|e(B23:53 KOSAKI Motohiro
[email protected]:

e$B$H!"e(Bready to writee$B$H$$$&I=8=$J$N$G!"e(BEPIPEe$B$K$J$C$A$c$&$h$&$Je(Bfde$B$Oe(Breadye$B$A$c$&$o$$!#$H$$$&$N$b2r<a$H$7$FA4A3IT<+A3$G$O$J$$$h$&$J!#!#!#e(B
e$B2?$+8+Mn$H$7$F$$$k$@$m$&$+!)e(B

ready to write e$B$N0UL#$O0J2<$N$h$&$K@bL@$5$l$F$$$k$N$G!“e(B
EPIPE e$B$@$m$&$,e(B would not block e$B$J$N$Ge(B ready
e$B$@!”$H$$$&$3$H$G!#e(B

A descriptor shall be considered ready for writing when a call to an
output
function with O_NONBLOCK clear would not block, whether or not the
function
would transfer data successfully.

e$B$J$!"e(BRuby 1.9 e$BE$K$O$=$b$=$b$J$s$Ge(B select
e$B$7$F$$$k$N$+!"$H$$$&E@$re(B
e$BD4$Y$J$$$H$$$1$J$$$H;W$C$F$$$^$9!#e(B

Ruby 1.8 e$BE*$K$Oe(B select
e$B$9$k$N$O$"$kDxEY$=$&$$$&$b$N$J$o$1$G$9$,!#e(B

s1.write(“a”) rescue p $!
e$B$=$&$$$($P!“e(B[ruby-dev:34567] e$B$H$$$&$N$b$”$j$^$7$?$,F1$8$+$J!#e(B
RugyKaigie$BD>A0$N$P$?$P$?$7$F$$$k;~4|$K62=L$G$9$,!"$3$N7o$Oe(BLinuxe$BB&$rD>$9;v$Ge(B
e$B9g0U$,$H$l$^$7$?!#e(Btcpe$B$Ne(Bselecte$B$bAj<jB&$,e(Bclosee$B$7$?=j$Ge(Bselecte$B$+$i%j%?!<%se(B
e$B$9$k;EMM$KJQ99$K$J$j$^$9!#e(B

e$B$3$l$GL@F|$N3+H/<T2q5D$Ge(BRubye$B3+H/<TMM$+$i%%3$i$l$J$$$+$H;W$&$HL$+$i4@$,e(B
e$B$H$^$j$^$;$s!J$d$d8XD%!Ke(B

e$B$^$D$b$He(B e$B$f$-$R$m$G$9e(B

In message “Re: [ruby-dev:41836] Re: [bug:trunk] GNU/Linux select hang
on a socket which TCP state is CLOSED”
on Wed, 7 Jul 2010 00:04:50 +0900, Tanaka A. [email protected]
writes:

|e$B$J$!"e(BRuby 1.9 e$BE$K$O$=$b$=$b$J$s$Ge(B select e$B$7$F$$$k$N$+!"$H$$$&E@$re(B
|e$BD4$Y$J$$$H$$$1$J$$$H;W$C$F$$$^$9!#e(B

e$B2a5n$K$O!Ve(Bselecte$B$J$/$F$b$$$$$8$c$s!W$H$$$&OC$K$O$J$C$F$^$9$M!#e(B
e$B$H$$$&$3$H$O!"MW$9$k$Ke(B1.8e$B$N$^$^JQ99$7$F$J$$$H$$$&$@$1$N$3$He(B
e$B$@$C$?$j$7$F!#e(B

e$B%A%1%C%He(B #3543 e$B$,99?7$5$l$^$7$?!#e(B (by Shyouhei U.)

e$B%9%F!<%?%9e(B Opene$B$+$ie(BThird Party’s Issuee$B$KJQ99e(B
ruby -v -e$B$K%;%C%He(B

e$BK\7o$Oe(B 3rd Party’s issue e$B$G$7$?e(B [ruby-dev:42140]

http://redmine.ruby-lang.org/issues/show/3543