Mercurial > hg > Members > kono > jpf-core
view src/main/gov/nasa/jpf/vm/SingleProcessVM.java @ 0:61d41facf527
initial v8 import (history reset)
author | Peter Mehlitz <Peter.C.Mehlitz@nasa.gov> |
---|---|
date | Fri, 23 Jan 2015 10:14:01 -0800 |
parents | |
children |
line wrap: on
line source
/* * Copyright (C) 2014, United States Government, as represented by the * Administrator of the National Aeronautics and Space Administration. * All rights reserved. * * The Java Pathfinder core (jpf-core) platform is licensed under the * Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package gov.nasa.jpf.vm; import java.util.HashMap; import java.util.Map; import gov.nasa.jpf.Config; import gov.nasa.jpf.JPF; import gov.nasa.jpf.JPFConfigException; import gov.nasa.jpf.util.IntTable; import gov.nasa.jpf.util.Misc; import gov.nasa.jpf.util.Predicate; import gov.nasa.jpf.vm.choice.BreakGenerator; /** * @author Nastaran Shafiei <nastaran.shafiei@gmail.com> * * Includes the VM initialization for executing single Java process * * To use this jpf.properties includes, * vm.class = gov.nasa.jpf.vm.SingleProcessVM */ public class SingleProcessVM extends VM { protected ApplicationContext appCtx; // we only have one protected Predicate<ThreadInfo> runnablePredicate; protected Predicate<ThreadInfo> daemonRunnable; protected SingleProcessVM (){} public SingleProcessVM (JPF jpf, Config conf) { super(jpf, conf); appCtx = createApplicationContext(); initializePredicates(); } void initializePredicates() { // set predicates used to query from threadlist runnablePredicate = new Predicate<ThreadInfo>(){ @Override public boolean isTrue (ThreadInfo ti){ return (ti.isRunnable()); } }; daemonRunnable = new Predicate<ThreadInfo>(){ @Override public boolean isTrue (ThreadInfo ti){ return (ti.isDaemon() && ti.isRunnable()); } }; } protected ApplicationContext createApplicationContext (){ String clsName; String[] args = null; String[] freeArgs = config.getFreeArgs(); clsName = config.getProperty("target"); // explicit 'target' takes precedence if (clsName == null){ if (freeArgs != null){ // if it is non-null, there is at least one entry // note that application property filenames have been removed by Config since they are part of its initialization clsName = freeArgs[0]; if (freeArgs.length > 1){ // if there is no 'target' command line overrides 'target.args' args = Misc.arrayWithoutFirst(freeArgs, 1); } else { args = config.getStringArray("target.args"); } } } else { // since there was a 'target', 'target.args' override command line args = config.getCompactStringArray("target.args"); if (args == null){ if (freeArgs != null){ args = freeArgs; } } } // sanity checks if (args == null){ args = EMPTY_ARGS; } if (clsName == null){ throw new JPFConfigException("no target class specified, terminating"); } if (!isValidClassName(clsName)){ throw new JPFConfigException("main class not a valid class name: " + clsName); } // can be any static method that has a (String[]), (String) or () signature String mainEntry = config.getProperty("target.entry", "main([Ljava/lang/String;)V"); String host = config.getString("target.host", "localhost"); SystemClassLoaderInfo sysCli = createSystemClassLoaderInfo(0); return new ApplicationContext( 0, clsName, mainEntry, args, host, sysCli); } @Override public boolean initialize(){ try { // this has to happen before we load the startup classes during initializeMainThread scheduler.initialize(this, appCtx); ThreadInfo tiMain = initializeMainThread(appCtx, 0); initializeFinalizerThread(appCtx, 1); if (tiMain == null) { return false; // bail out } initSystemState(tiMain); initialized = true; notifyVMInitialized(); return true; } catch (JPFConfigException cfe){ log.severe(cfe.getMessage()); return false; } catch (ClassInfoException cie){ log.severe(cie.getMessage()); return false; } // all other exceptions are JPF errors that should cause stack traces } @Override public int getNumberOfApplications(){ return 1; } @Override public String getSUTName() { return appCtx.mainClassName; } @Override public String getSUTDescription(){ StringBuilder sb = new StringBuilder(); sb.append(appCtx.mainClassName); sb.append('.'); sb.append(Misc.upToFirst( appCtx.mainEntry, '(')); sb.append('('); String[] args = appCtx.args; for (int i=0; i<args.length; i++){ if (i>0){ sb.append(','); } sb.append('"'); sb.append(args[i]); sb.append('"'); } sb.append(')'); return sb.toString(); } @Override public ApplicationContext getApplicationContext(int obj) { return appCtx; } @Override public ApplicationContext[] getApplicationContexts(){ return new ApplicationContext[] { appCtx }; } @Override public ApplicationContext getCurrentApplicationContext(){ ThreadInfo ti = ThreadInfo.getCurrentThread(); if (ti != null){ return ti.getApplicationContext(); } else { return appCtx; } } /** * The program is terminated if there are no alive threads, and there is no nonDaemon left. * * NOTE - this is only approximated in real life. Daemon threads can still run for a few cycles * after the last non-daemon died, which opens an interesting source of errors we * actually might want to check for */ @Override public boolean isEndState () { // note this uses 'alive', not 'runnable', hence isEndStateProperty won't // catch deadlocks - but that would be NoDeadlockProperty anyway boolean hasNonTerminatedDaemon = getThreadList().hasAnyMatching(getUserLiveNonDaemonPredicate()); boolean hasRunnable = getThreadList().hasAnyMatching(getUserTimedoutRunnablePredicate()); boolean isEndState = !(hasNonTerminatedDaemon && hasRunnable); if(processFinalizers) { if(isEndState) { if(getFinalizerThread().isRunnable()) { return false; } } } return isEndState; } @Override public boolean isDeadlocked () { boolean hasNonDaemons = false; boolean hasBlockedThreads = false; if (ss.isBlockedInAtomicSection()) { return true; // blocked in atomic section } ThreadInfo[] threads = getThreadList().getThreads(); boolean hasUserThreads = false; for (int i = 0; i < threads.length; i++) { ThreadInfo ti = threads[i]; if (ti.isAlive()){ hasNonDaemons |= !ti.isDaemon(); // shortcut - if there is at least one runnable, we are not deadlocked if (ti.isTimeoutRunnable()) { // willBeRunnable() ? return false; } if(!ti.isSystemThread()) { hasUserThreads = true; } // means it is not NEW or TERMINATED, i.e. live & blocked hasBlockedThreads = true; } } boolean isDeadlock = hasNonDaemons && hasBlockedThreads; if(processFinalizers && isDeadlock && !hasUserThreads) { // all threads are blocked, system threads. If the finalizer thread // is in-use, then this is a deadlocked state. return (!getFinalizerThread().isIdle()); } return isDeadlock; } @Override public void terminateProcess (ThreadInfo ti) { SystemState ss = getSystemState(); ThreadInfo[] liveThreads = getLiveThreads(); ThreadInfo finalizerTi = null; for (int i = 0; i < liveThreads.length; i++) { if(!liveThreads[i].isSystemThread()) { // keep the stack frames around, so that we can inspect the snapshot liveThreads[i].setTerminated(); } else { // FinalizerThread is not killed at this point. We need to keep it around in // case fianlizable objects are GCed after System.exit() returns. finalizerTi = liveThreads[i]; } } ss.setMandatoryNextChoiceGenerator( new BreakGenerator("exit", ti, true), "exit without break CG"); // if there is a finalizer thread, we have to run the last GC, to queue finalizable objects, if any if(finalizerTi != null) { assert finalizerTi.isAlive(); activateGC(); } } @Override public Map<Integer,IntTable<String>> getInitialInternStringsMap() { Map<Integer,IntTable<String>> interns = new HashMap<Integer,IntTable<String>>(); interns.put(0, appCtx.getInternStrings()); return interns; } //---------- Predicates used to query threads from ThreadList ---------- // @Override public Predicate<ThreadInfo> getRunnablePredicate() { return runnablePredicate; } @Override public Predicate<ThreadInfo> getAppTimedoutRunnablePredicate() { return getRunnablePredicate(); } @Override public Predicate<ThreadInfo> getDaemonRunnablePredicate() { return daemonRunnable; } // ---------- Methods for handling finalizers ---------- // @Override void updateFinalizerQueues () { getFinalizerThread().processNewFinalizables(); } }