2 * Copyright (C) 2014, United States Government, as represented by the
3 * Administrator of the National Aeronautics and Space Administration.
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
10 * http://www.apache.org/licenses/LICENSE-2.0.
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.
20 import gov.nasa.jpf.annotation.NeverBreak;
21 import sun.nio.ch.Interruptible;
24 * MJI model class for java.lang.Thread library abstraction
26 * <2do> this should not require the JPF ThreadList to retrieve corresponding ThreadInfos
27 * (the ThreadList might not store terminated threads)
29 public class Thread implements Runnable {
31 public interface UncaughtExceptionHandler {
32 // note this doesn't stop the thread from being terminated
33 void uncaughtException (Thread t, Throwable x);
36 static int nameThreadNum; // to construct the default thread name
38 public static final int MIN_PRIORITY = 1;
39 public static final int NORM_PRIORITY = 5;
40 public static final int MAX_PRIORITY = 10;
42 // don't rename this - it's used by ThreadGoup.uncaughtException()
43 private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler; // null by default
45 // initialized in init(), except of the main thread (which gets explicitly initialized by the VM)
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()
57 // those are only accessed from peers since thread obects are per se shared
59 ThreadLocal.Entry<?>[] threadLocals;
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
64 boolean blockPark = true; // this is used to remember unpark() calls before park() (they don't accumulate)
66 Permit permit; // the object is used for wait/notify
68 // referenced by java.util.concurrent.locks.LockSupport via sun.misc.Unsafe
69 // DON'T CHANGE THIS NAME
70 volatile Object parkBlocker;
72 // used to store Thread.stop() exceptions
73 Throwable stopException;
75 private volatile UncaughtExceptionHandler uncaughtExceptionHandler; // null by default
78 public enum State { BLOCKED, NEW, RUNNABLE, TERMINATED, TIMED_WAITING, WAITING }
81 public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler xh) {
82 defaultUncaughtExceptionHandler = xh;
85 public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){
86 return defaultUncaughtExceptionHandler;
91 this(null, null, null, 0L);
94 public Thread (Runnable target) {
95 this(null, target, null, 0L);
98 public Thread (Runnable target, String name) {
99 this(null, target, name, 0L);
102 public Thread (String name) {
103 this(null, null, name, 0L);
106 public Thread (ThreadGroup group, String name) {
107 this(group, null, name, 0L);
110 public Thread (ThreadGroup group, Runnable target) {
111 this(group, target, null, 0L);
114 public Thread (ThreadGroup group, Runnable target, String name) {
115 this(group, target, name, 0L);
118 public Thread (ThreadGroup group, Runnable target, String name, long stackSize) {
119 Thread cur = currentThread();
122 this.group = cur.getThreadGroup();
127 this.group.add(this);
130 this.name = "Thread-" + ++nameThreadNum;
135 this.permit = new Permit();
137 // those are always inherited from the current thread
138 this.priority = cur.getPriority();
139 this.isDaemon = cur.isDaemon();
141 this.target = target;
143 // do our associated native init
144 init0(this.group, target, this.name, stackSize);
146 initThreadLocals(cur);
148 // TODO: Fix for Groovy's model-checking
149 this.tid = this.getId();
154 // this takes care of ThreadInfo initialization
155 native void init0 (ThreadGroup group, Runnable target, String name, long stackSize);
157 // this is here since InheritableThreadLocals would require childValue(parentVal) roundtrips.
158 // Unfortunately we can't defer this until the ThreadLocal is actually accessed since
159 // we have to capture the value at the point of child creation
160 // Note this executes in the parent thread
161 private void initThreadLocals (Thread parent){
162 ThreadLocal.Entry<?>[] tl = parent.threadLocals;
165 ThreadLocal.Entry<?>[] inherited = null;
168 for (int i=0; i<len; i++){
169 ThreadLocal.Entry<?> e = tl[i];
170 ThreadLocal.Entry<?> ec = e.getChildEntry();
172 if (inherited == null){
173 inherited = new ThreadLocal.Entry<?>[len];
179 if (inherited != null){
180 ThreadLocal.Entry<?>[] a = new ThreadLocal.Entry<?>[j];
181 System.arraycopy(inherited,0,a,0,j);
187 public static int activeCount () {
191 public void setUncaughtExceptionHandler(UncaughtExceptionHandler xh) {
192 uncaughtExceptionHandler = xh;
195 public UncaughtExceptionHandler getUncaughtExceptionHandler(){
196 if (uncaughtExceptionHandler != null){
197 return uncaughtExceptionHandler;
203 public void setContextClassLoader (ClassLoader cl) {
206 public ClassLoader getContextClassLoader () {
211 public synchronized void setDaemon (boolean isDaemon) {
212 this.isDaemon = isDaemon;
213 setDaemon0(isDaemon);
216 public boolean isDaemon () {
220 public native long getId();
222 public StackTraceElement[] getStackTrace() {
223 return null; // not yet implemented
226 public native int getState0();
228 public Thread.State getState() {
231 case 0: return State.BLOCKED;
232 case 1: return State.NEW;
233 case 2: return State.RUNNABLE;
234 case 3: return State.TERMINATED;
235 case 4: return State.TIMED_WAITING;
236 case 5: return State.WAITING;
239 return null; // shoudl be intercepted by a getState0 assertion
242 public synchronized void setName (String name) {
244 throw new IllegalArgumentException("thread name can't be null");
251 public String getName () {
255 public void setPriority (int priority) {
256 if ((priority < MIN_PRIORITY) || (priority > MAX_PRIORITY)) {
257 throw new IllegalArgumentException("thread priority out of range");
260 this.priority = priority;
261 setPriority0(priority);
264 public int getPriority () {
268 public ThreadGroup getThreadGroup () {
272 public void checkAccess () {
276 public native int countStackFrames ();
278 public static native Thread currentThread ();
280 public void destroy () {
283 public static void dumpStack () {
286 public static int enumerate (Thread[] tarray) {
287 Thread cur = currentThread();
289 return cur.group.enumerate(tarray);
292 public static native boolean holdsLock (Object obj);
294 // this one needs to be native because it might change the thread status
295 public native void interrupt ();
297 // those don't have to be native, but we keep it symmetric
298 public static native boolean interrupted ();
299 public native boolean isInterrupted ();
301 public native boolean isAlive ();
305 * note these are not synchronized anymore since they are intercepted by the
306 * native peer. The reason is that we don't want two CGs per join call (one for the
307 * sync call, and one for the wait) because this can cause serious
308 * performance degradation
310 public void join () throws InterruptedException {
314 throw new InterruptedException();
318 // apparently, the JDK doesn't throw InterruptedExceptions if
319 // we get interrupted after waiting in the join
325 public void join (long millis) throws InterruptedException {
329 public void join (long millis, int nanos) throws InterruptedException {
332 throw new java.lang.IllegalArgumentException("timeout value is negative");
334 } else if (millis == 0){
340 throw new InterruptedException();
352 if (target != null) {
357 public static void sleep (long millis) throws InterruptedException {
361 public static native void sleep (long millis, int nanos)
362 throws InterruptedException;
364 public native void start();
365 public native void stop();
366 public native void stop(Throwable obj);
368 public native void suspend();
369 public native void resume();
373 public String toString () {
374 return ("Thread[" + name + ',' + priority + ',' + (group == null ? "" : group.getName()) + ']');
377 public static native void yield ();
379 native void setDaemon0 (boolean on);
381 native void setName0 (String name);
383 native void setPriority0 (int priority);
388 * automatically called by system upon thread termination to clean up
391 * NOTE - we clean up atomically during ThreadInfo.finish(), to avoid any
392 * additional states. This is important since group per se is a shared object
393 * We only include this method here as a specification for ThreadInfo
395 private void exit () {
397 group.threadTerminated(this);
403 uncaughtExceptionHandler = null;
407 // <2do> not implemented yet
408 native void blockedOn (Interruptible b);
411 // we probably will remove these fields once we modeled java.util.concurrent.ThreadLocalRandom
412 // to make it deterministic
413 long threadLocalRandomSeed;
414 int threadLocalRandomProbe;
415 int threadLocalRandomSecondarySeed;