vmprocessor.java
来自「纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统」· Java 代码 · 共 373 行
JAVA
373 行
/*
* $Id: VmProcessor.java,v 1.11 2004/02/24 08:04:48 epr Exp $
*/
package org.jnode.vm;
import org.jnode.vm.classmgr.VmStatics;
/**
* Abstract processor wrapper.
*
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
public abstract class VmProcessor extends VmSystemObject {
/** The thread switch indicator KEEP THIS THE FIRST FIELD!!! */
private volatile int threadSwitchIndicator;
/** The current thread on this processor */
private volatile VmThread currentThread;
/** The next thread to schedule on this processor */
volatile VmThread nextThread;
/** Stack end of current thread. This field is used by the native code. */
volatile Address stackEnd;
/** The identifier of this processor */
private final int id;
/** IRQ manager for this processor */
private IRQManager irqMgr;
/** Address of threadSwitchIndicator */
private Address tsiAddress;
/** My ready queue */
private final VmThreadQueue readyQueue;
/** My sleep queue */
private final VmThreadQueue sleepQueue;
/** The architecture of this processor */
private final VmArchitecture architecture;
/** The idle thread */
private IdleThread idleThread;
private int lockCount;
/** CPU identification */
private transient CpuID cpuId;
/** The statics table (int[]) */
private volatile Object staticsTable;
/** Indicate the a thread switch is needed */
public static final int TSI_SWITCH_NEEDED = 0x0001;
/** Indicate that the system is ready for thread switching */
public static final int TSI_SYSTEM_READY = 0x0002;
/** Indicate the a thread switch is in progress */
public static final int TSI_SWITCH_ACTIVE = 0x0004;
/** Indicate the a thread switch cannot occur */
public static final int TSI_BLOCK_SWITCH = 0x0008;
/** Indicate the a thread switch is requested */
public static final int TSI_SWITCH_REQUESTED = TSI_SWITCH_NEEDED | TSI_SYSTEM_READY;
/**
* Initialize this instance
*
* @param id
* @param architecture
*/
public VmProcessor(int id, VmArchitecture architecture, VmStatics statics) {
this.id = id;
this.architecture = architecture;
this.staticsTable = statics.getTable();
this.readyQueue = new VmThreadQueue("ready", false);
this.sleepQueue = new VmThreadQueue("sleep", true);
this.currentThread = createThread();
}
/**
* Gets the architecture of this processor.
* @return the architecture of this processor
*/
public final VmArchitecture getArchitecture() {
return architecture;
}
/**
* Gets the current thread on this processor
* @return The current thread on this processor
* @throws PragmaUninterruptible
*/
public final VmThread getCurrentThread()
throws PragmaUninterruptible {
return currentThread;
}
/**
* Gets the identifier of this processor.
*
* @return Returns the id.
*/
public final int getId() {
return this.id;
}
/**
* Block any yieldpoints on this processor.
* @throws PragmaUninterruptible
*/
final void disableReschedule()
throws PragmaUninterruptible {
Unsafe.atomicOr(getTSIAddress(), TSI_BLOCK_SWITCH);
lockCount++;
}
/**
* Unblock any yieldpoints on this processor.
* @throws PragmaUninterruptible
*/
final void enableReschedule()
throws PragmaUninterruptible {
lockCount--;
if (lockCount == 0) {
Unsafe.atomicAnd(getTSIAddress(), ~TSI_BLOCK_SWITCH);
}
}
/**
* @return Returns the threadSwitchIndicator.
*/
public final int getThreadSwitchIndicator() {
return this.threadSwitchIndicator;
}
/**
* Add the given thread to the ready queue to the scheduler and remove it from the sleep queue
* (if it still was on the sleep queue)
*
* @param thread
* @param ignorePriority
* If true, the thread is always added to the back of the list, regarding its
* priority.
* @param caller
* @throws PragmaUninterruptible
*/
final void addToReadyQueue(VmThread thread, boolean ignorePriority, String caller)
throws PragmaUninterruptible {
if (thread.isRunning() || thread.isYielding()) {
sleepQueue.remove(thread);
readyQueue.add(thread, ignorePriority, caller);
} else {
Unsafe.debug("Thread must be in running state to add to ready queue, not ");
Unsafe.debug(thread.getThreadState());
architecture.getStackReader().debugStackTrace();
Unsafe.die("addToReadyQueue");
}
}
/**
* Add the given thread to the sleep queue to this scheduler.
*
* @param thread
* @throws PragmaUninterruptible
*/
final void addToSleepQueue(VmThread thread)
throws PragmaUninterruptible {
sleepQueue.add(thread, false, null);
}
/**
* Give up the current cpu-time, and add the current thread to the back of the ready queue.
*
* @param ignorePriority
* If true, the thread is always added to the back of the list, regarding its
* priority.
* @throws PragmaUninterruptible
*/
final void yield(boolean ignorePriority)
throws PragmaUninterruptible {
final VmThread t = this.currentThread;
t.setYieldingState();
addToReadyQueue(t, ignorePriority, "proc.yield");
threadSwitchIndicator |= TSI_SWITCH_NEEDED;
if (threadSwitchIndicator != TSI_SWITCH_REQUESTED) {
Unsafe.debug("Yield with invalid tsi: " + threadSwitchIndicator);
architecture.getStackReader().debugStackTrace();
Unsafe.die("yield");
}
Unsafe.yieldPoint();
}
/**
* Given the current cpu-time. The current thread is not added to any queue.
* @throws PragmaUninterruptible
*/
final void suspend()
throws PragmaUninterruptible {
if (lockCount != 1) {
Unsafe.debug("Suspend with invalid lockCount: ");
Unsafe.debug(lockCount);
architecture.getStackReader().debugStackTrace();
Unsafe.die("suspend");
}
final VmThread t = this.currentThread;
t.setYieldingState();
threadSwitchIndicator |= TSI_SWITCH_NEEDED;
enableReschedule();
if (threadSwitchIndicator != TSI_SWITCH_REQUESTED) {
Unsafe.debug("Suspend with invalid tsi: ");
Unsafe.debug(threadSwitchIndicator);
architecture.getStackReader().debugStackTrace();
Unsafe.die("reschedule");
}
Unsafe.yieldPoint();
}
/**
* This method is called by the timer interrupt with interrupts disabled. Keep this method as
* short and as fast as possible!
* @throws PragmaUninterruptible
*/
final void reschedule()
throws PragmaUninterruptible, PragmaLoadStatics {
//Unsafe.debug("R");
this.nextThread = null;
try {
// Get the current thread
final VmThread current = currentThread;
// Dispatch interrupts if we already have an IRQ manager.
final IRQManager irqMgr = this.irqMgr;
if (irqMgr != null) {
irqMgr.dispatchInterrupts(current);
}
// Add the current thread to the ready queue, if the state
// is running.
if (current.isRunning()) {
addToReadyQueue(current, false, "proc.reschedule");
} else {
//Screen.debug("<Non-running thread in reschedule "+ current.getThreadState() + "
// called "+ current.asThread().getName() + "/>");
//Unsafe.die();
}
// Determine the new thread.
VmThread newThread;
// Should we wakeup a sleeping thread?
newThread = sleepQueue.first();
if (newThread != null) {
final long curTime = VmSystem.currentKernelMillis();
if (newThread.canWakeup(curTime)) {
sleepQueue.remove(newThread);
} else {
newThread = null;
}
}
// Take the first thread from the ready queue
if (newThread == null) {
newThread = readyQueue.first();
if (newThread != null) {
readyQueue.remove(newThread);
}
}
// It no other thread want to run, that means that the idle thread
// has been halted, we give up.
if (newThread == null) {
Unsafe.debug("No Threads to run!");
Unsafe.die("reschedule");
}
newThread.wakeUpByScheduler();
this.nextThread = newThread;
} catch (Throwable ex) {
try {
ex.printStackTrace();
} catch (Throwable ex2) {
Unsafe.debug("Exception in Exception in Scheduler");
/* Ignore */
}
Unsafe.die("reschedule");
}
}
/**
* Create a new thread
* @return The new thread
*/
protected abstract VmThread createThread();
/**
* Create a new thread
* @param javaThread
* @return The new thread
*/
public abstract VmThread createThread(Thread javaThread);
/**
* Gets the IRQ counters array.
* @return The irq counter array
*/
protected abstract int[] getIrqCounters();
/**
* Mark the system are ready for thread switching
*/
final void systemReadyForThreadSwitch() {
if (idleThread == null) {
idleThread = new IdleThread();
idleThread.start();
}
Unsafe.atomicOr(getTSIAddress(), TSI_SYSTEM_READY);
}
/**
* Gets the address of the threadSwitchIndicator field in this object. It is assumed the this
* field is the first field of this class!
* @return The address of the thread switch indicator
*/
private final Address getTSIAddress() {
if (tsiAddress == null) {
tsiAddress = Unsafe.addressOf(this);
}
return tsiAddress;
}
/**
* Gets my IRQ manager.
* @return The irq manager
*/
public final synchronized IRQManager getIRQManager() {
if (irqMgr == null) {
irqMgr = new IRQManager(getIrqCounters());
}
return irqMgr;
}
/**
* Gets the CPU identification of this processor.
* @return The CPU id.
*/
public final CpuID getCPUID() {
if (cpuId == null) {
final int length = Unsafe.getCPUID(null);
final int[] id = new int[length];
Unsafe.getCPUID(id);
cpuId = loadCPUID(id);
}
return cpuId;
}
/**
* Load the CPU id.
* @param id The idenfication returned by Unsafe.getCpuID
* @return CpuID
*/
protected abstract CpuID loadCPUID(int[] id);
/**
* Set the CPU id.
* @param id The new cpu id
*/
protected final void setCPUID(CpuID id) {
this.cpuId = id;
}
/**
* @return Returns the staticsTable.
*/
final Object getStaticsTable() {
return this.staticsTable;
}
/**
* @param staticsTable The staticsTable to set.
*/
final void setStaticsTable(Object staticsTable) {
this.staticsTable = staticsTable;
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?