/*
* Minha.pt: middleware testing platform.
* Copyright (c) 2011-2014, Universidade do Minho.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package pt.minha.models.local;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import pt.minha.api.Host;
import pt.minha.kernel.simulation.Resource;
import pt.minha.kernel.simulation.Timeline;
import pt.minha.models.fake.java.lang.Thread;
import pt.minha.models.global.EntryHandler;
import pt.minha.models.global.EntryInterface;
import pt.minha.models.global.ExitHandler;
import pt.minha.models.global.ResultHolder;
import pt.minha.models.global.disk.Storage;
import pt.minha.models.global.net.NetworkStack;
import pt.minha.models.local.lang.SimulationThread;
public class SimulationProcess implements EntryInterface {
private Set<SimulationThread> threads = new HashSet<SimulationThread>();
private long threadId = 0;
private Resource cpu;
private NetworkStack network;
private Storage storage;
private Host host;
private Map<Object,Object> sysProps;
private Thread.UncaughtExceptionHandler defaultHandler;
public SimulationProcess(Host host, Resource cpu, NetworkStack network, Storage storage, Map<Object,Object> props) {
this.host = host;
this.cpu = cpu;
this.network = network;
this.storage = storage;
this.sysProps = props;
}
public Host getHost() {
return host;
}
public Resource getCPU() {
return cpu;
}
public NetworkStack getNetwork() {
return network;
}
public Storage getStorage() {
return storage;
}
public Timeline getTimeline() {
return cpu.getTimeline();
}
public long getNextThreadId() {
return threadId++;
}
public Map<Object, Object> getSystemProperties() {
return sysProps;
}
public Thread.UncaughtExceptionHandler getDefaultHandler() {
return defaultHandler;
}
public void setDefaultHandler(Thread.UncaughtExceptionHandler defaultHandler) {
this.defaultHandler = defaultHandler;
}
/* The following methods are supposed to be called outside simulation events,
* as such, must be synchronized. */
public synchronized void addThread(SimulationThread simulationThread) {
threads.add(simulationThread);
}
public synchronized void removeThread(SimulationThread simulationThread) {
threads.remove(simulationThread);
}
public void stop() throws InterruptedException {
while(true) {
SimulationThread t = null;
synchronized(this) {
for(SimulationThread st: threads) {
if (!st.fake_isDaemon()) {
t = st;
break;
}
}
}
if (t==null)
break;
t.fake_join(0);
}
cpu.stop();
}
@Override
public EntryHandler createEntry(String impl) {
return new Trampoline(this, impl);
}
@SuppressWarnings("unchecked")
@Override
public <T> T createExit(Class<T> intf, final ExitHandler target) {
return (T) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class<?>[]{ intf }, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
SimulationThread.stopTime(target.getOverheadBefore());
ResultHolder result = new ResultHolder(method);
try {
if (target.isMilestone())
SimulationThread.currentSimulationThread().getTimeline().getScheduler().stop();
if (target.invoke(method, args, result)) {
if (target.getDelay()>0)
SimulationThread.currentSimulationThread().idle(target.getDelay(), false, false);
return result.waitResult();
}
return result.getFakeResult();
} finally {
SimulationThread.startTime(target.getOverheadAfter());
}
}
});
}
@Override
public void close() throws IOException {
ArrayList<SimulationThread> l = new ArrayList<SimulationThread>(threads);
for(SimulationThread t: l)
t.close();
network.close();
}
}