Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/nio/ch/Invoker.java
38918 views
/*1* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.nio.ch;2627import java.nio.channels.*;28import java.util.concurrent.*;29import java.security.AccessController;30import sun.security.action.GetIntegerAction;3132/**33* Defines static methods to invoke a completion handler or arbitrary task.34*/3536class Invoker {37private Invoker() { }3839// maximum number of completion handlers that may be invoked on the current40// thread before it re-directs invocations to the thread pool. This helps41// avoid stack overflow and lessens the risk of starvation.42private static final int maxHandlerInvokeCount = AccessController.doPrivileged(43new GetIntegerAction("sun.nio.ch.maxCompletionHandlersOnStack", 16));4445// Per-thread object with reference to channel group and a counter for46// the number of completion handlers invoked. This should be reset to 047// when all completion handlers have completed.48static class GroupAndInvokeCount {49private final AsynchronousChannelGroupImpl group;50private int handlerInvokeCount;51GroupAndInvokeCount(AsynchronousChannelGroupImpl group) {52this.group = group;53}54AsynchronousChannelGroupImpl group() {55return group;56}57int invokeCount() {58return handlerInvokeCount;59}60void setInvokeCount(int value) {61handlerInvokeCount = value;62}63void resetInvokeCount() {64handlerInvokeCount = 0;65}66void incrementInvokeCount() {67handlerInvokeCount++;68}69}70private static final ThreadLocal<GroupAndInvokeCount> myGroupAndInvokeCount =71new ThreadLocal<GroupAndInvokeCount>() {72@Override protected GroupAndInvokeCount initialValue() {73return null;74}75};7677/**78* Binds this thread to the given group79*/80static void bindToGroup(AsynchronousChannelGroupImpl group) {81myGroupAndInvokeCount.set(new GroupAndInvokeCount(group));82}8384/**85* Returns the GroupAndInvokeCount object for this thread.86*/87static GroupAndInvokeCount getGroupAndInvokeCount() {88return myGroupAndInvokeCount.get();89}9091/**92* Returns true if the current thread is in a channel group's thread pool93*/94static boolean isBoundToAnyGroup() {95return myGroupAndInvokeCount.get() != null;96}9798/**99* Returns true if the current thread is in the given channel's thread100* pool and we haven't exceeded the maximum number of handler frames on101* the stack.102*/103static boolean mayInvokeDirect(GroupAndInvokeCount myGroupAndInvokeCount,104AsynchronousChannelGroupImpl group)105{106if ((myGroupAndInvokeCount != null) &&107(myGroupAndInvokeCount.group() == group) &&108(myGroupAndInvokeCount.invokeCount() < maxHandlerInvokeCount))109{110return true;111}112return false;113}114115/**116* Invoke handler without checking the thread identity or number of handlers117* on the thread stack.118*/119static <V,A> void invokeUnchecked(CompletionHandler<V,? super A> handler,120A attachment,121V value,122Throwable exc)123{124if (exc == null) {125handler.completed(value, attachment);126} else {127handler.failed(exc, attachment);128}129130// clear interrupt131Thread.interrupted();132133// clear thread locals when in default thread pool134if (System.getSecurityManager() != null) {135Thread me = Thread.currentThread();136if (me instanceof sun.misc.InnocuousThread) {137GroupAndInvokeCount thisGroupAndInvokeCount = myGroupAndInvokeCount.get();138((sun.misc.InnocuousThread)me).eraseThreadLocals();139if (thisGroupAndInvokeCount != null) {140myGroupAndInvokeCount.set(thisGroupAndInvokeCount);141}142}143}144}145146/**147* Invoke handler assuming thread identity already checked148*/149static <V,A> void invokeDirect(GroupAndInvokeCount myGroupAndInvokeCount,150CompletionHandler<V,? super A> handler,151A attachment,152V result,153Throwable exc)154{155myGroupAndInvokeCount.incrementInvokeCount();156Invoker.invokeUnchecked(handler, attachment, result, exc);157}158159/**160* Invokes the handler. If the current thread is in the channel group's161* thread pool then the handler is invoked directly, otherwise it is162* invoked indirectly.163*/164static <V,A> void invoke(AsynchronousChannel channel,165CompletionHandler<V,? super A> handler,166A attachment,167V result,168Throwable exc)169{170boolean invokeDirect = false;171boolean identityOkay = false;172GroupAndInvokeCount thisGroupAndInvokeCount = myGroupAndInvokeCount.get();173if (thisGroupAndInvokeCount != null) {174if ((thisGroupAndInvokeCount.group() == ((Groupable)channel).group()))175identityOkay = true;176if (identityOkay &&177(thisGroupAndInvokeCount.invokeCount() < maxHandlerInvokeCount))178{179// group match180invokeDirect = true;181}182}183if (invokeDirect) {184invokeDirect(thisGroupAndInvokeCount, handler, attachment, result, exc);185} else {186try {187invokeIndirectly(channel, handler, attachment, result, exc);188} catch (RejectedExecutionException ree) {189// channel group shutdown; fallback to invoking directly190// if the current thread has the right identity.191if (identityOkay) {192invokeDirect(thisGroupAndInvokeCount,193handler, attachment, result, exc);194} else {195throw new ShutdownChannelGroupException();196}197}198}199}200201/**202* Invokes the handler indirectly via the channel group's thread pool.203*/204static <V,A> void invokeIndirectly(AsynchronousChannel channel,205final CompletionHandler<V,? super A> handler,206final A attachment,207final V result,208final Throwable exc)209{210try {211((Groupable)channel).group().executeOnPooledThread(new Runnable() {212public void run() {213GroupAndInvokeCount thisGroupAndInvokeCount =214myGroupAndInvokeCount.get();215if (thisGroupAndInvokeCount != null)216thisGroupAndInvokeCount.setInvokeCount(1);217invokeUnchecked(handler, attachment, result, exc);218}219});220} catch (RejectedExecutionException ree) {221throw new ShutdownChannelGroupException();222}223}224225/**226* Invokes the handler "indirectly" in the given Executor227*/228static <V,A> void invokeIndirectly(final CompletionHandler<V,? super A> handler,229final A attachment,230final V value,231final Throwable exc,232Executor executor)233{234try {235executor.execute(new Runnable() {236public void run() {237invokeUnchecked(handler, attachment, value, exc);238}239});240} catch (RejectedExecutionException ree) {241throw new ShutdownChannelGroupException();242}243}244245/**246* Invokes the given task on the thread pool associated with the given247* channel. If the current thread is in the thread pool then the task is248* invoked directly.249*/250static void invokeOnThreadInThreadPool(Groupable channel,251Runnable task)252{253boolean invokeDirect;254GroupAndInvokeCount thisGroupAndInvokeCount = myGroupAndInvokeCount.get();255AsynchronousChannelGroupImpl targetGroup = channel.group();256if (thisGroupAndInvokeCount == null) {257invokeDirect = false;258} else {259invokeDirect = (thisGroupAndInvokeCount.group == targetGroup);260}261try {262if (invokeDirect) {263task.run();264} else {265targetGroup.executeOnPooledThread(task);266}267} catch (RejectedExecutionException ree) {268throw new ShutdownChannelGroupException();269}270}271272/**273* Invoke handler with completed result. This method does not check the274* thread identity or the number of handlers on the thread stack.275*/276static <V,A> void invokeUnchecked(PendingFuture<V,A> future) {277assert future.isDone();278CompletionHandler<V,? super A> handler = future.handler();279if (handler != null) {280invokeUnchecked(handler,281future.attachment(),282future.value(),283future.exception());284}285}286287/**288* Invoke handler with completed result. If the current thread is in the289* channel group's thread pool then the handler is invoked directly,290* otherwise it is invoked indirectly.291*/292static <V,A> void invoke(PendingFuture<V,A> future) {293assert future.isDone();294CompletionHandler<V,? super A> handler = future.handler();295if (handler != null) {296invoke(future.channel(),297handler,298future.attachment(),299future.value(),300future.exception());301}302}303304/**305* Invoke handler with completed result. The handler is invoked indirectly,306* via the channel group's thread pool.307*/308static <V,A> void invokeIndirectly(PendingFuture<V,A> future) {309assert future.isDone();310CompletionHandler<V,? super A> handler = future.handler();311if (handler != null) {312invokeIndirectly(future.channel(),313handler,314future.attachment(),315future.value(),316future.exception());317}318}319}320321322