This is an automated email from the ASF dual-hosted git repository.

remm pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/9.0.x by this push:
     new 500b2a4  Simplify NIO block read and write
500b2a4 is described below

commit 500b2a4114142335789babce4e42e0fae330dea8
Author: remm <r...@apache.org>
AuthorDate: Thu May 27 10:44:23 2021 +0200

    Simplify NIO block read and write
    
    Now better validated with Tomcat 10.
---
 .../catalina/security/SecurityClassLoad.java       |   3 -
 .../apache/tomcat/util/net/LocalStrings.properties |   5 -
 .../tomcat/util/net/LocalStrings_fr.properties     |   5 -
 .../tomcat/util/net/LocalStrings_ja.properties     |   5 -
 .../tomcat/util/net/LocalStrings_ko.properties     |   5 -
 .../tomcat/util/net/LocalStrings_zh_CN.properties  |   5 -
 .../tomcat/util/net/NioBlockingSelector.java       | 535 ---------------------
 java/org/apache/tomcat/util/net/NioEndpoint.java   | 237 ++++-----
 .../apache/tomcat/util/net/NioSelectorPool.java    | 348 --------------
 .../apache/tomcat/util/net/SecureNioChannel.java   |  28 +-
 webapps/docs/changelog.xml                         |   4 +
 webapps/docs/config/http.xml                       |  35 --
 12 files changed, 128 insertions(+), 1087 deletions(-)

diff --git a/java/org/apache/catalina/security/SecurityClassLoad.java 
b/java/org/apache/catalina/security/SecurityClassLoad.java
index 141a1d3..19b9c21 100644
--- a/java/org/apache/catalina/security/SecurityClassLoad.java
+++ b/java/org/apache/catalina/security/SecurityClassLoad.java
@@ -187,9 +187,6 @@ public final class SecurityClassLoad {
         // net
         loader.loadClass(basePackage + "util.net.Constants");
         loader.loadClass(basePackage + "util.net.DispatchType");
-        loader.loadClass(basePackage + 
"util.net.NioBlockingSelector$BlockPoller$RunnableAdd");
-        loader.loadClass(basePackage + 
"util.net.NioBlockingSelector$BlockPoller$RunnableCancel");
-        loader.loadClass(basePackage + 
"util.net.NioBlockingSelector$BlockPoller$RunnableRemove");
         loader.loadClass(basePackage + 
"util.net.AprEndpoint$AprSocketWrapper$AprOperationState");
         loader.loadClass(basePackage + 
"util.net.NioEndpoint$NioSocketWrapper$NioOperationState");
         loader.loadClass(basePackage + 
"util.net.Nio2Endpoint$Nio2SocketWrapper$Nio2OperationState");
diff --git a/java/org/apache/tomcat/util/net/LocalStrings.properties 
b/java/org/apache/tomcat/util/net/LocalStrings.properties
index b1e5c2a..f3f1619 100644
--- a/java/org/apache/tomcat/util/net/LocalStrings.properties
+++ b/java/org/apache/tomcat/util/net/LocalStrings.properties
@@ -142,11 +142,6 @@ endpoint.warn.noRemotePort=Unable to determine remote port 
for socket [{0}]
 endpoint.warn.noUtilityExecutor=No utility executor was set, creating one
 endpoint.warn.unlockAcceptorFailed=Acceptor thread [{0}] failed to unlock. 
Forcing hard socket shutdown.
 
-nioBlockingSelector.keyNotRegistered=Key no longer registered
-nioBlockingSelector.possibleLeak=Possible key leak, cancelling key in the 
finalizer
-nioBlockingSelector.processingError=Error processing selection key operations
-nioBlockingSelector.selectError=Error selecting key
-
 sniExtractor.clientHelloInvalid=The ClientHello message was not correctly 
formatted
 sniExtractor.clientHelloTooBig=The ClientHello was not presented in a single 
TLS record so no SNI information could be extracted
 sniExtractor.tooEarly=It is illegal to call this method before the client 
hello has been parsed
diff --git a/java/org/apache/tomcat/util/net/LocalStrings_fr.properties 
b/java/org/apache/tomcat/util/net/LocalStrings_fr.properties
index 626ccae..11c19fd 100644
--- a/java/org/apache/tomcat/util/net/LocalStrings_fr.properties
+++ b/java/org/apache/tomcat/util/net/LocalStrings_fr.properties
@@ -142,11 +142,6 @@ endpoint.warn.noRemotePort=Impossible de déterminer le 
port distant pour le soc
 endpoint.warn.noUtilityExecutor=Aucun exécuteur utilitaire configuré, un 
nouveau sera crée
 endpoint.warn.unlockAcceptorFailed=Le thread qui accepte les sockets [{0}] 
n''a pu être débloqué, arrêt forcé su socket serveur
 
-nioBlockingSelector.keyNotRegistered=La clé n'est plus enregistrée
-nioBlockingSelector.possibleLeak=Une fuite de mémoire sur la clé a pu se 
produire, la clé est annulée dans le finalizer
-nioBlockingSelector.processingError=Erreur lors du traitement des opérations 
de sélection des clés
-nioBlockingSelector.selectError=Erreur lors de la sélection de clés
-
 sniExtractor.clientHelloInvalid=Le message ClientHello n'était pas formaté 
correctement
 sniExtractor.clientHelloTooBig=Le ClientHello n'a pas été présenté dans un 
seul enregistrement TLS donc l'information SNI n'a pu être extraite
 sniExtractor.tooEarly=Il est illégal d'appeler cette méthode avant que le 
hello du client ait été traité
diff --git a/java/org/apache/tomcat/util/net/LocalStrings_ja.properties 
b/java/org/apache/tomcat/util/net/LocalStrings_ja.properties
index 690a2f0..4f69f18 100644
--- a/java/org/apache/tomcat/util/net/LocalStrings_ja.properties
+++ b/java/org/apache/tomcat/util/net/LocalStrings_ja.properties
@@ -142,11 +142,6 @@ endpoint.warn.noRemotePort=ソケット[{0}] のリモートポート番号を
 endpoint.warn.noUtilityExecutor=ユーティリティエグゼキュターが構成されていません。新たに作成します。
 endpoint.warn.unlockAcceptorFailed=Acceptor スレッド[{0}]のロックを解除できませんでした。 
強制的にハードソケットをシャットダウンします。
 
-nioBlockingSelector.keyNotRegistered=セレクタにキーが登録されていません。
-nioBlockingSelector.possibleLeak=潜在的なキーのリークです。finalizer でキーをキャンセルします。
-nioBlockingSelector.processingError=選択キー操作の処理中のエラー
-nioBlockingSelector.selectError=キー・セットの選択中のエラー
-
 sniExtractor.clientHelloInvalid=ClientHelloメッセージが正しくフォーマットされていません。
 
sniExtractor.clientHelloTooBig=ClientHelloは単一のTLSレコードには表示されないため、SNI情報は抽出できませんでした
 sniExtractor.tooEarly=クライアントのhelloが解析される前にこのメソッドを呼び出すことは違法です
diff --git a/java/org/apache/tomcat/util/net/LocalStrings_ko.properties 
b/java/org/apache/tomcat/util/net/LocalStrings_ko.properties
index f08c4e2..6fae3c6 100644
--- a/java/org/apache/tomcat/util/net/LocalStrings_ko.properties
+++ b/java/org/apache/tomcat/util/net/LocalStrings_ko.properties
@@ -142,11 +142,6 @@ endpoint.warn.noRemotePort=소켓 [{0}]을(를) 위한 원격 포트를 결정
 endpoint.warn.noUtilityExecutor=UtilityExecutor가 설정되지 않아, 새로 생성합니다.
 endpoint.warn.unlockAcceptorFailed=Acceptor 쓰레드 [{0}]이(가) 잠금을 풀지 못했습니다. 강제로 
소켓을 셧다운합니다.
 
-nioBlockingSelector.keyNotRegistered=키가 더 이상 등록되어 있지 않습니다.
-nioBlockingSelector.possibleLeak=키 누수가 가능한 상황입니다. finalize()에서 키를 취소합니다.
-nioBlockingSelector.processingError=Selection 키 오퍼레이션들을 처리 중 오류 발생
-nioBlockingSelector.selectError=키를 select하는 중 오류 발생
-
 sniExtractor.clientHelloInvalid=ClientHello 메시지가 정확히 포맷되지 않았습니다.
 sniExtractor.clientHelloTooBig=ClientHello가 단일 TLS 레코드에 존재하지 않았기에, SNI 정보를 추출할 
수 없었습니다.
 sniExtractor.tooEarly=클라이언트 헬로 메시지가 파싱되기 전에 이 메소드를 호출하는 것은 허용되지 않습니다.
diff --git a/java/org/apache/tomcat/util/net/LocalStrings_zh_CN.properties 
b/java/org/apache/tomcat/util/net/LocalStrings_zh_CN.properties
index 6d50b76..6f33320 100644
--- a/java/org/apache/tomcat/util/net/LocalStrings_zh_CN.properties
+++ b/java/org/apache/tomcat/util/net/LocalStrings_zh_CN.properties
@@ -140,11 +140,6 @@ endpoint.warn.noRemotePort=无法确定 socket [{0}] 的远程端口
 endpoint.warn.noUtilityExecutor=没有公共的executor 被设置时,创建一个.
 endpoint.warn.unlockAcceptorFailed=接收器线程[{0}]解锁失败。强制硬套接字关闭。
 
-nioBlockingSelector.keyNotRegistered=密钥不再注册
-nioBlockingSelector.possibleLeak=可能的密钥泄漏,正在取消终结器中的密钥
-nioBlockingSelector.processingError=处理选择键操作时出错
-nioBlockingSelector.selectError=选择键时出错
-
 sniExtractor.clientHelloInvalid=ClientHello信息未正常格式化
 sniExtractor.clientHelloTooBig=):ClientHello 没有出现在单个TLS记录中,因此无法提取SNI信息
 sniExtractor.tooEarly=在客户端问候被解析之前调用这个方法是非法的
