Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443/* * PROJECT: ReactOS Kernel * LICENSE: GPL - See COPYING in the top level directory * FILE: ntoskrnl/ke/thrdobj.c * PURPOSE: Implements routines to manage the Kernel Thread Object * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) */
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>#define NDEBUG#include <debug.h>
extern EX_WORK_QUEUE ExWorkerQueue[MaximumWorkQueue];extern LIST_ENTRY PspReaperListHead;
/* FUNCTIONS *****************************************************************/
UCHARNTAPIKeFindNextRightSetAffinity(IN UCHAR Number, IN KAFFINITY Set){ KAFFINITY Bit; ULONG Result; ASSERT(Set != 0);
/* Calculate the mask */ Bit = (AFFINITY_MASK(Number) - 1) & Set;
/* If it's 0, use the one we got */ if (!Bit) Bit = Set;
/* Now find the right set and return it */ BitScanReverseAffinity(&Result, Bit); return (UCHAR)Result;}
BOOLEANNTAPIKeReadStateThread(IN PKTHREAD Thread){ ASSERT_THREAD(Thread);
/* Return signal state */ return (BOOLEAN)Thread->Header.SignalState;}
KPRIORITYNTAPIKeQueryBasePriorityThread(IN PKTHREAD Thread){ LONG BaseIncrement; KIRQL OldIrql; PKPROCESS Process; ASSERT_THREAD(Thread); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Raise IRQL to synch level */ OldIrql = KeRaiseIrqlToSynchLevel();
/* Lock the thread */ KiAcquireThreadLock(Thread);
/* Get the Process */ Process = Thread->ApcStatePointer[0]->Process;
/* Calculate the base increment */ BaseIncrement = Thread->BasePriority - Process->BasePriority;
/* If saturation occured, return the saturation increment instead */ if (Thread->Saturation) BaseIncrement = (HIGH_PRIORITY + 1) / 2 * Thread->Saturation;
/* Release thread lock */ KiReleaseThreadLock(Thread);
/* Lower IRQl and return Increment */ KeLowerIrql(OldIrql); return BaseIncrement;}
BOOLEANNTAPIKeSetDisableBoostThread(IN OUT PKTHREAD Thread, IN BOOLEAN Disable){ ASSERT_THREAD(Thread);
/* Check if we're enabling or disabling */ if (Disable) { /* Set the bit */ return InterlockedBitTestAndSet(&Thread->ThreadFlags, 1); } else { /* Remove the bit */ return InterlockedBitTestAndReset(&Thread->ThreadFlags, 1); }}
VOIDNTAPIKeReadyThread(IN PKTHREAD Thread){ KIRQL OldIrql; ASSERT_THREAD(Thread); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Lock the Dispatcher Database */ OldIrql = KiAcquireDispatcherLock();
/* Make the thread ready */ KiReadyThread(Thread);
/* Unlock dispatcher database */ KiReleaseDispatcherLock(OldIrql);}
ULONGNTAPIKeAlertResumeThread(IN PKTHREAD Thread){ ULONG PreviousCount; KLOCK_QUEUE_HANDLE ApcLock; ASSERT_THREAD(Thread); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Lock the Dispatcher Database and the APC Queue */ KiAcquireApcLockRaiseToSynch(Thread, &ApcLock); KiAcquireDispatcherLockAtSynchLevel();
/* Return if Thread is already alerted. */ if (!Thread->Alerted[KernelMode]) { /* If it's Blocked, unblock if it we should */ if ((Thread->State == Waiting) && (Thread->Alertable)) { /* Abort the wait */ KiUnwaitThread(Thread, STATUS_ALERTED, THREAD_ALERT_INCREMENT); } 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 */ Thread->SuspendCount--; if (!(Thread->SuspendCount) && !(Thread->FreezeCount)) { /* Signal and satisfy */ Thread->SuspendSemaphore.Header.SignalState++; KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT); } }
/* Release Locks and return the Old State */ KiReleaseDispatcherLockFromSynchLevel(); KiReleaseApcLockFromSynchLevel(&ApcLock); KiExitDispatcher(ApcLock.OldIrql); return PreviousCount;}
BOOLEANNTAPIKeAlertThread(IN PKTHREAD Thread, IN KPROCESSOR_MODE AlertMode){ BOOLEAN PreviousState; KLOCK_QUEUE_HANDLE ApcLock; ASSERT_THREAD(Thread); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Lock the Dispatcher Database and the APC Queue */ KiAcquireApcLockRaiseToSynch(Thread, &ApcLock); KiAcquireDispatcherLockAtSynchLevel();
/* Save the Previous State */ PreviousState = Thread->Alerted[AlertMode];
/* Check if it's already alerted */ if (!PreviousState) { /* Check if the thread is alertable, and blocked in the given mode */ if ((Thread->State == Waiting) && (Thread->Alertable) && (AlertMode <= Thread->WaitMode)) { /* Abort the wait to alert the thread */ KiUnwaitThread(Thread, STATUS_ALERTED, THREAD_ALERT_INCREMENT); } else { /* Otherwise, merely set the alerted state */ Thread->Alerted[AlertMode] = TRUE; } }
/* Release the Dispatcher Lock */ KiReleaseDispatcherLockFromSynchLevel(); KiReleaseApcLockFromSynchLevel(&ApcLock); KiExitDispatcher(ApcLock.OldIrql);
/* Return the old state */ return PreviousState;}
VOIDNTAPIKeBoostPriorityThread(IN PKTHREAD Thread, IN KPRIORITY Increment){ KIRQL OldIrql; KPRIORITY Priority; ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Lock the Dispatcher Database */ OldIrql = KiAcquireDispatcherLock();
/* Only threads in the dynamic range get boosts */ if (Thread->Priority < LOW_REALTIME_PRIORITY) { /* Lock the thread */ KiAcquireThreadLock(Thread);
/* Check again, and make sure there's not already a boost */ if ((Thread->Priority < LOW_REALTIME_PRIORITY) && !(Thread->PriorityDecrement)) { /* Compute the new priority and see if it's higher */ Priority = Thread->BasePriority + Increment; if (Priority > Thread->Priority) { if (Priority >= LOW_REALTIME_PRIORITY) { Priority = LOW_REALTIME_PRIORITY - 1; }
/* Reset the quantum */ Thread->Quantum = Thread->QuantumReset;
/* Set the new Priority */ KiSetPriorityThread(Thread, Priority); } }
/* Release thread lock */ KiReleaseThreadLock(Thread); }
/* Release the dispatcher lokc */ KiReleaseDispatcherLock(OldIrql);}
ULONGNTAPIKeForceResumeThread(IN PKTHREAD Thread){ KLOCK_QUEUE_HANDLE ApcLock; ULONG PreviousCount; ASSERT_THREAD(Thread); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Lock the APC Queue */ KiAcquireApcLockRaiseToSynch(Thread, &ApcLock);
/* Save the old Suspend Count */ PreviousCount = Thread->SuspendCount + Thread->FreezeCount;
/* If the thread is suspended, wake it up!!! */ if (PreviousCount) { /* Unwait it completely */ Thread->SuspendCount = 0; Thread->FreezeCount = 0;
/* Lock the dispatcher */ KiAcquireDispatcherLockAtSynchLevel();
/* Signal and satisfy */ Thread->SuspendSemaphore.Header.SignalState++; KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT);
/* Release the dispatcher */ KiReleaseDispatcherLockFromSynchLevel(); }
/* Release Lock and return the Old State */ KiReleaseApcLockFromSynchLevel(&ApcLock); KiExitDispatcher(ApcLock.OldIrql); return PreviousCount;}
VOIDNTAPIKeFreezeAllThreads(VOID){ KLOCK_QUEUE_HANDLE LockHandle, ApcLock; PKTHREAD Current, CurrentThread = KeGetCurrentThread(); PKPROCESS Process = CurrentThread->ApcState.Process; PLIST_ENTRY ListHead, NextEntry; LONG OldCount; ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Lock the process */ KiAcquireProcessLockRaiseToSynch(Process, &LockHandle);
/* If someone is already trying to free us, try again */ while (CurrentThread->FreezeCount) { /* Release and re-acquire the process lock so the APC will go through */ KiReleaseProcessLock(&LockHandle); KiAcquireProcessLockRaiseToSynch(Process, &LockHandle); }
/* Enter a critical region */ KeEnterCriticalRegion();
/* Loop the Process's Threads */ ListHead = &Process->ThreadListHead; NextEntry = ListHead->Flink; do { /* Get the current thread */ Current = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry);
/* Lock it */ KiAcquireApcLockAtSynchLevel(Current, &ApcLock);
/* Make sure it's not ours, and check if APCs are enabled */ if ((Current != CurrentThread) && (Current->ApcQueueable)) { /* Sanity check */ OldCount = Current->SuspendCount; ASSERT(OldCount != MAXIMUM_SUSPEND_COUNT);
/* Increase the freeze count */ Current->FreezeCount++;
/* Make sure it wasn't already suspended */ if (!(OldCount) && !(Current->SuspendCount)) { /* Did we already insert it? */ if (!Current->SuspendApc.Inserted) { /* Insert the APC */ Current->SuspendApc.Inserted = TRUE; KiInsertQueueApc(&Current->SuspendApc, IO_NO_INCREMENT); } else { /* Lock the dispatcher */ KiAcquireDispatcherLockAtSynchLevel();
/* Unsignal the semaphore, the APC was already inserted */ Current->SuspendSemaphore.Header.SignalState--;
/* Release the dispatcher */ KiReleaseDispatcherLockFromSynchLevel(); } } }
/* Release the APC lock */ KiReleaseApcLockFromSynchLevel(&ApcLock);
/* Move to the next thread */ NextEntry = NextEntry->Flink; } while (NextEntry != ListHead);
/* Release the process lock and exit the dispatcher */ KiReleaseProcessLockFromSynchLevel(&LockHandle); KiExitDispatcher(LockHandle.OldIrql);}
ULONGNTAPIKeResumeThread(IN PKTHREAD Thread){ KLOCK_QUEUE_HANDLE ApcLock; ULONG PreviousCount; ASSERT_THREAD(Thread); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Lock the APC Queue */ KiAcquireApcLockRaiseToSynch(Thread, &ApcLock);
/* Save the Old Count */ PreviousCount = Thread->SuspendCount;
/* Check if it existed */ if (PreviousCount) { /* Decrease the suspend count */ Thread->SuspendCount--;
/* Check if the thrad is still suspended or not */ if ((!Thread->SuspendCount) && (!Thread->FreezeCount)) { /* Acquire the dispatcher lock */ KiAcquireDispatcherLockAtSynchLevel();
/* Signal the Suspend Semaphore */ Thread->SuspendSemaphore.Header.SignalState++; KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT);
/* Release the dispatcher lock */ KiReleaseDispatcherLockFromSynchLevel(); } }
/* Release APC Queue lock and return the Old State */ KiReleaseApcLockFromSynchLevel(&ApcLock); KiExitDispatcher(ApcLock.OldIrql); return PreviousCount;}
VOIDNTAPIKeRundownThread(VOID){ KIRQL OldIrql; PKTHREAD Thread = KeGetCurrentThread(); PLIST_ENTRY NextEntry, ListHead; PKMUTANT Mutant; ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Optimized path if nothing is on the list at the moment */ if (IsListEmpty(&Thread->MutantListHead)) return;
/* Lock the Dispatcher Database */ OldIrql = KiAcquireDispatcherLock();
/* Get the List Pointers */ ListHead = &Thread->MutantListHead; NextEntry = ListHead->Flink; while (NextEntry != ListHead) { /* Get the Mutant */ Mutant = CONTAINING_RECORD(NextEntry, KMUTANT, MutantListEntry); ASSERT_MUTANT(Mutant);
/* Make sure it's not terminating with APCs off */ if (Mutant->ApcDisable) { /* Bugcheck the system */ KeBugCheckEx(THREAD_TERMINATE_HELD_MUTEX, (ULONG_PTR)Thread, (ULONG_PTR)Mutant, 0, 0); }
/* Now we can remove it */ RemoveEntryList(&Mutant->MutantListEntry);
/* Unconditionally abandon it */ Mutant->Header.SignalState = 1; Mutant->Abandoned = TRUE; Mutant->OwnerThread = NULL;
/* Check if the Wait List isn't empty */ if (!IsListEmpty(&Mutant->Header.WaitListHead)) { /* Wake the Mutant */ KiWaitTest(&Mutant->Header, MUTANT_INCREMENT); }
/* Move on */ NextEntry = Thread->MutantListHead.Flink; }
/* Release the Lock */ KiReleaseDispatcherLock(OldIrql);}
VOIDNTAPIKeStartThread(IN OUT PKTHREAD Thread){ KLOCK_QUEUE_HANDLE LockHandle;#ifdef CONFIG_SMP PKNODE Node; PKPRCB NodePrcb; KAFFINITY Set, Mask;#endif UCHAR IdealProcessor = 0; PKPROCESS Process = Thread->ApcState.Process;
/* Setup static fields from parent */ Thread->DisableBoost = Process->DisableBoost;#if defined(_M_IX86) Thread->Iopl = Process->Iopl;#endif Thread->Quantum = Process->QuantumReset; Thread->QuantumReset = Process->QuantumReset; Thread->SystemAffinityActive = FALSE;
/* Lock the process */ KiAcquireProcessLockRaiseToSynch(Process, &LockHandle);
/* Setup volatile data */ Thread->Priority = Process->BasePriority; Thread->BasePriority = Process->BasePriority; Thread->Affinity = Process->Affinity; Thread->UserAffinity = Process->Affinity;
#ifdef CONFIG_SMP /* Get the KNODE and its PRCB */ Node = KeNodeBlock[Process->IdealNode]; NodePrcb = KiProcessorBlock[Process->ThreadSeed];
/* Calculate affinity mask */#ifdef _M_ARM DbgBreakPoint(); Set = 0;#else Set = ~NodePrcb->MultiThreadProcessorSet;#endif Mask = Node->ProcessorMask & Process->Affinity; Set &= Mask; if (Set) Mask = Set;
/* Get the new thread seed */ IdealProcessor = KeFindNextRightSetAffinity(Process->ThreadSeed, Mask); Process->ThreadSeed = IdealProcessor;
/* Sanity check */ ASSERT((Thread->UserAffinity & AFFINITY_MASK(IdealProcessor)));#endif
/* Set the Ideal Processor */ Thread->IdealProcessor = IdealProcessor; Thread->UserIdealProcessor = IdealProcessor;
/* Lock the Dispatcher Database */ KiAcquireDispatcherLockAtSynchLevel();
/* Insert the thread into the process list */ InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry);
/* Increase the stack count */ ASSERT(Process->StackCount != MAXULONG_PTR); Process->StackCount++;
/* Release locks and return */ KiReleaseDispatcherLockFromSynchLevel(); KiReleaseProcessLock(&LockHandle);}
VOIDNTAPIKiSuspendRundown(IN PKAPC Apc){ /* Does nothing */ UNREFERENCED_PARAMETER(Apc);}
VOIDNTAPIKiSuspendNop(IN PKAPC Apc, IN PKNORMAL_ROUTINE *NormalRoutine, IN PVOID *NormalContext, IN PVOID *SystemArgument1, IN PVOID *SystemArgument2){ /* Does nothing */ UNREFERENCED_PARAMETER(Apc); UNREFERENCED_PARAMETER(NormalRoutine); UNREFERENCED_PARAMETER(NormalContext); UNREFERENCED_PARAMETER(SystemArgument1); UNREFERENCED_PARAMETER(SystemArgument2);}
VOIDNTAPIKiSuspendThread(IN PVOID NormalContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2){ /* Non-alertable kernel-mode suspended wait */ KeWaitForSingleObject(&KeGetCurrentThread()->SuspendSemaphore, Suspended, KernelMode, FALSE, NULL);}
ULONGNTAPIKeSuspendThread(PKTHREAD Thread){ KLOCK_QUEUE_HANDLE ApcLock; ULONG PreviousCount; ASSERT_THREAD(Thread); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Lock the APC Queue */ KiAcquireApcLockRaiseToSynch(Thread, &ApcLock);
/* Save the Old Count */ PreviousCount = Thread->SuspendCount;
/* Handle the maximum */ if (PreviousCount == MAXIMUM_SUSPEND_COUNT) { /* Raise an exception */ KiReleaseApcLock(&ApcLock); RtlRaiseStatus(STATUS_SUSPEND_COUNT_EXCEEDED); }
/* Should we bother to queue at all? */ if (Thread->ApcQueueable) { /* Increment the suspend count */ Thread->SuspendCount++;
/* Check if we should suspend it */ if (!(PreviousCount) && !(Thread->FreezeCount)) { /* Is the APC already inserted? */ if (!Thread->SuspendApc.Inserted) { /* Not inserted, insert it */ Thread->SuspendApc.Inserted = TRUE; KiInsertQueueApc(&Thread->SuspendApc, IO_NO_INCREMENT); } else { /* Lock the dispatcher */ KiAcquireDispatcherLockAtSynchLevel();
/* Unsignal the semaphore, the APC was already inserted */ Thread->SuspendSemaphore.Header.SignalState--;
/* Release the dispatcher */ KiReleaseDispatcherLockFromSynchLevel(); } } }
/* Release Lock and return the Old State */ KiReleaseApcLockFromSynchLevel(&ApcLock); KiExitDispatcher(ApcLock.OldIrql); return PreviousCount;}
VOIDNTAPIKeThawAllThreads(VOID){ KLOCK_QUEUE_HANDLE LockHandle, ApcLock; PKTHREAD Current, CurrentThread = KeGetCurrentThread(); PKPROCESS Process = CurrentThread->ApcState.Process; PLIST_ENTRY ListHead, NextEntry; LONG OldCount; ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Lock the process */ KiAcquireProcessLockRaiseToSynch(Process, &LockHandle);
/* Loop the Process's Threads */ ListHead = &Process->ThreadListHead; NextEntry = ListHead->Flink; do { /* Get the current thread */ Current = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry);
/* Lock it */ KiAcquireApcLockAtSynchLevel(Current, &ApcLock);
/* Make sure we are frozen */ OldCount = Current->FreezeCount; if (OldCount) { /* Decrease the freeze count */ Current->FreezeCount--;
/* Check if both counts are zero now */ if (!(Current->SuspendCount) && (!Current->FreezeCount)) { /* Lock the dispatcher */ KiAcquireDispatcherLockAtSynchLevel();
/* Signal the suspend semaphore and wake it */ Current->SuspendSemaphore.Header.SignalState++; KiWaitTest(&Current->SuspendSemaphore, 0);
/* Unlock the dispatcher */ KiReleaseDispatcherLockFromSynchLevel(); } }
/* Release the APC lock */ KiReleaseApcLockFromSynchLevel(&ApcLock);
/* Go to the next one */ NextEntry = NextEntry->Flink; } while (NextEntry != ListHead);
/* Release the process lock and exit the dispatcher */ KiReleaseProcessLockFromSynchLevel(&LockHandle); KiExitDispatcher(LockHandle.OldIrql);
/* Leave the critical region */ KeLeaveCriticalRegion();}
BOOLEANNTAPIKeTestAlertThread(IN KPROCESSOR_MODE AlertMode){ PKTHREAD Thread = KeGetCurrentThread(); BOOLEAN OldState; KLOCK_QUEUE_HANDLE ApcLock; ASSERT_THREAD(Thread); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Lock the Dispatcher Database and the APC Queue */ KiAcquireApcLockRaiseToSynch(Thread, &ApcLock);
/* Save the old State */ OldState = Thread->Alerted[AlertMode];
/* Check the Thread is alerted */ if (OldState) { /* Disable alert for this mode */ Thread->Alerted[AlertMode] = FALSE; } else if ((AlertMode != KernelMode) && (!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 */ KiReleaseApcLock(&ApcLock); return OldState;}
NTSTATUSNTAPIKeInitThread(IN OUT PKTHREAD Thread, IN PVOID KernelStack, IN PKSYSTEM_ROUTINE SystemRoutine, IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext, IN PCONTEXT Context, IN PVOID Teb, IN PKPROCESS Process){ BOOLEAN AllocatedStack = FALSE; ULONG i; PKWAIT_BLOCK TimerWaitBlock; PKTIMER Timer; NTSTATUS Status;
/* Initialize the Dispatcher Header */ Thread->Header.Type = ThreadObject; Thread->Header.ThreadControlFlags = 0; Thread->Header.DebugActive = FALSE; Thread->Header.SignalState = 0; InitializeListHead(&(Thread->Header.WaitListHead));
/* Initialize the Mutant List */ InitializeListHead(&Thread->MutantListHead);
/* Initialize the wait blocks */ for (i = 0; i< (THREAD_WAIT_OBJECTS + 1); i++) { /* Put our pointer */ Thread->WaitBlock[i].Thread = Thread; }
/* Set swap settings */ Thread->EnableStackSwap = TRUE; Thread->IdealProcessor = 1; Thread->SwapBusy = FALSE; Thread->KernelStackResident = TRUE; Thread->AdjustReason = AdjustNone;
/* Initialize the lock */ KeInitializeSpinLock(&Thread->ThreadLock);
/* Setup the Service Descriptor Table for Native Calls */ Thread->ServiceTable = KeServiceDescriptorTable;
/* Setup APC Fields */ InitializeListHead(&Thread->ApcState.ApcListHead[KernelMode]); InitializeListHead(&Thread->ApcState.ApcListHead[UserMode]); Thread->ApcState.Process = Process; Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState; Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState; Thread->ApcStateIndex = OriginalApcEnvironment; Thread->ApcQueueable = TRUE; KeInitializeSpinLock(&Thread->ApcQueueLock);
/* Initialize the Suspend APC */ KeInitializeApc(&Thread->SuspendApc, Thread, OriginalApcEnvironment, KiSuspendNop, KiSuspendRundown, KiSuspendThread, KernelMode, NULL);
/* Initialize the Suspend Semaphore */ KeInitializeSemaphore(&Thread->SuspendSemaphore, 0, 2);
/* Setup the timer */ Timer = &Thread->Timer; KeInitializeTimer(Timer); TimerWaitBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK]; TimerWaitBlock->Object = Timer; TimerWaitBlock->WaitKey = STATUS_TIMEOUT; TimerWaitBlock->WaitType = WaitAny; TimerWaitBlock->NextWaitBlock = NULL;
/* Link the two wait lists together */ TimerWaitBlock->WaitListEntry.Flink = &Timer->Header.WaitListHead; TimerWaitBlock->WaitListEntry.Blink = &Timer->Header.WaitListHead;
/* Set the TEB and process */ Thread->Teb = Teb; Thread->Process = Process;
/* Check if we have a kernel stack */ if (!KernelStack) { /* We don't, allocate one */ KernelStack = MmCreateKernelStack(FALSE, 0); if (!KernelStack) return STATUS_INSUFFICIENT_RESOURCES;
/* Remember for later */ AllocatedStack = TRUE; }
/* Set the Thread Stacks */ Thread->InitialStack = KernelStack; Thread->StackBase = KernelStack; Thread->StackLimit = (ULONG_PTR)KernelStack - KERNEL_STACK_SIZE; Thread->KernelStackResident = TRUE;
/* Enter SEH to avoid crashes due to user mode */ Status = STATUS_SUCCESS; _SEH2_TRY { /* Initialize the Thread Context */ KiInitializeContextThread(Thread, SystemRoutine, StartRoutine, StartContext, Context); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Set failure status */ Status = STATUS_UNSUCCESSFUL;
/* Check if a stack was allocated */ if (AllocatedStack) { /* Delete the stack */ MmDeleteKernelStack((PVOID)Thread->StackBase, FALSE); Thread->InitialStack = NULL; } } _SEH2_END;
/* Set the Thread to initialized */ Thread->State = Initialized; return Status;}
VOIDNTAPIKeInitializeThread(IN PKPROCESS Process, IN OUT PKTHREAD Thread, IN PKSYSTEM_ROUTINE SystemRoutine, IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext, IN PCONTEXT Context, IN PVOID Teb, IN PVOID KernelStack){ /* Initialize and start the thread on success */ if (NT_SUCCESS(KeInitThread(Thread, KernelStack, SystemRoutine, StartRoutine, StartContext, Context, Teb, Process))) { /* Start it */ KeStartThread(Thread); }}
VOIDNTAPIKeUninitThread(IN PKTHREAD Thread){ /* Delete the stack */ MmDeleteKernelStack((PVOID)Thread->StackBase, FALSE); Thread->InitialStack = NULL;}
/* PUBLIC FUNCTIONS **********************************************************/
/* * @unimplemented */VOIDNTAPIKeCapturePersistentThreadState(IN PVOID CurrentThread, IN ULONG Setting1, IN ULONG Setting2, IN ULONG Setting3, IN ULONG Setting4, IN ULONG Setting5, IN PVOID ThreadState){ UNIMPLEMENTED;}
/* * @implemented */#undef KeGetCurrentThreadPKTHREADNTAPIKeGetCurrentThread(VOID){ /* Return the current thread on this PCR */ return _KeGetCurrentThread();}
/* * @implemented */#undef KeGetPreviousModeUCHARNTAPIKeGetPreviousMode(VOID){ /* Return the previous mode of this thread */ return _KeGetPreviousMode();}
/* * @implemented */ULONGNTAPIKeQueryRuntimeThread(IN PKTHREAD Thread, OUT PULONG UserTime){ ASSERT_THREAD(Thread);
/* Return the User Time */ *UserTime = Thread->UserTime;
/* Return the Kernel Time */ return Thread->KernelTime;}
/* * @implemented */BOOLEANNTAPIKeSetKernelStackSwapEnable(IN BOOLEAN Enable){ BOOLEAN PreviousState; PKTHREAD Thread = KeGetCurrentThread();
/* Save Old State */ PreviousState = Thread->EnableStackSwap;
/* Set New State */ Thread->EnableStackSwap = Enable;
/* Return Old State */ return PreviousState;}
/* * @implemented */KPRIORITYNTAPIKeQueryPriorityThread(IN PKTHREAD Thread){ ASSERT_THREAD(Thread);
/* Return the current priority */ return Thread->Priority;}
/* * @implemented */VOIDNTAPIKeRevertToUserAffinityThread(VOID){ KIRQL OldIrql; PKPRCB Prcb; PKTHREAD NextThread, CurrentThread = KeGetCurrentThread(); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); ASSERT(CurrentThread->SystemAffinityActive != FALSE);
/* Lock the Dispatcher Database */ OldIrql = KiAcquireDispatcherLock();
/* Set the user affinity and processor and disable system affinity */ CurrentThread->Affinity = CurrentThread->UserAffinity; CurrentThread->IdealProcessor = CurrentThread->UserIdealProcessor; CurrentThread->SystemAffinityActive = FALSE;
/* Get the current PRCB and check if it doesn't match this affinity */ Prcb = KeGetCurrentPrcb(); if (!(Prcb->SetMember & CurrentThread->Affinity)) { /* Lock the PRCB */ KiAcquirePrcbLock(Prcb);
/* Check if there's no next thread scheduled */ if (!Prcb->NextThread) { /* Select a new thread and set it on standby */ NextThread = KiSelectNextThread(Prcb); NextThread->State = Standby; Prcb->NextThread = NextThread; }
/* Release the PRCB lock */ KiReleasePrcbLock(Prcb); }
/* Unlock dispatcher database */ KiReleaseDispatcherLock(OldIrql);}
/* * @implemented */UCHARNTAPIKeSetIdealProcessorThread(IN PKTHREAD Thread, IN UCHAR Processor){ CCHAR OldIdealProcessor; KIRQL OldIrql; ASSERT(Processor <= MAXIMUM_PROCESSORS);
/* Lock the Dispatcher Database */ OldIrql = KiAcquireDispatcherLock();
/* Save Old Ideal Processor */ OldIdealProcessor = Thread->UserIdealProcessor;
/* Make sure a valid CPU was given */ if (Processor < KeNumberProcessors) { /* Check if the user ideal CPU is in the affinity */ if (Thread->Affinity & AFFINITY_MASK(Processor)) { /* Set the ideal processor */ Thread->IdealProcessor = Processor;
/* Check if system affinity is used */ if (!Thread->SystemAffinityActive) { /* It's not, so update the user CPU too */ Thread->UserIdealProcessor = Processor; } } }
/* Release dispatcher lock and return the old ideal CPU */ KiReleaseDispatcherLock(OldIrql); return OldIdealProcessor;}
/* * @implemented */VOIDNTAPIKeSetSystemAffinityThread(IN KAFFINITY Affinity){ KIRQL OldIrql; PKPRCB Prcb; PKTHREAD NextThread, CurrentThread = KeGetCurrentThread(); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); ASSERT((Affinity & KeActiveProcessors) != 0);
/* Lock the Dispatcher Database */ OldIrql = KiAcquireDispatcherLock();
/* Restore the affinity and enable system affinity */ CurrentThread->Affinity = Affinity; CurrentThread->SystemAffinityActive = TRUE;
#ifdef CONFIG_SMP /* Calculate the ideal processor from the affinity set */ CurrentThread->IdealProcessor = KiFindIdealProcessor(Affinity, CurrentThread->IdealProcessor);#endif
/* Get the current PRCB and check if it doesn't match this affinity */ Prcb = KeGetCurrentPrcb(); if (!(Prcb->SetMember & CurrentThread->Affinity)) { /* Lock the PRCB */ KiAcquirePrcbLock(Prcb);
/* Check if there's no next thread scheduled */ if (!Prcb->NextThread) { /* Select a new thread and set it on standby */ NextThread = KiSelectNextThread(Prcb); NextThread->State = Standby; Prcb->NextThread = NextThread; }
/* Release the PRCB lock */ KiReleasePrcbLock(Prcb); }
/* Unlock dispatcher database */ KiReleaseDispatcherLock(OldIrql);}
/* * @implemented */LONGNTAPIKeSetBasePriorityThread(IN PKTHREAD Thread, IN LONG Increment){ KIRQL OldIrql; KPRIORITY OldBasePriority, Priority, BasePriority; LONG OldIncrement; PKPROCESS Process; ASSERT_THREAD(Thread); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Get the process */ Process = Thread->ApcState.Process;
/* Lock the Dispatcher Database */ OldIrql = KiAcquireDispatcherLock();
/* Lock the thread */ KiAcquireThreadLock(Thread);
/* Save the old base priority and increment */ OldBasePriority = Thread->BasePriority; OldIncrement = OldBasePriority - Process->BasePriority;
/* If priority saturation happened, use the saturated increment */ if (Thread->Saturation) OldIncrement = (HIGH_PRIORITY + 1) / 2 * Thread->Saturation;
/* Reset the saturation value */ Thread->Saturation = 0;
/* Now check if saturation is being used for the new value */ if (abs(Increment) >= ((HIGH_PRIORITY + 1) / 2)) { /* Check if we need positive or negative saturation */ Thread->Saturation = (Increment > 0) ? 1 : -1; }
/* Normalize the Base Priority */ BasePriority = Process->BasePriority + Increment; if (Process->BasePriority >= LOW_REALTIME_PRIORITY) { /* Check if it's too low */ if (BasePriority < LOW_REALTIME_PRIORITY) { /* Set it to the lowest real time level */ BasePriority = LOW_REALTIME_PRIORITY; }
/* Check if it's too high */ if (BasePriority > HIGH_PRIORITY) BasePriority = HIGH_PRIORITY;
/* We are at real time, so use the raw base priority */ Priority = BasePriority; } else { /* Check if it's entering the real time range */ if (BasePriority >= LOW_REALTIME_PRIORITY) { /* Set it to the highest dynamic level */ BasePriority = LOW_REALTIME_PRIORITY - 1; }
/* Check if it's too low and normalize it */ if (BasePriority <= LOW_PRIORITY) BasePriority = 1;
/* Check if Saturation is used */ if (Thread->Saturation) { /* Use the raw base priority */ Priority = BasePriority; } else { /* Otherwise, calculate the new priority */ Priority = KiComputeNewPriority(Thread, 0); Priority += (BasePriority - OldBasePriority);
/* Check if it entered the real-time range */ if (Priority >= LOW_REALTIME_PRIORITY) { /* Normalize it down to the highest dynamic priority */ Priority = LOW_REALTIME_PRIORITY - 1; } else if (Priority <= LOW_PRIORITY) { /* It went too low, normalize it */ Priority = 1; } } }
/* Finally set the new base priority */ Thread->BasePriority = (SCHAR)BasePriority;
/* Reset the decrements */ Thread->PriorityDecrement = 0;
/* Check if we're changing priority after all */ if (Priority != Thread->Priority) { /* Reset the quantum and do the actual priority modification */ Thread->Quantum = Thread->QuantumReset; KiSetPriorityThread(Thread, Priority); }
/* Release thread lock */ KiReleaseThreadLock(Thread);
/* Release the dispatcher database and return old increment */ KiReleaseDispatcherLock(OldIrql); return OldIncrement;}
/* * @implemented */KAFFINITYNTAPIKeSetAffinityThread(IN PKTHREAD Thread, IN KAFFINITY Affinity){ KIRQL OldIrql; KAFFINITY OldAffinity; ASSERT_THREAD(Thread); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Lock the dispatcher database */ OldIrql = KiAcquireDispatcherLock();
/* Call the internal function */ OldAffinity = KiSetAffinityThread(Thread, Affinity);
/* Release the dispatcher database and return old affinity */ KiReleaseDispatcherLock(OldIrql); return OldAffinity;}
/* * @implemented */KPRIORITYNTAPIKeSetPriorityThread(IN PKTHREAD Thread, IN KPRIORITY Priority){ KIRQL OldIrql; KPRIORITY OldPriority; ASSERT_THREAD(Thread); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); ASSERT((Priority <= HIGH_PRIORITY) && (Priority >= LOW_PRIORITY)); ASSERT(KeIsExecutingDpc() == FALSE);
/* Lock the Dispatcher Database */ OldIrql = KiAcquireDispatcherLock();
/* Lock the thread */ KiAcquireThreadLock(Thread);
/* Save the old Priority and reset decrement */ OldPriority = Thread->Priority; Thread->PriorityDecrement = 0;
/* Make sure that an actual change is being done */ if (Priority != Thread->Priority) { /* Reset the quantum */ Thread->Quantum = Thread->QuantumReset;
/* Check if priority is being set too low and normalize if so */ if ((Thread->BasePriority != 0) && !(Priority)) Priority = 1;
/* Set the new Priority */ KiSetPriorityThread(Thread, Priority); }
/* Release thread lock */ KiReleaseThreadLock(Thread);
/* Release the dispatcher database */ KiReleaseDispatcherLock(OldIrql);
/* Return Old Priority */ return OldPriority;}
/* * @implemented */VOIDNTAPIKeTerminateThread(IN KPRIORITY Increment){ PLIST_ENTRY *ListHead; PETHREAD Entry, SavedEntry; PETHREAD *ThreadAddr; KLOCK_QUEUE_HANDLE LockHandle; PKTHREAD Thread = KeGetCurrentThread(); PKPROCESS Process = Thread->ApcState.Process; ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Lock the process */ KiAcquireProcessLockRaiseToSynch(Process, &LockHandle);
/* Make sure we won't get Swapped */ KiSetThreadSwapBusy(Thread);
/* Save the Kernel and User Times */ Process->KernelTime += Thread->KernelTime; Process->UserTime += Thread->UserTime;
/* Get the current entry and our Port */ Entry = (PETHREAD)PspReaperListHead.Flink; ThreadAddr = &((PETHREAD)Thread)->ReaperLink;
/* Add it to the reaper's list */ do { /* Get the list head */ ListHead = &PspReaperListHead.Flink;
/* Link ourselves */ *ThreadAddr = Entry; SavedEntry = Entry;
/* Now try to do the exchange */ Entry = InterlockedCompareExchangePointer((PVOID*)ListHead, ThreadAddr, Entry);
/* Break out if the change was succesful */ } while (Entry != SavedEntry);
/* Acquire the dispatcher lock */ KiAcquireDispatcherLockAtSynchLevel();
/* Check if the reaper wasn't active */ if (!Entry) { /* Activate it as a work item, directly through its Queue */ KiInsertQueue(&ExWorkerQueue[HyperCriticalWorkQueue].WorkerQueue, &PspReaperWorkItem.List, FALSE); }
/* Check the thread has an associated queue */ if (Thread->Queue) { /* Remove it from the list, and handle the queue */ RemoveEntryList(&Thread->QueueListEntry); KiActivateWaiterQueue(Thread->Queue); }
/* Signal the thread */ Thread->Header.SignalState = TRUE; if (!IsListEmpty(&Thread->Header.WaitListHead)) { /* Unwait the threads */ KxUnwaitThread(&Thread->Header, Increment); }
/* Remove the thread from the list */ RemoveEntryList(&Thread->ThreadListEntry);
/* Release the process lock */ KiReleaseProcessLockFromSynchLevel(&LockHandle);
/* Set us as terminated, decrease the Process's stack count */ Thread->State = Terminated;
/* Decrease stack count */ ASSERT(Process->StackCount != 0); ASSERT(Process->State == ProcessInMemory); Process->StackCount--; if (!(Process->StackCount) && !(IsListEmpty(&Process->ThreadListHead))) { /* FIXME: Swap stacks */ }
/* Rundown arch-specific parts */ KiRundownThread(Thread);
/* Swap to a new thread */ KiReleaseDispatcherLockFromSynchLevel(); KiSwapThread(Thread, KeGetCurrentPrcb());}