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/01/16 16:14:44 UTC

svn commit: r1433976 - in /tomcat/trunk/java/org/apache: coyote/ajp/AjpAprProtocol.java coyote/http11/Http11AprProtocol.java tomcat/util/net/AprEndpoint.java tomcat/util/net/res/LocalStrings.properties

Author: markt
Date: Wed Jan 16 15:14:44 2013
New Revision: 1433976

URL: http://svn.apache.org/viewvc?rev=1433976&view=rev
Log:
APR/native refactoring
- Switch to Remy's updated Poller/Sendfile implementation that uses a single Poller and multiple Pollsets rather than multiple Pollers each with a single Pollset

The updated implementation is from JBoss's web container and is provided under Remy's (remm) iCLA.

This is untested (I don't have an OSX build of the native lib handy right now). I'll test later today.

Modified:
    tomcat/trunk/java/org/apache/coyote/ajp/AjpAprProtocol.java
    tomcat/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java
    tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java
    tomcat/trunk/java/org/apache/tomcat/util/net/res/LocalStrings.properties

Modified: tomcat/trunk/java/org/apache/coyote/ajp/AjpAprProtocol.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/ajp/AjpAprProtocol.java?rev=1433976&r1=1433975&r2=1433976&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/ajp/AjpAprProtocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/ajp/AjpAprProtocol.java Wed Jan 16 15:14:44 2013
@@ -135,8 +135,7 @@ public class AjpAprProtocol extends Abst
             if (addToPoller) {
                 ((AprEndpoint)proto.endpoint).getPoller().add(
                         socket.getSocket().longValue(),
-                        proto.endpoint.getKeepAliveTimeout(),
-                        AprEndpoint.Poller.FLAGS_READ);
+                        proto.endpoint.getKeepAliveTimeout(), true, false);
             }
         }
 

Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java?rev=1433976&r1=1433975&r2=1433976&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java Wed Jan 16 15:14:44 2013
@@ -252,8 +252,7 @@ public class Http11AprProtocol extends A
             if (addToPoller && proto.endpoint.isRunning()) {
                 ((AprEndpoint)proto.endpoint).getPoller().add(
                         socket.getSocket().longValue(),
-                        proto.endpoint.getKeepAliveTimeout(),
-                        AprEndpoint.Poller.FLAGS_READ);
+                        proto.endpoint.getKeepAliveTimeout(), true, false);
             }
         }
 
@@ -297,8 +296,7 @@ public class Http11AprProtocol extends A
                 if (proto.endpoint.isRunning()) {
                     ((AprEndpoint) proto.endpoint).getCometPoller().add(
                             socket.getSocket().longValue(),
-                            proto.endpoint.getSoTimeout(),
-                            AprEndpoint.Poller.FLAGS_READ);
+                            proto.endpoint.getSoTimeout(), true, false);
                 } else {
                     // Process a STOP directly
                     ((AprEndpoint) proto.endpoint).processSocket(
@@ -308,8 +306,7 @@ public class Http11AprProtocol extends A
             } else {
                 // Upgraded
                 ((AprEndpoint) proto.endpoint).getPoller().add(
-                        socket.getSocket().longValue(), -1,
-                        AprEndpoint.Poller.FLAGS_READ);
+                        socket.getSocket().longValue(), -1, true, false);
             }
         }
 

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java?rev=1433976&r1=1433975&r2=1433976&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java Wed Jan 16 15:14:44 2013
@@ -25,7 +25,6 @@ import java.util.Iterator;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.Executor;
 import java.util.concurrent.RejectedExecutionException;
-import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
@@ -184,33 +183,27 @@ public class AprEndpoint extends Abstrac
     /**
      * The socket poller.
      */
-    protected Poller[] pollers = null;
-    protected int pollerRoundRobin = 0;
+    protected Poller poller = null;
     public Poller getPoller() {
-        pollerRoundRobin = (pollerRoundRobin + 1) % pollers.length;
-        return pollers[pollerRoundRobin];
+        return poller;
     }
 
 
     /**
      * The socket poller used for Comet support.
      */
-    protected Poller[] cometPollers = null;
-    protected int cometPollerRoundRobin = 0;
+    protected Poller cometPoller = null;
     public Poller getCometPoller() {
-        cometPollerRoundRobin = (cometPollerRoundRobin + 1) % cometPollers.length;
-        return cometPollers[cometPollerRoundRobin];
+        return cometPoller;
     }
 
 
     /**
      * The static file sender.
      */
-    protected Sendfile[] sendfiles = null;
-    protected int sendfileRoundRobin = 0;
+    protected Sendfile sendfile = null;
     public Sendfile getSendfile() {
-        sendfileRoundRobin = (sendfileRoundRobin + 1) % sendfiles.length;
-        return sendfiles[sendfileRoundRobin];
+        return sendfile;
     }
 
 
@@ -364,15 +357,11 @@ public class AprEndpoint extends Abstrac
      * Number of keepalive sockets.
      */
     public int getKeepAliveCount() {
-        if (pollers == null) {
+        if (poller == null) {
             return 0;
         }
 
-        int keepAliveCount = 0;
-        for (int i = 0; i < pollers.length; i++) {
-            keepAliveCount += pollers[i].getKeepAliveCount();
-        }
-        return keepAliveCount;
+        return poller.getConnectionCount();
     }
 
 
@@ -380,15 +369,11 @@ public class AprEndpoint extends Abstrac
      * Number of sendfile sockets.
      */
     public int getSendfileCount() {
-        if (sendfiles == null) {
+        if (sendfile == null) {
             return 0;
         }
 
-        int sendfileCount = 0;
-        for (int i = 0; i < sendfiles.length; i++) {
-            sendfileCount += sendfiles[i].getSendfileCount();
-        }
-        return sendfileCount;
+        return sendfile.getSendfileCount();
     }
 
 
@@ -609,39 +594,32 @@ public class AprEndpoint extends Abstrac
 
             initializeConnectionLatch();
 
-            // Start poller threads
-            pollers = new Poller[pollerThreadCount];
-            for (int i = 0; i < pollerThreadCount; i++) {
-                pollers[i] = new Poller(false);
-                pollers[i].init();
-                pollers[i].setName(getName() + "-Poller-" + i);
-                pollers[i].setPriority(threadPriority);
-                pollers[i].setDaemon(true);
-                pollers[i].start();
-            }
-
-            // Start comet poller threads
-            cometPollers = new Poller[pollerThreadCount];
-            for (int i = 0; i < pollerThreadCount; i++) {
-                cometPollers[i] = new Poller(true);
-                cometPollers[i].init();
-                cometPollers[i].setName(getName() + "-CometPoller-" + i);
-                cometPollers[i].setPriority(threadPriority);
-                cometPollers[i].setDaemon(true);
-                cometPollers[i].start();
-            }
+            // Start poller thread
+            poller = new Poller(false);
+            poller.init();
+            Thread pollerThread = new Thread(poller, getName() + "-Poller");
+            pollerThread.setPriority(threadPriority);
+            pollerThread.setDaemon(true);
+            pollerThread.start();
+
+            // Start comet poller thread
+            cometPoller = new Poller(true);
+            cometPoller.init();
+            Thread cometPollerThread =
+                    new Thread(cometPoller, getName() + "-CometPoller");
+            cometPollerThread.setPriority(threadPriority);
+            cometPollerThread.setDaemon(true);
+            cometPollerThread.start();
 
-            // Start sendfile threads
+            // Start sendfile thread
             if (useSendfile) {
-                sendfiles = new Sendfile[sendfileThreadCount];
-                for (int i = 0; i < sendfileThreadCount; i++) {
-                    sendfiles[i] = new Sendfile();
-                    sendfiles[i].init();
-                    sendfiles[i].setName(getName() + "-Sendfile-" + i);
-                    sendfiles[i].setPriority(threadPriority);
-                    sendfiles[i].setDaemon(true);
-                    sendfiles[i].start();
-                }
+                sendfile = new Sendfile();
+                sendfile.init();
+                Thread sendfileThread =
+                        new Thread(sendfile, getName() + "-Sendfile");
+                sendfileThread.setPriority(threadPriority);
+                sendfileThread.setDaemon(true);
+                sendfileThread.start();
             }
 
             startAcceptorThreads();
@@ -691,31 +669,25 @@ public class AprEndpoint extends Abstrac
                    }
                 }
             }
