8c538f590e350434dcf5d59f688036036435b976
[jpf-core.git] / src / classes / java / lang / Thread.java
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 }