Adding the old tracker variable for debugging/testing purposes.
[jpf-core.git] / src / main / gov / nasa / jpf / vm / SingleProcessVM.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 gov.nasa.jpf.vm;
19
20 import java.util.HashMap;
21 import java.util.Map;
22
23 import gov.nasa.jpf.Config;
24 import gov.nasa.jpf.JPF;
25 import gov.nasa.jpf.JPFConfigException;
26 import gov.nasa.jpf.util.IntTable;
27 import gov.nasa.jpf.util.Misc;
28 import gov.nasa.jpf.util.Predicate;
29 import gov.nasa.jpf.vm.choice.BreakGenerator;
30
31
32 /**
33  * @author Nastaran Shafiei <nastaran.shafiei@gmail.com>
34  * 
35  * Includes the VM initialization for executing single Java process
36  * 
37  * To use this jpf.properties includes,
38  *              vm.class = gov.nasa.jpf.vm.SingleProcessVM
39  */
40 public class SingleProcessVM extends VM {
41
42   protected ApplicationContext appCtx; // we only have one
43   
44   protected Predicate<ThreadInfo> runnablePredicate;
45   protected Predicate<ThreadInfo> daemonRunnable;
46   
47   protected SingleProcessVM (){}
48
49   public SingleProcessVM (JPF jpf, Config conf) {
50     super(jpf, conf);
51     
52     appCtx = createApplicationContext();
53     
54     initializePredicates();
55   }
56     
57   void initializePredicates() {
58     // set predicates used to query from threadlist
59     runnablePredicate = new Predicate<ThreadInfo>(){
60       @Override
61         public boolean isTrue (ThreadInfo ti){
62         return (ti.isRunnable());
63       }
64     };
65     
66     daemonRunnable = new Predicate<ThreadInfo>(){
67       @Override
68         public boolean isTrue (ThreadInfo ti){
69         return (ti.isDaemon() && ti.isRunnable());
70       }
71     };
72   }
73   
74   protected ApplicationContext createApplicationContext (){
75     String clsName;
76     String[] args = null;
77     
78     String[] freeArgs = config.getFreeArgs();
79     clsName = config.getProperty("target"); // explicit 'target' takes precedence
80     
81     if (clsName == null){
82       if (freeArgs != null){ // if it is non-null, there is at least one entry
83         // note that application property filenames have been removed by Config since they are part of its initialization
84         clsName = freeArgs[0];
85         
86         if (freeArgs.length > 1){ // if there is no 'target' command line overrides 'target.args'
87           args = Misc.arrayWithoutFirst(freeArgs, 1);
88         } else {
89           args = config.getStringArray("target.args");
90         }
91       }
92     } else {
93       // since there was a 'target', 'target.args' override command line
94       args = config.getCompactStringArray("target.args");
95       if (args == null){
96         if (freeArgs != null){
97           args = freeArgs;
98         }
99       }
100     }
101     
102     // sanity checks
103     if (args == null){
104       args = EMPTY_ARGS;
105     }
106     if (clsName == null){
107       throw new JPFConfigException("no target class specified, terminating");
108     }
109     if (!isValidClassName(clsName)){
110       throw new JPFConfigException("main class not a valid class name: " + clsName);      
111     }
112     
113     // can be any static method that has a (String[]), (String) or () signature
114     String mainEntry = config.getProperty("target.entry", "main([Ljava/lang/String;)V");
115
116     String host = config.getString("target.host", "localhost");
117     
118     SystemClassLoaderInfo sysCli = createSystemClassLoaderInfo(0);
119     
120     return new ApplicationContext( 0, clsName, mainEntry, args, host, sysCli);
121   }
122   
123   
124   @Override
125   public boolean initialize(){
126     try {
127       // this has to happen before we load the startup classes during initializeMainThread
128       scheduler.initialize(this, appCtx);
129       
130       ThreadInfo tiMain = initializeMainThread(appCtx, 0);
131       initializeFinalizerThread(appCtx, 1);
132
133       if (tiMain == null) {
134         return false; // bail out
135       }
136
137       initSystemState(tiMain);
138       initialized = true;
139       notifyVMInitialized();
140       return true;
141       
142     } catch (JPFConfigException cfe){
143       log.severe(cfe.getMessage());
144       return false;
145     } catch (ClassInfoException cie){
146       log.severe(cie.getMessage());
147       return false;
148     }
149     // all other exceptions are JPF errors that should cause stack traces
150   }
151
152   
153   @Override
154   public int getNumberOfApplications(){
155     return 1;
156   }
157   
158   @Override
159   public String getSUTName() {
160     return appCtx.mainClassName;
161   }
162
163   @Override
164   public String getSUTDescription(){
165     StringBuilder sb = new StringBuilder();
166     sb.append(appCtx.mainClassName);
167     sb.append('.');
168     sb.append(Misc.upToFirst( appCtx.mainEntry, '('));
169     
170     sb.append('(');
171     String[] args = appCtx.args;
172     for (int i=0; i<args.length; i++){
173       if (i>0){
174         sb.append(',');
175       }
176       sb.append('"');
177       sb.append(args[i]);
178       sb.append('"');
179     }
180     sb.append(')');
181     return sb.toString();
182   }
183   
184   @Override
185   public ApplicationContext getApplicationContext(int obj) {
186     return appCtx;
187   }
188
189   @Override
190   public ApplicationContext[] getApplicationContexts(){
191     return new ApplicationContext[] { appCtx };
192   }
193   
194   @Override
195   public ApplicationContext getCurrentApplicationContext(){
196     ThreadInfo ti = ThreadInfo.getCurrentThread();
197     if (ti != null){
198       return ti.getApplicationContext();
199     } else {
200       return appCtx;
201     }
202   }
203   
204   /**
205    * The program is terminated if there are no alive threads, and there is no nonDaemon left.
206    * 
207    * NOTE - this is only approximated in real life. Daemon threads can still run for a few cycles
208    * after the last non-daemon died, which opens an interesting source of errors we
209    * actually might want to check for
210    */
211   @Override
212   public boolean isEndState () {
213     // note this uses 'alive', not 'runnable', hence isEndStateProperty won't
214     // catch deadlocks - but that would be NoDeadlockProperty anyway
215     
216     boolean hasNonTerminatedDaemon = getThreadList().hasAnyMatching(getUserLiveNonDaemonPredicate());
217     boolean hasRunnable = getThreadList().hasAnyMatching(getUserTimedoutRunnablePredicate());
218     boolean isEndState = !(hasNonTerminatedDaemon && hasRunnable);
219     
220     if(processFinalizers) {
221       if(isEndState) {
222         if(getFinalizerThread().isRunnable()) {
223           return false;
224         }
225       }
226     }
227     
228     return isEndState;
229   }
230
231   @Override
232   public boolean isDeadlocked () { 
233     boolean hasNonDaemons = false;
234     boolean hasBlockedThreads = false;
235
236     if (ss.isBlockedInAtomicSection()) {
237       return true; // blocked in atomic section
238     }
239
240     ThreadInfo[] threads = getThreadList().getThreads();
241
242     boolean hasUserThreads = false;
243     for (int i = 0; i < threads.length; i++) {
244       ThreadInfo ti = threads[i];
245       
246       if (ti.isAlive()){
247         hasNonDaemons |= !ti.isDaemon();
248
249         // shortcut - if there is at least one runnable, we are not deadlocked
250         if (ti.isTimeoutRunnable()) { // willBeRunnable() ?
251           return false;
252         }
253         
254         if(!ti.isSystemThread()) {
255           hasUserThreads = true;
256         }
257
258         // means it is not NEW or TERMINATED, i.e. live & blocked
259         hasBlockedThreads = true;
260       }
261     }
262
263     boolean isDeadlock = hasNonDaemons && hasBlockedThreads;
264     
265     if(processFinalizers && isDeadlock && !hasUserThreads) {
266       // all threads are blocked, system threads. If the finalizer thread  
267       // is in-use, then this is a deadlocked state.
268       return (!getFinalizerThread().isIdle());
269     }
270     
271     return isDeadlock;
272   }
273   
274   @Override
275   public void terminateProcess (ThreadInfo ti) {
276     SystemState ss = getSystemState();
277     ThreadInfo[] liveThreads = getLiveThreads();
278     ThreadInfo finalizerTi = null;
279
280     for (int i = 0; i < liveThreads.length; i++) {
281       if(!liveThreads[i].isSystemThread()) {
282         // keep the stack frames around, so that we can inspect the snapshot
283         liveThreads[i].setTerminated();
284       } else {
285         // FinalizerThread is not killed at this point. We need to keep it around in 
286         // case fianlizable objects are GCed after System.exit() returns.
287         finalizerTi = liveThreads[i];
288       }
289     }
290     
291     ss.setMandatoryNextChoiceGenerator( new BreakGenerator("exit", ti, true), "exit without break CG");
292     
293     // if there is a finalizer thread, we have to run the last GC, to queue finalizable objects, if any
294     if(finalizerTi != null) {
295       assert finalizerTi.isAlive();
296       activateGC();
297     }
298   }
299   
300   @Override
301   public Map<Integer,IntTable<String>> getInitialInternStringsMap() {
302     Map<Integer,IntTable<String>> interns = new HashMap<Integer,IntTable<String>>();
303     interns.put(0, appCtx.getInternStrings());
304     return interns;
305   }
306   
307   //---------- Predicates used to query threads from ThreadList ---------- //
308   
309   @Override
310   public Predicate<ThreadInfo> getRunnablePredicate() {
311     return runnablePredicate;
312   }
313   
314   @Override
315   public Predicate<ThreadInfo> getAppTimedoutRunnablePredicate() {
316     return getRunnablePredicate();
317   }
318   
319   @Override
320   public Predicate<ThreadInfo> getDaemonRunnablePredicate() {
321     return daemonRunnable;
322   }
323   
324   // ---------- Methods for handling finalizers ---------- //
325
326   @Override
327   void updateFinalizerQueues () {
328     getFinalizerThread().processNewFinalizables();
329   }
330 }