-            for (int i = 0; i < pollers.length; i++) {
-                try {
-                    pollers[i].destroy();
-                } catch (Exception e) {
-                    // Ignore
-                }
+            try {
+                poller.destroy();
+            } catch (Exception e) {
+                // Ignore
+            }
+            poller = null;
+            try {
+                cometPoller.destroy();
+            } catch (Exception e) {
+                // Ignore
             }
-            pollers = null;
-            for (int i = 0; i < cometPollers.length; i++) {
+            cometPoller = null;
+            if (useSendfile) {
                 try {
-                    cometPollers[i].destroy();
+                    sendfile.destroy();
                 } catch (Exception e) {
                     // Ignore
                 }
-            }
-            cometPollers = null;
-            if (useSendfile) {
-                for (int i = 0; i < sendfiles.length; i++) {
-                    try {
-                        sendfiles[i].destroy();
-                    } catch (Exception e) {
-                        // Ignore
-                    }
-                }
-                sendfiles = null;
+                sendfile = null;
             }
         }
         shutdownExecutor();
@@ -1116,32 +1088,232 @@ public class AprEndpoint extends Abstrac
     }
 
 
-    // ----------------------------------------------------- Poller Inner Class
-    /**
-     * Poller class.
-     */
-    public class Poller extends Thread {
+    // -------------------------------------------------- SocketInfo Inner Class
+
+    public static class SocketInfo {
+        public static final int READ = 1;
+        public static final int WRITE = 2;
+        public long socket;
+        public int timeout;
+        public int flags;
+        public boolean read() {
+            return (flags & READ) == READ;
+        }
+        public boolean write() {
+            return (flags & WRITE) == WRITE;
+        }
+        public static int merge(int flag1, int flag2) {
+            return ((flag1 & READ) | (flag2 & READ))
+                | ((flag1 & WRITE) | (flag2 & WRITE));
+        }
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append("Socket: [");
+            sb.append(socket);
+            sb.append("], timeout: [");
+            sb.append(timeout);
+            sb.append("], flags: [");
+            sb.append(flags);
+            return sb.toString();
+        }
+    }
 
-        public static final int FLAGS_READ = Poll.APR_POLLIN;
-        public static final int FLAGS_WRITE  = Poll.APR_POLLOUT;
 
-        private long connectionPollset = 0;
-        private long pool = 0;
-        private long[] desc;
+    // ---------------------------------------------- SocketTimeouts Inner Class
 
