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 */
static KEVENT QueueThreadTerminate;
static PVOID ThreadObject;
static PVOID QueueThreadObject;
static VOID NTAPI MotorStopDpcFunc(PKDPC UnusedDpc,
@ -378,8 +378,8 @@ static VOID NTAPI Unload(PDRIVER_OBJECT DriverObject)
KdPrint(("floppy: unloading\n"));
KeSetEvent(&QueueThreadTerminate, 0, FALSE);
KeWaitForSingleObject(ThreadObject, Executive, KernelMode, FALSE, 0);
ObDereferenceObject(ThreadObject);
KeWaitForSingleObject(QueueThreadObject, Executive, KernelMode, FALSE, 0);
ObDereferenceObject(QueueThreadObject);
for(i = 0; i < gNumberOfControllers; i++)
{
@ -1152,7 +1152,7 @@ NTSTATUS NTAPI DriverEntry(PDRIVER_OBJECT DriverObject,
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"));
return STATUS_UNSUCCESSFUL;

View file

@ -36,23 +36,34 @@ typedef VOID STDCALL_FUNC
struct _DISPATCHER_HEADER;
typedef enum _KERNEL_OBJECTS {
KNotificationEvent = 0,
KSynchronizationEvent = 1,
KMutant = 2,
KProcess = 3,
KQueue = 4,
KSemaphore = 5,
KThread = 6,
KNotificationTimer = 8,
KSynchronizationTimer = 9,
KApc = 18,
KDpc = 19,
KDeviceQueue = 20,
KEventPair = 21,
KInterrupt = 22,
KProfile = 23
} KERNEL_OBJECTS;
typedef enum _KOBJECTS {
EventNotificationObject = 0,
EventSynchronizationObject = 1,
MutantObject = 2,
ProcessObject = 3,
QueueObject = 4,
SemaphoreObject = 5,
ThreadObject = 6,
GateObject = 7,
TimerNotificationObject = 8,
TimerSynchronizationObject = 9,
Spare2Object = 10,
Spare3Object = 11,
Spare4Object = 12,
Spare5Object = 13,
Spare6Object = 14,
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>

View file

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

View file

@ -498,7 +498,7 @@ VOID STDCALL PsExitSpecialApc(PKAPC Apc,
#define PROCESS_PRIO_RT 18
VOID
VOID STDCALL
KeInitializeThread(PKPROCESS Process, PKTHREAD Thread, BOOLEAN First);
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 */
RtlZeroMemory(Apc, sizeof(KAPC));
Apc->Type = KApc;
Apc->Type = ApcObject;
Apc->Size = sizeof(KAPC);
/* Set the Environment */

View file

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

View file

@ -1,11 +1,11 @@
/* $Id$
*
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/ke/kthread.c
* 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 *****************************************************************/
@ -16,19 +16,93 @@
/* FUNCTIONS *****************************************************************/
VOID
KiServiceCheck (VOID)
ULONG
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)
{
PsInitWin32Thread (Thread);
/* Lock the Dispatcher Database and the APC Queue */
OldIrql = KeAcquireDispatcherDatabaseLock();
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
STDCALL
KeCapturePersistentThreadState(
IN PVOID CurrentThread,
KeCapturePersistentThreadState(IN PVOID CurrentThread,
IN ULONG Setting1,
IN ULONG Setting2,
IN ULONG Setting3,
IN ULONG Setting4,
IN ULONG Setting5,
IN PVOID ThreadState
)
IN PVOID ThreadState)
{
UNIMPLEMENTED;
}
/*
* FUNCTION: Initialize the microkernel state of the thread
*/
VOID
KeFreeStackPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
PFN_TYPE Page, SWAPENTRY SwapEntry, BOOLEAN Dirty)
STDCALL
KeInitializeThread(PKPROCESS Process,
PKTHREAD Thread,
BOOLEAN First)
{
ASSERT(SwapEntry == 0);
if (Page != 0)
{
MmReleasePageMemoryConsumer(MC_NPPOOL, Page);
PVOID KernelStack;
NTSTATUS Status;
extern unsigned int init_stack_top;
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,9 +342,7 @@ KeFreeStackPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
*/
KPRIORITY
STDCALL
KeQueryPriorityThread (
IN PKTHREAD Thread
)
KeQueryPriorityThread (IN PKTHREAD Thread)
{
return Thread->Priority;
}
@ -77,10 +352,8 @@ KeQueryPriorityThread (
*/
ULONG
STDCALL
KeQueryRuntimeThread(
IN PKTHREAD Thread,
OUT PULONG UserTime
)
KeQueryRuntimeThread(IN PKTHREAD Thread,
OUT PULONG UserTime)
{
/* Return the User Time */
*UserTime = Thread->UserTime;
@ -89,6 +362,18 @@ KeQueryRuntimeThread(
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
KeReleaseThread(PKTHREAD Thread)
/*
@ -123,14 +408,14 @@ KeReleaseThread(PKTHREAD Thread)
*/
BOOLEAN
STDCALL
KeSetKernelStackSwapEnable(
IN BOOLEAN Enable
)
KeSetKernelStackSwapEnable(IN BOOLEAN Enable)
{
PKTHREAD Thread;
PKTHREAD Thread = KeGetCurrentThread();
BOOLEAN PreviousState;
KIRQL OldIrql;
Thread = KeGetCurrentThread();
/* Lock the Dispatcher Database */
OldIrql = KeAcquireDispatcherDatabaseLock();
/* Save Old State */
PreviousState = Thread->EnableStackSwap;
@ -138,182 +423,13 @@ KeSetKernelStackSwapEnable(
/* Set New State */
Thread->EnableStackSwap = Enable;
/* No, Release Lock */
KeReleaseDispatcherDatabaseLock(OldIrql);
/* Return Old State */
return PreviousState;
}
VOID
KeInitializeThread(PKPROCESS Process, PKTHREAD Thread, BOOLEAN First)
/*
* 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
*/
}
/*
* @implemented
*/
@ -321,33 +437,33 @@ VOID
STDCALL
KeRevertToUserAffinityThread(VOID)
{
#ifdef CONFIG_SMP
PKTHREAD CurrentThread;
KIRQL oldIrql;
oldIrql = KeAcquireDispatcherDatabaseLock();
CurrentThread = KeGetCurrentThread();
PKTHREAD CurrentThread = KeGetCurrentThread();
KIRQL OldIrql;
ASSERT(CurrentThread->SystemAffinityActive != FALSE);
/* Lock the Dispatcher Database */
OldIrql = KeAcquireDispatcherDatabaseLock();
/* Return to User Affinity */
CurrentThread->Affinity = CurrentThread->UserAffinity;
/* Disable System Affinity */
CurrentThread->SystemAffinityActive = FALSE;
if (CurrentThread->Affinity & (1 << KeGetCurrentProcessorNumber()))
{
KeReleaseDispatcherDatabaseLock(oldIrql);
}
else
{
CurrentThread->WaitIrql = oldIrql;
/* Check if we need to Dispatch a New thread */
if (CurrentThread->Affinity & (1 << KeGetCurrentProcessorNumber())) {
/* No, just release */
KeReleaseDispatcherDatabaseLock(OldIrql);
} else {
/* We need to dispatch a new thread */
CurrentThread->WaitIrql = OldIrql;
PsDispatchThreadNoLock(THREAD_STATE_READY);
KeLowerIrql(oldIrql);
KeLowerIrql(OldIrql);
}
#endif
}
/*
@ -355,11 +471,14 @@ KeRevertToUserAffinityThread(VOID)
*/
CCHAR
STDCALL
KeSetIdealProcessorThread (
IN PKTHREAD Thread,
KeSetIdealProcessorThread(IN PKTHREAD Thread,
IN CCHAR Processor)
{
CCHAR PreviousIdealProcessor;
KIRQL OldIrql;
/* Lock the Dispatcher Database */
OldIrql = KeAcquireDispatcherDatabaseLock();
/* Save Old Ideal Processor */
PreviousIdealProcessor = Thread->IdealProcessor;
@ -367,6 +486,9 @@ KeSetIdealProcessorThread (
/* Set New Ideal Processor */
Thread->IdealProcessor = Processor;
/* Release Lock */
KeReleaseDispatcherDatabaseLock(OldIrql);
/* Return Old Ideal Processor */
return PreviousIdealProcessor;
}
@ -378,86 +500,237 @@ VOID
STDCALL
KeSetSystemAffinityThread(IN KAFFINITY Affinity)
{
#ifdef CONFIG_SMP
PKTHREAD CurrentThread;
KIRQL oldIrql;
oldIrql = KeAcquireDispatcherDatabaseLock();
CurrentThread = KeGetCurrentThread();
PKTHREAD CurrentThread = KeGetCurrentThread();
KIRQL OldIrql;
ASSERT(Affinity & ((1 << KeNumberProcessors) - 1));
/* Lock the Dispatcher Database */
OldIrql = KeAcquireDispatcherDatabaseLock();
/* Set the System Affinity Specified */
CurrentThread->Affinity = Affinity;
/* Enable System Affinity */
CurrentThread->SystemAffinityActive = TRUE;
if (Affinity & (1 << KeGetCurrentProcessorNumber()))
{
KeReleaseDispatcherDatabaseLock(oldIrql);
}
else
{
CurrentThread->WaitIrql = oldIrql;
/* Check if we need to Dispatch a New thread */
if (Affinity & (1 << KeGetCurrentProcessorNumber())) {
/* No, just release */
KeReleaseDispatcherDatabaseLock(OldIrql);
} else {
/* We need to dispatch a new thread */
CurrentThread->WaitIrql = OldIrql;
PsDispatchThreadNoLock(THREAD_STATE_READY);
KeLowerIrql(oldIrql);
KeLowerIrql(OldIrql);
}
#endif
}
/*
* @implemented
*/
/* The Increment Argument seems to be ignored by NT and always 0 when called */
VOID
STDCALL
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);
}
/*
* 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
STDCALL
NtDelayExecution(IN BOOLEAN Alertable,
IN PLARGE_INTEGER DelayInterval)
{
KPROCESSOR_MODE PreviousMode;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
LARGE_INTEGER SafeInterval;
NTSTATUS Status;
PreviousMode = ExGetPreviousMode();
/* Check if parameters are valid */
if(PreviousMode != KernelMode) {
if(PreviousMode != KernelMode)
{
NTSTATUS Status = STATUS_SUCCESS;
_SEH_TRY {
_SEH_TRY
{
ProbeForRead(DelayInterval,
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
{
} _SEH_HANDLE {
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if(!NT_SUCCESS(Status))
{
return Status;
}
} _SEH_END;
}
return KeDelayExecutionThread(PreviousMode,
/* Call the Kernel Function */
Status = KeDelayExecutionThread(PreviousMode,
Alertable,
DelayInterval);
&SafeInterval);
/* Return Status */
return Status;
}

View file

@ -128,7 +128,7 @@ KiSideEffectsBeforeWake(DISPATCHER_HEADER * hdr,
case InternalProcessType:
break;
case InternalThreadType:
case ThreadObject:
break;
case InternalNotificationEvent:
@ -386,7 +386,7 @@ BOOLEAN KiDispatcherObjectWake(DISPATCHER_HEADER* hdr, KPRIORITY increment)
case InternalProcessType:
return(KeDispatcherObjectWakeAll(hdr, increment));
case InternalThreadType:
case ThreadObject:
return(KeDispatcherObjectWakeAll(hdr, increment));
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
*/