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 2013/08/30 21:06:07 UTC

svn commit: r1519050 - /tomcat/trunk/java/org/apache/coyote/ajp/AjpAprProcessor.java

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-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org