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 |