Author: markt
Date: Mon Mar 11 15:59:06 2013
New Revision: 1455201
URL: http://svn.apache.org/r1455201
Log:
Fix concurrency issue.
doWrite() add the socket to the poller if there are bytes left to wrote. The
may poller fire and execution could reach onWritePossible() before the
remaining bytes have been copied to the buffer thereby triggering an NPE.
Modified:
tomcat/trunk/java/org/apache/coyote/http11/upgrade/AbstractServletOutputStream.java
Modified:
tomcat/trunk/java/org/apache/coyote/http11/upgrade/AbstractServletOutputStream.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/upgrade/AbstractServletOutputStream.java?rev=1455201&r1=1455200&r2=1455201&view=diff
==============================================================================
---
tomcat/trunk/java/org/apache/coyote/http11/upgrade/AbstractServletOutputStream.java
(original)
+++
tomcat/trunk/java/org/apache/coyote/http11/upgrade/AbstractServletOutputStream.java
Mon Mar 11 15:59:06 2013
@@ -68,17 +68,19 @@ public abstract class AbstractServletOut
@Override
public void write(int b) throws IOException {
- preWriteChecks();
-
- writeInternal(new byte[] { (byte) b }, 0, 1);
+ synchronized (writeLock) {
+ preWriteChecks();
+ writeInternal(new byte[] { (byte) b }, 0, 1);
+ }
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
- preWriteChecks();
-
- writeInternal(b, off, len);
+ synchronized (writeLock) {
+ preWriteChecks();
+ writeInternal(b, off, len);
+ }
}
@@ -97,51 +99,50 @@ public abstract class AbstractServletOut
private void writeInternal(byte[] b, int off, int len) throws IOException {
- synchronized (writeLock) {
- if (listener == null) {
- // Simple case - blocking IO
- doWrite(true, b, off, len);
+ if (listener == null) {
+ // Simple case - blocking IO
+ doWrite(true, b, off, len);
+ } else {
+ // Non-blocking IO
+ // If the non-blocking read does not complete, doWrite() will add
+ // the socket back into the poller. The poller way trigger a new
+ // write event before this method has finished updating buffer.
This
+ // sync makes sure that buffer is updated before the next write
+ // executes.
+ int written = doWrite(false, b, off, len);
+ if (written < len) {
+ // TODO: - Reuse the buffer
+ // - Only reallocate if it gets too big (>8k?)
+ buffer = new byte[len - written];
+ System.arraycopy(b, off + written, buffer, 0, len - written);
} else {
- // Non-blocking IO
- // If the non-blocking read does not complete, doWrite() will
add
- // the socket back into the poller. The poller way trigger a
new
- // write event before this method has finished updating
buffer. This
- // sync makes sure that buffer is updated before the next write
- // executes.
- int written = doWrite(false, b, off, len);
- if (written < len) {
- // TODO: - Reuse the buffer
- // - Only reallocate if it gets too big (>8k?)
- buffer = new byte[len - written];
- System.arraycopy(b, off + written, buffer, 0, len -
written);
- } else {
- buffer = null;
- }
+ buffer = null;
}
}
}
protected final void onWritePossible() {
- try {
- writeInternal(buffer, 0, buffer.length);
- } catch (IOException ioe) {
- throw new RuntimeException(ioe);
- }
- // 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;
+ synchronized (writeLock) {
+ try {
+ writeInternal(buffer, 0, buffer.length);
+ } catch (IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+ // 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) {
+ listener.onWritePossible();
}
}
- if (fire) {
- listener.onWritePossible();
- }
-
}
/**
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]