All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.evosuite.runtime.thread.ThreadStopper Maven / Gradle / Ivy

There is a newer version: 1.0.6
Show newest version
/**
 * Copyright (C) 2010-2017 Gordon Fraser, Andrea Arcuri and EvoSuite
 * contributors
 *
 * This file is part of EvoSuite.
 *
 * EvoSuite is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 3.0 of the License, or
 * (at your option) any later version.
 *
 * EvoSuite is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with EvoSuite. If not, see .
 */
package org.evosuite.runtime.thread;

import java.util.Arrays;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import org.evosuite.runtime.RuntimeSettings;
import org.evosuite.runtime.mock.java.util.MockTimer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * This class is used to try to stop all threads
 * spawn by the SUT.
 * 
 * @author arcuri
 *
 */
public class ThreadStopper {

	private static final Logger logger = LoggerFactory.getLogger(ThreadStopper.class);

	protected transient Set currentRunningThreads;

	private final KillSwitch killSwitch;
	
	/**
	 * Set of threads that we shouldn't try to stop, usually 
	 * based on:  
	 * TestCaseExecutor.TEST_EXECUTION_THREAD,
	 * Properties.IGNORE_THREADS
	 */
	private final Set threadsToIgnore;

	/**
	 * for how many ms should we wait on joining the threads?
	 */
	private final long timeout; 

	/**
	 * time stamp from when timeout are calculated
	 */
	private long startTime;
	
	
	/**
	 * 
	 */
	public ThreadStopper(KillSwitch killSwitch, Set threadsToIgnore, long timeout){
		this.killSwitch = killSwitch;
		this.timeout = timeout;
		if(threadsToIgnore == null){
			this.threadsToIgnore = new LinkedHashSet<>();
		} else {
			this.threadsToIgnore = threadsToIgnore;
		}
		this.startTime = 0;
	}

	public ThreadStopper(KillSwitch killSwitch,  long timeout, String ... threadsToIgnore){
		this(killSwitch, new LinkedHashSet(Arrays.asList(threadsToIgnore)), timeout);
	}
	
	public void startRecordingTime(){
		startTime = System.currentTimeMillis();
	}
	
	public long getStartTime(){
		return startTime;
	}
	
	/**
	 * 

* After the test case is executed, if any SUT thread is still running, we * will wait for their termination. To identify which thread belong to SUT, * before test case execution we should check which are the threads that are * running. *

*

* WARNING: The sandbox might prevent accessing thread informations, * so need to check carefully when/where this method is called *

*/ public void storeCurrentThreads() { if (currentRunningThreads == null) { currentRunningThreads = Collections.newSetFromMap(new IdentityHashMap()); } else { currentRunningThreads.clear(); } Map threadMap = Thread.getAllStackTraces(); for (Thread t : threadMap.keySet()) { if (t.isAlive()) { currentRunningThreads.add(t); } } } /** * Try to kill (and then join) the SUT threads. Killing the SUT threads is * important, because some spawn threads could just wait on objects/locks, * and so make the test case executions always last TIMEOUT ms. */ public void killAndJoinClientThreads() throws IllegalStateException { if (currentRunningThreads == null) { throw new IllegalStateException( "The current threads are not set. You need to call storeCurrentThreads() first"); } if(RuntimeSettings.mockJVMNonDeterminism){ MockTimer.stopAllTimers(); } // Using enumerate here because getAllStackTraces may call hashCode of the SUT, // if the SUT is a subclass of Thread Thread[] threadArray = new Thread[Thread.activeCount() + 2]; Thread.enumerate(threadArray); /* * First we set the kill switch in the instrumented bytecode, this * to prevent issues with code that do not handle interrupt */ killSwitch.setKillSwitch(true); /* * try to interrupt the SUT threads */ checkThreads: for (Thread t : threadArray) { // May happen... if(t == null){ continue; } if (t.isAlive() && !currentRunningThreads.contains(t)) { /* * We may want to ignore some threads such as GUI event handlers */ for(String name : threadsToIgnore) { if(t.getName().startsWith(name)) { continue checkThreads; } } t.interrupt(); } } /* * now, join up to a total of TIMEOUT ms. */ checkThreads: for (Thread t : threadArray) { // May happen... if(t == null) continue; if (t.isAlive() && !currentRunningThreads.contains(t)) { for(String name : threadsToIgnore) { if(t.getName().startsWith(name)) { continue checkThreads; } } logger.info("Found new thread"); try { /* * In total the test case should not run for more than Properties.TIMEOUT ms */ long delta = System.currentTimeMillis() - startTime; long waitingTime = timeout - delta; if (waitingTime > 0) { t.join(waitingTime); } } catch (InterruptedException e) { // What can we do? break; } if (t.isAlive()) { logger.info("Thread is still alive: " + t.getName()); } } } /* * we need it, otherwise issue during search in which accessing enum in SUT would call toString, * and so throw a TimeoutExceeded exception */ killSwitch.setKillSwitch(false); /* * important. this is used to later check if current threads are set */ currentRunningThreads = null; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy