Author: markt
Date: Sat Jul  2 20:48:51 2016
New Revision: 1751096

URL: http://svn.apache.org/viewvc?rev=1751096&view=rev
Log:
Extend synchronization for NIO2 writes to avoid ConcurrentModificationException 
observed during testing.

Modified:
    
tomcat/tc8.0.x/trunk/java/org/apache/coyote/http11/InternalNio2OutputBuffer.java
    tomcat/tc8.0.x/trunk/webapps/docs/changelog.xml

Modified: 
tomcat/tc8.0.x/trunk/java/org/apache/coyote/http11/InternalNio2OutputBuffer.java
URL: 
http://svn.apache.org/viewvc/tomcat/tc8.0.x/trunk/java/org/apache/coyote/http11/InternalNio2OutputBuffer.java?rev=1751096&r1=1751095&r2=1751096&view=diff
==============================================================================
--- 
tomcat/tc8.0.x/trunk/java/org/apache/coyote/http11/InternalNio2OutputBuffer.java
 (original)
+++ 
tomcat/tc8.0.x/trunk/java/org/apache/coyote/http11/InternalNio2OutputBuffer.java
 Sat Jul  2 20:48:51 2016
@@ -382,59 +382,59 @@ public class InternalNio2OutputBuffer ex
             return false;
 
         ByteBuffer byteBuffer = 
socket.getSocket().getBufHandler().getWriteBuffer();
-        if (block) {
-            if (!isBlocking()) {
-                // The final flush is blocking, but the processing was using
-                // non blocking so wait until an async write is done
-                try {
-                    if (writePending.tryAcquire(socket.getTimeout(), 
TimeUnit.MILLISECONDS)) {
-                        writePending.release();
+        synchronized (completionHandler) {
+            if (block) {
+                if (!isBlocking()) {
+                    // The final flush is blocking, but the processing was 
using
+                    // non blocking so wait until an async write is done
+                    try {
+                        if (writePending.tryAcquire(socket.getTimeout(), 
TimeUnit.MILLISECONDS)) {
+                            writePending.release();
+                        }
+                    } catch (InterruptedException e) {
+                        // Ignore timeout
                     }
-                } catch (InterruptedException e) {
-                    // Ignore timeout
                 }
-            }
-            Future<Integer> future = null;
-            try {
-                if (bufferedWrites.size() > 0) {
-                    for (ByteBuffer buffer : bufferedWrites) {
-                        buffer.flip();
-                        while (buffer.hasRemaining()) {
-                            future = socket.getSocket().write(buffer);
-                            if (future.get(socket.getTimeout(), 
TimeUnit.MILLISECONDS).intValue() < 0) {
-                                throw new 
EOFException(sm.getString("iob.failedwrite"));
+                Future<Integer> future = null;
+                try {
+                    if (bufferedWrites.size() > 0) {
+                        for (ByteBuffer buffer : bufferedWrites) {
+                            buffer.flip();
+                            while (buffer.hasRemaining()) {
+                                future = socket.getSocket().write(buffer);
+                                if (future.get(socket.getTimeout(), 
TimeUnit.MILLISECONDS).intValue() < 0) {
+                                    throw new 
EOFException(sm.getString("iob.failedwrite"));
+                                }
                             }
                         }
+                        bufferedWrites.clear();
                     }
-                    bufferedWrites.clear();
-                }
-                if (!flipped) {
-                    byteBuffer.flip();
-                    flipped = true;
-                }
-                while (byteBuffer.hasRemaining()) {
-                    future = socket.getSocket().write(byteBuffer);
-                    if (future.get(socket.getTimeout(), 
TimeUnit.MILLISECONDS).intValue() < 0) {
-                        throw new 
EOFException(sm.getString("iob.failedwrite"));
+                    if (!flipped) {
+                        byteBuffer.flip();
+                        flipped = true;
                     }
-                }
-            } catch (ExecutionException e) {
-                if (e.getCause() instanceof IOException) {
-                    throw (IOException) e.getCause();
-                } else {
+                    while (byteBuffer.hasRemaining()) {
+                        future = socket.getSocket().write(byteBuffer);
+                        if (future.get(socket.getTimeout(), 
TimeUnit.MILLISECONDS).intValue() < 0) {
+                            throw new 
EOFException(sm.getString("iob.failedwrite"));
+                        }
+                    }
+                } catch (ExecutionException e) {
+                    if (e.getCause() instanceof IOException) {
+                        throw (IOException) e.getCause();
+                    } else {
+                        throw new IOException(e);
+                    }
+                } catch (InterruptedException e) {
                     throw new IOException(e);
+                } catch (TimeoutException e) {
+                    future.cancel(true);
+                    throw new SocketTimeoutException();
                 }
-            } catch (InterruptedException e) {
-                throw new IOException(e);
-            } catch (TimeoutException e) {
-                future.cancel(true);
-                throw new SocketTimeoutException();
-            }
-            byteBuffer.clear();
-            flipped = false;
-            return false;
-        } else {
-            synchronized (completionHandler) {
+                byteBuffer.clear();
+                flipped = false;
+                return false;
+            } else {
                 if (hasPermit || writePending.tryAcquire()) {
                     //prevent timeout for async
                     socket.access();

Modified: tomcat/tc8.0.x/trunk/webapps/docs/changelog.xml
URL: 
http://svn.apache.org/viewvc/tomcat/tc8.0.x/trunk/webapps/docs/changelog.xml?rev=1751096&r1=1751095&r2=1751096&view=diff
==============================================================================
--- tomcat/tc8.0.x/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/tc8.0.x/trunk/webapps/docs/changelog.xml Sat Jul  2 20:48:51 2016
@@ -89,6 +89,11 @@
         <code>InstanceManager.destroy()</code> to ensure that the method is
         executed. (markt)
       </fix>
+      <fix>
+        Extend synchronization for NIO2 writes to avoid
+        <code>ConcurrentModificationException</code> observed during testing.
+        (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

Reply via email to