This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch 9.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/9.0.x by this push: new 170e0f7 Improve the recycling of Processor objects to make it more robust. 170e0f7 is described below commit 170e0f792bd18ff031677890ba2fe50eb7a376c1 Author: Mark Thomas <ma...@apache.org> AuthorDate: Tue Mar 29 19:15:37 2022 +0100 Improve the recycling of Processor objects to make it more robust. --- java/org/apache/coyote/AbstractProtocol.java | 32 ++++++++++++---------- .../apache/tomcat/util/net/SocketWrapperBase.java | 17 ++++++++---- webapps/docs/changelog.xml | 4 +++ 3 files changed, 33 insertions(+), 20 deletions(-) diff --git a/java/org/apache/coyote/AbstractProtocol.java b/java/org/apache/coyote/AbstractProtocol.java index 4f854b9..562daec 100644 --- a/java/org/apache/coyote/AbstractProtocol.java +++ b/java/org/apache/coyote/AbstractProtocol.java @@ -797,7 +797,11 @@ public abstract class AbstractProtocol<S> implements ProtocolHandler, S socket = wrapper.getSocket(); - Processor processor = (Processor) wrapper.getCurrentProcessor(); + // We take complete ownership of the Processor inside of this method to ensure + // no other thread can release it while we're using it. Whatever processor is + // held by this variable will be associated with the SocketWrapper before this + // method returns. + Processor processor = (Processor) wrapper.takeCurrentProcessor(); if (getLog().isDebugEnabled()) { getLog().debug(sm.getString("abstractConnectionHandler.connectionsGet", processor, socket)); @@ -881,9 +885,6 @@ public abstract class AbstractProtocol<S> implements ProtocolHandler, processor.setSslSupport( wrapper.getSslSupport(getProtocol().getClientCertProvider())); - // Associate the processor with the connection - wrapper.setCurrentProcessor(processor); - SocketState state = SocketState.CLOSED; do { state = processor.process(wrapper, status); @@ -903,8 +904,6 @@ public abstract class AbstractProtocol<S> implements ProtocolHandler, release(processor); // Create the upgrade processor processor = upgradeProtocol.getProcessor(wrapper, getProtocol().getAdapter()); - // Associate with the processor with the connection - wrapper.setCurrentProcessor(processor); } else { if (getLog().isDebugEnabled()) { getLog().debug(sm.getString( @@ -924,8 +923,6 @@ public abstract class AbstractProtocol<S> implements ProtocolHandler, getLog().debug(sm.getString("abstractConnectionHandler.upgradeCreate", processor, wrapper)); } - // Associate with the processor with the connection - wrapper.setCurrentProcessor(processor); // Initialise the upgrade handler (which may trigger // some IO using the new protocol which is why the lines // above are necessary) @@ -963,8 +960,8 @@ public abstract class AbstractProtocol<S> implements ProtocolHandler, } else if (state == SocketState.OPEN) { // In keep-alive but between requests. OK to recycle // processor. Continue to poll for the next request. - wrapper.setCurrentProcessor(null); release(processor); + processor = null; wrapper.registerReadInterest(); } else if (state == SocketState.SENDFILE) { // Sendfile in progress. If it fails, the socket will be @@ -989,8 +986,7 @@ public abstract class AbstractProtocol<S> implements ProtocolHandler, // Connection closed. OK to recycle the processor. // Processors handling upgrades require additional clean-up // before release. - wrapper.setCurrentProcessor(null); - if (processor.isUpgrade()) { + if (processor != null && processor.isUpgrade()) { UpgradeToken upgradeToken = processor.getUpgradeToken(); HttpUpgradeHandler httpUpgradeHandler = upgradeToken.getHttpUpgradeHandler(); InstanceManager instanceManager = upgradeToken.getInstanceManager(); @@ -1011,7 +1007,13 @@ public abstract class AbstractProtocol<S> implements ProtocolHandler, } } } + release(processor); + processor = null; + } + + if (processor != null) { + wrapper.setCurrentProcessor(processor); } return state; } catch(java.net.SocketException e) { @@ -1047,7 +1049,6 @@ public abstract class AbstractProtocol<S> implements ProtocolHandler, // Make sure socket/processor is removed from the list of current // connections - wrapper.setCurrentProcessor(null); release(processor); return SocketState.CLOSED; } @@ -1081,7 +1082,9 @@ public abstract class AbstractProtocol<S> implements ProtocolHandler, /** * Expected to be used by the handler once the processor is no longer - * required. + * required. Care must be taken to ensure that this method is only + * called once per processor, after the request processing has + * completed. * * @param processor Processor being released (that was associated with * the socket) @@ -1119,8 +1122,7 @@ public abstract class AbstractProtocol<S> implements ProtocolHandler, */ @Override public void release(SocketWrapperBase<S> socketWrapper) { - Processor processor = (Processor) socketWrapper.getCurrentProcessor(); - socketWrapper.setCurrentProcessor(null); + Processor processor = (Processor) socketWrapper.takeCurrentProcessor(); release(processor); } diff --git a/java/org/apache/tomcat/util/net/SocketWrapperBase.java b/java/org/apache/tomcat/util/net/SocketWrapperBase.java index 81a89e3..3c1da33 100644 --- a/java/org/apache/tomcat/util/net/SocketWrapperBase.java +++ b/java/org/apache/tomcat/util/net/SocketWrapperBase.java @@ -29,6 +29,7 @@ import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; @@ -106,10 +107,12 @@ public abstract class SocketWrapperBase<E> { protected volatile OperationState<?> writeOperation = null; /** - * The org.apache.coyote.Processor instance currently associated - * with the wrapper. + * The org.apache.coyote.Processor instance currently associated with the + * wrapper. Only populated when required to maintain wrapper<->Processor + * mapping between calls to + * {@link AbstractEndpoint.Handler#process(SocketWrapperBase, SocketEvent)}. */ - protected Object currentProcessor = null; + private final AtomicReference<Object> currentProcessor = new AtomicReference<>(); public SocketWrapperBase(E socket, AbstractEndpoint<E,?> endpoint) { this.socket = socket; @@ -136,11 +139,15 @@ public abstract class SocketWrapperBase<E> { } public Object getCurrentProcessor() { - return currentProcessor; + return currentProcessor.get(); } public void setCurrentProcessor(Object currentProcessor) { - this.currentProcessor = currentProcessor; + this.currentProcessor.set(currentProcessor); + } + + public Object takeCurrentProcessor() { + return currentProcessor.getAndSet(null); } /** diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 8227405..f2da703 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -138,6 +138,10 @@ with TLS 1.3 but the JSSE TLS 1.3 implementation does not support PHA. (markt) </add> + <fix> + Improve the recycling of Processor objects to make it more robust. + (markt) + </fix> </changelog> </subsection> <subsection name="Jasper"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org