Fixing a few bugs in the statistics printout.
[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     // TODO: Fix for Groovy's model-checking
149     this.tid = this.getId();
150   }
151
152   private long tid;
153
154   // this takes care of ThreadInfo initialization
155   native void init0 (ThreadGroup group, Runnable target, String name, long stackSize);
156   
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;
163     if (tl != null){
164       int len = tl.length;
165       ThreadLocal.Entry<?>[] inherited = null;
166       int j=0;
167       
168       for (int i=0; i<len; i++){
169         ThreadLocal.Entry<?> e = tl[i];
170         ThreadLocal.Entry<?> ec = e.getChildEntry();
171         if (ec != null){
172           if (inherited == null){
173             inherited = new ThreadLocal.Entry<?>[len];
174           }
175           inherited[j++] = ec;
176         }
177       }
178       
179       if (inherited != null){
180         ThreadLocal.Entry<?>[] a = new ThreadLocal.Entry<?>[j];
181         System.arraycopy(inherited,0,a,0,j);
182         threadLocals = a;
183       }
184     }
185   }
186   
187   public static int activeCount () {
188     return 0;
189   }
190
191   public void setUncaughtExceptionHandler(UncaughtExceptionHandler xh) {
192     uncaughtExceptionHandler = xh;
193   }
194   
195   public UncaughtExceptionHandler getUncaughtExceptionHandler(){
196     if (uncaughtExceptionHandler != null){
197       return uncaughtExceptionHandler;
198     } else {
199       return group;
200     }
201   }
202   
203   public void setContextClassLoader (ClassLoader cl) {
204   }
205
206   public ClassLoader getContextClassLoader () {
207     // <NSY>
208     return null;
209   }
210
211   public synchronized void setDaemon (boolean isDaemon) {
212     this.isDaemon = isDaemon;
213     setDaemon0(isDaemon);
214   }
215
216   public boolean isDaemon () {
217     return isDaemon;
218   }
219
220   public native long getId();
221
222   public StackTraceElement[] getStackTrace() {
223     return null; // not yet implemented
224   }
225
226   public native int getState0();
227
228   public Thread.State getState() {
229     int i = getState0();
230     switch (i) {
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;
237     }
238
239     return null; // shoudl be intercepted by a getState0 assertion
240   }
241
242   public synchronized void setName (String name) {
243     if (name == null) {
244       throw new IllegalArgumentException("thread name can't be null");
245     }
246
247     this.name = name;
248     setName0(name);
249   }
250
251   public String getName () {
252     return name;
253   }
254
255   public void setPriority (int priority) {
256     if ((priority < MIN_PRIORITY) || (priority > MAX_PRIORITY)) {
257       throw new IllegalArgumentException("thread priority out of range");
258     }
259
260     this.priority = priority;
261     setPriority0(priority);
262   }
263
264   public int getPriority () {
265     return priority;
266   }
267
268   public ThreadGroup getThreadGroup () {
269     return group;
270   }
271
272   public void checkAccess () {
273     // <NSY>
274   }
275
276   public native int countStackFrames ();
277
278   public static native Thread currentThread ();
279
280   public void destroy () {
281   }
282
283   public static void dumpStack () {
284   }
285
286   public static int enumerate (Thread[] tarray) {
287     Thread cur = currentThread();
288
289     return cur.group.enumerate(tarray);
290   }
291
292   public static native boolean holdsLock (Object obj);
293
294   // this one needs to be native because it might change the thread status
295   public native void interrupt ();
296
297   // those don't have to be native, but we keep it symmetric
298   public static native boolean interrupted ();
299   public native boolean isInterrupted ();
300
301   public native boolean isAlive ();
302
303
304   /**
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
309    */
310   public void join () throws InterruptedException {
311     synchronized(this){
312
313       if (interrupted()) {
314         throw new InterruptedException();
315       }
316
317       while (isAlive()) {
318         // apparently, the JDK doesn't throw InterruptedExceptions if
319         // we get interrupted after waiting in the join
320         wait();
321       }
322     }
323   }
324
325   public void join (long millis) throws InterruptedException {
326     join(millis, 0);
327   }
328
329   public void join (long millis, int nanos) throws InterruptedException {
330
331     if (millis < 0){
332       throw new java.lang.IllegalArgumentException("timeout value is negative");
333
334     } else if (millis == 0){
335       join();
336
337     } else {
338       synchronized(this){
339         if (interrupted()){
340           throw new InterruptedException();
341         }
342
343         wait(millis);
344       }
345     }
346   }
347
348     
349
350   @Override
351   public void run () {
352     if (target != null) {
353       target.run();
354     }
355   }
356
357   public static void sleep (long millis) throws InterruptedException {
358     sleep(millis, 0);
359   }
360
361   public static native void sleep (long millis, int nanos)
362                             throws InterruptedException;
363
364   public native void start();
365   public native void stop();
366   public native void stop(Throwable obj);
367
368   public native void suspend();
369   public native void resume();
370
371
372   @Override
373   public String toString () {
374     return ("Thread[" + name + ',' + priority + ',' + (group == null ? "" : group.getName()) + ']');
375   }
376
377   public static native void yield ();
378
379   native void setDaemon0 (boolean on);
380
381   native void setName0 (String name);
382
383   native void setPriority0 (int priority);
384
385
386
387   /**
388    * automatically called by system upon thread termination to clean up
389    * references.
390    * 
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
394    */
395   private void exit () {
396     if (group != null){
397       group.threadTerminated(this);
398       group = null;
399     }
400     
401     threadLocals = null;    
402     parkBlocker = null;
403     uncaughtExceptionHandler = null;
404   }
405
406   // some Java 6 mojo
407   // <2do> not implemented yet
408   native void blockedOn (Interruptible b);
409
410   
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;
416 }