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.
18 package gov.nasa.jpf.vm;
20 import java.util.HashMap;
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;
33 * @author Nastaran Shafiei <nastaran.shafiei@gmail.com>
35 * Includes the VM initialization for executing single Java process
37 * To use this jpf.properties includes,
38 * vm.class = gov.nasa.jpf.vm.SingleProcessVM
40 public class SingleProcessVM extends VM {
42 protected ApplicationContext appCtx; // we only have one
44 protected Predicate<ThreadInfo> runnablePredicate;
45 protected Predicate<ThreadInfo> daemonRunnable;
47 protected SingleProcessVM (){}
49 public SingleProcessVM (JPF jpf, Config conf) {
52 appCtx = createApplicationContext();
54 initializePredicates();
57 void initializePredicates() {
58 // set predicates used to query from threadlist
59 runnablePredicate = new Predicate<ThreadInfo>(){
61 public boolean isTrue (ThreadInfo ti){
62 return (ti.isRunnable());
66 daemonRunnable = new Predicate<ThreadInfo>(){
68 public boolean isTrue (ThreadInfo ti){
69 return (ti.isDaemon() && ti.isRunnable());
74 protected ApplicationContext createApplicationContext (){
78 String[] freeArgs = config.getFreeArgs();
79 clsName = config.getProperty("target"); // explicit 'target' takes precedence
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];
86 if (freeArgs.length > 1){ // if there is no 'target' command line overrides 'target.args'
87 args = Misc.arrayWithoutFirst(freeArgs, 1);
89 args = config.getStringArray("target.args");
93 // since there was a 'target', 'target.args' override command line
94 args = config.getCompactStringArray("target.args");
96 if (freeArgs != null){
106 if (clsName == null){
107 throw new JPFConfigException("no target class specified, terminating");
109 if (!isValidClassName(clsName)){
110 throw new JPFConfigException("main class not a valid class name: " + clsName);
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");
116 String host = config.getString("target.host", "localhost");
118 SystemClassLoaderInfo sysCli = createSystemClassLoaderInfo(0);
120 return new ApplicationContext( 0, clsName, mainEntry, args, host, sysCli);
125 public boolean initialize(){
127 // this has to happen before we load the startup classes during initializeMainThread
128 scheduler.initialize(this, appCtx);
130 ThreadInfo tiMain = initializeMainThread(appCtx, 0);
131 initializeFinalizerThread(appCtx, 1);
133 if (tiMain == null) {
134 return false; // bail out
137 initSystemState(tiMain);
139 notifyVMInitialized();
142 } catch (JPFConfigException cfe){
143 log.severe(cfe.getMessage());
145 } catch (ClassInfoException cie){
146 log.severe(cie.getMessage());
149 // all other exceptions are JPF errors that should cause stack traces
154 public int getNumberOfApplications(){
159 public String getSUTName() {
160 return appCtx.mainClassName;
164 public String getSUTDescription(){
165 StringBuilder sb = new StringBuilder();
166 sb.append(appCtx.mainClassName);
168 sb.append(Misc.upToFirst( appCtx.mainEntry, '('));
171 String[] args = appCtx.args;
172 for (int i=0; i<args.length; i++){
181 return sb.toString();
185 public ApplicationContext getApplicationContext(int obj) {
190 public ApplicationContext[] getApplicationContexts(){
191 return new ApplicationContext[] { appCtx };
195 public ApplicationContext getCurrentApplicationContext(){
196 ThreadInfo ti = ThreadInfo.getCurrentThread();
198 return ti.getApplicationContext();
205 * The program is terminated if there are no alive threads, and there is no nonDaemon left.
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
212 public boolean isEndState () {
213 // note this uses 'alive', not 'runnable', hence isEndStateProperty won't
214 // catch deadlocks - but that would be NoDeadlockProperty anyway
216 boolean hasNonTerminatedDaemon = getThreadList().hasAnyMatching(getUserLiveNonDaemonPredicate());
217 boolean hasRunnable = getThreadList().hasAnyMatching(getUserTimedoutRunnablePredicate());
218 boolean isEndState = !(hasNonTerminatedDaemon && hasRunnable);
220 if(processFinalizers) {
222 if(getFinalizerThread().isRunnable()) {
232 public boolean isDeadlocked () {
233 boolean hasNonDaemons = false;
234 boolean hasBlockedThreads = false;
236 if (ss.isBlockedInAtomicSection()) {
237 return true; // blocked in atomic section
240 ThreadInfo[] threads = getThreadList().getThreads();
242 boolean hasUserThreads = false;
243 for (int i = 0; i < threads.length; i++) {
244 ThreadInfo ti = threads[i];
247 hasNonDaemons |= !ti.isDaemon();
249 // shortcut - if there is at least one runnable, we are not deadlocked
250 if (ti.isTimeoutRunnable()) { // willBeRunnable() ?
254 if(!ti.isSystemThread()) {
255 hasUserThreads = true;
258 // means it is not NEW or TERMINATED, i.e. live & blocked
259 hasBlockedThreads = true;
263 boolean isDeadlock = hasNonDaemons && hasBlockedThreads;
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());
275 public void terminateProcess (ThreadInfo ti) {
276 SystemState ss = getSystemState();
277 ThreadInfo[] liveThreads = getLiveThreads();
278 ThreadInfo finalizerTi = null;
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();
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];
291 ss.setMandatoryNextChoiceGenerator( new BreakGenerator("exit", ti, true), "exit without break CG");
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();
301 public Map<Integer,IntTable<String>> getInitialInternStringsMap() {
302 Map<Integer,IntTable<String>> interns = new HashMap<Integer,IntTable<String>>();
303 interns.put(0, appCtx.getInternStrings());
307 //---------- Predicates used to query threads from ThreadList ---------- //
310 public Predicate<ThreadInfo> getRunnablePredicate() {
311 return runnablePredicate;
315 public Predicate<ThreadInfo> getAppTimedoutRunnablePredicate() {
316 return getRunnablePredicate();
320 public Predicate<ThreadInfo> getDaemonRunnablePredicate() {
321 return daemonRunnable;
324 // ---------- Methods for handling finalizers ---------- //
327 void updateFinalizerQueues () {
328 getFinalizerThread().processNewFinalizables();