Alex Ionescu <ionucu@videotron.ca>

- Removed ke/alert.c and moved its functions where they belong.
- Commented and organized KeInitializeThread.
- Began switch to true KOBJECT enumeration used in NT.
- Implemented KeAlertResumeThread and NtAlertResumeThread.
- Harmonized Formatting in ke/kthread.c

svn path=/trunk/; revision=13974
This commit is contained in:
Thomas Bluemel 2005-03-12 19:23:04 +00:00
parent a8f6850b9f
commit b2a42182ef
10 changed files with 643 additions and 499 deletions

View file

@ -58,7 +58,7 @@ static ULONG gNumberOfControllers = 0;
/* Queue thread management */ /* Queue thread management */
static KEVENT QueueThreadTerminate; static KEVENT QueueThreadTerminate;
static PVOID ThreadObject; static PVOID QueueThreadObject;
static VOID NTAPI MotorStopDpcFunc(PKDPC UnusedDpc, static VOID NTAPI MotorStopDpcFunc(PKDPC UnusedDpc,
@ -378,8 +378,8 @@ static VOID NTAPI Unload(PDRIVER_OBJECT DriverObject)
KdPrint(("floppy: unloading\n")); KdPrint(("floppy: unloading\n"));
KeSetEvent(&QueueThreadTerminate, 0, FALSE); KeSetEvent(&QueueThreadTerminate, 0, FALSE);
KeWaitForSingleObject(ThreadObject, Executive, KernelMode, FALSE, 0); KeWaitForSingleObject(QueueThreadObject, Executive, KernelMode, FALSE, 0);
ObDereferenceObject(ThreadObject); ObDereferenceObject(QueueThreadObject);
for(i = 0; i < gNumberOfControllers; i++) for(i = 0; i < gNumberOfControllers; i++)
{ {
@ -1152,7 +1152,7 @@ NTSTATUS NTAPI DriverEntry(PDRIVER_OBJECT DriverObject,
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
if(ObReferenceObjectByHandle(ThreadHandle, STANDARD_RIGHTS_ALL, NULL, KernelMode, &ThreadObject, NULL) != STATUS_SUCCESS) if(ObReferenceObjectByHandle(ThreadHandle, STANDARD_RIGHTS_ALL, NULL, KernelMode, &QueueThreadObject, NULL) != STATUS_SUCCESS)
{ {
KdPrint(("floppy: Unable to reference returned thread handle; failing init\n")); KdPrint(("floppy: Unable to reference returned thread handle; failing init\n"));
return STATUS_UNSUCCESSFUL; return STATUS_UNSUCCESSFUL;

View file

@ -36,23 +36,34 @@ typedef VOID STDCALL_FUNC
struct _DISPATCHER_HEADER; struct _DISPATCHER_HEADER;
typedef enum _KERNEL_OBJECTS { typedef enum _KOBJECTS {
KNotificationEvent = 0, EventNotificationObject = 0,
KSynchronizationEvent = 1, EventSynchronizationObject = 1,
KMutant = 2, MutantObject = 2,
KProcess = 3, ProcessObject = 3,
KQueue = 4, QueueObject = 4,
KSemaphore = 5, SemaphoreObject = 5,
KThread = 6, ThreadObject = 6,
KNotificationTimer = 8, GateObject = 7,
KSynchronizationTimer = 9, TimerNotificationObject = 8,
KApc = 18, TimerSynchronizationObject = 9,
KDpc = 19, Spare2Object = 10,
KDeviceQueue = 20, Spare3Object = 11,
KEventPair = 21, Spare4Object = 12,
KInterrupt = 22, Spare5Object = 13,
KProfile = 23 Spare6Object = 14,
} KERNEL_OBJECTS; Spare7Object = 15,
Spare8Object = 16,
Spare9Object = 17,
ApcObject = 18,
DpcObject = 19,
DeviceQueueObject = 20,
EventPairObject = 21,
InterruptObject = 22,
ProfileObject = 23,
ThreadedDpcObject = 24,
MaximumKernelObject = 25
} KOBJECTS;
#include <pshpack1.h> #include <pshpack1.h>

View file

@ -113,8 +113,7 @@ OBJECTS_KE = \
ke/sem.o \ ke/sem.o \
ke/spinlock.o \ ke/spinlock.o \
ke/timer.o \ ke/timer.o \
ke/wait.o \ ke/wait.o
ke/alert.o
# Memory Manager (Mm) # Memory Manager (Mm)
OBJECTS_MM = \ OBJECTS_MM = \

View file

@ -498,7 +498,7 @@ VOID STDCALL PsExitSpecialApc(PKAPC Apc,
#define PROCESS_PRIO_RT 18 #define PROCESS_PRIO_RT 18
VOID VOID STDCALL
KeInitializeThread(PKPROCESS Process, PKTHREAD Thread, BOOLEAN First); KeInitializeThread(PKPROCESS Process, PKTHREAD Thread, BOOLEAN First);
NTSTATUS KeReleaseThread(PKTHREAD Thread); NTSTATUS KeReleaseThread(PKTHREAD Thread);

View file

@ -1,150 +0,0 @@
/* $Id:$
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/ke/alert.c
* PURPOSE: Alerts
*
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
*/
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>
/* GLOBALS *******************************************************************/
/* FUNCTIONS *****************************************************************/
BOOLEAN
STDCALL
KeTestAlertThread(IN KPROCESSOR_MODE AlertMode)
/*
* FUNCTION: Tests whether there are any pending APCs for the current thread
* and if so the APCs will be delivered on exit from kernel mode
*/
{
KIRQL OldIrql;
PKTHREAD Thread = KeGetCurrentThread();
BOOLEAN OldState;
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
OldIrql = KeAcquireDispatcherDatabaseLock();
KiAcquireSpinLock(&Thread->ApcQueueLock);
OldState = Thread->Alerted[AlertMode];
/* If the Thread is Alerted, Clear it */
if (OldState) {
Thread->Alerted[AlertMode] = FALSE;
} else if ((AlertMode == UserMode) && (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))) {
/* If the mode is User and the Queue isn't empty, set Pending */
Thread->ApcState.UserApcPending = TRUE;
}
KiReleaseSpinLock(&Thread->ApcQueueLock);
KeReleaseDispatcherDatabaseLock(OldIrql);
return OldState;
}
VOID
KeAlertThread(PKTHREAD Thread, KPROCESSOR_MODE AlertMode)
{
KIRQL oldIrql;
oldIrql = KeAcquireDispatcherDatabaseLock();
/* Return if thread is already alerted. */
if (Thread->Alerted[AlertMode] == FALSE)
{
if (Thread->State == THREAD_STATE_BLOCKED &&
(AlertMode == KernelMode || Thread->WaitMode == AlertMode) &&
Thread->Alertable)
{
KiAbortWaitThread(Thread, STATUS_ALERTED);
}
else
{
Thread->Alerted[AlertMode] = TRUE;
}
}
KeReleaseDispatcherDatabaseLock(oldIrql);
}
/*
*
* NOT EXPORTED
*/
NTSTATUS STDCALL
NtAlertResumeThread(IN HANDLE ThreadHandle,
OUT PULONG SuspendCount)
{
UNIMPLEMENTED;
return(STATUS_NOT_IMPLEMENTED);
}
/*
* @implemented
*
* EXPORTED
*/
NTSTATUS STDCALL
NtAlertThread (IN HANDLE ThreadHandle)
{
KPROCESSOR_MODE PreviousMode;
PETHREAD Thread;
NTSTATUS Status;
PreviousMode = ExGetPreviousMode();
Status = ObReferenceObjectByHandle(ThreadHandle,
THREAD_SUSPEND_RESUME,
PsThreadType,
PreviousMode,
(PVOID*)&Thread,
NULL);
if (!NT_SUCCESS(Status))
{
return(Status);
}
/* do an alert depending on the processor mode. If some kmode code wants to
enforce a umode alert it should call KeAlertThread() directly. If kmode
code wants to do a kmode alert it's sufficient to call it with Zw or just
use KeAlertThread() directly */
KeAlertThread(&Thread->Tcb, PreviousMode);
ObDereferenceObject(Thread);
return(STATUS_SUCCESS);
}
/*
* NOT EXPORTED
*/
NTSTATUS
STDCALL
NtTestAlert(VOID)
{
KPROCESSOR_MODE PreviousMode;
PreviousMode = ExGetPreviousMode();
/* Check and Alert Thread if needed */
return KeTestAlertThread(PreviousMode) ? STATUS_ALERTED : STATUS_SUCCESS;
}

View file

@ -58,7 +58,7 @@ KeInitializeApc(
/* Set up the basic APC Structure Data */ /* Set up the basic APC Structure Data */
RtlZeroMemory(Apc, sizeof(KAPC)); RtlZeroMemory(Apc, sizeof(KAPC));
Apc->Type = KApc; Apc->Type = ApcObject;
Apc->Size = sizeof(KAPC); Apc->Size = sizeof(KAPC);
/* Set the Environment */ /* Set the Environment */

View file

@ -88,7 +88,7 @@ KeInitializeDpc (PKDPC Dpc,
*/ */
{ {
DPRINT("DPC Initializing: %x with Routine: %x\n", Dpc, DeferredRoutine); DPRINT("DPC Initializing: %x with Routine: %x\n", Dpc, DeferredRoutine);
Dpc->Type = KDpc; Dpc->Type = DpcObject;
Dpc->Number= 0; Dpc->Number= 0;
Dpc->Importance= MediumImportance; Dpc->Importance= MediumImportance;
Dpc->DeferredRoutine = DeferredRoutine; Dpc->DeferredRoutine = DeferredRoutine;

View file

@ -1,11 +1,11 @@
/* $Id$ /*
*
* COPYRIGHT: See COPYING in the top level directory * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel * PROJECT: ReactOS kernel
* FILE: ntoskrnl/ke/kthread.c * FILE: ntoskrnl/ke/kthread.c
* PURPOSE: Microkernel thread support * PURPOSE: Microkernel thread support
* *
* PROGRAMMERS: David Welch (welch@cwcom.net) * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) - Commented, reorganized some stuff, fixed/implemented some functions.
* David Welch (welch@cwcom.net)
*/ */
/* INCLUDES *****************************************************************/ /* INCLUDES *****************************************************************/
@ -16,19 +16,93 @@
/* FUNCTIONS *****************************************************************/ /* FUNCTIONS *****************************************************************/
VOID ULONG
KiServiceCheck (VOID) STDCALL
KeAlertResumeThread(IN PKTHREAD Thread)
{ {
PETHREAD Thread; ULONG PreviousCount;
KIRQL OldIrql;
Thread = PsGetCurrentThread(); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
if (Thread->Tcb.ServiceTable != KeServiceDescriptorTableShadow) /* Lock the Dispatcher Database and the APC Queue */
{ OldIrql = KeAcquireDispatcherDatabaseLock();
PsInitWin32Thread (Thread); KiAcquireSpinLock(&Thread->ApcQueueLock);
Thread->Tcb.ServiceTable = KeServiceDescriptorTableShadow; /* Return if Thread is already alerted. */
if (Thread->Alerted[KernelMode] == FALSE) {
/* If it's Blocked, unblock if it we should */
if (Thread->State == THREAD_STATE_BLOCKED && Thread->Alertable) {
DPRINT("Aborting Wait\n");
KiAbortWaitThread(Thread, STATUS_ALERTED);
} else {
/* If not, simply Alert it */
Thread->Alerted[KernelMode] = TRUE;
}
} }
/* Save the old Suspend Count */
PreviousCount = Thread->SuspendCount;
/* If the thread is suspended, decrease one of the suspend counts */
if (PreviousCount) {
/* Decrease count. If we are now zero, unwait it completely */
if (--Thread->SuspendCount) {
/* Signal and satisfy */
Thread->SuspendSemaphore.Header.SignalState++;
KiDispatcherObjectWake(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT);
}
}
/* Release Locks and return the Old State */
KiReleaseSpinLock(&Thread->ApcQueueLock);
KeReleaseDispatcherDatabaseLock(OldIrql);
return PreviousCount;
}
BOOLEAN
STDCALL
KeAlertThread(PKTHREAD Thread,
KPROCESSOR_MODE AlertMode)
{
KIRQL OldIrql;
BOOLEAN PreviousState;
/* Acquire the Dispatcher Database Lock */
OldIrql = KeAcquireDispatcherDatabaseLock();
/* Save the Previous State */
PreviousState = Thread->Alerted[AlertMode];
/* Return if Thread is already alerted. */
if (PreviousState == FALSE) {
/* If it's Blocked, unblock if it we should */
if (Thread->State == THREAD_STATE_BLOCKED &&
(AlertMode == KernelMode || Thread->WaitMode == AlertMode) &&
Thread->Alertable) {
DPRINT("Aborting Wait\n");
KiAbortWaitThread(Thread, STATUS_ALERTED);
} else {
/* If not, simply Alert it */
Thread->Alerted[AlertMode] = TRUE;
}
}
/* Release the Dispatcher Lock */
KeReleaseDispatcherDatabaseLock(OldIrql);
/* Return the old state */
return PreviousState;
} }
/* /*
@ -36,28 +110,231 @@ KiServiceCheck (VOID)
*/ */
VOID VOID
STDCALL STDCALL
KeCapturePersistentThreadState( KeCapturePersistentThreadState(IN PVOID CurrentThread,
IN PVOID CurrentThread, IN ULONG Setting1,
IN ULONG Setting1, IN ULONG Setting2,
IN ULONG Setting2, IN ULONG Setting3,
IN ULONG Setting3, IN ULONG Setting4,
IN ULONG Setting4, IN ULONG Setting5,
IN ULONG Setting5, IN PVOID ThreadState)
IN PVOID ThreadState
)
{ {
UNIMPLEMENTED; UNIMPLEMENTED;
} }
/*
* FUNCTION: Initialize the microkernel state of the thread
*/
VOID VOID
KeFreeStackPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address, STDCALL
PFN_TYPE Page, SWAPENTRY SwapEntry, BOOLEAN Dirty) KeInitializeThread(PKPROCESS Process,
PKTHREAD Thread,
BOOLEAN First)
{ {
ASSERT(SwapEntry == 0); PVOID KernelStack;
if (Page != 0) NTSTATUS Status;
{ extern unsigned int init_stack_top;
MmReleasePageMemoryConsumer(MC_NPPOOL, Page); extern unsigned int init_stack;
PMEMORY_AREA StackArea;
ULONG i;
PHYSICAL_ADDRESS BoundaryAddressMultiple;
/* Initialize the Boundary Address */
BoundaryAddressMultiple.QuadPart = 0;
/* Initalize the Dispatcher Header */
KeInitializeDispatcherHeader(&Thread->DispatcherHeader,
ThreadObject,
sizeof(KTHREAD),
FALSE);
InitializeListHead(&Thread->MutantListHead);
/* If this is isn't the first thread, allocate the Kernel Stack */
if (!First) {
PFN_TYPE Page[MM_STACK_SIZE / PAGE_SIZE];
KernelStack = NULL;
MmLockAddressSpace(MmGetKernelAddressSpace());
Status = MmCreateMemoryArea(NULL,
MmGetKernelAddressSpace(),
MEMORY_AREA_KERNEL_STACK,
&KernelStack,
MM_STACK_SIZE,
0,
&StackArea,
FALSE,
FALSE,
BoundaryAddressMultiple);
MmUnlockAddressSpace(MmGetKernelAddressSpace());
/* Check for Success */
if (!NT_SUCCESS(Status)) {
DPRINT1("Failed to create thread stack\n");
KEBUGCHECK(0);
}
/* Mark the Stack */
for (i = 0; i < (MM_STACK_SIZE / PAGE_SIZE); i++) {
Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page[i]);
/* Check for success */
if (!NT_SUCCESS(Status)) {
KEBUGCHECK(0);
}
}
/* Create a Virtual Mapping for it */
Status = MmCreateVirtualMapping(NULL,
KernelStack,
PAGE_READWRITE,
Page,
MM_STACK_SIZE / PAGE_SIZE);
/* Check for success */
if (!NT_SUCCESS(Status)) {
KEBUGCHECK(0);
}
/* Set the Kernel Stack */
Thread->InitialStack = (PCHAR)KernelStack + MM_STACK_SIZE;
Thread->StackBase = (PCHAR)KernelStack + MM_STACK_SIZE;
Thread->StackLimit = (ULONG_PTR)KernelStack;
Thread->KernelStack = (PCHAR)KernelStack + MM_STACK_SIZE;
} else {
/* Use the Initial Stack */
Thread->InitialStack = (PCHAR)init_stack_top;
Thread->StackBase = (PCHAR)init_stack_top;
Thread->StackLimit = (ULONG_PTR)init_stack;
Thread->KernelStack = (PCHAR)init_stack_top;
} }
/*
* Establish the pde's for the new stack and the thread structure within the
* address space of the new process. They are accessed while taskswitching or
* while handling page faults. At this point it isn't possible to call the
* page fault handler for the missing pde's.
*/
MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread->StackLimit, MM_STACK_SIZE);
MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread, sizeof(ETHREAD));
/* Set the Thread to initalized */
Thread->State = THREAD_STATE_INITIALIZED;
/* The Native API function will initialize the TEB field later */
Thread->Teb = NULL;
/* Initialize stuff to zero */
Thread->TlsArray = NULL;
Thread->DebugActive = 0;
Thread->Alerted[0] = 0;
Thread->Alerted[1] = 0;
Thread->Iopl = 0;
/* Set up FPU/NPX Stuff */
Thread->NpxState = NPX_STATE_INVALID;
Thread->NpxIrql = 0;
/* Setup APC Fields */
InitializeListHead(&Thread->ApcState.ApcListHead[0]);
InitializeListHead(&Thread->ApcState.ApcListHead[1]);
Thread->ApcState.Process = Process;
Thread->ApcState.KernelApcInProgress = 0;
Thread->ApcState.KernelApcPending = 0;
Thread->ApcState.UserApcPending = 0;
Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState;
Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState;
Thread->ApcStateIndex = OriginalApcEnvironment;
Thread->ApcQueueable = TRUE;
RtlZeroMemory(&Thread->SavedApcState, sizeof(KAPC_STATE));
KeInitializeSpinLock(&Thread->ApcQueueLock);
/* Setup Wait Fields */
Thread->WaitStatus = STATUS_SUCCESS;
Thread->WaitIrql = PASSIVE_LEVEL;
Thread->WaitMode = 0;
Thread->WaitNext = FALSE;
Thread->WaitListEntry.Flink = NULL;
Thread->WaitListEntry.Blink = NULL;
Thread->WaitTime = 0;
Thread->WaitBlockList = NULL;
RtlZeroMemory(Thread->WaitBlock, sizeof(KWAIT_BLOCK) * 4);
RtlZeroMemory(&Thread->Timer, sizeof(KTIMER));
KeInitializeTimer(&Thread->Timer);
/* Setup scheduler Fields */
Thread->BasePriority = Process->BasePriority;
Thread->DecrementCount = 0;
Thread->PriorityDecrement = 0;
Thread->Quantum = Process->ThreadQuantum;
Thread->Saturation = 0;
Thread->Priority = Process->BasePriority;
Thread->UserAffinity = Process->Affinity;
Thread->SystemAffinityActive = 0;
Thread->Affinity = Process->Affinity;
Thread->Preempted = 0;
Thread->ProcessReadyQueue = 0;
Thread->KernelStackResident = 1;
Thread->NextProcessor = 0;
Thread->ContextSwitches = 0;
/* Setup Queue Fields */
Thread->Queue = NULL;
Thread->QueueListEntry.Flink = NULL;
Thread->QueueListEntry.Blink = NULL;
/* Setup Misc Fields */
Thread->LegoData = 0;
Thread->PowerState = 0;
Thread->ServiceTable = KeServiceDescriptorTable;
Thread->CallbackStack = NULL;
Thread->Win32Thread = NULL;
Thread->TrapFrame = NULL;
Thread->EnableStackSwap = 0;
Thread->LargeStack = 0;
Thread->ResourceIndex = 0;
Thread->PreviousMode = KernelMode;
Thread->KernelTime = 0;
Thread->UserTime = 0;
Thread->AutoAlignment = Process->AutoAlignment;
/* FIXME OPTIMIZATION OF DOOM. DO NOT ENABLE FIXME */
#if 0
Thread->WaitBlock[3].Object = (PVOID)&Thread->Timer;
Thread->WaitBlock[3].Thread = Thread;
Thread->WaitBlock[3].WaitKey = STATUS_TIMEOUT;
Thread->WaitBlock[3].WaitType = WaitAny;
Thread->WaitBlock[3].NextWaitBlock = NULL;
InsertTailList(&Thread->Timer.Header.WaitListHead,
&Thread->WaitBlock[3].WaitListEntry);
#endif
/* Initialize the Suspend APC */
KeInitializeApc(&Thread->SuspendApc,
Thread,
OriginalApcEnvironment,
PiSuspendThreadKernelRoutine,
PiSuspendThreadRundownRoutine,
PiSuspendThreadNormalRoutine,
KernelMode,
NULL);
/* Initialize the Suspend Semaphore */
KeInitializeSemaphore(&Thread->SuspendSemaphore, 0, 128);
/* Insert the Thread into the Process's Thread List */
InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry);
/* Set up the Suspend Counts */
Thread->FreezeCount = 0;
Thread->SuspendCount = 0;
/* Do x86 specific part */
} }
/* /*
@ -65,11 +342,9 @@ KeFreeStackPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
*/ */
KPRIORITY KPRIORITY
STDCALL STDCALL
KeQueryPriorityThread ( KeQueryPriorityThread (IN PKTHREAD Thread)
IN PKTHREAD Thread
)
{ {
return Thread->Priority; return Thread->Priority;
} }
/* /*
@ -77,16 +352,26 @@ KeQueryPriorityThread (
*/ */
ULONG ULONG
STDCALL STDCALL
KeQueryRuntimeThread( KeQueryRuntimeThread(IN PKTHREAD Thread,
IN PKTHREAD Thread, OUT PULONG UserTime)
OUT PULONG UserTime
)
{ {
/* Return the User Time */ /* Return the User Time */
*UserTime = Thread->UserTime; *UserTime = Thread->UserTime;
/* Return the Kernel Time */ /* Return the Kernel Time */
return Thread->KernelTime; return Thread->KernelTime;
}
VOID
KeFreeStackPage(PVOID Context,
MEMORY_AREA* MemoryArea,
PVOID Address,
PFN_TYPE Page,
SWAPENTRY SwapEntry,
BOOLEAN Dirty)
{
ASSERT(SwapEntry == 0);
if (Page) MmReleasePageMemoryConsumer(MC_NPPOOL, Page);
} }
NTSTATUS NTSTATUS
@ -123,195 +408,26 @@ KeReleaseThread(PKTHREAD Thread)
*/ */
BOOLEAN BOOLEAN
STDCALL STDCALL
KeSetKernelStackSwapEnable( KeSetKernelStackSwapEnable(IN BOOLEAN Enable)
IN BOOLEAN Enable
)
{ {
PKTHREAD Thread; PKTHREAD Thread = KeGetCurrentThread();
BOOLEAN PreviousState; BOOLEAN PreviousState;
KIRQL OldIrql;
Thread = KeGetCurrentThread(); /* Lock the Dispatcher Database */
OldIrql = KeAcquireDispatcherDatabaseLock();
/* Save Old State */ /* Save Old State */
PreviousState = Thread->EnableStackSwap; PreviousState = Thread->EnableStackSwap;
/* Set New State */ /* Set New State */
Thread->EnableStackSwap = Enable; Thread->EnableStackSwap = Enable;
/* Return Old State */ /* No, Release Lock */
return PreviousState; KeReleaseDispatcherDatabaseLock(OldIrql);
}
VOID /* Return Old State */
KeInitializeThread(PKPROCESS Process, PKTHREAD Thread, BOOLEAN First) return PreviousState;
/*
* FUNCTION: Initialize the microkernel state of the thread
*/
{
PVOID KernelStack;
NTSTATUS Status;
extern unsigned int init_stack_top;
extern unsigned int init_stack;
PMEMORY_AREA StackArea;
ULONG i;
PHYSICAL_ADDRESS BoundaryAddressMultiple;
BoundaryAddressMultiple.QuadPart = 0;
KeInitializeDispatcherHeader(&Thread->DispatcherHeader,
InternalThreadType,
sizeof(ETHREAD),
FALSE);
InitializeListHead(&Thread->MutantListHead);
if (!First)
{
PFN_TYPE Page[MM_STACK_SIZE / PAGE_SIZE];
KernelStack = NULL;
MmLockAddressSpace(MmGetKernelAddressSpace());
Status = MmCreateMemoryArea(NULL,
MmGetKernelAddressSpace(),
MEMORY_AREA_KERNEL_STACK,
&KernelStack,
MM_STACK_SIZE,
0,
&StackArea,
FALSE,
FALSE,
BoundaryAddressMultiple);
MmUnlockAddressSpace(MmGetKernelAddressSpace());
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to create thread stack\n");
KEBUGCHECK(0);
}
for (i = 0; i < (MM_STACK_SIZE / PAGE_SIZE); i++)
{
Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page[i]);
if (!NT_SUCCESS(Status))
{
KEBUGCHECK(0);
}
}
Status = MmCreateVirtualMapping(NULL,
KernelStack,
PAGE_READWRITE,
Page,
MM_STACK_SIZE / PAGE_SIZE);
if (!NT_SUCCESS(Status))
{
KEBUGCHECK(0);
}
Thread->InitialStack = (PCHAR)KernelStack + MM_STACK_SIZE;
Thread->StackBase = (PCHAR)KernelStack + MM_STACK_SIZE;
Thread->StackLimit = (ULONG_PTR)KernelStack;
Thread->KernelStack = (PCHAR)KernelStack + MM_STACK_SIZE;
}
else
{
Thread->InitialStack = (PCHAR)init_stack_top;
Thread->StackBase = (PCHAR)init_stack_top;
Thread->StackLimit = (ULONG_PTR)init_stack;
Thread->KernelStack = (PCHAR)init_stack_top;
}
/*
* Establish the pde's for the new stack and the thread structure within the
* address space of the new process. They are accessed while taskswitching or
* while handling page faults. At this point it isn't possible to call the
* page fault handler for the missing pde's.
*/
MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread->StackLimit, MM_STACK_SIZE);
MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread, sizeof(ETHREAD));
/*
* The Native API function will initialize the TEB field later
*/
Thread->Teb = NULL;
Thread->TlsArray = NULL;
Thread->DebugActive = 0;
Thread->State = THREAD_STATE_INITIALIZED;
Thread->Alerted[0] = 0;
Thread->Alerted[1] = 0;
Thread->Iopl = 0;
Thread->NpxState = NPX_STATE_INVALID;
Thread->Saturation = 0;
Thread->Priority = Process->BasePriority;
InitializeListHead(&Thread->ApcState.ApcListHead[0]);
InitializeListHead(&Thread->ApcState.ApcListHead[1]);
Thread->ApcState.Process = Process;
Thread->ApcState.KernelApcInProgress = 0;
Thread->ApcState.KernelApcPending = 0;
Thread->ApcState.UserApcPending = 0;
Thread->ContextSwitches = 0;
Thread->WaitStatus = STATUS_SUCCESS;
Thread->WaitIrql = PASSIVE_LEVEL;
Thread->WaitMode = 0;
Thread->WaitNext = FALSE;
Thread->WaitBlockList = NULL;
Thread->WaitListEntry.Flink = NULL;
Thread->WaitListEntry.Blink = NULL;
Thread->WaitTime = 0;
Thread->BasePriority = Process->BasePriority;
Thread->DecrementCount = 0;
Thread->PriorityDecrement = 0;
Thread->Quantum = Process->ThreadQuantum;
RtlZeroMemory(Thread->WaitBlock, sizeof(KWAIT_BLOCK)*4);
Thread->LegoData = 0;
Thread->UserAffinity = Process->Affinity;
Thread->SystemAffinityActive = 0;
Thread->PowerState = 0;
Thread->NpxIrql = 0;
Thread->ServiceTable = KeServiceDescriptorTable;
Thread->Queue = NULL;
KeInitializeSpinLock(&Thread->ApcQueueLock);
RtlZeroMemory(&Thread->Timer, sizeof(KTIMER));
KeInitializeTimer(&Thread->Timer);
Thread->QueueListEntry.Flink = NULL;
Thread->QueueListEntry.Blink = NULL;
Thread->Affinity = Process->Affinity;
Thread->Preempted = 0;
Thread->ProcessReadyQueue = 0;
Thread->KernelStackResident = 1;
Thread->NextProcessor = 0;
Thread->CallbackStack = NULL;
Thread->Win32Thread = NULL;
Thread->TrapFrame = NULL;
Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState;
Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState;
Thread->EnableStackSwap = 0;
Thread->LargeStack = 0;
Thread->ResourceIndex = 0;
Thread->PreviousMode = KernelMode;
Thread->KernelTime = 0;
Thread->UserTime = 0;
RtlZeroMemory(&Thread->SavedApcState, sizeof(KAPC_STATE));
Thread->ApcStateIndex = OriginalApcEnvironment;
Thread->ApcQueueable = TRUE;
Thread->AutoAlignment = Process->AutoAlignment;
KeInitializeApc(&Thread->SuspendApc,
Thread,
OriginalApcEnvironment,
PiSuspendThreadKernelRoutine,
PiSuspendThreadRundownRoutine,
PiSuspendThreadNormalRoutine,
KernelMode,
NULL);
KeInitializeSemaphore(&Thread->SuspendSemaphore, 0, 128);
InsertTailList(&Process->ThreadListHead,
&Thread->ThreadListEntry);
Thread->FreezeCount = 0;
Thread->SuspendCount = 0;
/*
* Do x86 specific part
*/
} }
/* /*
@ -321,33 +437,33 @@ VOID
STDCALL STDCALL
KeRevertToUserAffinityThread(VOID) KeRevertToUserAffinityThread(VOID)
{ {
#ifdef CONFIG_SMP PKTHREAD CurrentThread = KeGetCurrentThread();
PKTHREAD CurrentThread; KIRQL OldIrql;
KIRQL oldIrql;
oldIrql = KeAcquireDispatcherDatabaseLock(); ASSERT(CurrentThread->SystemAffinityActive != FALSE);
CurrentThread = KeGetCurrentThread(); /* Lock the Dispatcher Database */
OldIrql = KeAcquireDispatcherDatabaseLock();
ASSERT(CurrentThread->SystemAffinityActive != FALSE); /* Return to User Affinity */
CurrentThread->Affinity = CurrentThread->UserAffinity;
/* Return to User Affinity */ /* Disable System Affinity */
CurrentThread->Affinity = CurrentThread->UserAffinity; CurrentThread->SystemAffinityActive = FALSE;
/* Disable System Affinity */ /* Check if we need to Dispatch a New thread */
CurrentThread->SystemAffinityActive = FALSE; if (CurrentThread->Affinity & (1 << KeGetCurrentProcessorNumber())) {
if (CurrentThread->Affinity & (1 << KeGetCurrentProcessorNumber())) /* No, just release */
{ KeReleaseDispatcherDatabaseLock(OldIrql);
KeReleaseDispatcherDatabaseLock(oldIrql);
} } else {
else
{ /* We need to dispatch a new thread */
CurrentThread->WaitIrql = oldIrql; CurrentThread->WaitIrql = OldIrql;
PsDispatchThreadNoLock(THREAD_STATE_READY); PsDispatchThreadNoLock(THREAD_STATE_READY);
KeLowerIrql(oldIrql); KeLowerIrql(OldIrql);
} }
#endif
} }
/* /*
@ -355,20 +471,26 @@ KeRevertToUserAffinityThread(VOID)
*/ */
CCHAR CCHAR
STDCALL STDCALL
KeSetIdealProcessorThread ( KeSetIdealProcessorThread(IN PKTHREAD Thread,
IN PKTHREAD Thread, IN CCHAR Processor)
IN CCHAR Processor)
{ {
CCHAR PreviousIdealProcessor; CCHAR PreviousIdealProcessor;
KIRQL OldIrql;
/* Save Old Ideal Processor */ /* Lock the Dispatcher Database */
PreviousIdealProcessor = Thread->IdealProcessor; OldIrql = KeAcquireDispatcherDatabaseLock();
/* Set New Ideal Processor */ /* Save Old Ideal Processor */
Thread->IdealProcessor = Processor; PreviousIdealProcessor = Thread->IdealProcessor;
/* Return Old Ideal Processor */ /* Set New Ideal Processor */
return PreviousIdealProcessor; Thread->IdealProcessor = Processor;
/* Release Lock */
KeReleaseDispatcherDatabaseLock(OldIrql);
/* Return Old Ideal Processor */
return PreviousIdealProcessor;
} }
/* /*
@ -378,86 +500,237 @@ VOID
STDCALL STDCALL
KeSetSystemAffinityThread(IN KAFFINITY Affinity) KeSetSystemAffinityThread(IN KAFFINITY Affinity)
{ {
#ifdef CONFIG_SMP PKTHREAD CurrentThread = KeGetCurrentThread();
PKTHREAD CurrentThread; KIRQL OldIrql;
KIRQL oldIrql;
oldIrql = KeAcquireDispatcherDatabaseLock(); ASSERT(Affinity & ((1 << KeNumberProcessors) - 1));
CurrentThread = KeGetCurrentThread(); /* Lock the Dispatcher Database */
OldIrql = KeAcquireDispatcherDatabaseLock();
ASSERT(Affinity & ((1 << KeNumberProcessors) - 1)); /* Set the System Affinity Specified */
CurrentThread->Affinity = Affinity;
/* Set the System Affinity Specified */ /* Enable System Affinity */
CurrentThread->Affinity = Affinity; CurrentThread->SystemAffinityActive = TRUE;
/* Enable System Affinity */ /* Check if we need to Dispatch a New thread */
CurrentThread->SystemAffinityActive = TRUE; if (Affinity & (1 << KeGetCurrentProcessorNumber())) {
if (Affinity & (1 << KeGetCurrentProcessorNumber())) /* No, just release */
{ KeReleaseDispatcherDatabaseLock(OldIrql);
KeReleaseDispatcherDatabaseLock(oldIrql);
} } else {
else
{ /* We need to dispatch a new thread */
CurrentThread->WaitIrql = oldIrql; CurrentThread->WaitIrql = OldIrql;
PsDispatchThreadNoLock(THREAD_STATE_READY); PsDispatchThreadNoLock(THREAD_STATE_READY);
KeLowerIrql(oldIrql); KeLowerIrql(OldIrql);
} }
#endif
} }
/* /*
* @implemented * @implemented
*/ */
/* The Increment Argument seems to be ignored by NT and always 0 when called */
VOID VOID
STDCALL STDCALL
KeTerminateThread(IN KPRIORITY Increment) KeTerminateThread(IN KPRIORITY Increment)
{ {
/* The Increment Argument seems to be ignored by NT and always 0 when called */ /* Call our own internal routine */
PsTerminateCurrentThread(0);
/* Call our own internal routine */
PsTerminateCurrentThread(0);
} }
/*
* FUNCTION: Tests whether there are any pending APCs for the current thread
* and if so the APCs will be delivered on exit from kernel mode
*/
BOOLEAN
STDCALL
KeTestAlertThread(IN KPROCESSOR_MODE AlertMode)
{
KIRQL OldIrql;
PKTHREAD Thread = KeGetCurrentThread();
BOOLEAN OldState;
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Lock the Dispatcher Database and the APC Queue */
OldIrql = KeAcquireDispatcherDatabaseLock();
KiAcquireSpinLock(&Thread->ApcQueueLock);
/* Save the old State */
OldState = Thread->Alerted[AlertMode];
/* If the Thread is Alerted, Clear it */
if (OldState) {
Thread->Alerted[AlertMode] = FALSE;
} else if ((AlertMode == UserMode) && (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))) {
/* If the mode is User and the Queue isn't empty, set Pending */
Thread->ApcState.UserApcPending = TRUE;
}
/* Release Locks and return the Old State */
KiReleaseSpinLock(&Thread->ApcQueueLock);
KeReleaseDispatcherDatabaseLock(OldIrql);
return OldState;
}
VOID
KiServiceCheck (VOID)
{
PKTHREAD Thread = KeGetCurrentThread();
/* Check if we need to inialize Win32 for this Thread */
if (Thread->ServiceTable != KeServiceDescriptorTableShadow) {
/* We do. Initialize it and save the new table */
PsInitWin32Thread((PETHREAD)Thread);
Thread->ServiceTable = KeServiceDescriptorTableShadow;
}
}
/*
*
* NOT EXPORTED
*/
NTSTATUS
STDCALL
NtAlertResumeThread(IN HANDLE ThreadHandle,
OUT PULONG SuspendCount)
{
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
PETHREAD Thread;
NTSTATUS Status;
ULONG PreviousState;
/* Check if parameters are valid */
if(PreviousMode != KernelMode) {
_SEH_TRY {
ProbeForWrite(SuspendCount,
sizeof(HANDLE),
sizeof(ULONG));
} _SEH_HANDLE {
Status = _SEH_GetExceptionCode();
} _SEH_END;
}
/* Reference the Object */
Status = ObReferenceObjectByHandle(ThreadHandle,
THREAD_SUSPEND_RESUME,
PsThreadType,
PreviousMode,
(PVOID*)&Thread,
NULL);
/* Check for Success */
if (NT_SUCCESS(Status)) {
/* Call the Kernel Function */
PreviousState = KeAlertResumeThread(&Thread->Tcb);
/* Dereference Object */
ObDereferenceObject(Thread);
if (SuspendCount) {
_SEH_TRY {
*SuspendCount = PreviousState;
} _SEH_HANDLE {
Status = _SEH_GetExceptionCode();
} _SEH_END;
}
}
/* Return status */
return Status;
}
/*
* @implemented
*
* EXPORTED
*/
NTSTATUS
STDCALL
NtAlertThread (IN HANDLE ThreadHandle)
{
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
PETHREAD Thread;
NTSTATUS Status;
/* Reference the Object */
Status = ObReferenceObjectByHandle(ThreadHandle,
THREAD_SUSPEND_RESUME,
PsThreadType,
PreviousMode,
(PVOID*)&Thread,
NULL);
/* Check for Success */
if (NT_SUCCESS(Status)) {
/*
* Do an alert depending on the processor mode. If some kmode code wants to
* enforce a umode alert it should call KeAlertThread() directly. If kmode
* code wants to do a kmode alert it's sufficient to call it with Zw or just
* use KeAlertThread() directly
*/
KeAlertThread(&Thread->Tcb, PreviousMode);
/* Dereference Object */
ObDereferenceObject(Thread);
}
/* Return status */
return Status;
}
NTSTATUS NTSTATUS
STDCALL STDCALL
NtDelayExecution(IN BOOLEAN Alertable, NtDelayExecution(IN BOOLEAN Alertable,
IN PLARGE_INTEGER DelayInterval) IN PLARGE_INTEGER DelayInterval)
{ {
KPROCESSOR_MODE PreviousMode; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
LARGE_INTEGER SafeInterval; LARGE_INTEGER SafeInterval;
NTSTATUS Status;
PreviousMode = ExGetPreviousMode(); /* Check if parameters are valid */
if(PreviousMode != KernelMode) {
if(PreviousMode != KernelMode) _SEH_TRY {
{
NTSTATUS Status = STATUS_SUCCESS;
_SEH_TRY ProbeForRead(DelayInterval,
{ sizeof(LARGE_INTEGER),
ProbeForRead(DelayInterval, sizeof(ULONG));
sizeof(LARGE_INTEGER),
sizeof(ULONG));
/* make a copy on the kernel stack and let DelayInterval point to it so
we don't need to wrap KeDelayExecutionThread in SEH! */
SafeInterval = *DelayInterval;
DelayInterval = &SafeInterval;
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if(!NT_SUCCESS(Status)) /* make a copy on the kernel stack and let DelayInterval point to it so
{ we don't need to wrap KeDelayExecutionThread in SEH! */
return Status; SafeInterval = *DelayInterval;
}
} _SEH_HANDLE {
Status = _SEH_GetExceptionCode();
} _SEH_END;
} }
return KeDelayExecutionThread(PreviousMode, /* Call the Kernel Function */
Alertable, Status = KeDelayExecutionThread(PreviousMode,
DelayInterval); Alertable,
&SafeInterval);
/* Return Status */
return Status;
} }