diff --git a/java/org/apache/tomcat/util/net/NioBlockingSelector.java 
b/java/org/apache/tomcat/util/net/NioBlockingSelector.java
deleted file mode 100644
index 1499139..0000000
--- a/java/org/apache/tomcat/util/net/NioBlockingSelector.java
+++ /dev/null
@@ -1,535 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tomcat.util.net;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.net.SocketTimeoutException;
-import java.nio.ByteBuffer;
-import java.nio.channels.CancelledKeyException;
-import java.nio.channels.ClosedChannelException;
-import java.nio.channels.SelectionKey;
-import java.nio.channels.Selector;
-import java.nio.channels.SocketChannel;
-import java.util.Iterator;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.juli.logging.Log;
-import org.apache.juli.logging.LogFactory;
-import org.apache.tomcat.util.ExceptionUtils;
-import org.apache.tomcat.util.collections.SynchronizedQueue;
-import org.apache.tomcat.util.collections.SynchronizedStack;
-import org.apache.tomcat.util.net.NioEndpoint.NioSocketWrapper;
-import org.apache.tomcat.util.res.StringManager;
-
-public class NioBlockingSelector {
-
-    private static final Log log = 
LogFactory.getLog(NioBlockingSelector.class);
-    protected static final StringManager sm = 
StringManager.getManager(NioBlockingSelector.class);
-
-    private final SynchronizedStack<KeyReference> keyReferenceStack =
-            new SynchronizedStack<>();
-
-    protected Selector sharedSelector;
-
-    protected BlockPoller poller;
-
-    public void open(String name, Selector selector) {
-        sharedSelector = selector;
-        poller = new BlockPoller();
-        poller.selector = sharedSelector;
-        poller.setDaemon(true);
-        poller.setName(name + "-BlockPoller");
-        poller.start();
-    }
-
-    public void close() {
-        if (poller != null) {
-            poller.disable();
-            poller.interrupt();
-            poller = null;
-        }
-    }
-
-    /**
-     * Performs a blocking write using the bytebuffer for data to be written
-     * If the <code>selector</code> parameter is null, then it will perform a 
busy write that could
-     * take up a lot of CPU cycles.
-     *
-     * @param buf ByteBuffer - the buffer containing the data, we will write 
as long as <code>(buf.hasRemaining()==true)</code>
-     * @param socket SocketChannel - the socket to write data to
-     * @param writeTimeout long - the timeout for this write operation in 
milliseconds, -1 means no timeout
-     * @return the number of bytes written
-     * @throws EOFException if write returns -1
-     * @throws SocketTimeoutException if the write times out
-     * @throws IOException if an IO Exception occurs in the underlying socket 
logic
-     */
-    public int write(ByteBuffer buf, NioChannel socket, long writeTimeout)
-            throws IOException {
-        SelectionKey key = 
socket.getIOChannel().keyFor(socket.getSocketWrapper().getPoller().getSelector());
-        if (key == null) {
-            throw new 
IOException(sm.getString("nioBlockingSelector.keyNotRegistered"));
-        }
-        KeyReference reference = keyReferenceStack.pop();
-        if (reference == null) {
-            reference = new KeyReference();
-        }
-        NioSocketWrapper att = (NioSocketWrapper) key.attachment();
-        if (att.previousIOException != null) {
-            /*
-             * Socket has previously seen an IOException on write.
-             *
-             * Blocking writes assume that buffer is always fully written so
-             * there is no code checking for incomplete writes, retaining
-             * the unwritten data and attempting to write it as part of a
-             * subsequent write call.
-             *
-             * Because of the above, when an IOException is triggered we
-             * need so skip subsequent attempts to write as otherwise it
-             * will appear to the client as if some data was dropped just
-             * before the connection is lost. It is better if the client
-             * just sees the dropped connection.
-             */
-            throw new IOException(att.previousIOException);
-        }
-        int written = 0;
-        boolean timedout = false;
-        int keycount = 1; //assume we can write
-        long time = System.currentTimeMillis(); //start the timeout timer
-        try {
-            while (!timedout && buf.hasRemaining()) {
-                if (keycount > 0) { //only write if we were registered for a 
write
-                    int cnt = socket.write(buf); //write the data
-                    if (cnt == -1) {
-                        throw new EOFException();
-                    }
-                    written += cnt;
-                    if (cnt > 0) {
-                        time = System.currentTimeMillis(); //reset our timeout 
timer
-                        continue; //we successfully wrote, try again without a 
selector
-                    }
-                }
-                try {
-                    if (att.getWriteLatch() == null || 
att.getWriteLatch().getCount() == 0) {
-                        att.startWriteLatch(1);
-                    }
-                    poller.add(att, SelectionKey.OP_WRITE, reference);
-                    
att.awaitWriteLatch(AbstractEndpoint.toTimeout(writeTimeout), 
TimeUnit.MILLISECONDS);
-                } catch (InterruptedException ignore) {
-                    // Ignore
-                }
-                if (att.getWriteLatch() != null && 
att.getWriteLatch().getCount() > 0) {
-                    //we got interrupted, but we haven't received notification 
from the poller.
-                    keycount = 0;
-                } else {
-                    //latch countdown has happened
-                    keycount = 1;
-                    att.resetWriteLatch();
-                }
-
-                if (writeTimeout > 0 && (keycount == 0)) {
-                    timedout = (System.currentTimeMillis() - time) >= 
writeTimeout;
-                }
-            }
-            if (timedout) {
-                att.previousIOException = new SocketTimeoutException();
-                throw att.previousIOException;
-            }
-        } finally {
-            poller.remove(att, SelectionKey.OP_WRITE);
-            if (timedout && reference.key != null) {
-                poller.cancelKey(reference.key);
-            }
-            reference.key = null;
-            keyReferenceStack.push(reference);
-        }
-        return written;
-    }
-
-    /**
-     * Performs a blocking read using the bytebuffer for data to be read
-     * If the <code>selector</code> parameter is null, then it will perform a 
busy read that could
-     * take up a lot of CPU cycles.
-     *
-     * @param buf ByteBuffer - the buffer containing the data, we will read as 
until we have read at least one byte or we timed out
-     * @param socket SocketChannel - the socket to write data to
-     * @param readTimeout long - the timeout for this read operation in 
milliseconds, -1 means no timeout
-     * @return the number of bytes read
-     * @throws EOFException if read returns -1
-     * @throws SocketTimeoutException if the read times out
-     * @throws IOException if an IO Exception occurs in the underlying socket 
logic
-     */
-    public int read(ByteBuffer buf, NioChannel socket, long readTimeout) 
throws IOException {
-        SelectionKey key = 
socket.getIOChannel().keyFor(socket.getSocketWrapper().getPoller().getSelector());
-        if (key == null) {
-            throw new 
IOException(sm.getString("nioBlockingSelector.keyNotRegistered"));
-        }
-        KeyReference reference = keyReferenceStack.pop();
-        if (reference == null) {
-            reference = new KeyReference();
-        }
-        NioSocketWrapper att = (NioSocketWrapper) key.attachment();
-        int read = 0;
-        boolean timedout = false;
-        int keycount = 1; //assume we can read
-        long time = System.currentTimeMillis(); //start the timeout timer
-        try {
-            while (!timedout) {
-                if (keycount > 0) { //only read if we were registered for a 
read
-                    read = socket.read(buf);
-                    if (read != 0) {
-                        break;
-                    }
-                }
-                try {
-                    if (att.getReadLatch()==null || 
att.getReadLatch().getCount()==0) {
-                        att.startReadLatch(1);
-                    }
-                    poller.add(att,SelectionKey.OP_READ, reference);
-                    
att.awaitReadLatch(AbstractEndpoint.toTimeout(readTimeout), 
TimeUnit.MILLISECONDS);
-                } catch (InterruptedException ignore) {
-                    // Ignore
-                }
-                if ( att.getReadLatch()!=null && 
att.getReadLatch().getCount()> 0) {
-                    //we got interrupted, but we haven't received notification 
from the poller.
-                    keycount = 0;
-                }else {
-                    //latch countdown has happened
-                    keycount = 1;
-                    att.resetReadLatch();
-                }
-                if (readTimeout >= 0 && (keycount == 0)) {
-                    timedout = (System.currentTimeMillis() - time) >= 
readTimeout;
-                }
-            }
-            if (timedout) {
-                throw new SocketTimeoutException();
-            }
-        } finally {
-            poller.remove(att,SelectionKey.OP_READ);
-            if (timedout && reference.key != null) {
-                poller.cancelKey(reference.key);
-            }
-            reference.key = null;
-            keyReferenceStack.push(reference);
-        }
-        return read;
-    }
-
-
-    protected static class BlockPoller extends Thread {
-        protected volatile boolean run = true;
-        protected Selector selector = null;
-        protected final SynchronizedQueue<Runnable> events = new 
SynchronizedQueue<>();
-        public void disable() {
-            run = false;
-            selector.wakeup();
-        }
-        protected final AtomicInteger wakeupCounter = new AtomicInteger(0);
-
-        public void cancelKey(final SelectionKey key) {
-            Runnable r = new RunnableCancel(key);
-            events.offer(r);
-            wakeup();
-        }
-
-        public void wakeup() {
-            if (wakeupCounter.addAndGet(1)==0) {
-                selector.wakeup();
-            }
-        }
-
-        public void cancel(SelectionKey sk, NioSocketWrapper key, int ops){
-            if (sk != null) {
-                sk.cancel();
-                sk.attach(null);
-                if (SelectionKey.OP_WRITE == (ops & SelectionKey.OP_WRITE)) {
-                    countDown(key.getWriteLatch());
-                }
-                if (SelectionKey.OP_READ == (ops & SelectionKey.OP_READ)) {
-                    countDown(key.getReadLatch());
-                }
-            }
-        }
-
-        public void add(final NioSocketWrapper key, final int ops, final 
KeyReference ref) {
-            if (key == null) {
-                return;
-            }
-            NioChannel nch = key.getSocket();
-            final SocketChannel ch = nch.getIOChannel();
-            if (ch == null) {
-                return;
-            }
-            Runnable r = new RunnableAdd(ch, key, ops, ref);
-            events.offer(r);
-            wakeup();
-        }
-
-        public void remove(final NioSocketWrapper key, final int ops) {
-            if (key == null) {
-                return;
-            }
-            NioChannel nch = key.getSocket();
-            final SocketChannel ch = nch.getIOChannel();
-            if (ch == null) {
-                return;
-            }
-            Runnable r = new RunnableRemove(ch, key, ops);
-            events.offer(r);
-            wakeup();
-        }
-
-        public boolean events() {
-            Runnable r = null;
-            /* We only poll and run the runnable events when we start this
-             * method. Further events added to the queue later will be delayed
-             * to the next execution of this method.
-             *
-             * We do in this way, because running event from the events queue
-             * may lead the working thread to add more events to the queue (for
-             * example, the worker thread may add another RunnableAdd event 
when
-             * waken up by a previous RunnableAdd event who got an invalid
-             * SelectionKey). Trying to consume all the events in an increasing
-             * queue till it's empty, will make the loop hard to be terminated,
-             * which will kill a lot of time, and greatly affect performance of
-             * the poller loop.
-             */
-            int size = events.size();
-            for (int i = 0; i < size && (r = events.poll()) != null; i++) {
-                r.run();
-            }
-            return (size > 0);
-        }
-
-        @Override
-        public void run() {
-            while (run) {
-                try {
-                    events();
-                    int keyCount = 0;
-                    try {
-                        if (wakeupCounter.getAndSet(-1) > 0) {
-                            keyCount = selector.selectNow();
-                        } else {
-                            keyCount = selector.select(1000);
-                        }
-                        wakeupCounter.set(0);
-                        if (!run) {
-                            break;
-                        }
-                    } catch (NullPointerException x) {
-                        // sun bug 5076772 on windows JDK 1.5
-                        if (selector == null) {
-                            throw x;
-                        }
-                        if (log.isDebugEnabled()) {
-                            log.debug("Possibly encountered sun bug 5076772 on 
windows JDK 1.5", x);
-                        }
-                        continue;
-                    } catch (CancelledKeyException x) {
-                        // sun bug 5076772 on windows JDK 1.5
-                        if (log.isDebugEnabled()) {
-                            log.debug("Possibly encountered sun bug 5076772 on 
windows JDK 1.5", x);
-                        }
-                        continue;
-                    } catch (Throwable x) {
-                        ExceptionUtils.handleThrowable(x);
-                        
log.error(sm.getString("nioBlockingSelector.selectError"), x);
-                        continue;
-                    }
-
-                    Iterator<SelectionKey> iterator = keyCount > 0
-                            ? selector.selectedKeys().iterator()
-                            : null;
-
-                    // Walk through the collection of ready keys and dispatch
-                    // any active event.
-                    while (run && iterator != null && iterator.hasNext()) {
-                        SelectionKey sk = iterator.next();
-                        NioSocketWrapper socketWrapper = (NioSocketWrapper) 
sk.attachment();
-                        try {
-                            iterator.remove();
-                            sk.interestOps(sk.interestOps() & 
(~sk.readyOps()));
-                            if (sk.isReadable()) {
-                                countDown(socketWrapper.getReadLatch());
-                            }
-                            if (sk.isWritable()) {
-                                countDown(socketWrapper.getWriteLatch());
-                            }
-                        } catch (CancelledKeyException ckx) {
-                            sk.cancel();
-                            countDown(socketWrapper.getReadLatch());
-                            countDown(socketWrapper.getWriteLatch());
-                        }
-                    }
-                } catch (Throwable t) {
-                    
log.error(sm.getString("nioBlockingSelector.processingError"), t);
-                }
-            }
-            events.clear();
-            // If using a shared selector, the NioSelectorPool will also try 
and
-            // close the selector. Try and avoid the ClosedSelectorException
-            // although because multiple threads are involved there is always
-            // the possibility of an Exception here.
-            if (selector.isOpen()) {
-                try {
-                    // Cancels all remaining keys
-                    selector.selectNow();
-                } catch (Exception ignore) {
-                    if (log.isDebugEnabled()) {
-                        log.debug("", ignore);
-                    }
-                }
-            }
-            try {
-                selector.close();
-            } catch (Exception ignore) {
-                if (log.isDebugEnabled()) {
-                    log.debug("", ignore);
-                }
-            }
-        }
-
-        public void countDown(CountDownLatch latch) {
-            if (latch == null) {
-                return;
-            }
-            latch.countDown();
-        }
-
-
-        private class RunnableAdd implements Runnable {
-
-            private final SocketChannel ch;
-            private final NioSocketWrapper key;
-            private final int ops;
-            private final KeyReference ref;
-
-            public RunnableAdd(SocketChannel ch, NioSocketWrapper key, int 
ops, KeyReference ref) {
-                this.ch = ch;
-                this.key = key;
-                this.ops = ops;
-                this.ref = ref;
-            }
-
-            @Override
-            public void run() {
-                SelectionKey sk = ch.keyFor(selector);
-                try {
-                    if (sk == null) {
-                        sk = ch.register(selector, ops, key);
-                        ref.key = sk;
-                    } else if (!sk.isValid()) {
-                        cancel(sk, key, ops);
-                    } else {
-                        sk.interestOps(sk.interestOps() | ops);
-                    }
-                } catch (CancelledKeyException cx) {
-                    cancel(sk, key, ops);
-                } catch (ClosedChannelException cx) {
-                    cancel(null, key, ops);
-                }
-            }
-        }
-
-
-        private class RunnableRemove implements Runnable {
-
-            private final SocketChannel ch;
-            private final NioSocketWrapper key;
-            private final int ops;
-
-            public RunnableRemove(SocketChannel ch, NioSocketWrapper key, int 
ops) {
-                this.ch = ch;
-                this.key = key;
-                this.ops = ops;
-            }
-
-            @Override
-            public void run() {
-                SelectionKey sk = ch.keyFor(selector);
-                try {
-                    if (sk == null) {
-                        if (SelectionKey.OP_WRITE == (ops & 
SelectionKey.OP_WRITE)) {
-                            countDown(key.getWriteLatch());
-                        }
-                        if (SelectionKey.OP_READ == (ops & 
SelectionKey.OP_READ)) {
-                            countDown(key.getReadLatch());
-                        }
-                    } else {
-                        if (sk.isValid()) {
-                            sk.interestOps(sk.interestOps() & (~ops));
-                            if (SelectionKey.OP_WRITE == (ops & 
SelectionKey.OP_WRITE)) {
-                                countDown(key.getWriteLatch());
-                            }
-                            if (SelectionKey.OP_READ == (ops & 
SelectionKey.OP_READ)) {
-                                countDown(key.getReadLatch());
-                            }
-                            if (sk.interestOps() == 0) {
-                                sk.cancel();
-                                sk.attach(null);
-                            }
-                        } else {
-                            sk.cancel();
-                            sk.attach(null);
-                        }
-                    }
-                } catch (CancelledKeyException cx) {
-                    if (sk != null) {
-                        sk.cancel();
-                        sk.attach(null);
-                    }
-                }
-            }
-
-        }
-
-
-        public static class RunnableCancel implements Runnable {
-
-            private final SelectionKey key;
-
-            public RunnableCancel(SelectionKey key) {
-                this.key = key;
-            }
-
-            @Override
-            public void run() {
-                key.cancel();
-            }
-        }
-    }
-
-
-    public static class KeyReference {
-        SelectionKey key = null;
-
-        @Override
-        protected void finalize() {
-            if (key != null && key.isValid()) {
-                log.warn(sm.getString("nioBlockingSelector.possibleLeak"));
-                try {
-                    key.cancel();
-                } catch (Exception ignore) {
-                }
-            }
-        }
-    }
-}
diff --git a/java/org/apache/tomcat/util/net/NioEndpoint.java 
b/java/org/apache/tomcat/util/net/NioEndpoint.java
index 241ff5f..e8b017b 100644
--- a/java/org/apache/tomcat/util/net/NioEndpoint.java
+++ b/java/org/apache/tomcat/util/net/NioEndpoint.java
@@ -55,7 +55,6 @@ import javax.net.ssl.SSLEngine;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
 import org.apache.tomcat.util.ExceptionUtils;
-import org.apache.tomcat.util.IntrospectionUtils;
 import org.apache.tomcat.util.collections.SynchronizedQueue;
 import org.apache.tomcat.util.collections.SynchronizedStack;
 import org.apache.tomcat.util.compat.JreCompat;
@@ -90,8 +89,6 @@ public class NioEndpoint extends 
AbstractJsseEndpoint<NioChannel,SocketChannel>
 
     // ----------------------------------------------------------------- Fields
 
-    private NioSelectorPool selectorPool = new NioSelectorPool();
-
     /**
      * Server socket "pointer".
      */
@@ -117,25 +114,6 @@ public class NioEndpoint extends 
AbstractJsseEndpoint<NioChannel,SocketChannel>
 
 
     /**
-     * Generic properties, introspected
-     */
-    @Override
-    public boolean setProperty(String name, String value) {
-        final String selectorPoolName = "selectorPool.";
-        try {
-            if (name.startsWith(selectorPoolName)) {
-                return IntrospectionUtils.setProperty(selectorPool, 
name.substring(selectorPoolName.length()), value);
-            } else {
-                return super.setProperty(name, value);
-            }
-        } catch (Exception e) {
-            log.error(sm.getString("endpoint.setAttributeError", name, value), 
e);
-            return false;
-        }
-    }
-
-
-    /**
      * Use System.inheritableChannel to obtain channel from stdin/stdout.
      */
     private boolean useInheritedChannel = false;
@@ -200,10 +178,6 @@ public class NioEndpoint extends 
AbstractJsseEndpoint<NioChannel,SocketChannel>
     private Poller poller = null;
 
 
-    public void setSelectorPool(NioSelectorPool selectorPool) {
-        this.selectorPool = selectorPool;
-    }
-
     /**
      * Is deferAccept supported?
      */
@@ -256,8 +230,6 @@ public class NioEndpoint extends 
AbstractJsseEndpoint<NioChannel,SocketChannel>
 
         // Initialize SSL if needed
         initialiseSsl();
-
-        selectorPool.open(getName());
     }
 
     // Separated out to make it easier for folks that extend NioEndpoint to
@@ -335,7 +307,7 @@ public class NioEndpoint extends 
AbstractJsseEndpoint<NioChannel,SocketChannel>
 
             // Start poller thread
             poller = new Poller();
-            Thread pollerThread = new Thread(poller, getName() + 
"-ClientPoller");
+            Thread pollerThread = new Thread(poller, getName() + "-Poller");
             pollerThread.setPriority(threadPriority);
             pollerThread.setDaemon(true);
             pollerThread.start();
@@ -406,7 +378,6 @@ public class NioEndpoint extends 
AbstractJsseEndpoint<NioChannel,SocketChannel>
         if (getHandler() != null ) {
             getHandler().recycle();
         }
-        selectorPool.close();
         if (log.isDebugEnabled()) {
             log.debug("Destroy completed for " +
                     new InetSocketAddress(getAddress(), getPortWithOffset()));
@@ -429,6 +400,7 @@ public class NioEndpoint extends 
AbstractJsseEndpoint<NioChannel,SocketChannel>
         }
     }
 
