|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.nio.ch; |
|
|
|
import java.nio.channels.*; |
|
import java.util.concurrent.*; |
|
import java.security.AccessController; |
|
import sun.security.action.GetIntegerAction; |
|
import jdk.internal.misc.InnocuousThread; |
|
|
|
/** |
|
* Defines static methods to invoke a completion handler or arbitrary task. |
|
*/ |
|
|
|
class Invoker { |
|
private Invoker() { } |
|
|
|
// maximum number of completion handlers that may be invoked on the current |
|
// thread before it re-directs invocations to the thread pool. This helps |
|
|
|
private static final int maxHandlerInvokeCount = AccessController.doPrivileged( |
|
new GetIntegerAction("sun.nio.ch.maxCompletionHandlersOnStack", 16)); |
|
|
|
// Per-thread object with reference to channel group and a counter for |
|
// the number of completion handlers invoked. This should be reset to 0 |
|
|
|
static class GroupAndInvokeCount { |
|
private final AsynchronousChannelGroupImpl group; |
|
private int handlerInvokeCount; |
|
GroupAndInvokeCount(AsynchronousChannelGroupImpl group) { |
|
this.group = group; |
|
} |
|
AsynchronousChannelGroupImpl group() { |
|
return group; |
|
} |
|
int invokeCount() { |
|
return handlerInvokeCount; |
|
} |
|
void setInvokeCount(int value) { |
|
handlerInvokeCount = value; |
|
} |
|
void resetInvokeCount() { |
|
handlerInvokeCount = 0; |
|
} |
|
void incrementInvokeCount() { |
|
handlerInvokeCount++; |
|
} |
|
} |
|
private static final ThreadLocal<GroupAndInvokeCount> myGroupAndInvokeCount = |
|
new ThreadLocal<GroupAndInvokeCount>() { |
|
@Override protected GroupAndInvokeCount initialValue() { |
|
return null; |
|
} |
|
}; |
|
|
|
|
|
|
|
*/ |
|
static void bindToGroup(AsynchronousChannelGroupImpl group) { |
|
myGroupAndInvokeCount.set(new GroupAndInvokeCount(group)); |
|
} |
|
|
|
|
|
|
|
*/ |
|
static GroupAndInvokeCount getGroupAndInvokeCount() { |
|
return myGroupAndInvokeCount.get(); |
|
} |
|
|
|
|
|
|
|
*/ |
|
static boolean isBoundToAnyGroup() { |
|
return myGroupAndInvokeCount.get() != null; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static boolean mayInvokeDirect(GroupAndInvokeCount myGroupAndInvokeCount, |
|
AsynchronousChannelGroupImpl group) |
|
{ |
|
if ((myGroupAndInvokeCount != null) && |
|
(myGroupAndInvokeCount.group() == group) && |
|
(myGroupAndInvokeCount.invokeCount() < maxHandlerInvokeCount)) |
|
{ |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
static <V,A> void invokeUnchecked(CompletionHandler<V,? super A> handler, |
|
A attachment, |
|
V value, |
|
Throwable exc) |
|
{ |
|
if (exc == null) { |
|
handler.completed(value, attachment); |
|
} else { |
|
handler.failed(exc, attachment); |
|
} |
|
|
|
|
|
Thread.interrupted(); |
|
|
|
|
|
if (System.getSecurityManager() != null) { |
|
Thread me = Thread.currentThread(); |
|
if (me instanceof InnocuousThread) { |
|
GroupAndInvokeCount thisGroupAndInvokeCount = myGroupAndInvokeCount.get(); |
|
((InnocuousThread)me).eraseThreadLocals(); |
|
if (thisGroupAndInvokeCount != null) { |
|
myGroupAndInvokeCount.set(thisGroupAndInvokeCount); |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
static <V,A> void invokeDirect(GroupAndInvokeCount myGroupAndInvokeCount, |
|
CompletionHandler<V,? super A> handler, |
|
A attachment, |
|
V result, |
|
Throwable exc) |
|
{ |
|
myGroupAndInvokeCount.incrementInvokeCount(); |
|
Invoker.invokeUnchecked(handler, attachment, result, exc); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static <V,A> void invoke(AsynchronousChannel channel, |
|
CompletionHandler<V,? super A> handler, |
|
A attachment, |
|
V result, |
|
Throwable exc) |
|
{ |
|
boolean invokeDirect = false; |
|
boolean identityOkay = false; |
|
GroupAndInvokeCount thisGroupAndInvokeCount = myGroupAndInvokeCount.get(); |
|
if (thisGroupAndInvokeCount != null) { |
|
if ((thisGroupAndInvokeCount.group() == ((Groupable)channel).group())) |
|
identityOkay = true; |
|
if (identityOkay && |
|
(thisGroupAndInvokeCount.invokeCount() < maxHandlerInvokeCount)) |
|
{ |
|
|
|
invokeDirect = true; |
|
} |
|
} |
|
if (invokeDirect) { |
|
invokeDirect(thisGroupAndInvokeCount, handler, attachment, result, exc); |
|
} else { |
|
try { |
|
invokeIndirectly(channel, handler, attachment, result, exc); |
|
} catch (RejectedExecutionException ree) { |
|
// channel group shutdown; fallback to invoking directly |
|
|
|
if (identityOkay) { |
|
invokeDirect(thisGroupAndInvokeCount, |
|
handler, attachment, result, exc); |
|
} else { |
|
throw new ShutdownChannelGroupException(); |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
static <V,A> void invokeIndirectly(AsynchronousChannel channel, |
|
final CompletionHandler<V,? super A> handler, |
|
final A attachment, |
|
final V result, |
|
final Throwable exc) |
|
{ |
|
try { |
|
((Groupable)channel).group().executeOnPooledThread(new Runnable() { |
|
public void run() { |
|
GroupAndInvokeCount thisGroupAndInvokeCount = |
|
myGroupAndInvokeCount.get(); |
|
if (thisGroupAndInvokeCount != null) |
|
thisGroupAndInvokeCount.setInvokeCount(1); |
|
invokeUnchecked(handler, attachment, result, exc); |
|
} |
|
}); |
|
} catch (RejectedExecutionException ree) { |
|
throw new ShutdownChannelGroupException(); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
static <V,A> void invokeIndirectly(final CompletionHandler<V,? super A> handler, |
|
final A attachment, |
|
final V value, |
|
final Throwable exc, |
|
Executor executor) |
|
{ |
|
try { |
|
executor.execute(new Runnable() { |
|
public void run() { |
|
invokeUnchecked(handler, attachment, value, exc); |
|
} |
|
}); |
|
} catch (RejectedExecutionException ree) { |
|
throw new ShutdownChannelGroupException(); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static void invokeOnThreadInThreadPool(Groupable channel, |
|
Runnable task) |
|
{ |
|
boolean invokeDirect; |
|
GroupAndInvokeCount thisGroupAndInvokeCount = myGroupAndInvokeCount.get(); |
|
AsynchronousChannelGroupImpl targetGroup = channel.group(); |
|
if (thisGroupAndInvokeCount == null) { |
|
invokeDirect = false; |
|
} else { |
|
invokeDirect = (thisGroupAndInvokeCount.group == targetGroup); |
|
} |
|
try { |
|
if (invokeDirect) { |
|
task.run(); |
|
} else { |
|
targetGroup.executeOnPooledThread(task); |
|
} |
|
} catch (RejectedExecutionException ree) { |
|
throw new ShutdownChannelGroupException(); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
static <V,A> void invokeUnchecked(PendingFuture<V,A> future) { |
|
assert future.isDone(); |
|
CompletionHandler<V,? super A> handler = future.handler(); |
|
if (handler != null) { |
|
invokeUnchecked(handler, |
|
future.attachment(), |
|
future.value(), |
|
future.exception()); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static <V,A> void invoke(PendingFuture<V,A> future) { |
|
assert future.isDone(); |
|
CompletionHandler<V,? super A> handler = future.handler(); |
|
if (handler != null) { |
|
invoke(future.channel(), |
|
handler, |
|
future.attachment(), |
|
future.value(), |
|
future.exception()); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
static <V,A> void invokeIndirectly(PendingFuture<V,A> future) { |
|
assert future.isDone(); |
|
CompletionHandler<V,? super A> handler = future.handler(); |
|
if (handler != null) { |
|
invokeIndirectly(future.channel(), |
|
handler, |
|
future.attachment(), |
|
future.value(), |
|
future.exception()); |
|
} |
|
} |
|
} |