Author: markt Date: Fri Aug 30 19:06:07 2013 New Revision: 1519050 URL: http://svn.apache.org/r1519050 Log: Add the (as yet unused) plumbing to allow the AJP APR/native processor to perform non-blocking reads and writes.
Modified: tomcat/trunk/java/org/apache/coyote/ajp/AjpAprProcessor.java Modified: tomcat/trunk/java/org/apache/coyote/ajp/AjpAprProcessor.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/ajp/AjpAprProcessor.java?rev=1519050&r1=1519049&r2=1519050&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/ajp/AjpAprProcessor.java (original) +++ tomcat/trunk/java/org/apache/coyote/ajp/AjpAprProcessor.java Fri Aug 30 19:06:07 2013 @@ -19,6 +19,8 @@ package org.apache.coyote.ajp; import java.io.IOException; import java.io.InterruptedIOException; import java.nio.ByteBuffer; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; import org.apache.coyote.ActionCode; import org.apache.coyote.RequestInfo; @@ -280,7 +282,8 @@ public class AjpAprProcessor extends Abs long socketRef = socketWrapper.getSocket().longValue(); if (outputBuffer.position() > 0) { - if ((socketRef != 0) && Socket.sendbb(socketRef, 0, outputBuffer.position()) < 0) { + if ((socketRef != 0) && + writeSocket(0, outputBuffer.position(), true) < 0) { // There are no re-tries so clear the buffer to prevent a // possible overflow if the buffer is used again. BZ53119. outputBuffer.clear(); @@ -291,6 +294,51 @@ public class AjpAprProcessor extends Abs } + private int writeSocket(int pos, int len, boolean block) { + + Lock readLock = socketWrapper.getBlockingStatusReadLock(); + WriteLock writeLock = socketWrapper.getBlockingStatusWriteLock(); + long socket = socketWrapper.getSocket().longValue(); + + boolean writeDone = false; + int result = 0; + try { + readLock.lock(); + if (socketWrapper.getBlockingStatus() == block) { + result = Socket.sendbb(socket, pos, len); + writeDone = true; + } + } finally { + readLock.unlock(); + } + + if (!writeDone) { + try { + writeLock.lock(); + socketWrapper.setBlockingStatus(block); + // Set the current settings for this socket + Socket.optSet(socket, Socket.APR_SO_NONBLOCK, (block ? 0 : 1)); + // Downgrade the lock + try { + readLock.lock(); + writeLock.unlock(); + result = Socket.sendbb(socket, pos, len); + } finally { + readLock.unlock(); + } + } finally { + // Should have been released above but may not have been on some + // exception paths + if (writeLock.isHeldByCurrentThread()) { + writeLock.unlock(); + } + } + } + + return result; + } + + /** * Read at least the specified amount of bytes, and place them * in the input buffer. @@ -306,9 +354,8 @@ public class AjpAprProcessor extends Abs } int nRead; while (inputBuffer.remaining() < n) { - nRead = Socket.recvbb - (socketWrapper.getSocket().longValue(), inputBuffer.limit(), - inputBuffer.capacity() - inputBuffer.limit()); + nRead = readSocket(inputBuffer.limit(), + inputBuffer.capacity() - inputBuffer.limit(), true); if (nRead > 0) { inputBuffer.limit(inputBuffer.limit() + nRead); } else { @@ -339,9 +386,8 @@ public class AjpAprProcessor extends Abs } int nRead; while (inputBuffer.remaining() < n) { - nRead = Socket.recvbb - (socketWrapper.getSocket().longValue(), inputBuffer.limit(), - inputBuffer.capacity() - inputBuffer.limit()); + nRead = readSocket(inputBuffer.limit(), + inputBuffer.capacity() - inputBuffer.limit(), true); if (nRead > 0) { inputBuffer.limit(inputBuffer.limit() + nRead); } else { @@ -358,6 +404,51 @@ public class AjpAprProcessor extends Abs } + private int readSocket(int pos, int len, boolean block) { + + Lock readLock = socketWrapper.getBlockingStatusReadLock(); + WriteLock writeLock = socketWrapper.getBlockingStatusWriteLock(); + long socket = socketWrapper.getSocket().longValue(); + + boolean readDone = false; + int result = 0; + try { + readLock.lock(); + if (socketWrapper.getBlockingStatus() == block) { + result = Socket.recvbb(socket, pos, len); + readDone = true; + } + } finally { + readLock.unlock(); + } + + if (!readDone) { + try { + writeLock.lock(); + socketWrapper.setBlockingStatus(block); + // Set the current settings for this socket + Socket.optSet(socket, Socket.APR_SO_NONBLOCK, (block ? 0 : 1)); + // Downgrade the lock + try { + readLock.lock(); + writeLock.unlock(); + result = Socket.recvbb(socket, pos, len); + } finally { + readLock.unlock(); + } + } finally { + // Should have been released above but may not have been on some + // exception paths + if (writeLock.isHeldByCurrentThread()) { + writeLock.unlock(); + } + } + } + + return result; + } + + /** Receive a chunk of data. Called to implement the * 'special' packet in ajp13 and to receive the data * after we send a GET_BODY packet --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org