| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
package sun.nio.ch;  | 
 | 
 | 
 | 
import java.nio.channels.*;  | 
 | 
import java.util.concurrent.*;  | 
 | 
import java.security.AccessController;  | 
 | 
import sun.security.action.GetIntegerAction;  | 
 | 
 | 
 | 
/**  | 
 | 
 * 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 sun.misc.InnocuousThread) { | 
 | 
                GroupAndInvokeCount thisGroupAndInvokeCount = myGroupAndInvokeCount.get();  | 
 | 
                ((sun.misc.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());  | 
 | 
        }  | 
 | 
    }  | 
 | 
}  |