ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/ForkJoinWorkerThread.java
(Generate patch)

Comparing jsr166/src/main/java/util/concurrent/ForkJoinWorkerThread.java (file contents):
Revision 1.59 by jsr166, Thu May 23 01:29:19 2013 UTC vs.
Revision 1.60 by dl, Tue May 6 17:31:01 2014 UTC

# Line 6 | Line 6
6  
7   package java.util.concurrent;
8  
9 + import java.security.AccessControlContext;
10 + import java.security.ProtectionDomain;
11 +
12   /**
13   * A thread managed by a {@link ForkJoinPool}, which executes
14   * {@link ForkJoinTask}s.
# Line 32 | Line 35 | public class ForkJoinWorkerThread extend
35       * completes. This leads to a visibility race, that is tolerated
36       * by requiring that the workQueue field is only accessed by the
37       * owning thread.
38 +     *
39 +     * Support for (non-public) subclass InnocuousForkJoinWorkerThread
40 +     * requires that we break quite a lot of encapulation (via Unsafe)
41 +     * both here and in the subclass to access and set Thread fields.
42       */
43  
44      final ForkJoinPool pool;                // the pool this thread works in
# Line 51 | Line 58 | public class ForkJoinWorkerThread extend
58      }
59  
60      /**
61 +     * Version for InnocuousForkJoinWorkerThread
62 +     */
63 +    ForkJoinWorkerThread(ForkJoinPool pool, ThreadGroup threadGroup,
64 +                         AccessControlContext acc) {
65 +        super(threadGroup, null, "aForkJoinWorkerThread");
66 +        U.putOrderedObject(this, INHERITEDACCESSCONTROLCONTEXT, acc);
67 +        eraseThreadLocals(); // clear before registering
68 +        this.pool = pool;
69 +        this.workQueue = pool.registerWorker(this);
70 +    }
71 +
72 +    /**
73       * Returns the pool hosting this thread.
74       *
75       * @return the pool
# Line 102 | Line 121 | public class ForkJoinWorkerThread extend
121       * {@link ForkJoinTask}s.
122       */
123      public void run() {
124 <        Throwable exception = null;
125 <        try {
107 <            onStart();
108 <            pool.runWorker(workQueue);
109 <        } catch (Throwable ex) {
110 <            exception = ex;
111 <        } finally {
124 >        if (workQueue.array == null) { // only run once
125 >            Throwable exception = null;
126              try {
127 <                onTermination(exception);
127 >                onStart();
128 >                pool.runWorker(workQueue);
129              } catch (Throwable ex) {
130 <                if (exception == null)
116 <                    exception = ex;
130 >                exception = ex;
131              } finally {
132 <                pool.deregisterWorker(this, exception);
132 >                try {
133 >                    onTermination(exception);
134 >                } catch (Throwable ex) {
135 >                    if (exception == null)
136 >                        exception = ex;
137 >                } finally {
138 >                    pool.deregisterWorker(this, exception);
139 >                }
140 >            }
141 >        }
142 >    }
143 >
144 >    /**
145 >     * Erases ThreadLocals by nulling out Thread maps
146 >     */
147 >    final void eraseThreadLocals() {
148 >        U.putObject(this, THREADLOCALS, null);
149 >        U.putObject(this, INHERITABLETHREADLOCALS, null);
150 >    }
151 >
152 >    /**
153 >     * Non-public hook method for InnocuousForkJoinWorkerThread
154 >     */
155 >    void afterTopLevelExec() {
156 >    }
157 >
158 >    // Set up to allow setting thread fields in constructor
159 >    private static final sun.misc.Unsafe U;
160 >    private static final long THREADLOCALS;
161 >    private static final long INHERITABLETHREADLOCALS;
162 >    private static final long INHERITEDACCESSCONTROLCONTEXT;
163 >    static {
164 >        try {
165 >            U = sun.misc.Unsafe.getUnsafe();
166 >            Class<?> tk = Thread.class;
167 >            THREADLOCALS = U.objectFieldOffset
168 >                (tk.getDeclaredField("threadLocals"));
169 >            INHERITABLETHREADLOCALS = U.objectFieldOffset
170 >                (tk.getDeclaredField("inheritableThreadLocals"));
171 >            INHERITEDACCESSCONTROLCONTEXT = U.objectFieldOffset
172 >                (tk.getDeclaredField("inheritedAccessControlContext"));
173 >
174 >        } catch (Exception e) {
175 >            throw new Error(e);
176 >        }
177 >    }
178 >
179 >    /**
180 >     * A worker thread that has no permissions, is not a member of any
181 >     * user-defined ThreadGroup, and erases all ThreadLocals after
182 >     * running each top-level task.
183 >     */
184 >    static final class InnocuousForkJoinWorkerThread extends ForkJoinWorkerThread {
185 >        /** The ThreadGroup for all InnocuousForkJoinWorkerThreads */
186 >        private static final ThreadGroup innocuousThreadGroup =
187 >            createThreadGroup();
188 >
189 >        /** An AccessControlContext supporting no privileges */
190 >        private static final AccessControlContext INNOCUOUS_ACC =
191 >            new AccessControlContext(
192 >                new ProtectionDomain[] {
193 >                    new ProtectionDomain(null, null)
194 >                });
195 >
196 >        InnocuousForkJoinWorkerThread(ForkJoinPool pool) {
197 >            super(pool, innocuousThreadGroup, INNOCUOUS_ACC);
198 >        }
199 >
200 >        @Override // to erase ThreadLocals
201 >        void afterTopLevelExec() {
202 >            eraseThreadLocals();
203 >        }
204 >
205 >        @Override // to always report system loader
206 >        public ClassLoader getContextClassLoader() {
207 >            return ClassLoader.getSystemClassLoader();
208 >        }
209 >
210 >        @Override // to silently fail
211 >        public void setUncaughtExceptionHandler(UncaughtExceptionHandler x) { }
212 >
213 >        @Override // paranoically
214 >        public void setContextClassLoader(ClassLoader cl) {
215 >            throw new SecurityException("setContextClassLoader");
216 >        }
217 >
218 >        /**
219 >         * Returns a new group with the system ThreadGroup (the
220 >         * topmost, parentless group) as parent.  Uses Unsafe to
221 >         * traverse Thread group and ThreadGroup parent fields.
222 >         */
223 >        private static ThreadGroup createThreadGroup() {
224 >            try {
225 >                sun.misc.Unsafe u = sun.misc.Unsafe.getUnsafe();
226 >                Class<?> tk = Thread.class;
227 >                Class<?> gk = ThreadGroup.class;
228 >                long tg = u.objectFieldOffset(tk.getDeclaredField("group"));
229 >                long gp = u.objectFieldOffset(gk.getDeclaredField("parent"));
230 >                ThreadGroup group = (ThreadGroup)
231 >                    u.getObject(Thread.currentThread(), tg);
232 >                while (group != null) {
233 >                    ThreadGroup parent = (ThreadGroup)u.getObject(group, gp);
234 >                    if (parent == null)
235 >                        return new ThreadGroup(group,
236 >                                               "InnocuousForkJoinWorkerThreadGroup");
237 >                    group = parent;
238 >                }
239 >            } catch (Exception e) {
240 >                throw new Error(e);
241              }
242 +            // fall through if null as cannot-happen safeguard
243 +            throw new Error("Cannot create ThreadGroup");
244          }
245      }
246 +
247   }
248 +

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines