singrdk/base/Kernel/Singularity/Scheduling/Scheduler.cs

298 lines
8.7 KiB
C#

///////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: Scheduler.cs
//
// Note:
//
// #define DEBUG_SCHEDULER
#if DEBUG
#define SHOW_TWIDDLE
#else
//#define SHOW_TWIDDLE
#endif
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading;
using Microsoft.Singularity;
using Microsoft.Singularity.Hal;
using Microsoft.Singularity.Io;
namespace Microsoft.Singularity.Scheduling
{
[NoCCtor]
[CLSCompliant(false)]
public class Scheduler
{
// Global
[AccessedByRuntime("referenced from halidt.asm")]
private static SpinLock dispatchLock;
// List of per-processor idle threads.
protected static ThreadQueue idleThreads;
[NoHeapAllocation]
public static void DispatchLock()
{
dispatchLock.Acquire();
}
[NoHeapAllocation]
public static bool EnsureDispatchLock(int currentThreadIndex) {
if (dispatchLock.IsHeldBy(currentThreadIndex)) {
return false;
} else {
DispatchLock();
return true;
}
}
[NoHeapAllocation]
public static void DispatchRelease()
{
dispatchLock.Release();
}
[Conditional("DEBUG")]
[NoHeapAllocation]
public static void AssertDispatchLockHeld()
{
VTable.Assert(Processor.InterruptsDisabled());
VTable.Assert(dispatchLock.IsHeldBy(Thread.CurrentThread));
}
public static unsafe void Initialize()
{
// Scheduler visualization hack
// we use unsafe access to minimize the scheduler overhead.
screenMem = IoMemory.MapPhysicalMemory(0xb8000, 80*50*2, true, true);
screenPos = 0;
screenPtr = (ushort *)screenMem.VirtualAddress;
// Create the idle threads queue
idleThreads = new ThreadQueue();
// Create the twiddle values.
twiddles = new ushort[] {
(ushort)(0xe000 | '|'),
(ushort)(0xe000 | '/'),
(ushort)(0xe000 | '-'),
(ushort)(0xe000 | '\\')
};
tpos = 0;
}
public static void Finalize()
{
}
////////////////////////////////////////// Heads-up Scheduler Display.
//
private static IoMemory screenMem;
private static int screenPos;
private static unsafe ushort * screenPtr;
[Inline]
[NoHeapAllocation]
private static unsafe void DisplayThread(int id)
{
#if SHOW_TWIDDLE
screenPtr[screenPos] = (ushort)(0x2a00| ('@'+id));
screenPos = (screenPos + 1) % 80;
#endif
}
private static ushort[] twiddles;
private static int tpos;
[Inline]
[NoHeapAllocation]
private static unsafe void Twiddle()
{
#if SHOW_TWIDDLE
screenPtr[screenPos] = twiddles[tpos];
tpos = ++tpos & 3;
#endif
}
/////////////////////////////////////////////////// Logging Functions.
//
[NoHeapAllocation]
public static void SelectingThread(Thread thread)
{
Scheduler.AssertDispatchLockHeld();
Thread.CurrentThread.ActiveProcessor = null;
if (thread != null) {
int id = thread.GetThreadId();
DisplayThread(id);
thread.ActiveProcessor = Processor.CurrentProcessor;
#if DEBUG_DISPATCH
DebugStub.Print("Thread {0:x8} Selecting {1:x8}\n",
__arglist(
Kernel.AddressOf(Thread.CurrentThread),
Kernel.AddressOf(thread)));
#endif // DEBUG_DISPATCH
Tracing.Log(Tracing.Debug, "Selecting tid={0:x3}", (uint)id);
VTable.Assert(!thread.schedulerEntry.Enqueued);
}
Twiddle();
}
[NoHeapAllocation]
public static bool IsIdleThread(int threadIndex) {
Thread thread = Thread.threadTable[threadIndex];
return (thread != null &&
idleThreads.IsEnqueued(thread.schedulerEntry));
}
[Conditional("DEBUG_SCHEDULER")]
[CLSCompliant(false)]
public static void LogWakeThread(Thread thread)
{
}
[Conditional("DEBUG_SCHEDULER")]
public static void LogSchedulerLate()
{
}
[Conditional("DEBUG_SCHEDULER")]
public static void LogContextSwitch()
{
}
[Conditional("DEBUG_SCHEDULER")]
public static void LogTimeJump()
{
}
[Conditional("DEBUG_SCHEDULER")]
public static void LogSleepAdd()
{
}
[Conditional("DEBUG_SCHEDULER")]
public static void LogReschedule()
{
}
/////////////////////////////////////////// Scheduling Event Handlers.
//
// Each of these should be replaced by the scheduler mixin.
//
[CLSCompliant(false)]
public static void OnThreadStateInitialize(Thread thread, bool constructorCalled)
{
// Only initialize thread-local state! No locks held and interrupts on.
DebugStub.Break();
}
[CLSCompliant(false)]
public static void OnThreadStart(Thread thread)
{
AssertDispatchLockHeld();
Debug.Assert(thread.freezeCount == 0);
DebugStub.Break();
}
[CLSCompliant(false)]
public static Thread OnThreadBlocked(Thread thread, SchedulerTime stop)
{
// Scheduler should return the target thread.
AssertDispatchLockHeld();
DebugStub.Break();
return null;
}
[CLSCompliant(false)]
[NoHeapAllocation]
public static void OnThreadUnblocked(Thread thread)
{
// The scheduler should add this thread to the runnable queue,
// but should not perform a context switch yet.
AssertDispatchLockHeld();
DebugStub.Break();
}
[CLSCompliant(false)]
[NoHeapAllocation]
public static Thread OnThreadYield(Thread thread)
{
AssertDispatchLockHeld();
DebugStub.Break();
return null;
}
[CLSCompliant(false)]
public static Thread OnThreadStop(Thread thread)
{
AssertDispatchLockHeld();
DebugStub.Break();
return null;
}
[CLSCompliant(false)]
public static void OnThreadFreezeIncrement(Thread thread)
{
// Increment freezeCount and unschedule the thread until
// freezeCount==0. (Used for Thread.Stop, Thread.Suspend,
// and modifying a thread's garbage collection state)
//
// If the thread is already running on a processor,
// the scheduler need not unschedule it immediately, but:
// - the thread must be unscheduled within a bounded time
// (e.g. a time slice)
// - once unscheduled, the thread must not be scheduled
// again until freezeCount==0.
AssertDispatchLockHeld();
DebugStub.Break();
}
[CLSCompliant(false)]
public static void OnThreadFreezeDecrement(Thread thread)
{
// Decrement freezeCount. If freezeCount reaches 0,
// the thread may now be scheduled (if it is
// not blocked).
AssertDispatchLockHeld();
DebugStub.Break();
}
[CLSCompliant(false)]
[NoHeapAllocation]
public static Thread OnTimerInterrupt(Thread thread, SchedulerTime now)
{
AssertDispatchLockHeld();
DebugStub.Break();
return null;
}
[CLSCompliant(false)]
[NoHeapAllocation]
public static Thread OnIoInterrupt(Thread thread)
{
AssertDispatchLockHeld();
DebugStub.Break();
return null;
}
[CLSCompliant(false)]
[NoHeapAllocation]
public static void OnProcessorShutdown(Thread thread)
{
AssertDispatchLockHeld();
DebugStub.Break();
}
}
}