285 lines
11 KiB
C#
285 lines
11 KiB
C#
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Microsoft Research Singularity
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// File: ThreadContext.cs
|
|
//
|
|
// Note:
|
|
//
|
|
|
|
namespace Microsoft.Singularity.X86
|
|
{
|
|
using System;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Runtime.InteropServices;
|
|
using System.Threading;
|
|
|
|
using Microsoft.Singularity.V1.Threads;
|
|
using Microsoft.Singularity.X86;
|
|
|
|
[NoCCtor]
|
|
[CLSCompliant(false)]
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
internal struct ThreadContext
|
|
{
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal ushort num;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal ushort regs;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal unsafe ThreadContext * prev;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal unsafe ThreadContext * next;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal UIntPtr cr2;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal UIntPtr cr3;
|
|
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal unsafe ThreadContext * prevInKern;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal unsafe ThreadContext * nextInKern;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal unsafe ThreadContext * prevInProc;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal unsafe ThreadContext * nextInProc;
|
|
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal UIntPtr err;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal UIntPtr eip;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal UIntPtr cs0;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal UIntPtr efl;
|
|
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal UIntPtr eax;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal UIntPtr ebx;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal UIntPtr ecx;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal UIntPtr edx;
|
|
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal UIntPtr esp;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal UIntPtr ebp;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal UIntPtr esi;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal UIntPtr edi;
|
|
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal UIntPtr stackBegin;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal UIntPtr stackLimit;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal ushort processId;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal bool uncaughtFlag; // true means "uncaught exception from process, so throw exception in kernel"
|
|
[AccessedByRuntime("referenced from halforgc.asm")]
|
|
internal bool suspendAlert; // true means "check whether thread should suspend"
|
|
|
|
// Note: These two forks must be exactly the same size, but their
|
|
// fields alias differently for kernel or process code.
|
|
#if SINGULARITY_KERNEL
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal unsafe Thread *_thread;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal UIntPtr processThread;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal unsafe System.GCs.CallStack.TransitionRecord * stackMarkers;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal unsafe System.GCs.CallStack.TransitionRecord * processMarkers;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal ushort threadIndex;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal ushort processThreadIndex;
|
|
#elif SINGULARITY_PROCESS
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal UIntPtr kernelThread;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal unsafe Thread *_thread;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal unsafe System.GCs.CallStack.TransitionRecord * kernelMarkers;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal unsafe System.GCs.CallStack.TransitionRecord * stackMarkers;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal ushort kernelThreadIndex;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal ushort threadIndex;
|
|
#endif
|
|
[AccessedByRuntime("referenced from halforgc.asm")]
|
|
internal unsafe int gcStates;
|
|
|
|
|
|
// See ThreadContext.IsInKernelMode
|
|
private unsafe System.GCs.CallStack.TransitionRecord * modeMarker;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal UIntPtr dr0;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal UIntPtr dr1;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal UIntPtr dr2;
|
|
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal UIntPtr dr3;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal UIntPtr dr6;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal UIntPtr dr7;
|
|
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal MmxContext mmx;
|
|
|
|
#if PAGING
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal UIntPtr abiStackHead;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal UIntPtr abiStackBegin;
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal UIntPtr abiStackLimit;
|
|
#endif
|
|
|
|
#if THREAD_TIME_ACCOUNTING
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal ulong lastExecutionTimeUpdate;
|
|
|
|
[AccessedByRuntime("referenced from c++")]
|
|
internal ulong executionTime;
|
|
#endif
|
|
//////////////////////////////////////////////// Methods & Properties.
|
|
//
|
|
internal Thread thread {
|
|
[NoHeapAllocation]
|
|
get { return GetThread(); }
|
|
}
|
|
|
|
[NoHeapAllocation]
|
|
internal unsafe bool IsFirst()
|
|
{
|
|
return (((UIntPtr)prev) == UIntPtr.Zero);
|
|
}
|
|
|
|
internal bool WasInterrupted {
|
|
[NoHeapAllocation]
|
|
get { return (efl & EFlags.IF) != 0; }
|
|
}
|
|
|
|
[AccessedByRuntime("referenced from c++")]
|
|
// Return true if the thread is in kernel mode, false if the
|
|
// thread is in process mode.
|
|
// Note that by the time this method returns, the thread might
|
|
// have already switched to a different mode; in other words,
|
|
// don't rely on this result of this method being up-to-date unless
|
|
// the thread is suspended or blocked.
|
|
[NoHeapAllocation]
|
|
internal unsafe bool IsInKernelMode()
|
|
{
|
|
// When a thread enters process mode, RuntimeEntryPoint
|
|
// sets modeMarker=processMarkers. Thus, in process mode:
|
|
//
|
|
// modeMarker == processMarkers
|
|
//
|
|
// When a thread in process mode calls the kernel, pushStackMark
|
|
// pushes a child process marker onto the stack, so that
|
|
// modeMarker is left pointing to the new processMarker's
|
|
// parent (the old processMarker). Thus, in kernel mode:
|
|
//
|
|
// modeMarker == parent(processMarkers)
|
|
//
|
|
// This keeps the mode in sync with the process stack markers,
|
|
// which is convenient though not essential. This assumes that
|
|
// the only reason a process pushes a stack marker is to enter
|
|
// kernel mode.
|
|
//
|
|
// Since processMarkers may be null, ThreadContext.ParentModeMarker
|
|
// defines a special definition for parent(null).
|
|
#if SINGULARITY_PROCESS
|
|
System.GCs.CallStack.TransitionRecord * processMarkers =
|
|
stackMarkers;
|
|
#endif // SINGULARITY_PROCESS
|
|
if (modeMarker == processMarkers) {
|
|
return false;
|
|
}
|
|
else {
|
|
VTable.Assert(modeMarker == ParentModeMarker(processMarkers));
|
|
return true;
|
|
}
|
|
}
|
|
|
|
[AccessedByRuntime("referenced from c++")]
|
|
[NoHeapAllocation]
|
|
internal unsafe void SetKernelMode()
|
|
{
|
|
#if SINGULARITY_PROCESS
|
|
System.GCs.CallStack.TransitionRecord * processMarkers =
|
|
stackMarkers;
|
|
#endif // SINGULARITY_PROCESS
|
|
modeMarker = ParentModeMarker(processMarkers);
|
|
}
|
|
|
|
[AccessedByRuntime("referenced from c++")]
|
|
[NoHeapAllocation]
|
|
internal unsafe void SetProcessMode()
|
|
{
|
|
#if SINGULARITY_PROCESS
|
|
System.GCs.CallStack.TransitionRecord * processMarkers =
|
|
stackMarkers;
|
|
#endif // SINGULARITY_PROCESS
|
|
modeMarker = processMarkers;
|
|
}
|
|
|
|
[NoHeapAllocation]
|
|
static private unsafe System.GCs.CallStack.TransitionRecord *
|
|
ParentModeMarker(System.GCs.CallStack.TransitionRecord * child)
|
|
{
|
|
System.GCs.CallStack.TransitionRecord * bottom =
|
|
(System.GCs.CallStack.TransitionRecord *) (-1);
|
|
|
|
VTable.Assert(child != bottom);
|
|
if (child == null) {
|
|
return bottom;
|
|
}
|
|
else {
|
|
return child->oldTransitionRecord;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////// External Methods.
|
|
//
|
|
[AccessedByRuntime("output to header: defined in c++")]
|
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
[StackBound(32)]
|
|
[NoHeapAllocation]
|
|
private extern Thread GetThread();
|
|
|
|
[AccessedByRuntime("output to header: defined in c++")]
|
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
[StackBound(32)]
|
|
[NoHeapAllocation]
|
|
internal extern void UpdateAfterGC(Thread thread);
|
|
|
|
[AccessedByRuntime("output to header: defined in c++")]
|
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
[GCAnnotation(GCOption.NOGC)]
|
|
[StackBound(32)]
|
|
[NoHeapAllocation]
|
|
internal extern void Initialize(int threadIndex, UIntPtr stackBegin, uint cr3);
|
|
|
|
#if SINGULARITY_KERNEL
|
|
[AccessedByRuntime("output to header: defined in c++")]
|
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
[GCAnnotation(GCOption.NOGC)]
|
|
[StackBound(32)]
|
|
[NoHeapAllocation]
|
|
internal extern void InitializeIdle(int threadIndex, UIntPtr stackBegin, uint cr3);
|
|
|
|
#endif
|
|
}
|
|
}
|