Mercurial > hg > Members > kono > jpf-core
comparison src/classes/java/lang/Thread.java @ 0:61d41facf527
initial v8 import (history reset)
author | Peter Mehlitz <Peter.C.Mehlitz@nasa.gov> |
---|---|
date | Fri, 23 Jan 2015 10:14:01 -0800 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:61d41facf527 |
---|---|
1 /* | |
2 * Copyright (C) 2014, United States Government, as represented by the | |
3 * Administrator of the National Aeronautics and Space Administration. | |
4 * All rights reserved. | |
5 * | |
6 * The Java Pathfinder core (jpf-core) platform is licensed under the | |
7 * Apache License, Version 2.0 (the "License"); you may not use this file except | |
8 * in compliance with the License. You may obtain a copy of the License at | |
9 * | |
10 * http://www.apache.org/licenses/LICENSE-2.0. | |
11 * | |
12 * Unless required by applicable law or agreed to in writing, software | |
13 * distributed under the License is distributed on an "AS IS" BASIS, | |
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
15 * See the License for the specific language governing permissions and | |
16 * limitations under the License. | |
17 */ | |
18 package java.lang; | |
19 | |
20 import gov.nasa.jpf.annotation.NeverBreak; | |
21 import sun.nio.ch.Interruptible; | |
22 | |
23 /** | |
24 * MJI model class for java.lang.Thread library abstraction | |
25 * | |
26 * <2do> this should not require the JPF ThreadList to retrieve corresponding ThreadInfos | |
27 * (the ThreadList might not store terminated threads) | |
28 */ | |
29 public class Thread implements Runnable { | |
30 | |
31 public interface UncaughtExceptionHandler { | |
32 // note this doesn't stop the thread from being terminated | |
33 void uncaughtException (Thread t, Throwable x); | |
34 } | |
35 | |
36 static int nameThreadNum; // to construct the default thread name | |
37 | |
38 public static final int MIN_PRIORITY = 1; | |
39 public static final int NORM_PRIORITY = 5; | |
40 public static final int MAX_PRIORITY = 10; | |
41 | |
42 // don't rename this - it's used by ThreadGoup.uncaughtException() | |
43 private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler; // null by default | |
44 | |
45 // initialized in init(), except of the main thread (which gets explicitly initialized by the VM) | |
46 ThreadGroup group; | |
47 Runnable target; | |
48 String name; | |
49 int priority; | |
50 boolean isDaemon; | |
51 | |
52 // this is an explicit thread state that gets set on a call of interrupt(), but | |
53 // only if the thread is not blocked. If it is, we only change the status. | |
54 // this gets cleared by calling interrupted() | |
55 boolean interrupted; | |
56 | |
57 // those are only accessed from peers since thread obects are per se shared | |
58 @NeverBreak | |
59 ThreadLocal.Entry<?>[] threadLocals; | |
60 | |
61 // this is what we use for sun.misc.Unsafe.park()/unpark() | |
62 // this is accessed from the native peer, VM.createMainThread() and sun.misc.Unsafe | |
63 static class Permit { | |
64 boolean blockPark = true; // this is used to remember unpark() calls before park() (they don't accumulate) | |
65 } | |
66 Permit permit; // the object is used for wait/notify | |
67 | |
68 // referenced by java.util.concurrent.locks.LockSupport via sun.misc.Unsafe | |
69 // DON'T CHANGE THIS NAME | |
70 volatile Object parkBlocker; | |
71 | |
72 // used to store Thread.stop() exceptions | |
73 Throwable stopException; | |
74 | |
75 private volatile UncaughtExceptionHandler uncaughtExceptionHandler; // null by default | |
76 | |
77 | |
78 public enum State { BLOCKED, NEW, RUNNABLE, TERMINATED, TIMED_WAITING, WAITING } | |
79 | |
80 | |
81 public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler xh) { | |
82 defaultUncaughtExceptionHandler = xh; | |
83 } | |
84 | |
85 public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){ | |
86 return defaultUncaughtExceptionHandler; | |
87 } | |
88 | |
89 | |
90 public Thread () { | |
91 this(null, null, null, 0L); | |
92 } | |
93 | |
94 public Thread (Runnable target) { | |
95 this(null, target, null, 0L); | |
96 } | |
97 | |
98 public Thread (Runnable target, String name) { | |
99 this(null, target, name, 0L); | |
100 } | |
101 | |
102 public Thread (String name) { | |
103 this(null, null, name, 0L); | |
104 } | |
105 | |
106 public Thread (ThreadGroup group, String name) { | |
107 this(group, null, name, 0L); | |
108 } | |
109 | |
110 public Thread (ThreadGroup group, Runnable target) { | |
111 this(group, target, null, 0L); | |
112 } | |
113 | |
114 public Thread (ThreadGroup group, Runnable target, String name) { | |
115 this(group, target, name, 0L); | |
116 } | |
117 | |
118 public Thread (ThreadGroup group, Runnable target, String name, long stackSize) { | |
119 Thread cur = currentThread(); | |
120 | |
121 if (group == null) { | |
122 this.group = cur.getThreadGroup(); | |
123 } else { | |
124 this.group = group; | |
125 } | |
126 | |
127 this.group.add(this); | |
128 | |
129 if (name == null) { | |
130 this.name = "Thread-" + ++nameThreadNum; | |
131 } else { | |
132 this.name = name; | |
133 } | |
134 | |
135 this.permit = new Permit(); | |
136 | |
137 // those are always inherited from the current thread | |
138 this.priority = cur.getPriority(); | |
139 this.isDaemon = cur.isDaemon(); | |
140 | |
141 this.target = target; | |
142 | |
143 // do our associated native init | |
144 init0(this.group, target, this.name, stackSize); | |
145 | |
146 initThreadLocals(cur); | |
147 } | |
148 | |
149 // this takes care of ThreadInfo initialization | |
150 native void init0 (ThreadGroup group, Runnable target, String name, long stackSize); | |
151 | |
152 // this is here since InheritableThreadLocals would require childValue(parentVal) roundtrips. | |
153 // Unfortunately we can't defer this until the ThreadLocal is actually accessed since | |
154 // we have to capture the value at the point of child creation | |
155 // Note this executes in the parent thread | |
156 private void initThreadLocals (Thread parent){ | |
157 ThreadLocal.Entry<?>[] tl = parent.threadLocals; | |
158 if (tl != null){ | |
159 int len = tl.length; | |
160 ThreadLocal.Entry<?>[] inherited = null; | |
161 int j=0; | |
162 | |
163 for (int i=0; i<len; i++){ | |
164 ThreadLocal.Entry<?> e = tl[i]; | |
165 ThreadLocal.Entry<?> ec = e.getChildEntry(); | |
166 if (ec != null){ | |
167 if (inherited == null){ | |
168 inherited = new ThreadLocal.Entry<?>[len]; | |
169 } | |
170 inherited[j++] = ec; | |
171 } | |
172 } | |
173 | |
174 if (inherited != null){ | |
175 ThreadLocal.Entry<?>[] a = new ThreadLocal.Entry<?>[j]; | |
176 System.arraycopy(inherited,0,a,0,j); | |
177 threadLocals = a; | |
178 } | |
179 } | |
180 } | |
181 | |
182 public static int activeCount () { | |
183 return 0; | |
184 } | |
185 | |
186 public void setUncaughtExceptionHandler(UncaughtExceptionHandler xh) { | |
187 uncaughtExceptionHandler = xh; | |
188 } | |
189 | |
190 public UncaughtExceptionHandler getUncaughtExceptionHandler(){ | |
191 if (uncaughtExceptionHandler != null){ | |
192 return uncaughtExceptionHandler; | |
193 } else { | |
194 return group; | |
195 } | |
196 } | |
197 | |
198 public void setContextClassLoader (ClassLoader cl) { | |
199 } | |
200 | |
201 public ClassLoader getContextClassLoader () { | |
202 // <NSY> | |
203 return null; | |
204 } | |
205 | |
206 public synchronized void setDaemon (boolean isDaemon) { | |
207 this.isDaemon = isDaemon; | |
208 setDaemon0(isDaemon); | |
209 } | |
210 | |
211 public boolean isDaemon () { | |
212 return isDaemon; | |
213 } | |
214 | |
215 public native long getId(); | |
216 | |
217 public StackTraceElement[] getStackTrace() { | |
218 return null; // not yet implemented | |
219 } | |
220 | |
221 public native int getState0(); | |
222 | |
223 public Thread.State getState() { | |
224 int i = getState0(); | |
225 switch (i) { | |
226 case 0: return State.BLOCKED; | |
227 case 1: return State.NEW; | |
228 case 2: return State.RUNNABLE; | |
229 case 3: return State.TERMINATED; | |
230 case 4: return State.TIMED_WAITING; | |
231 case 5: return State.WAITING; | |
232 } | |
233 | |
234 return null; // shoudl be intercepted by a getState0 assertion | |
235 } | |
236 | |
237 public synchronized void setName (String name) { | |
238 if (name == null) { | |
239 throw new IllegalArgumentException("thread name can't be null"); | |
240 } | |
241 | |
242 this.name = name; | |
243 setName0(name); | |
244 } | |
245 | |
246 public String getName () { | |
247 return name; | |
248 } | |
249 | |
250 public void setPriority (int priority) { | |
251 if ((priority < MIN_PRIORITY) || (priority > MAX_PRIORITY)) { | |
252 throw new IllegalArgumentException("thread priority out of range"); | |
253 } | |
254 | |
255 this.priority = priority; | |
256 setPriority0(priority); | |
257 } | |
258 | |
259 public int getPriority () { | |
260 return priority; | |
261 } | |
262 | |
263 public ThreadGroup getThreadGroup () { | |
264 return group; | |
265 } | |
266 | |
267 public void checkAccess () { | |
268 // <NSY> | |
269 } | |
270 | |
271 public native int countStackFrames (); | |
272 | |
273 public static native Thread currentThread (); | |
274 | |
275 public void destroy () { | |
276 } | |
277 | |
278 public static void dumpStack () { | |
279 } | |
280 | |
281 public static int enumerate (Thread[] tarray) { | |
282 Thread cur = currentThread(); | |
283 | |
284 return cur.group.enumerate(tarray); | |
285 } | |
286 | |
287 public static native boolean holdsLock (Object obj); | |
288 | |
289 // this one needs to be native because it might change the thread status | |
290 public native void interrupt (); | |
291 | |
292 // those don't have to be native, but we keep it symmetric | |
293 public static native boolean interrupted (); | |
294 public native boolean isInterrupted (); | |
295 | |
296 public native boolean isAlive (); | |
297 | |
298 | |
299 /** | |
300 * note these are not synchronized anymore since they are intercepted by the | |
301 * native peer. The reason is that we don't want two CGs per join call (one for the | |
302 * sync call, and one for the wait) because this can cause serious | |
303 * performance degradation | |
304 */ | |
305 public void join () throws InterruptedException { | |
306 synchronized(this){ | |
307 | |
308 if (interrupted()) { | |
309 throw new InterruptedException(); | |
310 } | |
311 | |
312 while (isAlive()) { | |
313 // apparently, the JDK doesn't throw InterruptedExceptions if | |
314 // we get interrupted after waiting in the join | |
315 wait(); | |
316 } | |
317 } | |
318 } | |
319 | |
320 public void join (long millis) throws InterruptedException { | |
321 join(millis, 0); | |
322 } | |
323 | |
324 public void join (long millis, int nanos) throws InterruptedException { | |
325 | |
326 if (millis < 0){ | |
327 throw new java.lang.IllegalArgumentException("timeout value is negative"); | |
328 | |
329 } else if (millis == 0){ | |
330 join(); | |
331 | |
332 } else { | |
333 synchronized(this){ | |
334 if (interrupted()){ | |
335 throw new InterruptedException(); | |
336 } | |
337 | |
338 wait(millis); | |
339 } | |
340 } | |
341 } | |
342 | |
343 | |
344 | |
345 @Override | |
346 public void run () { | |
347 if (target != null) { | |
348 target.run(); | |
349 } | |
350 } | |
351 | |
352 public static void sleep (long millis) throws InterruptedException { | |
353 sleep(millis, 0); | |
354 } | |
355 | |
356 public static native void sleep (long millis, int nanos) | |
357 throws InterruptedException; | |
358 | |
359 public native void start(); | |
360 public native void stop(); | |
361 public native void stop(Throwable obj); | |
362 | |
363 public native void suspend(); | |
364 public native void resume(); | |
365 | |
366 | |
367 @Override | |
368 public String toString () { | |
369 return ("Thread[" + name + ',' + priority + ',' + (group == null ? "" : group.getName()) + ']'); | |
370 } | |
371 | |
372 public static native void yield (); | |
373 | |
374 native void setDaemon0 (boolean on); | |
375 | |
376 native void setName0 (String name); | |
377 | |
378 native void setPriority0 (int priority); | |
379 | |
380 | |
381 | |
382 /** | |
383 * automatically called by system upon thread termination to clean up | |
384 * references. | |
385 * | |
386 * NOTE - we clean up atomically during ThreadInfo.finish(), to avoid any | |
387 * additional states. This is important since group per se is a shared object | |
388 * We only include this method here as a specification for ThreadInfo | |
389 */ | |
390 private void exit () { | |
391 if (group != null){ | |
392 group.threadTerminated(this); | |
393 group = null; | |
394 } | |
395 | |
396 threadLocals = null; | |
397 parkBlocker = null; | |
398 uncaughtExceptionHandler = null; | |
399 } | |
400 | |
401 // some Java 6 mojo | |
402 // <2do> not implemented yet | |
403 native void blockedOn (Interruptible b); | |
404 | |
405 | |
406 // we probably will remove these fields once we modeled java.util.concurrent.ThreadLocalRandom | |
407 // to make it deterministic | |
408 long threadLocalRandomSeed; | |
409 int threadLocalRandomProbe; | |
410 int threadLocalRandomSecondarySeed; | |
411 } |