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