Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

458 lines
9.8 KiB

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
Thread.c
Abstract:
This file contains functions for tracking and manipulating threads
Author:
Dave Hastings (daveh) 18-Apr-1992
Revision History:
--*/
#include <monitorp.h>
#include <malloc.h>
extern VDM_INTERRUPTHANDLER DpmiInterruptHandlers[];
extern VDM_FAULTHANDLER DpmiFaultHandlers[];
// Instantiated in vdpm.c
extern PFAMILY_TABLE *pgDpmVdmFamTbls;
//
// Local Types
//
typedef struct _MonitorThread {
struct _MonitorThread *Previous;
struct _MonitorThread *Next;
PVOID Teb;
HANDLE Thread;
VDM_TIB VdmTib;
} MONITORTHREAD, *PMONITORTHREAD;
//
// Local Variables
//
PMONITORTHREAD ThreadList = NULL; // List of all threads registered
VOID
InitVdmTib(
PVDM_TIB VdmTib
)
/*++
Routine Description:
This routine is used to initialize the VdmTib.
Arguments:
VdmTib - supplies a pointer to the vdm tib to be initialized
Return Value:
None.
--*/
{
VdmTib->IntelMSW = 0;
VdmTib->VdmContext.SegGs = 0;
VdmTib->VdmContext.SegFs = 0;
VdmTib->VdmContext.SegEs = 0;
VdmTib->VdmContext.SegDs = 0;
VdmTib->VdmContext.SegCs = 0;
VdmTib->VdmContext.Eip = 0xFFF0L;
VdmTib->VdmContext.EFlags = 0x02L | EFLAGS_INTERRUPT_MASK;
VdmTib->MonitorContext.SegDs = KGDT_R3_DATA | RPL_MASK;
VdmTib->MonitorContext.SegEs = KGDT_R3_DATA | RPL_MASK;
VdmTib->MonitorContext.SegGs = 0;
VdmTib->MonitorContext.SegFs = KGDT_R3_TEB | RPL_MASK;
VdmTib->PrinterInfo.prt_State = NULL;
VdmTib->PrinterInfo.prt_Control = NULL;
VdmTib->PrinterInfo.prt_Status = NULL;
VdmTib->PrinterInfo.prt_HostState = NULL;
ASSERT(VDM_NUMBER_OF_LPT == 3);
VdmTib->PrinterInfo.prt_Mode[0] =
VdmTib->PrinterInfo.prt_Mode[1] =
VdmTib->PrinterInfo.prt_Mode[2] = PRT_MODE_NO_SIMULATION;
VdmTib->VdmFaultTable = DpmiFaultHandlers;
VdmTib->VdmInterruptTable = DpmiInterruptHandlers;
VdmTib->ContinueExecution = FALSE;
VdmTib->NumTasks = -1;
VdmTib->Size = sizeof(VDM_TIB);
}
VOID
cpu_createthread(
HANDLE Thread,
PVDM_TIB VdmTib
)
/*++
Routine Description:
This routine adds a thread to the list of threads that could be executing
in application mode.
Arguments:
Thread -- Supplies a thread handle
VdmContext -- Supplies a pointer to the VdmContext for the new thread
Return Value:
None.
--*/
{
PMONITORTHREAD NewThread, CurrentThread;
THREAD_BASIC_INFORMATION ThreadInfo;
HANDLE MonitorThreadHandle;
NTSTATUS Status;
//
// Correctly initialize the floating point context for the thread
//
InitialContext.ContextFlags = CONTEXT_FLOATING_POINT;
if (DebugContextActive)
InitialContext.ContextFlags |= CONTEXT_DEBUG_REGISTERS;
Status = NtSetContextThread(
Thread,
&InitialContext
);
if (!NT_SUCCESS(Status)) {
#if DBG
DbgPrint("NtVdm terminating : Could not set float context for\n"
" thread handle 0x%x, status %lx\n", Thread, Status);
DbgBreakPoint();
#endif
TerminateVDM();
}
//
// Set up a structure to keep track of the new thread
//
NewThread = malloc(sizeof(MONITORTHREAD));
if (!NewThread) {
#if DBG
DbgPrint("NTVDM: Could not allocate space for new thread\n");
DbgBreakPoint();
#endif
TerminateVDM();
}
RtlZeroMemory(NewThread, sizeof(MONITORTHREAD));
if (VdmTib == NULL) {
InitVdmTib(&NewThread->VdmTib);
} else {
RtlCopyMemory(&NewThread->VdmTib, VdmTib, sizeof(VDM_TIB));
NewThread->VdmTib.ContinueExecution = FALSE;
NewThread->VdmTib.NumTasks = -1;
NewThread->VdmTib.VdmContext.EFlags = 0x02L | EFLAGS_INTERRUPT_MASK;
NewThread->VdmTib.MonitorContext.EFlags = 0x02L | EFLAGS_INTERRUPT_MASK;
}
// All tasks start with a ptr to the VDM global tables
NewThread->VdmTib.pDpmFamTbls = (PFAMILY_TABLE *)pgDpmVdmFamTbls;
//
// Create a handle for the monitor to use
//
Status = NtDuplicateObject(
NtCurrentProcess(),
Thread,
NtCurrentProcess(),
&MonitorThreadHandle,
0,
0,
DUPLICATE_SAME_ACCESS
);
if (!NT_SUCCESS(Status)) {
#if DBG
DbgPrint("NTVDM: Could not duplicate thread handle\n");
DbgBreakPoint();
#endif
TerminateVDM();
}
NewThread->Thread = MonitorThreadHandle;
Status = NtQueryInformationThread(
MonitorThreadHandle,
ThreadBasicInformation,
&ThreadInfo,
sizeof(THREAD_BASIC_INFORMATION),
NULL
);
if (!NT_SUCCESS(Status)) {
#if DBG
DbgPrint("NTVDM: Could not get thread information\n");
DbgBreakPoint();
#endif
TerminateVDM();
}
NewThread->Teb = ThreadInfo.TebBaseAddress;
((PTEB)(NewThread->Teb))->Vdm = &NewThread->VdmTib;
//
// Insert the new thread in the list. The list is sorted in ascending
// order of Teb address
//
if (!ThreadList) {
ThreadList = NewThread;
NewThread->Next = NULL;
NewThread->Previous = NULL;
return;
}
CurrentThread = ThreadList;
while ((CurrentThread->Next) && (CurrentThread->Teb < NewThread->Teb)) {
CurrentThread = CurrentThread->Next;
}
if (NewThread->Teb > CurrentThread->Teb) {
CurrentThread->Next = NewThread;
NewThread->Previous = CurrentThread;
NewThread->Next = NULL;
} else {
ASSERT((CurrentThread->Teb != NewThread->Teb));
NewThread->Previous = CurrentThread->Previous;
NewThread->Next = CurrentThread;
CurrentThread->Previous = NewThread;
if (NewThread->Previous) {
NewThread->Previous->Next = NewThread;
} else {
ThreadList = NewThread;
}
}
}
VOID
cpu_exitthread(
VOID
)
/*++
Routine Description:
This routine frees the thread tracking information, and closes the thread
handle
Arguments:
Return Value:
None.
--*/
{
PVOID CurrentTeb;
NTSTATUS Status;
PMONITORTHREAD ThreadInfo;
CurrentTeb = NtCurrentTeb();
ThreadInfo = ThreadList;
//
// Find this thread in the list
//
while ((ThreadInfo) && (ThreadInfo->Teb != CurrentTeb)) {
ThreadInfo = ThreadInfo->Next;
}
if (!ThreadInfo) {
#if DBG
DbgPrint("NTVDM: Could not find thread in list\n");
DbgBreakPoint();
#endif
return;
}
//
// Close our handle to this thread
//
Status = NtClose(ThreadInfo->Thread);
#if DBG
if (!NT_SUCCESS(Status)) {
DbgPrint("NTVDM: Could not close thread handle\n");
}
#endif
//
// Remove this thread from the list
//
if (ThreadInfo->Previous) {
ThreadInfo->Previous->Next = ThreadInfo->Next;
} else {
ThreadList = ThreadInfo->Next;
}
if (ThreadInfo->Next) {
ThreadInfo->Next->Previous = ThreadInfo->Previous;
}
free(ThreadInfo);
}
HANDLE
ThreadLookUp(
PVOID Teb
)
/*++
Routine Description:
This routine returns the handle for the specified thread.
Arguments:
Teb -- Supplies the teb pointer of the thread
Return Value:
Returns the handle of the thread, or NULL
--*/
{
PMONITORTHREAD Thread;
Thread = ThreadList;
while ((Thread) && (Thread->Teb != Teb)) {
Thread = Thread->Next;
}
if (Thread) {
return Thread->Thread;
} else {
return NULL;
}
}
BOOL
ThreadSetDebugContext(
PULONG pDebugRegisters
)
/*++
Routine Description:
This routine sets the debug registers for all the threads that the
monitor knows about.
Arguments:
pDebugRegisters -- Pointer to 6 dwords containing the requested debug
register contents.
Return Value:
none
--*/
{
PMONITORTHREAD Thread;
NTSTATUS Status = STATUS_SUCCESS;
Thread = ThreadList;
InitialContext.ContextFlags = CONTEXT_DEBUG_REGISTERS;
InitialContext.Dr0 = *pDebugRegisters++;
InitialContext.Dr1 = *pDebugRegisters++;
InitialContext.Dr2 = *pDebugRegisters++;
InitialContext.Dr3 = *pDebugRegisters++;
InitialContext.Dr6 = *pDebugRegisters++;
InitialContext.Dr7 = *pDebugRegisters++;
while (Thread) {
Status = NtSetContextThread(
Thread->Thread,
&InitialContext
);
if (!NT_SUCCESS(Status))
break;
Thread = Thread->Next;
}
if (!NT_SUCCESS(Status))
return (FALSE);
else {
DebugContextActive = ((InitialContext.Dr7 & 0x0f) != 0);
return (TRUE);
}
}
BOOL
ThreadGetDebugContext(
PULONG pDebugRegisters
)
/*++
Routine Description:
This routine gets the debug registers for the current thread.
Arguments:
pDebugRegisters -- Pointer to 6 dwords to receive the debug
register contents.
Return Value:
none
--*/
{
CONTEXT CurrentContext;
NTSTATUS Status;
CurrentContext.ContextFlags = CONTEXT_DEBUG_REGISTERS;
Status = NtGetContextThread(NtCurrentThread(), &CurrentContext);
if (!NT_SUCCESS(Status)) {
return FALSE;
}
*pDebugRegisters++ = CurrentContext.Dr0;
*pDebugRegisters++ = CurrentContext.Dr1;
*pDebugRegisters++ = CurrentContext.Dr2;
*pDebugRegisters++ = CurrentContext.Dr3;
*pDebugRegisters++ = CurrentContext.Dr6;
*pDebugRegisters++ = CurrentContext.Dr7;
return (TRUE);
}