You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2015/01/08 14:11:25 UTC
svn commit: r1650285 -
/tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Endpoint.java
Author: markt
Date: Thu Jan 8 13:11:24 2015
New Revision: 1650285
URL: http://svn.apache.org/r1650285
Log:
Rework notify to handle nested inline completion handlers correctly.
Modified:
tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Endpoint.java
Modified: tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Endpoint.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Endpoint.java?rev=1650285&r1=1650284&r2=1650285&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Endpoint.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/Nio2Endpoint.java Thu Jan 8 13:11:24 2015
@@ -714,6 +714,13 @@ public class Nio2Endpoint extends Abstra
public static class Nio2SocketWrapper extends SocketWrapperBase<Nio2Channel> {
+ private static final ThreadLocal<Boolean> writeCompletionInProgress = new ThreadLocal<Boolean>() {
+ @Override
+ protected Boolean initialValue() {
+ return Boolean.FALSE;
+ }
+ };
+
private SendfileData sendfileData = null;
private boolean upgradeInit = false;
@@ -726,6 +733,7 @@ public class Nio2Endpoint extends Abstra
private final CompletionHandler<Long, ByteBuffer[]> gatheringWriteCompletionHandler;
private final Semaphore writePending = new Semaphore(1);
private volatile boolean writeInterest = true;
+ private boolean writeNotify = false;
public Nio2SocketWrapper(Nio2Channel channel, Nio2Endpoint endpoint) {
@@ -774,11 +782,12 @@ public class Nio2Endpoint extends Abstra
this.writeCompletionHandler = new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer nBytes, ByteBuffer attachment) {
- boolean notify = false;
+ writeNotify = false;
synchronized (writeCompletionHandler) {
if (nBytes.intValue() < 0) {
failed(new EOFException(sm.getString("iob.failedwrite")), attachment);
} else if (Nio2SocketWrapper.this.bufferedWrites.size() > 0) {
+ writeCompletionInProgress.set(Boolean.TRUE);
// Continue writing data using a gathering write
ArrayList<ByteBuffer> arrayList = new ArrayList<>();
if (attachment.hasRemaining()) {
@@ -793,22 +802,25 @@ public class Nio2Endpoint extends Abstra
Nio2SocketWrapper.this.getSocket().write(array, 0, array.length,
Nio2SocketWrapper.this.getTimeout(), TimeUnit.MILLISECONDS,
array, gatheringWriteCompletionHandler);
+ writeCompletionInProgress.set(Boolean.FALSE);
} else if (attachment.hasRemaining()) {
// Regular write
+ writeCompletionInProgress.set(Boolean.TRUE);
Nio2SocketWrapper.this.getSocket().write(attachment, Nio2SocketWrapper.this.getTimeout(),
TimeUnit.MILLISECONDS, attachment, writeCompletionHandler);
+ writeCompletionInProgress.set(Boolean.FALSE);
} else {
// All data has been written
- if (writeInterest && !Nio2Endpoint.isInline()) {
+ if (writeInterest) {
writeInterest = false;
- notify = true;
+ writeNotify = true;
}
writePending.release();
socketWriteBuffer.clear();
writeBufferFlipped = false;
}
}
- if (notify) {
+ if (writeNotify && !writeCompletionInProgress.get().booleanValue()) {
endpoint.processSocket(Nio2SocketWrapper.this, SocketStatus.OPEN_WRITE, false);
}
}
@@ -830,12 +842,13 @@ public class Nio2Endpoint extends Abstra
gatheringWriteCompletionHandler = new CompletionHandler<Long, ByteBuffer[]>() {
@Override
public void completed(Long nBytes, ByteBuffer[] attachment) {
- boolean notify = false;
+ writeNotify = false;
synchronized (writeCompletionHandler) {
if (nBytes.longValue() < 0) {
failed(new EOFException(sm.getString("iob.failedwrite")), attachment);
} else if (Nio2SocketWrapper.this.bufferedWrites.size() > 0 || arrayHasData(attachment)) {
// Continue writing data
+ writeCompletionInProgress.set(Boolean.TRUE);
ArrayList<ByteBuffer> arrayList = new ArrayList<>();
for (ByteBuffer buffer : attachment) {
if (buffer.hasRemaining()) {
@@ -851,18 +864,19 @@ public class Nio2Endpoint extends Abstra
Nio2SocketWrapper.this.getSocket().write(array, 0, array.length,
Nio2SocketWrapper.this.getTimeout(), TimeUnit.MILLISECONDS,
array, gatheringWriteCompletionHandler);
+ writeCompletionInProgress.set(Boolean.FALSE);
} else {
// All data has been written
- if (writeInterest && !Nio2Endpoint.isInline()) {
+ if (writeInterest) {
writeInterest = false;
- notify = true;
+ writeNotify = true;
}
writePending.release();
socketWriteBuffer.clear();
writeBufferFlipped = false;
}
}
- if (notify) {
+ if (writeNotify && !writeCompletionInProgress.get().booleanValue()) {
endpoint.processSocket(Nio2SocketWrapper.this, SocketStatus.OPEN_WRITE, false);
}
}
@@ -1115,8 +1129,8 @@ public class Nio2Endpoint extends Abstra
// Could be "smart" with coordination with the main CoyoteOutputStream to
// indicate the end of a write
// Uses: if (writePending.tryAcquire(socketWrapper.getTimeout(), TimeUnit.MILLISECONDS))
- if (writePending.tryAcquire()) {
- synchronized (writeCompletionHandler) {
+ synchronized (writeCompletionHandler) {
+ if (writePending.tryAcquire()) {
// No pending completion handler, so writing to the main buffer
// is possible
int thisTime = transfer(buf, off, len, socketWriteBuffer);
@@ -1127,9 +1141,7 @@ public class Nio2Endpoint extends Abstra
addToBuffers(buf, off, len);
}
flush(false, true);
- }
- } else {
- synchronized (writeCompletionHandler) {
+ } else {
addToBuffers(buf, off, len);
}
}
@@ -1212,7 +1224,6 @@ public class Nio2Endpoint extends Abstra
socketWriteBuffer.flip();
writeBufferFlipped = true;
}
- Nio2Endpoint.startInline();
if (bufferedWrites.size() > 0) {
// Gathering write of the main buffer plus all leftovers
ArrayList<ByteBuffer> arrayList = new ArrayList<>();
@@ -1235,7 +1246,6 @@ public class Nio2Endpoint extends Abstra
// Nothing was written
writePending.release();
}
- Nio2Endpoint.endInline();
if (writePending.availablePermits() > 0) {
if (socketWriteBuffer.remaining() == 0) {
socketWriteBuffer.clear();
@@ -1475,13 +1485,8 @@ public class Nio2Endpoint extends Abstra
data.socket = socket;
data.buffer = buffer;
data.length -= nRead;
- startInline();
- try {
- socket.getSocket().write(buffer, socket.getTimeout(), TimeUnit.MILLISECONDS,
- data, sendfile);
- } finally {
- endInline();
- }
+ socket.getSocket().write(buffer, socket.getTimeout(), TimeUnit.MILLISECONDS,
+ data, sendfile);
if (data.doneInline) {
if (data.error) {
return SendfileState.ERROR;
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org