/** * **************************************************************************** * Copyright (c) 2010-2016 by Min Cai (min.cai.china@gmail.com). * <p> * This file is part of the Archimulator multicore architectural simulator. * <p> * Archimulator 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 3 of the License, or * (at your option) any later version. * <p> * Archimulator 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. * <p> * You should have received a copy of the GNU General Public License * along with Archimulator. If not, see <http://www.gnu.org/licenses/>. * **************************************************************************** */ package archimulator.os; import archimulator.common.*; import archimulator.core.Processor; import archimulator.core.Thread; import archimulator.isa.ArchitecturalRegisterFile; import archimulator.isa.StaticInstruction; import archimulator.os.signal.SignalMasks; import java.io.Serializable; import java.util.Stack; /** * Context. * * @author Min Cai */ public class Context extends BasicSimulationObject<CPUExperiment, Simulation> implements SimulationObject<CPUExperiment, Simulation>, Serializable { private int id; private ContextState state; private SignalMasks signalMasks; private int signalFinish; private ArchitecturalRegisterFile registerFile; private Kernel kernel; private int threadId = -1; private int userId; private int effectiveUserId; private int groupId; private int effectiveGroupId; private int processId; private Process process; private Context parent; private Stack<FunctionCallContext> functionCallContextStack; private boolean pseudoCallEncounteredInLastInstructionExecution; private boolean speculative; private ArchitecturalRegisterFile speculativeRegisterFile; /** * Create a context. * * @param kernel the kernel * @param contextMapping the context mapping * @return the newly created context */ public static Context load(Kernel kernel, ContextMapping contextMapping) { Process process = new BasicProcess(kernel, contextMapping); ArchitecturalRegisterFile regs = new ArchitecturalRegisterFile(process.isLittleEndian()); regs.setNpc(process.getProgramEntry()); regs.setNnpc(regs.getNpc() + 4); regs.setGpr(ArchitecturalRegisterFile.REGISTER_SP, process.getEnvironmentBase()); return new Context(kernel, process, null, regs, 0); } /** * Create a context. * * @param parent the parent context * @param registerFile the architectural register file * @param signalFinish the "finish" signal */ public Context(Context parent, ArchitecturalRegisterFile registerFile, int signalFinish) { this(parent.kernel, parent.process, parent, registerFile, signalFinish); } /** * Create a context. * * @param kernel the kernel * @param process the process * @param parent the parent context * @param registerFile the architectural register file * @param signalFinish the "finish" signal */ public Context(Kernel kernel, Process process, Context parent, ArchitecturalRegisterFile registerFile, int signalFinish) { super(kernel); this.kernel = kernel; this.parent = parent; this.registerFile = registerFile; this.signalFinish = signalFinish; this.id = kernel.currentContextId++; this.userId = (int) NativeSystemCalls.LIBC.getuid(); this.effectiveUserId = (int) NativeSystemCalls.LIBC.geteuid(); this.groupId = (int) NativeSystemCalls.LIBC.getgid(); this.effectiveGroupId = (int) NativeSystemCalls.LIBC.getegid(); this.processId = kernel.currentPid++; this.signalMasks = new SignalMasks(); this.state = ContextState.IDLE; this.functionCallContextStack = new Stack<>(); this.process = process; this.getBlockingEventDispatcher().dispatch(new ContextCreatedEvent(this)); } /** * Enter the speculative state. */ public void enterSpeculativeState() { try { this.process.getMemory().enterSpeculativeState(); this.speculativeRegisterFile = (ArchitecturalRegisterFile) this.registerFile.clone(); this.speculative = true; } catch (CloneNotSupportedException e) { throw new RuntimeException(e); } } /** * Exit the speculative state. */ public void exitSpeculativeState() { this.process.getMemory().exitSpeculativeState(); this.speculativeRegisterFile = null; this.speculative = false; } /** * Decode and return the next static instruction. * * @return the next static instruction */ public StaticInstruction decodeNextInstruction() { this.getRegisterFile().setPc(this.getRegisterFile().getNpc()); this.getRegisterFile().setNpc(this.getRegisterFile().getNnpc()); this.getRegisterFile().setNnpc(this.getRegisterFile().getNnpc() + 4); this.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_ZERO, 0); this.pseudoCallEncounteredInLastInstructionExecution = false; return this.decode(this.getRegisterFile().getPc()); } /** * Decode the static instruction at the specified mapped PC (program counter). * * @param mappedPc the mapped PC (program counter) * @return the static instruction at the specified mapped PC (program counter) */ protected StaticInstruction decode(int mappedPc) { return this.process.getStaticInstruction(mappedPc); } /** * Suspend the running of the context. */ public void suspend() { if ((this.state == ContextState.BLOCKED)) { throw new IllegalArgumentException(); } this.state = ContextState.BLOCKED; // Logger.infof(Logger.THREAD, "%s: thread suspended\n", this.getThread().getName()); } /** * Resume the running of the context. */ public void resume() { if ((this.state != ContextState.BLOCKED)) { throw new IllegalArgumentException(); } this.state = ContextState.RUNNING; // Logger.infof(Logger.THREAD, "%s: thread resumed\n", this.getThread().getName()); } /** * Finish the running of the context. */ public void finish() { if (this.state == ContextState.FINISHED) { throw new IllegalArgumentException(); } this.state = ContextState.FINISHED; this.kernel.getContexts().stream().filter(context -> context.getState() != ContextState.FINISHED && context.getParent() == this).forEach(Context::finish); if (this.signalFinish != 0 && this.parent != null) { this.parent.getSignalMasks().getPending().set(this.signalFinish); } // Logger.infof(Logger.THREAD, "%s: thread finished\n", this.getThread().getName()); } /** * Get the context's ID. * * @return the context's ID */ public int getId() { return id; } /** * Get the context's state. * * @return the context's state */ public ContextState getState() { return state; } /** * Set the context's state. * * @param state the context's state */ public void setState(ContextState state) { this.state = state; } /** * Get the currently in-use architectural register file, depending on whether the context is currently in the speculative mode or not. * * @return the currently in-use architectural register file, depending on whether the context is currently in the speculative mode or not */ public ArchitecturalRegisterFile getRegisterFile() { return !speculative ? registerFile : speculativeRegisterFile; } /** * Set the architectural register file. * * @param registerFile the architectural register file */ public void setRegisterFile(ArchitecturalRegisterFile registerFile) { this.registerFile = registerFile; } /** * Get the signal masks. * * @return the signal masks */ public SignalMasks getSignalMasks() { return signalMasks; } /** * Get the parent context. * * @return the parent context if any exists; otherwise null */ public Context getParent() { return parent; } /** * Get the kernel creating the context. * * @return the kernel creating the context */ public Kernel getKernel() { return kernel; } /** * Get the ID of the hardware thread that the context is mapped to. * * @return the ID of the hardware thread that the context is mapped to */ public int getThreadId() { return threadId; } /** * Set the ID of the hardware thread that the context is mapped to. * * @param threadId the ID of the hardware thread that the context is mapped to */ public void setThreadId(int threadId) { this.threadId = threadId; } /** * Get the hardware thread that the context is mapped to. * * @param processor the processor object * @return the hardware thread that the context is mapped to */ public Thread getThread(Processor processor) { int coreNum = this.threadId / processor.getCores().size(); int threadNum = this.threadId % processor.getCores().size(); return processor.getCores().get(coreNum).getThreads().get(threadNum); } /** * Get the process. * * @return the process */ public Process getProcess() { return process; } /** * Get the user ID. * * @return the user ID */ public int getUserId() { return userId; } /** * Get the effective user ID. * * @return the effective user ID */ public int getEffectiveUserId() { return effectiveUserId; } /** * Get the group ID. * * @return the group ID */ public int getGroupId() { return groupId; } /** * Get the effective group ID. * * @return the effective group ID */ public int getEffectiveGroupId() { return effectiveGroupId; } /** * Get the process's ID. * * @return the process's ID */ public int getProcessId() { return processId; } /** * Get the parent process's ID. * * @return the parent process's ID */ public int getParentProcessId() { return parent == null ? 1 : parent.getProcessId(); } /** * Get the stack of the function call contexts. * * @return the stack of the function call contexts */ public Stack<FunctionCallContext> getFunctionCallContextStack() { return functionCallContextStack; } /** * Get a value indicating whether the context is currently in the speculative mode or not. * * @return a value indicating whether the context is currently in the speculative mode or not */ public boolean isSpeculative() { return speculative; } /** * Get a value indicating whether the context is fetching instructions from the L1I cache or not (typically in the speculative execution scheme's hardware constructed context/thread). * * @return a value indicating whether the context is fetching instructions from the L1I cache or not */ public boolean useICache() { return true; } /** * Get a value indicating whether a pseudocall is encountered in the execution of the last instruction or not. * * @return a value indicating whether a pseudocall is encountered in the execution of the last instruction or not */ public boolean isPseudoCallEncounteredInLastInstructionExecution() { return pseudoCallEncounteredInLastInstructionExecution; } /** * Set a value indicating whether a pseudocall is encountered in the execution of the last instruction or not. * * @param pseudoCallEncounteredInLastInstructionExecution a value indicating whether a pseudocall is encountered in the execution of the last instruction or not */ public void setPseudoCallEncounteredInLastInstructionExecution(boolean pseudoCallEncounteredInLastInstructionExecution) { this.pseudoCallEncounteredInLastInstructionExecution = pseudoCallEncounteredInLastInstructionExecution; } @Override public String getName() { return "ctx" + threadId; } }