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 + -
显示快捷键?