jdk/src/share/classes/java/util/concurrent/ForkJoinWorkerThread.java
changeset 22070 9a4f43c9b15a
parent 18790 d25399d849bc
equal deleted inserted replaced
22010:a1ee9743f4ee 22070:9a4f43c9b15a
    32  * Expert Group and released to the public domain, as explained at
    32  * Expert Group and released to the public domain, as explained at
    33  * http://creativecommons.org/publicdomain/zero/1.0/
    33  * http://creativecommons.org/publicdomain/zero/1.0/
    34  */
    34  */
    35 
    35 
    36 package java.util.concurrent;
    36 package java.util.concurrent;
       
    37 
       
    38 import java.security.AccessControlContext;
       
    39 import java.security.ProtectionDomain;
    37 
    40 
    38 /**
    41 /**
    39  * A thread managed by a {@link ForkJoinPool}, which executes
    42  * A thread managed by a {@link ForkJoinPool}, which executes
    40  * {@link ForkJoinTask}s.
    43  * {@link ForkJoinTask}s.
    41  * This class is subclassable solely for the sake of adding
    44  * This class is subclassable solely for the sake of adding
    59      * pool field is set immediately upon construction, but the
    62      * pool field is set immediately upon construction, but the
    60      * workQueue field is not set until a call to registerWorker
    63      * workQueue field is not set until a call to registerWorker
    61      * completes. This leads to a visibility race, that is tolerated
    64      * completes. This leads to a visibility race, that is tolerated
    62      * by requiring that the workQueue field is only accessed by the
    65      * by requiring that the workQueue field is only accessed by the
    63      * owning thread.
    66      * owning thread.
       
    67      *
       
    68      * Support for (non-public) subclass InnocuousForkJoinWorkerThread
       
    69      * requires that we break quite a lot of encapulation (via Unsafe)
       
    70      * both here and in the subclass to access and set Thread fields.
    64      */
    71      */
    65 
    72 
    66     final ForkJoinPool pool;                // the pool this thread works in
    73     final ForkJoinPool pool;                // the pool this thread works in
    67     final ForkJoinPool.WorkQueue workQueue; // work-stealing mechanics
    74     final ForkJoinPool.WorkQueue workQueue; // work-stealing mechanics
    68 
    75 
    73      * @throws NullPointerException if pool is null
    80      * @throws NullPointerException if pool is null
    74      */
    81      */
    75     protected ForkJoinWorkerThread(ForkJoinPool pool) {
    82     protected ForkJoinWorkerThread(ForkJoinPool pool) {
    76         // Use a placeholder until a useful name can be set in registerWorker
    83         // Use a placeholder until a useful name can be set in registerWorker
    77         super("aForkJoinWorkerThread");
    84         super("aForkJoinWorkerThread");
       
    85         this.pool = pool;
       
    86         this.workQueue = pool.registerWorker(this);
       
    87     }
       
    88 
       
    89     /**
       
    90      * Version for InnocuousForkJoinWorkerThread
       
    91      */
       
    92     ForkJoinWorkerThread(ForkJoinPool pool, ThreadGroup threadGroup,
       
    93                          AccessControlContext acc) {
       
    94         super(threadGroup, null, "aForkJoinWorkerThread");
       
    95         U.putOrderedObject(this, INHERITEDACCESSCONTROLCONTEXT, acc);
       
    96         eraseThreadLocals(); // clear before registering
    78         this.pool = pool;
    97         this.pool = pool;
    79         this.workQueue = pool.registerWorker(this);
    98         this.workQueue = pool.registerWorker(this);
    80     }
    99     }
    81 
   100 
    82     /**
   101     /**
   129      * This method is required to be public, but should never be
   148      * This method is required to be public, but should never be
   130      * called explicitly. It performs the main run loop to execute
   149      * called explicitly. It performs the main run loop to execute
   131      * {@link ForkJoinTask}s.
   150      * {@link ForkJoinTask}s.
   132      */
   151      */
   133     public void run() {
   152     public void run() {
   134         Throwable exception = null;
   153         if (workQueue.array == null) { // only run once
       
   154             Throwable exception = null;
       
   155             try {
       
   156                 onStart();
       
   157                 pool.runWorker(workQueue);
       
   158             } catch (Throwable ex) {
       
   159                 exception = ex;
       
   160             } finally {
       
   161                 try {
       
   162                     onTermination(exception);
       
   163                 } catch (Throwable ex) {
       
   164                     if (exception == null)
       
   165                         exception = ex;
       
   166                 } finally {
       
   167                     pool.deregisterWorker(this, exception);
       
   168                 }
       
   169             }
       
   170         }
       
   171     }
       
   172 
       
   173     /**
       
   174      * Erases ThreadLocals by nulling out Thread maps
       
   175      */
       
   176     final void eraseThreadLocals() {
       
   177         U.putObject(this, THREADLOCALS, null);
       
   178         U.putObject(this, INHERITABLETHREADLOCALS, null);
       
   179     }
       
   180 
       
   181     /**
       
   182      * Non-public hook method for InnocuousForkJoinWorkerThread
       
   183      */
       
   184     void afterTopLevelExec() {
       
   185     }
       
   186 
       
   187     // Set up to allow setting thread fields in constructor
       
   188     private static final sun.misc.Unsafe U;
       
   189     private static final long THREADLOCALS;
       
   190     private static final long INHERITABLETHREADLOCALS;
       
   191     private static final long INHERITEDACCESSCONTROLCONTEXT;
       
   192     static {
   135         try {
   193         try {
   136             onStart();
   194             U = sun.misc.Unsafe.getUnsafe();
   137             pool.runWorker(workQueue);
   195             Class<?> tk = Thread.class;
   138         } catch (Throwable ex) {
   196             THREADLOCALS = U.objectFieldOffset
   139             exception = ex;
   197                 (tk.getDeclaredField("threadLocals"));
   140         } finally {
   198             INHERITABLETHREADLOCALS = U.objectFieldOffset
       
   199                 (tk.getDeclaredField("inheritableThreadLocals"));
       
   200             INHERITEDACCESSCONTROLCONTEXT = U.objectFieldOffset
       
   201                 (tk.getDeclaredField("inheritedAccessControlContext"));
       
   202 
       
   203         } catch (Exception e) {
       
   204             throw new Error(e);
       
   205         }
       
   206     }
       
   207 
       
   208     /**
       
   209      * A worker thread that has no permissions, is not a member of any
       
   210      * user-defined ThreadGroup, and erases all ThreadLocals after
       
   211      * running each top-level task.
       
   212      */
       
   213     static final class InnocuousForkJoinWorkerThread extends ForkJoinWorkerThread {
       
   214         /** The ThreadGroup for all InnocuousForkJoinWorkerThreads */
       
   215         private static final ThreadGroup innocuousThreadGroup =
       
   216             createThreadGroup();
       
   217 
       
   218         /** An AccessControlContext supporting no privileges */
       
   219         private static final AccessControlContext INNOCUOUS_ACC =
       
   220             new AccessControlContext(
       
   221                 new ProtectionDomain[] {
       
   222                     new ProtectionDomain(null, null)
       
   223                 });
       
   224 
       
   225         InnocuousForkJoinWorkerThread(ForkJoinPool pool) {
       
   226             super(pool, innocuousThreadGroup, INNOCUOUS_ACC);
       
   227         }
       
   228 
       
   229         @Override // to erase ThreadLocals
       
   230         void afterTopLevelExec() {
       
   231             eraseThreadLocals();
       
   232         }
       
   233 
       
   234         @Override // to always report system loader
       
   235         public ClassLoader getContextClassLoader() {
       
   236             return ClassLoader.getSystemClassLoader();
       
   237         }
       
   238 
       
   239         @Override // to silently fail
       
   240         public void setUncaughtExceptionHandler(UncaughtExceptionHandler x) { }
       
   241 
       
   242         @Override // paranoically
       
   243         public void setContextClassLoader(ClassLoader cl) {
       
   244             throw new SecurityException("setContextClassLoader");
       
   245         }
       
   246 
       
   247         /**
       
   248          * Returns a new group with the system ThreadGroup (the
       
   249          * topmost, parentless group) as parent.  Uses Unsafe to
       
   250          * traverse Thread group and ThreadGroup parent fields.
       
   251          */
       
   252         private static ThreadGroup createThreadGroup() {
   141             try {
   253             try {
   142                 onTermination(exception);
   254                 sun.misc.Unsafe u = sun.misc.Unsafe.getUnsafe();
   143             } catch (Throwable ex) {
   255                 Class<?> tk = Thread.class;
   144                 if (exception == null)
   256                 Class<?> gk = ThreadGroup.class;
   145                     exception = ex;
   257                 long tg = u.objectFieldOffset(tk.getDeclaredField("group"));
   146             } finally {
   258                 long gp = u.objectFieldOffset(gk.getDeclaredField("parent"));
   147                 pool.deregisterWorker(this, exception);
   259                 ThreadGroup group = (ThreadGroup)
       
   260                     u.getObject(Thread.currentThread(), tg);
       
   261                 while (group != null) {
       
   262                     ThreadGroup parent = (ThreadGroup)u.getObject(group, gp);
       
   263                     if (parent == null)
       
   264                         return new ThreadGroup(group,
       
   265                                                "InnocuousForkJoinWorkerThreadGroup");
       
   266                     group = parent;
       
   267                 }
       
   268             } catch (Exception e) {
       
   269                 throw new Error(e);
   148             }
   270             }
   149         }
   271             // fall through if null as cannot-happen safeguard
   150     }
   272             throw new Error("Cannot create ThreadGroup");
       
   273         }
       
   274     }
       
   275 
   151 }
   276 }
       
   277