View file

@ -128,7 +128,7 @@ KiSideEffectsBeforeWake(DISPATCHER_HEADER * hdr,
case InternalProcessType: case InternalProcessType:
break; break;
case InternalThreadType: case ThreadObject:
break; break;
case InternalNotificationEvent: case InternalNotificationEvent:
@ -386,7 +386,7 @@ BOOLEAN KiDispatcherObjectWake(DISPATCHER_HEADER* hdr, KPRIORITY increment)
case InternalProcessType: case InternalProcessType:
return(KeDispatcherObjectWakeAll(hdr, increment)); return(KeDispatcherObjectWakeAll(hdr, increment));
case InternalThreadType: case ThreadObject:
return(KeDispatcherObjectWakeAll(hdr, increment)); return(KeDispatcherObjectWakeAll(hdr, increment));
case InternalMutexType: case InternalMutexType:

View file

@ -1055,6 +1055,17 @@ NtYieldExecution(VOID)
} }
/*
* NOT EXPORTED
*/
NTSTATUS STDCALL
NtTestAlert(VOID)
{
/* Check and Alert Thread if needed */
return KeTestAlertThread(ExGetPreviousMode()) ? STATUS_ALERTED : STATUS_SUCCESS;
}
/* /*
* @implemented * @implemented
*/ */