This is an automated email from the ASF dual-hosted git repository.
markt pushed a commit to branch 10.1.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/10.1.x by this push:
new b4d81f0599 Refactor to remove code paths that could result in lost
notifications
b4d81f0599 is described below
commit b4d81f05996a4d1a0333e2776f8c0cf1b0204c6b
Author: Mark Thomas <[email protected]>
AuthorDate: Thu Jul 6 13:25:14 2023 +0100
Refactor to remove code paths that could result in lost notifications
The scenario is considered unlikely but if, in the original code, the
Poller notified the [read|write]Lock after the read/write registration
but before execution entered the synchronized block, that notification
would be lost. This could lead to a timeout rather than the expected
read/write.
Flagged by Coverity Scan for issues with spurious wake-ups. That wasn't
an issue but this was.
---
java/org/apache/tomcat/util/net/NioEndpoint.java | 77 ++++++++++++------------
webapps/docs/changelog.xml | 5 ++
2 files changed, 43 insertions(+), 39 deletions(-)
diff --git a/java/org/apache/tomcat/util/net/NioEndpoint.java
b/java/org/apache/tomcat/util/net/NioEndpoint.java
index 5f9beb80c8..e817945272 100644
--- a/java/org/apache/tomcat/util/net/NioEndpoint.java
+++ b/java/org/apache/tomcat/util/net/NioEndpoint.java
@@ -1267,26 +1267,25 @@ public class NioEndpoint extends
AbstractJsseEndpoint<NioChannel,SocketChannel>
throw new SocketTimeoutException();
}
}
- n = getSocket().read(buffer);
- if (n == -1) {
- throw new EOFException();
- } else if (n == 0) {
- if (!readBlocking) {
- readBlocking = true;
- registerReadInterest();
- }
- synchronized (readLock) {
- if (readBlocking) {
- try {
- if (timeout > 0) {
- startNanos = System.nanoTime();
- readLock.wait(timeout);
- } else {
- readLock.wait();
- }
- } catch (InterruptedException e) {
- // Continue
+ synchronized (readLock) {
+ n = getSocket().read(buffer);
+ if (n == -1) {
+ throw new EOFException();
+ } else if (n == 0) {
+ // Ensure a spurious wake-up doesn't trigger a
duplicate registration
+ if (!readBlocking) {
+ readBlocking = true;
+ registerReadInterest();
+ }
+ try {
+ if (timeout > 0) {
+ startNanos = System.nanoTime();
+ readLock.wait(timeout);
+ } else {
+ readLock.wait();
}
+ } catch (InterruptedException e) {
+ // Continue
}
}
}
@@ -1378,33 +1377,33 @@ public class NioEndpoint extends
AbstractJsseEndpoint<NioChannel,SocketChannel>
throw previousIOException;
}
}
- n = getSocket().write(buffer);
- if (n == 0 && (buffer.hasRemaining() ||
getSocket().getOutboundRemaining() > 0)) {
+ synchronized (writeLock) {
+ n = getSocket().write(buffer);
// n == 0 could be an incomplete write but it could
also
// indicate that a previous incomplete write of the
// outbound buffer (for TLS) has now completed. Only
// block if there is still data to write.
- writeBlocking = true;
- registerWriteInterest();
- synchronized (writeLock) {
- if (writeBlocking) {
- try {
- if (timeout > 0) {
- startNanos = System.nanoTime();
- writeLock.wait(timeout);
- } else {
- writeLock.wait();
- }
- } catch (InterruptedException e) {
- // Continue
+ if (n == 0 && (buffer.hasRemaining() ||
getSocket().getOutboundRemaining() > 0)) {
+ // Ensure a spurious wake-up doesn't trigger a
duplicate registration
+ if (!writeBlocking) {
+ writeBlocking = true;
+ registerWriteInterest();
+ }
+ try {
+ if (timeout > 0) {
+ startNanos = System.nanoTime();
+ writeLock.wait(timeout);
+ } else {
+ writeLock.wait();
}
- writeBlocking = false;
+ } catch (InterruptedException e) {
+ // Continue
}
+ } else if (startNanos > 0) {
+ // If something was written, reset timeout
+ timeout = getWriteTimeout();
+ startNanos = 0;
}
- } else if (startNanos > 0) {
- // If something was written, reset timeout
- timeout = getWriteTimeout();
- startNanos = 0;
}
} while (buffer.hasRemaining() ||
getSocket().getOutboundRemaining() > 0);
} else {
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index dd78d44509..a25727b227 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -154,6 +154,11 @@
based keys/certificates and logs the relevant information for each.
(markt)
</fix>
+ <fix>
+ Refactor blocking reads and writes for the NIO connector to remove
+ code paths that could allow a notification from the Poller to be missed
+ resuting in a timeout rather than the expected read or write. (markt)
+ </fix>
</changelog>
</subsection>
<subsection name="WebSocket">
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]