+
     // ------------------------------------------------------ Protected Methods
 
 
@@ -465,11 +437,6 @@ public class NioEndpoint extends 
AbstractJsseEndpoint<NioChannel,SocketChannel>
     }
 
 
-    protected NioSelectorPool getSelectorPool() {
-        return selectorPool;
-    }
-
-
     protected SynchronizedStack<NioChannel> getNioChannels() {
         return nioChannels;
     }
@@ -512,7 +479,7 @@ public class NioEndpoint extends 
AbstractJsseEndpoint<NioChannel,SocketChannel>
                         socketProperties.getAppWriteBufSize(),
                         socketProperties.getDirectBuffer());
                 if (isSSLEnabled()) {
-                    channel = new SecureNioChannel(bufhandler, selectorPool, 
this);
+                    channel = new SecureNioChannel(bufhandler, this);
                 } else {
                     channel = new NioChannel(bufhandler);
                 }
@@ -863,7 +830,7 @@ public class NioEndpoint extends 
AbstractJsseEndpoint<NioChannel,SocketChannel>
             try {
                 if (close) {
                     cancelledKey(sk, socketWrapper);
-                } else if (sk.isValid() && socketWrapper != null) {
+                } else if (sk.isValid()) {
                     if (sk.isReadable() || sk.isWritable()) {
                         if (socketWrapper.getSendfileData() != null) {
                             processSendfile(sk, socketWrapper, false);
@@ -876,6 +843,11 @@ public class NioEndpoint extends 
AbstractJsseEndpoint<NioChannel,SocketChannel>
                                     if 
(!socketWrapper.readOperation.process()) {
                                         closeSocket = true;
                                     }
+                                } else if (socketWrapper.readBlocking) {
+                                    synchronized (socketWrapper.readLock) {
+                                        socketWrapper.readBlocking = false;
+                                        socketWrapper.readLock.notify();
+                                    }
                                 } else if (!processSocket(socketWrapper, 
SocketEvent.OPEN_READ, true)) {
                                     closeSocket = true;
                                 }
@@ -885,6 +857,11 @@ public class NioEndpoint extends 
AbstractJsseEndpoint<NioChannel,SocketChannel>
                                     if 
(!socketWrapper.writeOperation.process()) {
                                         closeSocket = true;
                                     }
+                                } else if (socketWrapper.writeBlocking) {
+                                    synchronized (socketWrapper.writeLock) {
+                                        socketWrapper.writeBlocking = false;
+                                        socketWrapper.writeLock.notify();
+                                    }
                                 } else if (!processSocket(socketWrapper, 
SocketEvent.OPEN_WRITE, true)) {
                                     closeSocket = true;
                                 }
@@ -1117,17 +1094,19 @@ public class NioEndpoint extends 
AbstractJsseEndpoint<NioChannel,SocketChannel>
 
     public static class NioSocketWrapper extends SocketWrapperBase<NioChannel> 
{
 
-        private final NioSelectorPool pool;
         private final SynchronizedStack<NioChannel> nioChannels;
         private final Poller poller;
 
         private int interestOps = 0;
-        private CountDownLatch readLatch = null;
-        private CountDownLatch writeLatch = null;
         private volatile SendfileData sendfileData = null;
         private volatile long lastRead = System.currentTimeMillis();
         private volatile long lastWrite = lastRead;
 
+        private final Object readLock;
+        private volatile boolean readBlocking = false;
+        private final Object writeLock;
+        private volatile boolean writeBlocking = false;
+
         public NioSocketWrapper(NioChannel channel, NioEndpoint endpoint) {
             super(channel, endpoint);
             if (endpoint.getUnixDomainSocketPath() != null) {
@@ -1139,48 +1118,16 @@ public class NioEndpoint extends 
AbstractJsseEndpoint<NioChannel,SocketChannel>
                 remoteHost = "localhost";
                 remotePort = 0;
             }
-            pool = endpoint.getSelectorPool();
             nioChannels = endpoint.getNioChannels();
             poller = endpoint.getPoller();
             socketBufferHandler = channel.getBufHandler();
+            readLock = (readPending == null) ? new Object() : readPending;
+            writeLock = (writePending == null) ? new Object() : writePending;
         }
 
         public Poller getPoller() { return poller; }
         public int interestOps() { return interestOps; }
         public int interestOps(int ops) { this.interestOps  = ops; return ops; 
}
-        public CountDownLatch getReadLatch() { return readLatch; }
-        public CountDownLatch getWriteLatch() { return writeLatch; }
-        protected CountDownLatch resetLatch(CountDownLatch latch) {
-            if (latch == null || latch.getCount() == 0) {
-                return null;
-            } else {
-                throw new 
IllegalStateException(sm.getString("endpoint.nio.latchMustBeZero"));
-            }
-        }
-        public void resetReadLatch() { readLatch = resetLatch(readLatch); }
-        public void resetWriteLatch() { writeLatch = resetLatch(writeLatch); }
-
-        protected CountDownLatch startLatch(CountDownLatch latch, int cnt) {
-            if (latch == null || latch.getCount() == 0) {
-                return new CountDownLatch(cnt);
-            } else {
-                throw new 
IllegalStateException(sm.getString("endpoint.nio.latchMustBeZero"));
-            }
-        }
-        public void startReadLatch(int cnt) { readLatch = 
startLatch(readLatch, cnt); }
-        public void startWriteLatch(int cnt) { writeLatch = 
startLatch(writeLatch, cnt); }
-
-        protected void awaitLatch(CountDownLatch latch, long timeout, TimeUnit 
unit) throws InterruptedException {
-            if (latch == null) {
-                throw new 
IllegalStateException(sm.getString("endpoint.nio.nullLatch"));
-            }
-            // Note: While the return value is ignored if the latch does time
-            //       out, logic further up the call stack will trigger a
-            //       SocketTimeoutException
-            latch.await(timeout, unit);
-        }
-        public void awaitReadLatch(long timeout, TimeUnit unit) throws 
InterruptedException { awaitLatch(readLatch, timeout, unit); }
-        public void awaitWriteLatch(long timeout, TimeUnit unit) throws 
InterruptedException { awaitLatch(writeLatch, timeout, unit); }
 
         public void setSendfileData(SendfileData sf) { this.sendfileData = sf;}
         public SendfileData getSendfileData() { return this.sendfileData; }
@@ -1319,72 +1266,134 @@ public class NioEndpoint extends 
AbstractJsseEndpoint<NioChannel,SocketChannel>
         }
 
 
-        private int fillReadBuffer(boolean block, ByteBuffer to) throws 
IOException {
-            int nRead;
-            NioChannel socket = getSocket();
-            if (socket == NioChannel.CLOSED_NIO_CHANNEL) {
+        private int fillReadBuffer(boolean block, ByteBuffer buffer) throws 
IOException {
+            int n = 0;
+            if (getSocket() == NioChannel.CLOSED_NIO_CHANNEL) {
                 throw new ClosedChannelException();
             }
             if (block) {
-                Selector selector = null;
-                try {
-                    selector = pool.get();
-                } catch (IOException x) {
-                    // Ignore
-                }
-                try {
-                    nRead = pool.read(to, socket, selector, getReadTimeout());
-                } finally {
-                    if (selector != null) {
-                        pool.put(selector);
+                long timeout = getReadTimeout();
+                long startNanos = 0;
+                do {
+                    if (startNanos > 0) {
+                        long elapsedMillis = 
TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNanos);
+                        if (elapsedMillis == 0) {
+                            elapsedMillis = 1;
+                        }
+                        timeout -= elapsedMillis;
+                        if (timeout <= 0) {
+                            throw new SocketTimeoutException();
+                        }
                     }
-                }
+                    n = getSocket().read(buffer);
+                    if (n == -1) {
+                        throw new EOFException();
+                    } else if (n == 0) {
+                        readBlocking = true;
+                        registerReadInterest();
+                        synchronized (readLock) {
+                            if (readBlocking) {
+                                try {
+                                    if (timeout > 0) {
+                                        startNanos = System.nanoTime();
+                                        readLock.wait(timeout);
+                                    } else {
+                                        readLock.wait();
+                                    }
+                                } catch (InterruptedException e) {
+                                    // Continue
+                                }
+                                readBlocking = false;
+                            }
+                        }
+                    }
+                } while (n == 0); // TLS needs to loop as reading zero 
application bytes is possible
             } else {
-                nRead = socket.read(to);
-                if (nRead == -1) {
+                n = getSocket().read(buffer);
+                if (n == -1) {
                     throw new EOFException();
                 }
             }
-            return nRead;
+            return n;
         }
 
 
         @Override
-        protected void doWrite(boolean block, ByteBuffer from) throws 
IOException {
-            NioChannel socket = getSocket();
-            if (socket == NioChannel.CLOSED_NIO_CHANNEL) {
+        protected void doWrite(boolean block, ByteBuffer buffer) throws 
IOException {
+            int n = 0;
+            if (getSocket() == NioChannel.CLOSED_NIO_CHANNEL) {
                 throw new ClosedChannelException();
             }
             if (block) {
-                long writeTimeout = getWriteTimeout();
-                Selector selector = null;
-                try {
-                    selector = pool.get();
-                } catch (IOException x) {
-                    // Ignore
+                if (previousIOException != null) {
+                    /*
+                     * Socket has previously timed out.
+                     *
+                     * Blocking writes assume that buffer is always fully
+                     * written so there is no code checking for incomplete
+                     * writes, retaining the unwritten data and attempting to
+                     * write it as part of a subsequent write call.
+                     *
+                     * Because of the above, when a timeout is triggered we 
need
+                     * so skip subsequent attempts to write as otherwise it 
will
+                     * appear to the client as if some data was dropped just
+                     * before the connection is lost. It is better if the 
client
+                     * just sees the dropped connection.
+                     */
+                    throw new IOException(previousIOException);
                 }
-                try {
-                    pool.write(from, socket, selector, writeTimeout);
-                    // Make sure we are flushed
-                    do {
-                    } while (!socket.flush(true, selector, writeTimeout));
-                } finally {
-                    if (selector != null) {
-                        pool.put(selector);
+                long timeout = getWriteTimeout();
+                long startNanos = 0;
+                do {
+                    if (startNanos > 0) {
+                        long elapsedMillis = 
TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNanos);
+                        if (elapsedMillis == 0) {
+                            elapsedMillis = 1;
+                        }
+                        timeout -= elapsedMillis;
+                        if (timeout <= 0) {
+                            previousIOException = new SocketTimeoutException();
+                            throw previousIOException;
+                        }
                     }
-                }
+                    n = getSocket().write(buffer);
+                    if (n == -1) {
+                        throw new EOFException();
+                    } else if (n == 0) {
+                        writeBlocking = true;
+                        registerWriteInterest();
+                        synchronized (writeLock) {
+                            if (writeBlocking) {
+                                try {
+                                    if (timeout > 0) {
+                                        startNanos = System.nanoTime();
+                                        writeLock.wait(timeout);
+                                    } else {
+                                        writeLock.wait();
+                                    }
+                                } catch (InterruptedException e) {
+                                    // Continue
+                                }
+                                writeBlocking = false;
+                            }
+                        }
+                    } else if (startNanos > 0) {
+                        // If something was written, reset timeout
+                        timeout = getWriteTimeout();
+                        startNanos = 0;
+                    }
+                } while (buffer.hasRemaining());
                 // If there is data left in the buffer the socket will be 
registered for
                 // write further up the stack. This is to ensure the socket is 
only
                 // registered for write once as both container and user code 
can trigger
                 // write registration.
             } else {
-                int n = 0;
                 do {
-                    n = socket.write(from);
+                    n = getSocket().write(buffer);
                     if (n == -1) {
                         throw new EOFException();
                     }
-                } while (n > 0 && from.hasRemaining());
+                } while (n > 0 && buffer.hasRemaining());
             }
             updateLastWrite();
         }
diff --git a/java/org/apache/tomcat/util/net/NioSelectorPool.java 
b/java/org/apache/tomcat/util/net/NioSelectorPool.java
deleted file mode 100644
index e02c14a..0000000
--- a/java/org/apache/tomcat/util/net/NioSelectorPool.java
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tomcat.util.net;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.net.SocketTimeoutException;
-import java.nio.ByteBuffer;
-import java.nio.channels.SelectionKey;
-import java.nio.channels.Selector;
-import java.util.NoSuchElementException;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * Thread safe non blocking selector pool
- */
-public class NioSelectorPool {
-
-    protected NioBlockingSelector blockingSelector;
-
-    protected volatile Selector sharedSelector;
-
-    protected boolean shared = 
Boolean.parseBoolean(System.getProperty("org.apache.tomcat.util.net.NioSelectorShared",
 "true"));
-    protected int maxSelectors = 200;
-    protected long sharedSelectorTimeout = 30000;
-    protected int maxSpareSelectors = -1;
-    protected boolean enabled = true;
-
-    protected AtomicInteger active = new AtomicInteger(0);
-    protected AtomicInteger spare = new AtomicInteger(0);
-    protected ConcurrentLinkedQueue<Selector> selectors = new 
ConcurrentLinkedQueue<>();
-
-    protected Selector getSharedSelector() throws IOException {
-        if (shared && sharedSelector == null) {
-            synchronized (NioSelectorPool.class) {
-                if (sharedSelector == null) {
-                    sharedSelector = Selector.open();
-                }
-            }
-        }
-        return  sharedSelector;
-    }
-
-    public Selector get() throws IOException{
-        if (shared) {
-            return getSharedSelector();
-        }
-        if ((!enabled) || active.incrementAndGet() >= maxSelectors) {
-            if (enabled) {
-                active.decrementAndGet();
-            }
-            return null;
-        }
-        Selector s = null;
-        try {
-            s = selectors.size() > 0 ? selectors.poll() : null;
-            if (s == null) {
-                s = Selector.open();
-            } else {
-                spare.decrementAndGet();
-            }
-        } catch (NoSuchElementException x) {
-            try {
-                s = Selector.open();
-            } catch (IOException iox) {
-            }
-        } finally {
-            if (s == null) {
-                active.decrementAndGet();// we were unable to find a selector
-            }
-        }
-        return s;
-    }
-
-
-
-    public void put(Selector s) throws IOException {
-        if (shared) {
-            return;
-        }
-        if (enabled) {
-            active.decrementAndGet();
-        }
-        if (enabled && (maxSpareSelectors == -1 || spare.get() < 
Math.min(maxSpareSelectors, maxSelectors))) {
-            spare.incrementAndGet();
-            selectors.offer(s);
-        } else {
-            s.close();
-        }
-    }
-
-    public void close() throws IOException {
-        enabled = false;
-        Selector s;
-        while ((s = selectors.poll()) != null) {
-            s.close();
-        }
-        spare.set(0);
-        active.set(0);
-        if (blockingSelector != null) {
-            blockingSelector.close();
-        }
-        if (shared && getSharedSelector() != null) {
-            getSharedSelector().close();
-            sharedSelector = null;
-        }
-    }
-
-    public void open(String name) throws IOException {
-        enabled = true;
-        getSharedSelector();
-        if (shared) {
-            blockingSelector = new NioBlockingSelector();
-            blockingSelector.open(name, getSharedSelector());
-        }
-
-    }
-
-    /**
-     * Performs a write using the bytebuffer for data to be written and a
-     * selector to block (if blocking is requested). If the
-     * <code>selector</code> parameter is null, and blocking is requested then
-     * it will perform a busy write that could take up a lot of CPU cycles.
-     * @param buf           The buffer containing the data, we will write as 
long as <code>(buf.hasRemaining()==true)</code>
-     * @param socket        The socket to write data to
-     * @param selector      The selector to use for blocking, if null then a 
busy write will be initiated
-     * @param writeTimeout  The timeout for this write operation in 
milliseconds, -1 means no timeout
-     * @return the number of bytes written
-     * @throws EOFException if write returns -1
-     * @throws SocketTimeoutException if the write times out
-     * @throws IOException if an IO Exception occurs in the underlying socket 
logic
-     */
-    public int write(ByteBuffer buf, NioChannel socket, Selector selector, 
long writeTimeout)
-            throws IOException {
-        if (shared) {
-            return blockingSelector.write(buf, socket, writeTimeout);
-        }
-        if (socket.getSocketWrapper().previousIOException != null) {
-            /*
-             * Socket has previously seen an IOException on write.
-             *
-             * Blocking writes assume that buffer is always fully written so
-             * there is no code checking for incomplete writes, retaining
-             * the unwritten data and attempting to write it as part of a
-             * subsequent write call.
-             *
-             * Because of the above, when an IOException is triggered we
-             * need so skip subsequent attempts to write as otherwise it
-             * will appear to the client as if some data was dropped just
-             * before the connection is lost. It is better if the client
-             * just sees the dropped connection.
-             */
-            throw new 
IOException(socket.getSocketWrapper().previousIOException);
-        }
-        SelectionKey key = null;
-        int written = 0;
-        boolean timedout = false;
-        int keycount = 1; //assume we can write
-        long time = System.currentTimeMillis(); //start the timeout timer
-        try {
-            while ((!timedout) && buf.hasRemaining()) {
-                int cnt = 0;
-                if ( keycount > 0 ) { //only write if we were registered for a 
write
-                    cnt = socket.write(buf); //write the data
-                    if (cnt == -1) {
-                        throw new EOFException();
-                    }
-
-                    written += cnt;
-                    if (cnt > 0) {
-                        time = System.currentTimeMillis(); //reset our timeout 
timer
-                        continue; //we successfully wrote, try again without a 
selector
-                    }
-                }
-                if (selector != null) {
-                    //register OP_WRITE to the selector
-                    if (key == null) {
-                        key = socket.getIOChannel().register(selector, 
SelectionKey.OP_WRITE);
-                    } else {
-                        key.interestOps(SelectionKey.OP_WRITE);
-                    }
-                    if (writeTimeout == 0) {
-                        timedout = buf.hasRemaining();
-                    } else if (writeTimeout < 0) {
-                        keycount = selector.select();
-                    } else {
-                        keycount = selector.select(writeTimeout);
-                    }
-                }
-                if (writeTimeout > 0 && (selector == null || keycount == 0)) {
-                    timedout = (System.currentTimeMillis() - time) >= 
writeTimeout;
-                }
-            }
-            if (timedout) {
-                socket.getSocketWrapper().previousIOException = new 
SocketTimeoutException();
-                throw socket.getSocketWrapper().previousIOException;
-            }
-        } finally {
-            if (key != null) {
-                key.cancel();
-                if (selector != null)
-                 {
-                    selector.selectNow();//removes the key from this selector
-                }
-            }
-        }
-        return written;
-    }
-
-    /**
-     * Performs a blocking read using the bytebuffer for data to be read and a 
selector to block.
-     * If the <code>selector</code> parameter is null, then it will perform a 
busy read that could
-     * take up a lot of CPU cycles.
-     * @param buf ByteBuffer - the buffer containing the data, we will read as 
until we have read at least one byte or we timed out
-     * @param socket SocketChannel - the socket to write data to
-     * @param selector Selector - the selector to use for blocking, if null 
then a busy read will be initiated
-     * @param readTimeout long - the timeout for this read operation in 
milliseconds, -1 means no timeout
-     * @return the number of bytes read
-     * @throws EOFException if read returns -1
-     * @throws SocketTimeoutException if the read times out
-     * @throws IOException if an IO Exception occurs in the underlying socket 
logic
-     */
-    public int read(ByteBuffer buf, NioChannel socket, Selector selector, long 
readTimeout)
-            throws IOException {
-        if (shared) {
-            return blockingSelector.read(buf, socket, readTimeout);
-        }
-        SelectionKey key = null;
-        int read = 0;
-        boolean timedout = false;
-        int keycount = 1; //assume we can write
-        long time = System.currentTimeMillis(); //start the timeout timer
-        try {
-            while (!timedout) {
-                int cnt = 0;
-                if (keycount > 0) { //only read if we were registered for a 
read
-                    cnt = socket.read(buf);
-                    if (cnt == -1) {
-                        if (read == 0) {
-                            read = -1;
-                        }
-                        break;
-                    }
-                    read += cnt;
-                    if (cnt > 0)
-                     {
-                        continue; //read some more
-                    }
-                    if (cnt == 0 && read > 0) {
-                        break; //we are done reading
-                    }
-                }
-                if (selector != null) {//perform a blocking read
-                    //register OP_WRITE to the selector
-                    if (key == null) {
-                        key = socket.getIOChannel().register(selector, 
SelectionKey.OP_READ);
-                    } else {
-                        key.interestOps(SelectionKey.OP_READ);
-                    }
-                    if (readTimeout == 0) {
-                        timedout = (read == 0);
-                    } else if (readTimeout < 0) {
-                        keycount = selector.select();
-                    } else {
-                        keycount = selector.select(readTimeout);
-                    }
-                }
-                if (readTimeout > 0 && (selector == null || keycount == 0)) {
-                    timedout = (System.currentTimeMillis() - time) >= 
readTimeout;
-                }
-            }
-            if (timedout) {
-                throw new SocketTimeoutException();
-            }
-        } finally {
-            if (key != null) {
-                key.cancel();
-                if (selector != null) {
-                    selector.selectNow();//removes the key from this selector
-                }
-            }
-        }
-        return read;
-    }
-
-    public void setMaxSelectors(int maxSelectors) {
-        this.maxSelectors = maxSelectors;
-    }
-
-    public void setMaxSpareSelectors(int maxSpareSelectors) {
-        this.maxSpareSelectors = maxSpareSelectors;
-    }
-
-    public void setEnabled(boolean enabled) {
-        this.enabled = enabled;
-    }
-
-    public void setSharedSelectorTimeout(long sharedSelectorTimeout) {
-        this.sharedSelectorTimeout = sharedSelectorTimeout;
-    }
-
-    public int getMaxSelectors() {
-        return maxSelectors;
-    }
-
-    public int getMaxSpareSelectors() {
-        return maxSpareSelectors;
-    }
-
-    public boolean isEnabled() {
-        return enabled;
-    }
-
-    public long getSharedSelectorTimeout() {
-        return sharedSelectorTimeout;
-    }
-
-    public ConcurrentLinkedQueue<Selector> getSelectors() {
-        return selectors;
-    }
-
-    public AtomicInteger getSpare() {
-        return spare;
-    }
-
-    public boolean isShared() {
-        return shared;
-    }
-
-    public void setShared(boolean shared) {
-        this.shared = shared;
-    }
-}
diff --git a/java/org/apache/tomcat/util/net/SecureNioChannel.java 
b/java/org/apache/tomcat/util/net/SecureNioChannel.java
index 7a5b203..277193b 100644
--- a/java/org/apache/tomcat/util/net/SecureNioChannel.java
+++ b/java/org/apache/tomcat/util/net/SecureNioChannel.java
@@ -73,9 +73,7 @@ public class SecureNioChannel extends NioChannel {
 
     private final Map<String,List<String>> additionalTlsAttributes = new 
HashMap<>();
 
-    protected NioSelectorPool pool;
-
-    public SecureNioChannel(SocketBufferHandler bufHandler, NioSelectorPool 
pool, NioEndpoint endpoint) {
+    public SecureNioChannel(SocketBufferHandler bufHandler, NioEndpoint 
endpoint) {
         super(bufHandler);
 
         // Create the network buffers (these hold the encrypted data).
@@ -87,8 +85,6 @@ public class SecureNioChannel extends NioChannel {
             netOutBuffer = ByteBuffer.allocate(DEFAULT_NET_BUFFER_SIZE);
         }
 
-        // selector pool for blocking operations
-        this.pool = pool;
         this.endpoint = endpoint;
     }
 
@@ -117,28 +113,6 @@ public class SecureNioChannel extends NioChannel {
 
//===========================================================================================
 
     /**
-     * Flush the channel.
-     *
-     * @param block     Should a blocking write be used?
-     * @param s         The selector to use for blocking, if null then a busy
-     *                  write will be initiated
-     * @param timeout   The timeout for this write operation in milliseconds,
-     *                  -1 means no timeout
-     * @return <code>true</code> if the network buffer has been flushed out and
-     *         is empty else <code>false</code>
-     * @throws IOException If an I/O error occurs during the operation
-     */
-    @Override
-    public boolean flush(boolean block, Selector s, long timeout) throws 
IOException {
-        if (!block) {
-            flush(netOutBuffer);
-        } else {
-            pool.write(netOutBuffer, this, s, timeout);
-        }
-        return !netOutBuffer.hasRemaining();
-    }
-
-    /**
      * Flushes the buffer to the network, non blocking
      * @param buf ByteBuffer
      * @return boolean true if the buffer has been emptied out, false otherwise
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 1855d4a..91731c9 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -170,6 +170,10 @@
       <update>
         Simplify AprEndpoint socket bind for all platforms. (michaelo)
       </update>
+      <update>
+        Add back simplification of NIO block read and write, now better
+        validated in Tomcat 10. (remm)
+      </update>
     </changelog>
   </subsection>
   <subsection name="Jasper">
diff --git a/webapps/docs/config/http.xml b/webapps/docs/config/http.xml
index d9ee92f..054b8e6 100644
--- a/webapps/docs/config/http.xml
+++ b/webapps/docs/config/http.xml
@@ -903,31 +903,6 @@
         <code>-1</code> for unlimited cache and <code>0</code> for no 
cache.</p>
       </attribute>
 
-      <attribute name="selectorPool.maxSelectors" required="false">
-        <p>(int)The max selectors to be used in the pool, to reduce selector
-        contention. Use this option when the command line
-        <code>org.apache.tomcat.util.net.NioSelectorShared</code> value is set
-        to false. Default value is <code>200</code>.</p>
-      </attribute>
-
-      <attribute name="selectorPool.maxSpareSelectors" required="false">
-        <p>(int)The max spare selectors to be used in the pool, to reduce
-        selector contention. When a selector is returned to the pool, the 
system
-        can decide to keep it or let it be GC'd. Use this option when the
-        command line <code>org.apache.tomcat.util.net.NioSelectorShared</code>
-        value is set to false. Default value is <code>-1</code> 
(unlimited).</p>
-      </attribute>
-
-      <attribute name="selectorPool.shared" required="false">
-        <p>(bool)Set this value to <code>false</code> if you wish to
-        use a selector for each thread. When you set it to <code>false</code>, 
you can
-        control the size of the pool of selectors by using the
-        <strong>selectorPool.maxSelectors</strong> attribute.
-        Default is <code>true</code> or the value of the
-        <code>org.apache.tomcat.util.net.NioSelectorShared</code> system
-        property if present.</p>
-      </attribute>
-
       <attribute name="unixDomainSocketPath" required="false">
         <p>Where supported, the path to a Unix Domain Socket that this
         <strong>Connector</strong> will create and await incoming connections.
@@ -955,16 +930,6 @@
         more details.</p>
       </attribute>
 
-      <attribute name="command-line-options" required="false">
-        <p>The following command line options are available for the NIO
-        connector:<br/>
-        <code>-Dorg.apache.tomcat.util.net.NioSelectorShared=true|false</code>
-        - default is <code>true</code>. Set this value to <code>false</code> 
if you wish to
-        use a selector for each thread. When you set it to <code>false</code>, 
you can
-        control the size of the pool of selectors by using the
-        <strong>selectorPool.maxSelectors</strong> attribute.</p>
-      </attribute>
-
     </attributes>
   </subsection>
 

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

Reply via email to