Created
May 25, 2013 22:46
-
-
Save kosaki/5651028 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
commit d84ba638e4ba3c40023ff997aa5e8d3ed002af36 | |
Author: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> | |
Date: Tue Aug 24 16:05:48 2010 +0000 | |
tcp: select(writefds) don't hang up when a peer close connection | |
This issue come from ruby language community. Below test program | |
hang up when only run on Linux. | |
% 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> | |
[Hang Here] | |
FreeBSD, Solaris, Mac doesn't. because Ruby's write() method call | |
select() internally. and tcp_poll has a bug. | |
SUS defined 'ready for writing' of select() as following. | |
| A descriptor shall be considered ready for writing when a call to | |
| function with O_NONBLOCK clear would not block, whether or not th | |
| would transfer data successfully. | |
That said, EPIPE situation is clearly one of 'ready for writing'. | |
We don't have read-side issue because tcp_poll() already has read si | |
shutdown care. | |
| if (sk->sk_shutdown & RCV_SHUTDOWN) | |
| mask |= POLLIN | POLLRDNORM | POLLRDHUP; | |
So, Let's insert same logic in write side. | |
- reference url | |
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/31065 | |
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/31068 | |
Signed-off-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> | |
Signed-off-by: David S. Miller <davem@davemloft.net> | |
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c | |
index e2add5f..3fb1428 100644 | |
--- a/net/ipv4/tcp.c | |
+++ b/net/ipv4/tcp.c | |
@@ -451,7 +451,8 @@ unsigned int tcp_poll(struct file *file, struct sock | |
if (sk_stream_wspace(sk) >= sk_stream_mi | |
mask |= POLLOUT | POLLWRNORM; | |
} | |
- } | |
+ } else | |
+ mask |= POLLOUT | POLLWRNORM; | |
if (tp->urg_data & TCP_URG_VALID) | |
mask |= POLLPRI; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment