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 <[email protected]>
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: [email protected]
For additional commands, e-mail: [email protected]