-        private long[] addSocket;
-        private int[] addSocketTimeout;
-        private int[] addSocketFlags;
+    public class SocketTimeouts {
+        protected int size;
 
-        private AtomicInteger addCount = new AtomicInteger(0);
+        protected long[] sockets;
+        protected long[] timeouts;
+        protected int pos = 0;
 
-        private boolean comet = true;
+        public SocketTimeouts(int size) {
+            this.size = 0;
+            sockets = new long[size];
+            timeouts = new long[size];
+        }
 
-        protected volatile int keepAliveCount = 0;
-        public int getKeepAliveCount() { return keepAliveCount; }
+        public void add(long socket, long timeout) {
+            sockets[size] = socket;
+            timeouts[size] = timeout;
+            size++;
+        }
 
-        public Poller(boolean comet) {
-            this.comet = comet;
+        public boolean remove(long socket) {
+            for (int i = 0; i < size; i++) {
+                if (sockets[i] == socket) {
+                    sockets[i] = sockets[size - 1];
+                    timeouts[i] = timeouts[size - 1];
+                    size--;
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public long check(long date) {
+            while (pos < size) {
+                if (date >= timeouts[pos]) {
+                    long result = sockets[pos];
+                    sockets[pos] = sockets[size - 1];
+                    timeouts[pos] = timeouts[size - 1];
+                    size--;
+                    return result;
+                }
+                pos++;
+            }
+            pos = 0;
+            return 0;
+        }
+
+    }
+
+
+    // -------------------------------------------------- SocketList Inner Class
+
+    public class SocketList {
+        protected int size;
+        protected int pos;
+
+        protected long[] sockets;
+        protected int[] timeouts;
+        protected int[] flags;
+
+        protected SocketInfo info = new SocketInfo();
+
+        public SocketList(int size) {
+            this.size = 0;
+            pos = 0;
+            sockets = new long[size];
+            timeouts = new int[size];
+            flags = new int[size];
+        }
+
+        public int size() {
+            return this.size;
+        }
+
+        public SocketInfo get() {
+            if (pos == size) {
+                return null;
+            } else {
+                info.socket = sockets[pos];
+                info.timeout = timeouts[pos];
+                info.flags = flags[pos];
+                pos++;
+                return info;
+            }
+        }
+
+        public void clear() {
+            size = 0;
+            pos = 0;
+        }
+
+        public boolean add(long socket, int timeout, int flag) {
+            if (size == sockets.length) {
+                return false;
+            } else {
+                for (int i = 0; i < size; i++) {
+                    if (sockets[i] == socket) {
+                        flags[i] = SocketInfo.merge(flags[i], flag);
+                        return true;
+                    }
+                }
+                sockets[size] = socket;
+                timeouts[size] = timeout;
+                flags[size] = flag;
+                size++;
+                return true;
+            }
+        }
+
+        public void duplicate(SocketList copy) {
+            copy.size = size;
+            copy.pos = pos;
+            System.arraycopy(sockets, 0, copy.sockets, 0, size);
+            System.arraycopy(timeouts, 0, copy.timeouts, 0, size);
+            System.arraycopy(flags, 0, copy.flags, 0, size);
+        }
+
+    }
+
+    // ------------------------------------------------------ Poller Inner Class
+
+   public class Poller implements Runnable {
+
+        /**
+         * Pointers to the pollers.
+         */
+        protected long[] pollers = null;
+
+        /**
+         * Actual poller size.
+         */
+        protected int actualPollerSize = 0;
+
+        /**
+         * Amount of spots left in the poller.
+         */
+        protected int[] pollerSpace = null;
+
+        /**
+         * Amount of low level pollers in use by this poller.
+         */
+        protected int pollerCount;
+
+        /**
+         * Timeout value for the poll call.
+         */
+        protected int pollerTime;
+
+        /**
+         * Root pool.
+         */
+        protected long pool = 0;
+
+        /**
+         * Socket descriptors.
+         */
+        protected long[] desc;
+
+        /**
+         * List of sockets to be added to the poller.
+         */
+        protected SocketList addList = null;
+
+        /**
+         * List of sockets to be added to the poller.
+         */
+        protected SocketList localAddList = null;
+
+        /**
+         * Event mode flag.
+         */
+        protected boolean event = true;
+
+        /**
+         * Structure used for storing timeouts.
+         */
+        protected SocketTimeouts timeouts = null;
+
+
+        /**
+         * Last run of maintain. Maintain will run usually every 5s.
+         */
+        protected long lastMaintain = System.currentTimeMillis();
+
+
+        /**
+         * Amount of connections inside this poller.
+         */
+        protected int connectionCount = 0;
+        public int getConnectionCount() { return connectionCount; }
+
+        public Poller(boolean event) {
+            this.event = event;
         }
 
         /**
@@ -1149,63 +1321,128 @@ public class AprEndpoint extends Abstrac
          * will be 62 (recompiling APR is necessary to remove this limitation).
          */
         protected void init() {
+
             pool = Pool.create(serverSockPool);
-            int size = getMaxConnections() / pollerThreadCount;
-            int socketTimeout = socketProperties.getSoTimeout();
-            connectionPollset = allocatePoller(size, pool, socketTimeout);
-            if (connectionPollset == 0 && size > 1024) {
-                size = 1024;
-                connectionPollset = allocatePoller(size, pool, socketTimeout);
+
+            // Single poller by default
+            int defaultPollerSize = getMaxConnections();
+
+            if ((OS.IS_WIN32 || OS.IS_WIN64) && (defaultPollerSize > 1024)) {
+                // The maximum per poller to get reasonable performance is 1024
+                // Adjust poller size so that it won't reach the limit. This is
+                // a limitation of XP / Server 2003 that has been fixed in
+                // Vista / Server 2008 onwards.
+                defaultPollerSize = 1024;
             }
-            if (connectionPollset == 0) {
-                size = 62;
-                connectionPollset = allocatePoller(size, pool, socketTimeout);
+            actualPollerSize = defaultPollerSize;
+
+            timeouts = new SocketTimeouts(defaultPollerSize);
+
+            // At the moment, setting the timeout is useless, but it could get
+            // used again as the normal poller could be faster using maintain.
+            // It might not be worth bothering though.
+            long pollset = allocatePoller(actualPollerSize, pool, -1);
+            if (pollset == 0 && actualPollerSize > 1024) {
+                actualPollerSize = 1024;
+                pollset = allocatePoller(actualPollerSize, pool, -1);
             }
-            desc = new long[size * 2];
-            keepAliveCount = 0;
-            addSocket = new long[size];
-            addSocketTimeout = new int[size];
-            addSocketFlags = new int[size];
-            addCount.set(0);
+            if (pollset == 0) {
+                actualPollerSize = 62;
+                pollset = allocatePoller(actualPollerSize, pool, -1);
+            }
+
+            pollerCount = defaultPollerSize / actualPollerSize;
+            pollerTime = pollTime / pollerCount;
+
+            pollers = new long[pollerCount];
+            pollers[0] = pollset;
+            for (int i = 1; i < pollerCount; i++) {
+                pollers[i] = allocatePoller(actualPollerSize, pool, -1);
+            }
+
+            pollerSpace = new int[pollerCount];
+            for (int i = 0; i < pollerCount; i++) {
+                pollerSpace[i] = actualPollerSize;
+            }
+
+            desc = new long[actualPollerSize * 2];
+            connectionCount = 0;
+            addList = new SocketList(defaultPollerSize);
+            localAddList = new SocketList(defaultPollerSize);
+
         }
 
         /**
          * Destroy the poller.
          */
-        @Override
-        public void destroy() {
+        protected void destroy() {
+            // Wait for pollerTime before doing anything, so that the poller
+            // threads exit, otherwise parallel destruction of sockets which are
+            // still in the poller can cause problems
+            try {
+                synchronized (this) {
+                    this.wait(pollTime / 1000);
+                }
+            } catch (InterruptedException e) {
+                // Ignore
+            }
             // Close all sockets in the add queue
-            for (int i = 0; i < addCount.get(); i++) {
-                if (comet) {
-                    processSocket(addSocket[i], SocketStatus.STOP);
-                } else {
-                    destroySocket(addSocket[i]);
+            SocketInfo info = addList.get();
+            while (info != null) {
+                if (!event || (event && !processSocket(
+                        info.socket, SocketStatus.STOP))) {
+                    Socket.destroy(info.socket);
                 }
+                info = addList.get();
             }
+            addList.clear();
             // Close all sockets still in the poller
-            closePollset(connectionPollset);
-            Pool.destroy(pool);
-            keepAliveCount = 0;
-            addCount.set(0);
-            try {
-                while (this.isAlive()) {
-                    this.interrupt();
-                    this.join(1000);
+            for (int i = 0; i < pollerCount; i++) {
+                int rv = Poll.pollset(pollers[i], desc);
+                if (rv > 0) {
+                    for (int n = 0; n < rv; n++) {
+                        if (!event || (event && !processSocket(
+                                desc[n*2+1], SocketStatus.STOP))) {
+                            Socket.destroy(desc[n*2+1]);
+                        }
+                    }
                 }
-            } catch (InterruptedException e) {
-                // Ignore
             }
+            Pool.destroy(pool);
+            connectionCount = 0;
         }
 
-        private void closePollset(long pollset) {
-            int rv = Poll.pollset(pollset, desc);
-            if (rv > 0) {
-                for (int n = 0; n < rv; n++) {
-                    if (comet) {
-                        processSocket(desc[n*2+1], SocketStatus.STOP);
-                    } else {
-                        destroySocket(desc[n*2+1], true);
-                    }
+        /**
+         * Add specified socket and associated pool to the poller. The socket
+         * will be added to a temporary array, and polled first after a maximum
+         * amount of time equal to pollTime (in most cases, latency will be much
+         * lower, however).
+         *
+         * @param socket to add to the poller
+         */
+        public void add(long socket) {
+            int timeout = getKeepAliveTimeout();
+            if (timeout <= 0) {
+                timeout = getSoTimeout();
+            }
+            if (timeout <= 0) {
+                // Always put a timeout in
+                timeout = Integer.MAX_VALUE;
+            }
+            boolean ok = false;
+            synchronized (this) {
+                // Add socket to the list. Newly added sockets will wait
+                // at most for pollTime before being polled
+                if (addList.add(socket, timeout, SocketInfo.READ)) {
+                    ok = true;
+                    this.notify();
+                }
+            }
+            if (!ok) {
+                // Can't do anything: close the socket right away
+                if (!event || (event && !processSocket(
+                        socket, SocketStatus.ERROR))) {
+                    Socket.destroy(socket);
                 }
             }
         }
@@ -1214,128 +1451,314 @@ public class AprEndpoint extends Abstrac
          * Add specified socket and associated pool to the poller. The socket
          * will be added to a temporary array, and polled first after a maximum
          * amount of time equal to pollTime (in most cases, latency will be much
-         * lower, however).
+         * lower, however). Note: If both read and write are false, the socket
+         * will only be checked for timeout; if the socket was already present
+         * in the poller, a callback event will be generated and the socket will
+         * be removed from the poller.
          *
-         * @param socket    to add to the poller
-         * @param timeout   read timeout (in milliseconds) to use with this
-         *                  socket. Use -1 for infinite timeout
-         * @param flags     flags that define the events that are to be polled
-         *                  for
-         */
-        public void add(long socket, int timeout, int flags) {
-            if (!running) {
-                processSocket(socket, SocketStatus.STOP);
-                return;
+         * @param socket to add to the poller
+         * @param timeout to use for this connection
+         * @param read to do read polling
+         * @param write to do write polling
+         */
+        public void add(long socket, int timeout, boolean read, boolean write) {
+            if (timeout < 0) {
+                timeout = getSoTimeout();
+            }
+            if (timeout <= 0) {
+                // Always put a timeout in
+                timeout = Integer.MAX_VALUE;
             }
+            boolean ok = false;
             synchronized (this) {
                 // Add socket to the list. Newly added sockets will wait
                 // at most for pollTime before being polled
-                if (addCount.get() >= addSocket.length) {
-                    // Can't do anything: close the socket right away
-                    if (comet) {
-                        processSocket(socket, SocketStatus.ERROR);
-                    } else {
-                        destroySocket(socket);
+                if (addList.add(socket, timeout,
+                        (read ? SocketInfo.READ : 0) |
+                                (write ? SocketInfo.WRITE : 0))) {
+                    ok = true;
+                    this.notify();
+                }
+            }
+            if (!ok) {
+                // Can't do anything: close the socket right away
+                if (!event || (event && !processSocket(
+                        socket, SocketStatus.ERROR))) {
+                    Socket.destroy(socket);
+                }
+            }
+        }
+
+        /**
+         * Add specified socket to one of the pollers.
+         */
+        protected boolean addToPoller(long socket, int events) {
+            int rv = -1;
+            for (int i = 0; i < pollers.length; i++) {
+                if (pollerSpace[i] > 0) {
+                    rv = Poll.add(pollers[i], socket, events);
+                    if (rv == Status.APR_SUCCESS) {
+                        pollerSpace[i]--;
+                        connectionCount++;
+                        return true;
                     }
-                    return;
                 }
-                addSocket[addCount.get()] = socket;
-                addSocketTimeout[addCount.get()] = timeout;
-                addSocketFlags[addCount.get()] = flags;
-                addCount.incrementAndGet();
-                // TODO: interrupt poll ?
-                this.notify();
             }
+            return false;
+        }
+
+        /**
+         * Remove specified socket from the pollers.
+         */
+        protected boolean removeFromPoller(long socket) {
+            int rv = -1;
+            for (int i = 0; i < pollers.length; i++) {
+                if (pollerSpace[i] < actualPollerSize) {
+                    rv = Poll.remove(pollers[i], socket);
+                    if (rv != Status.APR_NOTFOUND) {
+                        pollerSpace[i]++;
+                        connectionCount--;
+                        break;
+                    }
+                }
+            }
+            return (rv == Status.APR_SUCCESS);
+        }
+
+        /**
+         * Timeout checks.
+         */
+        protected void maintain() {
+
+            long date = System.currentTimeMillis();
+            // Maintain runs at most once every 5s, although it will likely get
+            // called more
+            if ((date - lastMaintain) < 5000L) {
+                return;
+            } else {
+                lastMaintain = date;
+            }
+            long socket = timeouts.check(date);
+            while (socket != 0) {
+                removeFromPoller(socket);
+                if (!event || (event && !processSocket(
+                        socket, SocketStatus.TIMEOUT))) {
+                    Socket.destroy(socket);
+                }
+                socket = timeouts.check(date);
+            }
+
+        }
+
+        /**
+         * Displays the list of sockets in the pollers.
+         */
+        @Override
+        public String toString() {
+            StringBuffer buf = new StringBuffer();
+            buf.append("Poller event=[").append(event).append("]");
+            long[] res = new long[actualPollerSize * 2];
+            for (int i = 0; i < pollers.length; i++) {
+                int count = Poll.pollset(pollers[i], res);
+                buf.append(" [ ");
+                for (int j = 0; j < count; j++) {
+                    buf.append(desc[2*j+1]).append(" ");
+                }
+                buf.append("]");
+            }
+            return buf.toString();
         }
 
         /**
-         * The background thread that listens for incoming TCP/IP connections and
-         * hands them off to an appropriate processor.
+         * The background thread that listens for incoming TCP/IP connections
+         * and hands them off to an appropriate processor.
          */
         @Override
         public void run() {
 
-            long maintainTime = 0;
+            int maintain = 0;
             // Loop until we receive a shutdown command
             while (running) {
+
                 // Loop if endpoint is paused
-                while (paused && running) {
+                while (paused) {
                     try {
                         Thread.sleep(1000);
                     } catch (InterruptedException e) {
                         // Ignore
                     }
                 }
-
-                if (!running) {
-                    break;
-                }
-                if (keepAliveCount < 1 && addCount.get() < 1) {
-                    synchronized (this) {
-                        while (keepAliveCount < 1 && addCount.get() < 1 && running) {
-                            // Reset maintain time.
-                            maintainTime = 0;
-                            try {
-                                this.wait();
-                            } catch (InterruptedException e) {
-                                // Ignore
-                            }
+                // Check timeouts for suspended connections if the poller is
+                // empty
+                while (connectionCount < 1 && addList.size() < 1) {
+                    // Reset maintain time.
+                    try {
+                        if (getSoTimeout() > 0 && running) {
+                            maintain();
+                        }
+                        synchronized (this) {
+                            this.wait(10000);
                         }
+                    } catch (InterruptedException e) {
+                        // Ignore
+                    } catch (Throwable t) {
+                        ExceptionUtils.handleThrowable(t);
+                        getLog().warn(sm.getString("endpoint.timeout.err"));
                     }
                 }
 
-                if (!running) {
-                    break;
-                }
                 try {
                     // Add sockets which are waiting to the poller
-                    if (addCount.get() > 0) {
+                    if (addList.size() > 0) {
                         synchronized (this) {
-                            int successCount = 0;
-                            try {
-                                for (int i = (addCount.get() - 1); i >= 0; i--) {
-                                    int timeout = addSocketTimeout[i];
-                                    if (timeout > 0) {
-                                        // Convert milliseconds to microseconds
-                                        timeout = timeout * 1000;
+                            // Duplicate to another list, so that the syncing is
+                            // minimal
+                            addList.duplicate(localAddList);
+                            addList.clear();
+                        }
+                        SocketInfo info = localAddList.get();
+                        while (info != null) {
+                            if (info.read() || info.write()) {
+                                // Store timeout
+                                if (event) {
+                                    removeFromPoller(info.socket);
+                                }
+                                int events =
+                                        (info.read() ? Poll.APR_POLLIN : 0) |
+                                        (info.write() ? Poll.APR_POLLOUT : 0);
+                                if (!addToPoller(info.socket, events)) {
+                                    // Can't do anything: close the socket right
+                                    // away
+                                    if (!event || (event && !processSocket(
+                                            info.socket, SocketStatus.ERROR))) {
+                                        Socket.destroy(info.socket);
                                     }
-                                    int rv = Poll.addWithTimeout(
-                                            connectionPollset, addSocket[i],
-                                            addSocketFlags[i], timeout);
-                                    if (rv == Status.APR_SUCCESS) {
-                                        successCount++;
+                                } else {
+                                    timeouts.add(info.socket,
+                                            System.currentTimeMillis() +
+                                                    info.timeout);
+                                }
+                            } else {
+                                // Should never happen.
+                                timeouts.remove(info.socket);
+                                Socket.destroy(info.socket);
+                                getLog().warn(sm.getString(
+                                        "endpoint.apr.pollAddInvalid", info));
+                            }
+                            info = localAddList.get();
+                        }
+                    }
+
+                    // Poll for the specified interval
+                    for (int i = 0; i < pollers.length; i++) {
+
+                        // Flags to ask to reallocate the pool
+                        boolean reset = false;
+                        //ArrayList<Long> skip = null;
+
+                        int rv = 0;
+                        // Iterate on each pollers, but no need to poll empty pollers
+                        if (pollerSpace[i] < actualPollerSize) {
+                            rv = Poll.poll(pollers[i], pollerTime, desc, true);
+                        }
+                        if (rv > 0) {
+                            pollerSpace[i] += rv;
+                            connectionCount -= rv;
+                            for (int n = 0; n < rv; n++) {
+                                timeouts.remove(desc[n*2+1]);
+                                // Check for failed sockets and hand this socket off to a worker
+                                if (event) {
+                                    // Event processes either a read or a write depending on what the poller returns
+                                    if (((desc[n*2] & Poll.APR_POLLHUP) == Poll.APR_POLLHUP)
+                                            || ((desc[n*2] & Poll.APR_POLLERR) == Poll.APR_POLLERR)
+                                            || ((desc[n*2] & Poll.APR_POLLNVAL) == Poll.APR_POLLNVAL)) {
+                                        if (!processSocket(desc[n*2+1], SocketStatus.ERROR)) {
+                                            // Close socket and clear pool
+                                            Socket.destroy(desc[n*2+1]);
+                                        }
+                                    } else if ((desc[n*2] & Poll.APR_POLLIN) == Poll.APR_POLLIN) {
+                                        if (!processSocket(desc[n*2+1], SocketStatus.OPEN_READ)) {
+                                            // Close socket and clear pool
+                                            Socket.destroy(desc[n*2+1]);
+                                        }
+                                    } else if ((desc[n*2] & Poll.APR_POLLOUT) == Poll.APR_POLLOUT) {
+                                        if (!processSocket(desc[n*2+1], SocketStatus.OPEN_WRITE)) {
+                                            // Close socket and clear pool
+                                            Socket.destroy(desc[n*2+1]);
+                                        }
                                     } else {
-                                        // Can't do anything: close the socket right away
-                                        if (comet) {
-                                            processSocket(addSocket[i], SocketStatus.ERROR);
-                                        } else {
-                                            destroySocket(addSocket[i]);
+                                        // Unknown event
+                                        getLog().warn(sm.getString(
+                                                "endpoint.apr.pollUnknownEvent",
+                                                Long.valueOf(desc[n*2])));
+                                        if (!processSocket(desc[n*2+1], SocketStatus.ERROR)) {
+                                            // Close socket and clear pool
+                                            Socket.destroy(desc[n*2+1]);
                                         }
                                     }
+                                } else if (((desc[n*2] & Poll.APR_POLLHUP) == Poll.APR_POLLHUP)
+                                        || ((desc[n*2] & Poll.APR_POLLERR) == Poll.APR_POLLERR)
+                                        || ((desc[n*2] & Poll.APR_POLLNVAL) == Poll.APR_POLLNVAL)) {
+                                    // Close socket and clear pool
+                                    Socket.destroy(desc[n*2+1]);
+                                } else if ((desc[n*2] & Poll.APR_POLLIN) == Poll.APR_POLLIN) {
+                                    if (!processSocket(desc[n*2+1])) {
+                                        // Close socket and clear pool
+                                        Socket.destroy(desc[n*2+1]);
+                                    }
+                                } else {
+                                    // Unknown event
+                                    getLog().warn(sm.getString(
+                                            "endpoint.apr.pollUnknownEvent",
+                                            Long.valueOf(desc[n*2])));
+                                    // Close socket and clear pool
+                                    Socket.destroy(desc[n*2+1]);
                                 }
-                            } finally {
-                                keepAliveCount += successCount;
-                                addCount.set(0);
+                            }
+                        } else if (rv < 0) {
+                            int errn = -rv;
+                            // Any non timeup or interrupted error is critical
+                            if ((errn != Status.TIMEUP) && (errn != Status.EINTR)) {
+                                if (errn >  Status.APR_OS_START_USERERR) {
+                                    errn -=  Status.APR_OS_START_USERERR;
+                                }
+                                getLog().error(sm.getString(
+                                        "endpoint.apr.pollError",
+                                        Integer.valueOf(errn),
+                                        Error.strerror(errn)));
+                                // Destroy and reallocate the poller
+                                reset = true;
                             }
                         }
-                    }
 
-                    maintainTime += pollTime;
-                    // Poll for the specified interval
-                    if (doPoll(connectionPollset)) {
-                        continue;
+                        if (reset) {
+                            // Reallocate the current poller
+                            int count = Poll.pollset(pollers[i], desc);
+                            long newPoller = allocatePoller(actualPollerSize, pool, -1);
+                            // Don't restore connections for now, since I have not tested it
+                            pollerSpace[i] = actualPollerSize;
+                            connectionCount -= count;
+                            Poll.destroy(pollers[i]);
+                            pollers[i] = newPoller;
+                        }
+
                     }
 
-                    // Check timeouts (much less frequently than polling)
-                    if (maintainTime > 1000000L && running) {
-                        maintainTime = 0;
-                        if (socketProperties.getSoTimeout() > 0) {
-                            doTimeout(connectionPollset);
-                        }
+                    // Process socket timeouts
+                    if (getSoTimeout() > 0 && maintain++ > 1000 && running) {
+                        // This works and uses only one timeout mechanism for everything, but the
+                        // non event poller might be a bit faster by using the old maintain.
+                        maintain = 0;
+                        maintain();
                     }
+
                 } catch (Throwable t) {
                     ExceptionUtils.handleThrowable(t);
-                    log.error(sm.getString("endpoint.poll.error"), t);
+                    if (maintain == 0) {
+                        getLog().warn(sm.getString("endpoint.timeout.error"), t);
+                    } else {
+                        getLog().warn(sm.getString("endpoint.poll.error"), t);
+                    }
                 }
 
             }
@@ -1343,59 +1766,6 @@ public class AprEndpoint extends Abstrac
             synchronized (this) {
                 this.notifyAll();
             }
-
-        }
-
-        private boolean doPoll(long pollset) {
-            int rv = Poll.poll(pollset, pollTime, desc, true);
-            if (rv > 0) {
-                keepAliveCount -= rv;
-                for (int n = 0; n < rv; n++) {
-                    // Check for failed sockets and hand this socket off to a worker
-                    if (((desc[n*2] & Poll.APR_POLLHUP) == Poll.APR_POLLHUP)
-                            || ((desc[n*2] & Poll.APR_POLLERR) == Poll.APR_POLLERR)
-                            || (comet && (!processSocket(desc[n*2+1], SocketStatus.OPEN_READ)))
-                            || (!comet && (!processSocket(desc[n*2+1])))) {
-                        // Close socket and clear pool
-                        if (comet) {
-                            processSocket(desc[n*2+1], SocketStatus.DISCONNECT);
-                        } else {
-                            destroySocket(desc[n*2+1]);
-                        }
-                    }
-                }
-            } else if (rv < 0) {
-                int errn = -rv;
-                /* Any non timeup or interrupted error is critical */
-                if ((errn != Status.TIMEUP) && (errn != Status.EINTR)) {
-                    if (errn >  Status.APR_OS_START_USERERR) {
-                        errn -=  Status.APR_OS_START_USERERR;
-                    }
-                    log.error(sm.getString("endpoint.poll.fail", "" + errn, Error.strerror(errn)));
-                    // Handle poll critical failure
-                    synchronized (this) {
-                        destroy();
-                        init();
-                    }
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        private void doTimeout(long pollset) {
-            int rv = Poll.maintain(pollset, desc, true);
-            if (rv > 0) {
-                keepAliveCount -= rv;
-                for (int n = 0; n < rv; n++) {
-                    // Close socket and clear pool
-                    if (comet) {
-                        processSocket(desc[n], SocketStatus.TIMEOUT);
-                    } else {
-                        destroySocket(desc[n]);
-                    }
-                }
-            }
         }
     }
 
@@ -1426,73 +1796,71 @@ public class AprEndpoint extends Abstrac
     // --------------------------------------------------- Sendfile Inner Class
 
 
-    /**
-     * Sendfile class.
-     */
-    public class Sendfile extends Thread {
+    public class Sendfile implements Runnable {
 
         protected long sendfilePollset = 0;
         protected long pool = 0;
         protected long[] desc;
         protected HashMap<Long, SendfileData> sendfileData;
 
-        protected AtomicInteger sendfileCount = new AtomicInteger(0);
-        public int getSendfileCount() { return sendfileCount.get(); }
+        protected int sendfileCount;
+        public int getSendfileCount() { return sendfileCount; }
 
         protected ArrayList<SendfileData> addS;
-        protected AtomicInteger addCount = new AtomicInteger(0);
 
         /**
-         * Create the sendfile poller. With some versions of APR, the maximum poller size will
-         * be 62 (recompiling APR is necessary to remove this limitation).
+         * Create the sendfile poller. With some versions of APR, the maximum
+         * poller size will be 62 (recompiling APR is necessary to remove this
+         * limitation).
          */
         protected void init() {
             pool = Pool.create(serverSockPool);
-            int size = sendfileSize / sendfileThreadCount;
-            sendfilePollset = allocatePoller(size, pool, socketProperties.getSoTimeout());
+            int size = sendfileSize;
+            if (size <= 0) {
+                size = (OS.IS_WIN32 || OS.IS_WIN64) ? (1 * 1024) : (16 * 1024);
+            }
+            sendfilePollset = allocatePoller(size, pool, getSoTimeout());
             if (sendfilePollset == 0 && size > 1024) {
                 size = 1024;
-                sendfilePollset = allocatePoller(size, pool, socketProperties.getSoTimeout());
+                sendfilePollset = allocatePoller(size, pool, getSoTimeout());
             }
             if (sendfilePollset == 0) {
                 size = 62;
-                sendfilePollset = allocatePoller(size, pool, socketProperties.getSoTimeout());
+                sendfilePollset = allocatePoller(size, pool, getSoTimeout());
             }
             desc = new long[size * 2];
             sendfileData = new HashMap<>(size);
             addS = new ArrayList<>();
-            addCount.set(0);
         }
 
         /**
          * Destroy the poller.
          */
-        @Override
-        public void destroy() {
+        protected void destroy() {
+            // Wait for polltime before doing anything, so that the poller threads
+            // exit, otherwise parallel destruction of sockets which are still
+            // in the poller can cause problems
+            try {
+                synchronized (this) {
+                    this.wait(pollTime / 1000);
+                }
+            } catch (InterruptedException e) {
+                // Ignore
+            }
             // Close any socket remaining in the add queue
-            addCount.set(0);
             for (int i = (addS.size() - 1); i >= 0; i--) {
                 SendfileData data = addS.get(i);
-                destroySocket(data.socket);
+                Socket.destroy(data.socket);
             }
-            addS.clear();
             // Close all sockets still in the poller
             int rv = Poll.pollset(sendfilePollset, desc);
             if (rv > 0) {
                 for (int n = 0; n < rv; n++) {
-                    destroySocket(desc[n*2+1]);
+                    Socket.destroy(desc[n*2+1]);
                 }
             }
             Pool.destroy(pool);
             sendfileData.clear();
-            try {
-                while (this.isAlive()) {
-                    this.interrupt();
-                    this.join(1000);
-                }
-            } catch (InterruptedException e) {
-                // Ignore
-            }
         }
 
         /**
@@ -1501,7 +1869,7 @@ public class AprEndpoint extends Abstrac
          * will be handled asynchronously inside the kernel. As a result,
          * the poller will never be used.
          *
-         * @param data containing the reference to the data which should be sent
+         * @param data containing the reference to the data which should be snet
          * @return true if all the data has been sent right away, and false
          *              otherwise
          */
@@ -1509,13 +1877,6 @@ public class AprEndpoint extends Abstrac
             // Initialize fd from data given
             try {
                 data.fdpool = Socket.pool(data.socket);
-            } catch (Exception e) {
-                // Pool not created so no need to destroy it.
-                log.error(sm.getString("endpoint.sendfile.error"), e);
-                data.socket = 0;
-                return false;
-            }
-            try {
                 data.fd = File.open
                     (data.fileName, File.APR_FOPEN_READ
                      | File.APR_FOPEN_SENDFILE_ENABLED | File.APR_FOPEN_BINARY,
@@ -1529,36 +1890,32 @@ public class AprEndpoint extends Abstrac
                     if (nw < 0) {
                         if (!(-nw == Status.EAGAIN)) {
                             Pool.destroy(data.fdpool);
-                            // No need to close socket, this will be done by
-                            // calling code since data.socket == 0
                             data.socket = 0;
                             return false;
                         } else {
                             // Break the loop and add the socket to poller.
                             break;
                         }
-                    }
-
-                    data.pos = data.pos + nw;
-                    if (data.pos >= data.end) {
-                        // Entire file has been sent
-                        Pool.destroy(data.fdpool);
-                        // Set back socket to blocking mode
-                        Socket.timeoutSet(data.socket, socketProperties.getSoTimeout() * 1000);
-                        return true;
+                    } else {
+                        data.pos = data.pos + nw;
+                        if (data.pos >= data.end) {
+                            // Entire file has been sent
+                            Pool.destroy(data.fdpool);
+                            // Set back socket to blocking mode
+                            Socket.timeoutSet(
+                                    data.socket, getSoTimeout() * 1000);
+                            return true;
+                        }
                     }
                 }
             } catch (Exception e) {
-                log.error(sm.getString("endpoint.sendfile.error"), e);
-                Pool.destroy(data.fdpool);
-                data.socket = 0;
+                log.warn(sm.getString("endpoint.sendfile.error"), e);
                 return false;
             }
             // Add socket to the list. Newly added sockets will wait
             // at most for pollTime before being polled
             synchronized (this) {
                 addS.add(data);
-                addCount.incrementAndGet();
                 this.notify();
             }
             return false;
@@ -1572,14 +1929,14 @@ public class AprEndpoint extends Abstrac
         protected void remove(SendfileData data) {
             int rv = Poll.remove(sendfilePollset, data.socket);
             if (rv == Status.APR_SUCCESS) {
-                sendfileCount.decrementAndGet();
+                sendfileCount--;
             }
-            sendfileData.remove(Long.valueOf(data.socket));
+            sendfileData.remove(new Long(data.socket));
         }
 
         /**
-         * The background thread that listens for incoming TCP/IP connections and
-         * hands them off to an appropriate processor.
+         * The background thread that listens for incoming TCP/IP connections
+         * and hands them off to an appropriate processor.
          */
         @Override
         public void run() {
@@ -1589,57 +1946,46 @@ public class AprEndpoint extends Abstrac
             while (running) {
 
                 // Loop if endpoint is paused
-                while (paused && running) {
+                while (paused) {
                     try {
                         Thread.sleep(1000);
                     } catch (InterruptedException e) {
                         // Ignore
                     }
                 }
-
-                if (!running) {
-                    break;
-                }
-                if (sendfileCount.get() < 1 && addCount.get() < 1) {
-                    synchronized (this) {
-                        while (sendfileCount.get() < 1 && addS.size() < 1 && running) {
-                            // Reset maintain time.
-                            maintainTime = 0;
-                            try {
-                                this.wait();
-                            } catch (InterruptedException e) {
-                                // Ignore
-                            }
+                // Loop if poller is empty
+                while (sendfileCount < 1 && addS.size() < 1) {
+                    // Reset maintain time.
+                    maintainTime = 0;
+                    try {
+                        synchronized (this) {
+                            this.wait();
                         }
+                    } catch (InterruptedException e) {
+                        // Ignore
                     }
                 }
 
-                if (!running) {
-                    break;
-                }
                 try {
                     // Add socket to the poller
-                    if (addCount.get() > 0) {
+                    if (addS.size() > 0) {
                         synchronized (this) {
-                            int successCount = 0;
-                            try {
-                                for (int i = (addS.size() - 1); i >= 0; i--) {
-                                    SendfileData data = addS.get(i);
-                                    int rv = Poll.add(sendfilePollset, data.socket, Poll.APR_POLLOUT);
-                                    if (rv == Status.APR_SUCCESS) {
-                                        sendfileData.put(Long.valueOf(data.socket), data);
-                                        successCount++;
-                                    } else {
-                                        log.warn(sm.getString("endpoint.sendfile.addfail", "" + rv, Error.strerror(rv)));
-                                        // Can't do anything: close the socket right away
-                                        destroySocket(data.socket);
-                                    }
+                            for (int i = (addS.size() - 1); i >= 0; i--) {
+                                SendfileData data = addS.get(i);
+                                int rv = Poll.add(sendfilePollset, data.socket, Poll.APR_POLLOUT);
+                                if (rv == Status.APR_SUCCESS) {
+                                    sendfileData.put(new Long(data.socket), data);
+                                    sendfileCount++;
+                                } else {
+                                    getLog().warn(sm.getString(
+                                            "endpoint.sendfile.addfail",
+                                            Integer.valueOf(rv),
+                                            Error.strerror(rv)));
+                                    // Can't do anything: close the socket right away
+                                    Socket.destroy(data.socket);
                                 }
-                            } finally {
-                                sendfileCount.addAndGet(successCount);
-                                addS.clear();
-                                addCount.set(0);
                             }
+                            addS.clear();
                         }
                     }
 
@@ -1650,7 +1996,7 @@ public class AprEndpoint extends Abstrac
                         for (int n = 0; n < rv; n++) {
                             // Get the sendfile state
                             SendfileData state =
-                                sendfileData.get(Long.valueOf(desc[n*2+1]));
+                                sendfileData.get(new Long(desc[n*2+1]));
                             // Problem events
                             if (((desc[n*2] & Poll.APR_POLLHUP) == Poll.APR_POLLHUP)
                                     || ((desc[n*2] & Poll.APR_POLLERR) == Poll.APR_POLLERR)) {
@@ -1658,7 +2004,7 @@ public class AprEndpoint extends Abstrac
                                 remove(state);
                                 // Destroy file descriptor pool, which should close the file
                                 // Close the socket, as the response would be incomplete
-                                destroySocket(state.socket);
+                                Socket.destroy(state.socket);
                                 continue;
                             }
                             // Write some data using sendfile
@@ -1670,7 +2016,7 @@ public class AprEndpoint extends Abstrac
                                 remove(state);
                                 // Close the socket, as the response would be incomplete
                                 // This will close the file too.
-                                destroySocket(state.socket);
+                                Socket.destroy(state.socket);
                                 continue;
                             }
 
@@ -1680,16 +2026,15 @@ public class AprEndpoint extends Abstrac
                                 if (state.keepAlive) {
                                     // Destroy file descriptor pool, which should close the file
                                     Pool.destroy(state.fdpool);
-                                    Socket.timeoutSet(state.socket, socketProperties.getSoTimeout() * 1000);
+                                    Socket.timeoutSet(state.socket,
+                                            getSoTimeout() * 1000);
                                     // If all done put the socket back in the poller for
                                     // processing of further requests
-                                    getPoller().add(state.socket,
-                                            getKeepAliveTimeout(),
-                                            Poller.FLAGS_READ);
+                                    getPoller().add(state.socket);
                                 } else {
                                     // Close the socket since this is
                                     // the end of not keep-alive request.
-                                    destroySocket(state.socket);
+                                    Socket.destroy(state.socket);
                                 }
                             }
                         }
@@ -1700,7 +2045,10 @@ public class AprEndpoint extends Abstrac
                             if (errn >  Status.APR_OS_START_USERERR) {
                                 errn -=  Status.APR_OS_START_USERERR;
                             }
-                            log.error(sm.getString("endpoint.poll.fail", "" + errn, Error.strerror(errn)));
+                            getLog().error(sm.getString(
+                                    "Unexpected poller error",
+                                    Integer.valueOf(errn),
+                                    Error.strerror(errn)));
                             // Handle poll critical failure
                             synchronized (this) {
                                 destroy();
@@ -1710,24 +2058,25 @@ public class AprEndpoint extends Abstrac
                         }
                     }
                     // Call maintain for the sendfile poller
-                    if (socketProperties.getSoTimeout() > 0 && maintainTime > 1000000L && running) {
-                        rv = Poll.maintain(sendfilePollset, desc, true);
+                    if (getSoTimeout() > 0 &&
+                            maintainTime > 1000000L && running) {
+                        rv = Poll.maintain(sendfilePollset, desc, false);
                         maintainTime = 0;
                         if (rv > 0) {
                             for (int n = 0; n < rv; n++) {
                                 // Get the sendfile state
-                                SendfileData state = sendfileData.get(Long.valueOf(desc[n]));
+                                SendfileData state = sendfileData.get(new Long(desc[n]));
                                 // Close socket and clear pool
                                 remove(state);
                                 // Destroy file descriptor pool, which should close the file
                                 // Close the socket, as the response would be incomplete
-                                destroySocket(state.socket);
+                                Socket.destroy(state.socket);
                             }
                         }
                     }
                 } catch (Throwable t) {
                     ExceptionUtils.handleThrowable(t);
-                    log.error(sm.getString("endpoint.poll.error"), t);
+                    getLog().error(sm.getString("endpoint.poll.error"), t);
                 }
             }
 
@@ -1739,7 +2088,6 @@ public class AprEndpoint extends Abstrac
 
     }
 
-
     // ------------------------------------------------ Handler Inner Interface
 
 
@@ -1779,7 +2127,7 @@ public class AprEndpoint extends Abstrac
                 if (!deferAccept) {
                     if (setSocketOptions(socket.getSocket().longValue())) {
                         getPoller().add(socket.getSocket().longValue(),
-                                getSoTimeout(), Poller.FLAGS_READ);
+                                getSoTimeout(), true, false);
                     } else {
                         // Close socket and pool
                         destroySocket(socket.getSocket().longValue());

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/res/LocalStrings.properties
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/res/LocalStrings.properties?rev=1433976&r1=1433975&r2=1433976&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/res/LocalStrings.properties (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/res/LocalStrings.properties Wed Jan 16 15:14:44 2013
@@ -36,6 +36,11 @@ endpoint.poll.error=Unexpected poller er
 endpoint.process.fail=Error allocating socket processor
 endpoint.sendfile.error=Unexpected sendfile error
 endpoint.sendfile.addfail=Sendfile failure: [{0}] {1}
+endpoint.timeout.err=Error processing socket timeout
 endpoint.apr.noSslCertFile=Connector attribute SSLCertificateFile must be defined when using SSL with APR
+endpoint.apr.pollAddInvalid=Invalid attempted to add a socket [{0}] to the poller
+endpoint.apr.pollError=Poller failed with error [{0}] : [{1}]
+endpoint.apr.pollUnknownEvent=A socket was returned from the poller with an unrecognized event [{0}]
 endpoint.apr.invalidSslProtocol=An invalid value [{0}] was provided for the SSLProtocol attribute
+endpoint.apr.poll
 endpoint.nio.selectorCloseFail=Failed to close selector when closing the poller



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


Re: svn commit: r1433976 - in /tomcat/trunk/java/org/apache: coyote/ajp/AjpAprProtocol.java coyote/http11/Http11AprProtocol.java tomcat/util/net/AprEndpoint.java tomcat/util/net/res/LocalStrings.properties

Posted by Mark Thomas <ma...@apache.org>.
On 16/01/2013 16:12, jean-frederic clere wrote:
> On 01/16/2013 04:53 PM, Remy Maucherat wrote:
>> On Wed, 2013-01-16 at 15:14 +0000, markt@apache.org wrote:
>>> This is untested (I don't have an OSX build of the native lib handy
>>> right now). I'll test later today.
>>
>> I'm not sure native on OS X is 100% stable, for whatever reason (due to
>> apparent concurrency issues with the poller once read + write polling is
>> used). It could depend on the APR / Tomcat Native version used and be
>> fixed now,
> 
> I plan to test later too, with apr 1.4.6, openssl 1.0.1c  and
> tc-native-1.1.x.

I meant that I'd test on Windows later :)

Once we have a 1.1.25 build I'll see if I can find some time to test on OSX.

Mark


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


Re: svn commit: r1433976 - in /tomcat/trunk/java/org/apache: coyote/ajp/AjpAprProtocol.java coyote/http11/Http11AprProtocol.java tomcat/util/net/AprEndpoint.java tomcat/util/net/res/LocalStrings.properties

Posted by jean-frederic clere <jf...@gmail.com>.
On 01/16/2013 04:53 PM, Remy Maucherat wrote:
> On Wed, 2013-01-16 at 15:14 +0000, markt@apache.org wrote:
>> This is untested (I don't have an OSX build of the native lib handy right now). I'll test later today.
>
> I'm not sure native on OS X is 100% stable, for whatever reason (due to
> apparent concurrency issues with the poller once read + write polling is
> used). It could depend on the APR / Tomcat Native version used and be
> fixed now,

I plan to test later too, with apr 1.4.6, openssl 1.0.1c  and 
tc-native-1.1.x.

Cheers

Jean-Frederic

  but certainly there were issues on OS X that didn't occur on
> Linux (or Windows, ...) at the time. I didn't test or investigate
> myself, so I don't know more than that, good luck with the testing.
>
> Rémy
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: dev-help@tomcat.apache.org
>
>


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


Re: svn commit: r1433976 - in /tomcat/trunk/java/org/apache: coyote/ajp/AjpAprProtocol.java coyote/http11/Http11AprProtocol.java tomcat/util/net/AprEndpoint.java tomcat/util/net/res/LocalStrings.properties

Posted by Remy Maucherat <re...@apache.org>.
On Wed, 2013-01-16 at 15:14 +0000, markt@apache.org wrote:
> This is untested (I don't have an OSX build of the native lib handy right now). I'll test later today.

I'm not sure native on OS X is 100% stable, for whatever reason (due to
apparent concurrency issues with the poller once read + write polling is
used). It could depend on the APR / Tomcat Native version used and be
fixed now, but certainly there were issues on OS X that didn't occur on
Linux (or Windows, ...) at the time. I didn't test or investigate
myself, so I don't know more than that, good luck with the testing.

Rémy



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org