-
Bug
-
Resolution: Fixed
-
P4
-
11.0.6, 13.0.2, 14
-
b07
-
linux
Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-8315379 | 11.0.22 | Andrei Pangin | P4 | Resolved | Fixed | b01 |
On Linux, ServerSocket.accept() throws "java.net.SocketTimeoutException: Accept timed out" if the call is interrupted by a signal.
To see the error, run the following program:
public class SocketAcceptTest {
public static void main(String[] args) throws Exception {
new ServerSocket(0).accept();
}
}
Then find tid of the main thread, and send a signal to it, e.g. SIGPIPE which is caught but ignored by the JVM:
kill -SIGPIPE <tid>
Usually <tid> = <pid> + 1
The program will terminate with SocketTimeoutException, although the operation should never time out.
Exception in thread "main" java.net.SocketTimeoutException: Accept timed out
at java.base/java.net.PlainSocketImpl.socketAccept(Native Method)
at java.base/java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:458)
at java.base/java.net.ServerSocket.implAccept(ServerSocket.java:565)
at java.base/java.net.ServerSocket.accept(ServerSocket.java:533)
at Test.main(Test.java:6)
The problem always happens on JDK 11 and also on JDK 13/14, if run with -Djdk.net.usePlainSocketImpl=true
Works fine on JDK 8 and on JDK 13/14, if run with new Socket implementation (JEP 353).
The original problem was encountered when profiling Tomcat with async-profiler, see https://github.com/jvm-profiling-tools/async-profiler/issues/295
Evaluation:
PlainSocketImpl_socketAccept() calls NET_Timeout (i.e. poll) with a negative timeout, which should mean "wait infinitely". However, a signal may interrupt a call, it returns EINTR, and then the loop in NET_Timeout immediately breaks because of the negative value:
if (rv < 0 && errno == EINTR) {
jlong newNanoTime = JVM_NanoTime(env, 0);
nanoTimeout -= newNanoTime - prevNanoTime;
if (nanoTimeout < NET_NSEC_PER_MSEC) {
return 0;
}
prevNanoTime = newNanoTime;
}
To see the error, run the following program:
public class SocketAcceptTest {
public static void main(String[] args) throws Exception {
new ServerSocket(0).accept();
}
}
Then find tid of the main thread, and send a signal to it, e.g. SIGPIPE which is caught but ignored by the JVM:
kill -SIGPIPE <tid>
Usually <tid> = <pid> + 1
The program will terminate with SocketTimeoutException, although the operation should never time out.
Exception in thread "main" java.net.SocketTimeoutException: Accept timed out
at java.base/java.net.PlainSocketImpl.socketAccept(Native Method)
at java.base/java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:458)
at java.base/java.net.ServerSocket.implAccept(ServerSocket.java:565)
at java.base/java.net.ServerSocket.accept(ServerSocket.java:533)
at Test.main(Test.java:6)
The problem always happens on JDK 11 and also on JDK 13/14, if run with -Djdk.net.usePlainSocketImpl=true
Works fine on JDK 8 and on JDK 13/14, if run with new Socket implementation (JEP 353).
The original problem was encountered when profiling Tomcat with async-profiler, see https://github.com/jvm-profiling-tools/async-profiler/issues/295
Evaluation:
PlainSocketImpl_socketAccept() calls NET_Timeout (i.e. poll) with a negative timeout, which should mean "wait infinitely". However, a signal may interrupt a call, it returns EINTR, and then the loop in NET_Timeout immediately breaks because of the negative value:
if (rv < 0 && errno == EINTR) {
jlong newNanoTime = JVM_NanoTime(env, 0);
nanoTimeout -= newNanoTime - prevNanoTime;
if (nanoTimeout < NET_NSEC_PER_MSEC) {
return 0;
}
prevNanoTime = newNanoTime;
}
- backported by
-
JDK-8315379 PlainSocketImpl.socketAccept() handles EINTR incorrectly
-
- Resolved
-
- duplicates
-
JDK-8247750 ServerSocket#accept thows SocketTimeoutException even soTimout is not set
-
- Closed
-
- relates to
-
JDK-8247750 ServerSocket#accept thows SocketTimeoutException even soTimout is not set
-
- Closed
-