Author: markt Date: Tue May 20 18:41:56 2014 New Revision: 1596360 URL: http://svn.apache.org/r1596360 Log: Backport of r1575885 Better align 7.0.x with trunk to aid back-ports
Modified: tomcat/tc7.0.x/trunk/ (props changed) tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/AbstractServletOutputStream.java Propchange: tomcat/tc7.0.x/trunk/ ------------------------------------------------------------------------------ Merged /tomcat/trunk:r1575885 Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/AbstractServletOutputStream.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/AbstractServletOutputStream.java?rev=1596360&r1=1596359&r2=1596360&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/AbstractServletOutputStream.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/AbstractServletOutputStream.java Tue May 20 18:41:56 2014 @@ -32,14 +32,29 @@ public abstract class AbstractServletOut protected static final StringManager sm = StringManager.getManager(Constants.Package); + // Used to ensure that isReady() and onWritePossible() have a consistent + // view of buffer and fireListener when determining if the listener should + // fire. private final Object fireListenerLock = new Object(); + + // Used to ensure that only one thread writes to the socket at a time and + // that buffer is consistently updated with any unwritten data after the + // write. Note it is not necessary to hold this lock when checking if buffer + // contains data but, depending on how the result is used, some form of + // synchronization may be required (see fireListenerLock for an example). private final Object writeLock = new Object(); private volatile boolean closeRequired = false; + // Start in blocking-mode private volatile WriteListener listener = null; + + // Guarded by fireListenerLock private volatile boolean fireListener = false; + private volatile ClassLoader applicationLoader = null; + + // Writes guarded by writeLock private volatile byte[] buffer; /** @@ -152,26 +167,26 @@ public abstract class AbstractServletOut throw new IOException(t); } } + } - // Make sure isReady() and onWritePossible() have a consistent view of - // buffer and fireListener when determining if the listener should fire - boolean fire = false; - - synchronized (fireListenerLock) { - if (buffer == null && fireListener) { - fireListener = false; - fire = true; - } + // Make sure isReady() and onWritePossible() have a consistent view of + // buffer and fireListener when determining if the listener should fire + boolean fire = false; + + synchronized (fireListenerLock) { + if (buffer == null && fireListener) { + fireListener = false; + fire = true; } - if (fire) { - Thread thread = Thread.currentThread(); - ClassLoader originalClassLoader = thread.getContextClassLoader(); - try { - thread.setContextClassLoader(applicationLoader); - listener.onWritePossible(); - } finally { - thread.setContextClassLoader(originalClassLoader); - } + } + if (fire) { + Thread thread = Thread.currentThread(); + ClassLoader originalClassLoader = thread.getContextClassLoader(); + try { + thread.setContextClassLoader(applicationLoader); + listener.onWritePossible(); + } finally { + thread.setContextClassLoader(originalClassLoader); } } } @@ -194,7 +209,8 @@ public abstract class AbstractServletOut /** * Abstract method to be overridden by concrete implementations. The base * class will ensure that there are no concurrent calls to this method for - * the same socket. + * the same socket by ensuring that the writeLock is held when making any + * calls this method. */ protected abstract int doWrite(boolean block, byte[] b, int off, int len) throws IOException; --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org