2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/thrdobj.c
5 * PURPOSE: Implements routines to manage the Kernel Thread Object
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
13 #include <internal/debug.h>
15 extern EX_WORK_QUEUE ExWorkerQueue
[MaximumWorkQueue
];
16 extern LIST_ENTRY PspReaperListHead
;
18 ULONG KiMask32Array
[MAXIMUM_PRIORITY
] =
20 0x1, 0x2, 0x4, 0x8, 0x10, 0x20,
21 0x40, 0x80, 0x100, 0x200, 0x4000, 0x800,
22 0x1000, 0x2000, 0x4000, 0x8000, 0x10000, 0x20000,
23 0x40000, 0x80000, 0x100000, 0x200000, 0x400000, 0x800000,
24 0x1000000, 0x2000000, 0x4000000, 0x8000000, 0x10000000, 0x20000000,
25 0x40000000, 0x80000000
28 /* FUNCTIONS *****************************************************************/
32 KeFindNextRightSetAffinity(IN UCHAR Number
,
38 /* Calculate the mask */
39 Bit
= (AFFINITY_MASK(Number
) - 1) & Set
;
41 /* If it's 0, use the one we got */
44 /* Now find the right set and return it */
45 BitScanReverse(&Result
, Bit
);
51 KeAlertResumeThread(IN PKTHREAD Thread
)
54 KLOCK_QUEUE_HANDLE ApcLock
;
55 ASSERT_THREAD(Thread
);
56 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
58 /* Lock the Dispatcher Database and the APC Queue */
59 KiAcquireApcLock(Thread
, &ApcLock
);
60 KiAcquireDispatcherLockAtDpcLevel();
62 /* Return if Thread is already alerted. */
63 if (!Thread
->Alerted
[KernelMode
])
65 /* If it's Blocked, unblock if it we should */
66 if ((Thread
->State
== Waiting
) && (Thread
->Alertable
))
69 KiAbortWaitThread(Thread
, STATUS_ALERTED
, THREAD_ALERT_INCREMENT
);
73 /* If not, simply Alert it */
74 Thread
->Alerted
[KernelMode
] = TRUE
;
78 /* Save the old Suspend Count */
79 PreviousCount
= Thread
->SuspendCount
;
81 /* If the thread is suspended, decrease one of the suspend counts */
84 /* Decrease count. If we are now zero, unwait it completely */
85 if (--Thread
->SuspendCount
)
87 /* Signal and satisfy */
88 Thread
->SuspendSemaphore
.Header
.SignalState
++;
89 KiWaitTest(&Thread
->SuspendSemaphore
.Header
, IO_NO_INCREMENT
);
93 /* Release Locks and return the Old State */
94 KiReleaseDispatcherLockFromDpcLevel();
95 KiReleaseApcLockFromDpcLevel(&ApcLock
);
96 KiExitDispatcher(ApcLock
.OldIrql
);
102 KeAlertThread(IN PKTHREAD Thread
,
103 IN KPROCESSOR_MODE AlertMode
)
105 BOOLEAN PreviousState
;
106 KLOCK_QUEUE_HANDLE ApcLock
;
107 ASSERT_THREAD(Thread
);
108 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
110 /* Lock the Dispatcher Database and the APC Queue */
111 KiAcquireApcLock(Thread
, &ApcLock
);
112 KiAcquireDispatcherLockAtDpcLevel();
114 /* Save the Previous State */
115 PreviousState
= Thread
->Alerted
[AlertMode
];
117 /* Check if it's already alerted */
120 /* Check if the thread is alertable, and blocked in the given mode */
121 if ((Thread
->State
== Waiting
) &&
122 ((AlertMode
== KernelMode
) || (Thread
->WaitMode
== AlertMode
)) &&
125 /* Abort the wait to alert the thread */
126 KiAbortWaitThread(Thread
, STATUS_ALERTED
, THREAD_ALERT_INCREMENT
);
130 /* Otherwise, merely set the alerted state */
131 Thread
->Alerted
[AlertMode
] = TRUE
;
135 /* Release the Dispatcher Lock */
136 KiReleaseDispatcherLockFromDpcLevel();
137 KiReleaseApcLockFromDpcLevel(&ApcLock
);
138 KiExitDispatcher(ApcLock
.OldIrql
);
140 /* Return the old state */
141 return PreviousState
;
146 KeForceResumeThread(IN PKTHREAD Thread
)
148 KLOCK_QUEUE_HANDLE ApcLock
;
150 ASSERT_THREAD(Thread
);
151 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
153 /* Lock the APC Queue */
154 KiAcquireApcLock(Thread
, &ApcLock
);
156 /* Save the old Suspend Count */
157 PreviousCount
= Thread
->SuspendCount
+ Thread
->FreezeCount
;
159 /* If the thread is suspended, wake it up!!! */
162 /* Unwait it completely */
163 Thread
->SuspendCount
= 0;
164 Thread
->FreezeCount
= 0;
166 /* Lock the dispatcher */
167 KiAcquireDispatcherLockAtDpcLevel();
169 /* Signal and satisfy */
170 Thread
->SuspendSemaphore
.Header
.SignalState
++;
171 KiWaitTest(&Thread
->SuspendSemaphore
.Header
, IO_NO_INCREMENT
);
173 /* Release the dispatcher */
174 KiReleaseDispatcherLockFromDpcLevel();
177 /* Release Lock and return the Old State */
178 KiReleaseApcLockFromDpcLevel(&ApcLock
);
179 KiExitDispatcher(ApcLock
.OldIrql
);
180 return PreviousCount
;
184 * Used by the debugging code to freeze all the process's threads
185 * while the debugger is examining their state.
189 KeFreezeAllThreads(IN PKPROCESS Process
)
191 KLOCK_QUEUE_HANDLE LockHandle
, ApcLock
;
192 PKTHREAD Current
, CurrentThread
= KeGetCurrentThread();
193 PLIST_ENTRY ListHead
, NextEntry
;
195 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
197 /* Lock the process */
198 KiAcquireProcessLock(Process
, &LockHandle
);
200 /* If someone is already trying to free us, try again */
201 while (CurrentThread
->FreezeCount
)
203 /* Release and re-acquire the process lock so the APC will go through */
204 KiReleaseProcessLock(&LockHandle
);
205 KiAcquireProcessLock(Process
, &LockHandle
);
208 /* Enter a critical region */
209 KeEnterCriticalRegion();
211 /* Loop the Process's Threads */
212 ListHead
= &Process
->ThreadListHead
;
213 NextEntry
= ListHead
->Flink
;
214 while (NextEntry
!= ListHead
)
216 /* Get the current thread */
217 Current
= CONTAINING_RECORD(NextEntry
, KTHREAD
, ThreadListEntry
);
220 KiAcquireApcLockAtDpcLevel(Current
, &ApcLock
);
222 /* Make sure it's not ours, and check if APCs are enabled */
223 if ((Current
!= CurrentThread
) && (Current
->ApcQueueable
))
226 OldCount
= Current
->SuspendCount
;
227 ASSERT(OldCount
!= MAXIMUM_SUSPEND_COUNT
);
229 /* Increase the freeze count */
230 Current
->FreezeCount
++;
232 /* Make sure it wasn't already suspended */
233 if (!(OldCount
) && !(Current
->SuspendCount
))
235 /* Did we already insert it? */
236 if (!Current
->SuspendApc
.Inserted
)
239 Current
->SuspendApc
.Inserted
= TRUE
;
240 KiInsertQueueApc(&Current
->SuspendApc
, IO_NO_INCREMENT
);
244 /* Lock the dispatcher */
245 KiAcquireDispatcherLockAtDpcLevel();
247 /* Unsignal the semaphore, the APC was already inserted */
248 Current
->SuspendSemaphore
.Header
.SignalState
--;
250 /* Release the dispatcher */
251 KiReleaseDispatcherLockFromDpcLevel();
256 /* Release the APC lock */
257 KiReleaseApcLockFromDpcLevel(&ApcLock
);
260 /* Release the process lock and exit the dispatcher */
261 KiReleaseProcessLock(&LockHandle
);
262 KiExitDispatcher(LockHandle
.OldIrql
);
267 KeResumeThread(IN PKTHREAD Thread
)
269 KLOCK_QUEUE_HANDLE ApcLock
;
271 ASSERT_THREAD(Thread
);
272 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
274 /* Lock the APC Queue */
275 KiAcquireApcLock(Thread
, &ApcLock
);
277 /* Save the Old Count */
278 PreviousCount
= Thread
->SuspendCount
;
280 /* Check if it existed */
283 /* Decrease the suspend count */
284 Thread
->SuspendCount
--;
286 /* Check if the thrad is still suspended or not */
287 if ((!Thread
->SuspendCount
) && (!Thread
->FreezeCount
))
289 /* Acquire the dispatcher lock */
290 KiAcquireDispatcherLockAtDpcLevel();
292 /* Signal the Suspend Semaphore */
293 Thread
->SuspendSemaphore
.Header
.SignalState
++;
294 KiWaitTest(&Thread
->SuspendSemaphore
.Header
, IO_NO_INCREMENT
);
296 /* Release the dispatcher lock */
297 KiReleaseDispatcherLockFromDpcLevel();
301 /* Release APC Queue lock and return the Old State */
302 KiReleaseApcLockFromDpcLevel(&ApcLock
);
303 KiExitDispatcher(ApcLock
.OldIrql
);
304 return PreviousCount
;
309 KeRundownThread(VOID
)
312 PKTHREAD Thread
= KeGetCurrentThread();
313 PLIST_ENTRY NextEntry
, ListHead
;
316 /* Optimized path if nothing is on the list at the moment */
317 if (IsListEmpty(&Thread
->MutantListHead
)) return;
319 /* Lock the Dispatcher Database */
320 OldIrql
= KiAcquireDispatcherLock();
322 /* Get the List Pointers */
323 ListHead
= &Thread
->MutantListHead
;
324 NextEntry
= ListHead
->Flink
;
325 while (NextEntry
!= ListHead
)
328 Mutant
= CONTAINING_RECORD(NextEntry
, KMUTANT
, MutantListEntry
);
330 /* Make sure it's not terminating with APCs off */
331 if (Mutant
->ApcDisable
)
333 /* Bugcheck the system */
334 KEBUGCHECKEX(0, //THREAD_TERMINATE_HELD_MUTEX,
341 /* Now we can remove it */
342 RemoveEntryList(&Mutant
->MutantListEntry
);
344 /* Unconditionally abandon it */
345 Mutant
->Header
.SignalState
= 1;
346 Mutant
->Abandoned
= TRUE
;
347 Mutant
->OwnerThread
= NULL
;
349 /* Check if the Wait List isn't empty */
350 if (!IsListEmpty(&Mutant
->Header
.WaitListHead
))
352 /* Wake the Mutant */
353 KiWaitTest(&Mutant
->Header
, MUTANT_INCREMENT
);
357 NextEntry
= NextEntry
->Flink
;
360 /* Release the Lock */
361 KiReleaseDispatcherLock(OldIrql
);
366 KeStartThread(IN OUT PKTHREAD Thread
)
368 KLOCK_QUEUE_HANDLE LockHandle
;
374 UCHAR IdealProcessor
= 0;
375 PKPROCESS Process
= Thread
->ApcState
.Process
;
377 /* Setup static fields from parent */
378 Thread
->Iopl
= Process
->Iopl
;
379 Thread
->Quantum
= Process
->QuantumReset
;
380 Thread
->QuantumReset
= Process
->QuantumReset
;
381 Thread
->SystemAffinityActive
= FALSE
;
383 /* Lock the process */
384 KiAcquireProcessLock(Process
, &LockHandle
);
386 /* Setup volatile data */
387 Thread
->Priority
= Process
->BasePriority
;
388 Thread
->BasePriority
= Process
->BasePriority
;
389 Thread
->Affinity
= Process
->Affinity
;
390 Thread
->UserAffinity
= Process
->Affinity
;
393 /* Get the KNODE and its PRCB */
394 Node
= KeNodeBlock
[Process
->IdealNode
];
395 NodePrcb
= (PKPRCB
)(KPCR_BASE
+ (Process
->ThreadSeed
* PAGE_SIZE
));
397 /* Calculate affinity mask */
398 Set
= ~NodePrcb
->MultiThreadProcessorSet
;
399 Mask
= (ULONG
)(Node
->ProcessorMask
& Process
->Affinity
);
403 /* Get the new thread seed */
404 IdealProcessor
= KeFindNextRightSetAffinity(Process
->ThreadSeed
, Mask
);
405 Process
->ThreadSeed
= IdealProcessor
;
408 ASSERT((Thread
->UserAffinity
& AFFINITY_MASK(IdealProcessor
)));
411 /* Set the Ideal Processor */
412 Thread
->IdealProcessor
= IdealProcessor
;
413 Thread
->UserIdealProcessor
= IdealProcessor
;
415 /* Lock the Dispatcher Database */
416 KiAcquireDispatcherLockAtDpcLevel();
418 /* Insert the thread into the process list */
419 InsertTailList(&Process
->ThreadListHead
, &Thread
->ThreadListEntry
);
421 /* Increase the stack count */
422 ASSERT(Process
->StackCount
!= MAXULONG_PTR
);
423 Process
->StackCount
++;
425 /* Release locks and return */
426 KiReleaseDispatcherLockFromDpcLevel();
427 KiReleaseProcessLock(&LockHandle
);
432 KiSuspendRundown(IN PKAPC Apc
)
435 UNREFERENCED_PARAMETER(Apc
);
440 KiSuspendNop(IN PKAPC Apc
,
441 IN PKNORMAL_ROUTINE
*NormalRoutine
,
442 IN PVOID
*NormalContext
,
443 IN PVOID
*SystemArgument1
,
444 IN PVOID
*SystemArgument2
)
447 UNREFERENCED_PARAMETER(Apc
);
448 UNREFERENCED_PARAMETER(NormalRoutine
);
449 UNREFERENCED_PARAMETER(NormalContext
);
450 UNREFERENCED_PARAMETER(SystemArgument1
);
451 UNREFERENCED_PARAMETER(SystemArgument2
);
456 KiSuspendThread(IN PVOID NormalContext
,
457 IN PVOID SystemArgument1
,
458 IN PVOID SystemArgument2
)
460 /* Non-alertable kernel-mode suspended wait */
461 KeWaitForSingleObject(&KeGetCurrentThread()->SuspendSemaphore
,
470 KeSuspendThread(PKTHREAD Thread
)
472 KLOCK_QUEUE_HANDLE ApcLock
;
474 ASSERT_THREAD(Thread
);
475 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
477 /* Lock the APC Queue */
478 KiAcquireApcLock(Thread
, &ApcLock
);
480 /* Save the Old Count */
481 PreviousCount
= Thread
->SuspendCount
;
483 /* Handle the maximum */
484 if (PreviousCount
== MAXIMUM_SUSPEND_COUNT
)
486 /* Raise an exception */
487 KiReleaseApcLock(&ApcLock
);
488 RtlRaiseStatus(STATUS_SUSPEND_COUNT_EXCEEDED
);
491 /* Should we bother to queue at all? */
492 if (Thread
->ApcQueueable
)
494 /* Increment the suspend count */
495 Thread
->SuspendCount
++;
497 /* Check if we should suspend it */
498 if (!(PreviousCount
) && !(Thread
->FreezeCount
))
500 /* Is the APC already inserted? */
501 if (!Thread
->SuspendApc
.Inserted
)
503 /* Not inserted, insert it */
504 Thread
->SuspendApc
.Inserted
= TRUE
;
505 KiInsertQueueApc(&Thread
->SuspendApc
, IO_NO_INCREMENT
);
509 /* Lock the dispatcher */
510 KiAcquireDispatcherLockAtDpcLevel();
512 /* Unsignal the semaphore, the APC was already inserted */
513 Thread
->SuspendSemaphore
.Header
.SignalState
--;
515 /* Release the dispatcher */
516 KiReleaseDispatcherLockFromDpcLevel();
521 /* Release Lock and return the Old State */
522 KiReleaseApcLockFromDpcLevel(&ApcLock
);
523 KiExitDispatcher(ApcLock
.OldIrql
);
524 return PreviousCount
;
529 KeTestAlertThread(IN KPROCESSOR_MODE AlertMode
)
531 PKTHREAD Thread
= KeGetCurrentThread();
533 KLOCK_QUEUE_HANDLE ApcLock
;
534 ASSERT_THREAD(Thread
);
535 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
537 /* Lock the Dispatcher Database and the APC Queue */
538 KiAcquireApcLock(Thread
, &ApcLock
);
539 KiAcquireDispatcherLockAtDpcLevel();
541 /* Save the old State */
542 OldState
= Thread
->Alerted
[AlertMode
];
544 /* Check the Thread is alerted */
547 /* Disable alert for this mode */
548 Thread
->Alerted
[AlertMode
] = FALSE
;
550 else if ((AlertMode
!= KernelMode
) &&
551 (!IsListEmpty(&Thread
->ApcState
.ApcListHead
[UserMode
])))
553 /* If the mode is User and the Queue isn't empty, set Pending */
554 Thread
->ApcState
.UserApcPending
= TRUE
;
557 /* Release Locks and return the Old State */
558 KiReleaseDispatcherLockFromDpcLevel();
559 KiReleaseApcLockFromDpcLevel(&ApcLock
);
560 KiExitDispatcher(ApcLock
.OldIrql
);
566 KeInitThread(IN OUT PKTHREAD Thread
,
567 IN PVOID KernelStack
,
568 IN PKSYSTEM_ROUTINE SystemRoutine
,
569 IN PKSTART_ROUTINE StartRoutine
,
570 IN PVOID StartContext
,
573 IN PKPROCESS Process
)
575 BOOLEAN AllocatedStack
= FALSE
;
577 PKWAIT_BLOCK TimerWaitBlock
;
581 /* Initalize the Dispatcher Header */
582 KeInitializeDispatcherHeader(&Thread
->DispatcherHeader
,
584 sizeof(KTHREAD
) / sizeof(LONG
),
587 /* Initialize the Mutant List */
588 InitializeListHead(&Thread
->MutantListHead
);
590 /* Initialize the wait blocks */
591 for (i
= 0; i
< (THREAD_WAIT_OBJECTS
+ 1); i
++)
593 /* Put our pointer */
594 Thread
->WaitBlock
[i
].Thread
= Thread
;
597 /* Set swap settings */
598 Thread
->EnableStackSwap
= FALSE
;//TRUE;
599 Thread
->IdealProcessor
= 1;
600 Thread
->SwapBusy
= FALSE
;
601 Thread
->AdjustReason
= 0;
603 /* Initialize the lock */
604 KeInitializeSpinLock(&Thread
->ThreadLock
);
606 /* Setup the Service Descriptor Table for Native Calls */
607 Thread
->ServiceTable
= KeServiceDescriptorTable
;
609 /* Setup APC Fields */
610 InitializeListHead(&Thread
->ApcState
.ApcListHead
[0]);
611 InitializeListHead(&Thread
->ApcState
.ApcListHead
[1]);
612 Thread
->ApcState
.Process
= Process
;
613 Thread
->ApcStatePointer
[OriginalApcEnvironment
] = &Thread
->ApcState
;
614 Thread
->ApcStatePointer
[AttachedApcEnvironment
] = &Thread
->SavedApcState
;
615 Thread
->ApcStateIndex
= OriginalApcEnvironment
;
616 Thread
->ApcQueueable
= TRUE
;
617 KeInitializeSpinLock(&Thread
->ApcQueueLock
);
619 /* Initialize the Suspend APC */
620 KeInitializeApc(&Thread
->SuspendApc
,
622 OriginalApcEnvironment
,
629 /* Initialize the Suspend Semaphore */
630 KeInitializeSemaphore(&Thread
->SuspendSemaphore
, 0, 2);
632 /* Setup the timer */
633 Timer
= &Thread
->Timer
;
634 KeInitializeTimer(Timer
);
635 TimerWaitBlock
= &Thread
->WaitBlock
[TIMER_WAIT_BLOCK
];
636 TimerWaitBlock
->Object
= Timer
;
637 TimerWaitBlock
->WaitKey
= STATUS_TIMEOUT
;
638 TimerWaitBlock
->WaitType
= WaitAny
;
639 TimerWaitBlock
->NextWaitBlock
= NULL
;
641 /* Link the two wait lists together */
642 TimerWaitBlock
->WaitListEntry
.Flink
= &Timer
->Header
.WaitListHead
;
643 TimerWaitBlock
->WaitListEntry
.Blink
= &Timer
->Header
.WaitListHead
;
648 /* Check if we have a kernel stack */
651 /* We don't, allocate one */
652 KernelStack
= (PVOID
)((ULONG_PTR
)MmCreateKernelStack(FALSE
) +
654 if (!KernelStack
) return STATUS_INSUFFICIENT_RESOURCES
;
656 /* Remember for later */
657 AllocatedStack
= TRUE
;
660 /* Set the Thread Stacks */
661 Thread
->InitialStack
= (PCHAR
)KernelStack
;
662 Thread
->StackBase
= (PCHAR
)KernelStack
;
663 Thread
->StackLimit
= (ULONG_PTR
)KernelStack
- KERNEL_STACK_SIZE
;
664 Thread
->KernelStackResident
= TRUE
;
667 MmUpdatePageDir((PEPROCESS
)Process
,
668 (PVOID
)Thread
->StackLimit
,
670 MmUpdatePageDir((PEPROCESS
)Process
, (PVOID
)Thread
, sizeof(ETHREAD
));
672 /* Enter SEH to avoid crashes due to user mode */
673 Status
= STATUS_SUCCESS
;
676 /* Initalize the Thread Context */
677 Ke386InitThreadWithContext(Thread
,
685 /* Set failure status */
686 Status
= STATUS_UNSUCCESSFUL
;
688 /* Check if a stack was allocated */
691 /* Delete the stack */
692 MmDeleteKernelStack(Thread
->StackBase
, FALSE
);
693 Thread
->InitialStack
= NULL
;
698 /* Set the Thread to initalized */
699 Thread
->State
= Initialized
;
705 KeInitializeThread(IN PKPROCESS Process
,
706 IN OUT PKTHREAD Thread
,
707 IN PKSYSTEM_ROUTINE SystemRoutine
,
708 IN PKSTART_ROUTINE StartRoutine
,
709 IN PVOID StartContext
,
712 IN PVOID KernelStack
)
714 /* Initailize and start the thread on success */
715 if (NT_SUCCESS(KeInitThread(Thread
,
725 KeStartThread(Thread
);
731 KeUninitThread(IN PKTHREAD Thread
)
733 /* Delete the stack */
734 MmDeleteKernelStack(Thread
->StackBase
, FALSE
);
735 Thread
->InitialStack
= NULL
;
738 /* PUBLIC FUNCTIONS **********************************************************/
745 KeCapturePersistentThreadState(IN PVOID CurrentThread
,
751 IN PVOID ThreadState
)
759 #undef KeGetCurrentThread
762 KeGetCurrentThread(VOID
)
764 /* Return the current thread on this PCR */
765 return ((PKIPCR
)KeGetPcr())->PrcbData
.CurrentThread
;
773 KeGetPreviousMode(VOID
)
775 /* Return the previous mode of this thread */
776 return KeGetCurrentThread()->PreviousMode
;
784 KeQueryRuntimeThread(IN PKTHREAD Thread
,
787 ASSERT_THREAD(Thread
);
789 /* Return the User Time */
790 *UserTime
= Thread
->UserTime
;
792 /* Return the Kernel Time */
793 return Thread
->KernelTime
;
801 KeSetKernelStackSwapEnable(IN BOOLEAN Enable
)
803 BOOLEAN PreviousState
;
804 PKTHREAD Thread
= KeGetCurrentThread();
807 PreviousState
= Thread
->EnableStackSwap
;
810 Thread
->EnableStackSwap
= Enable
;
812 /* Return Old State */
813 return PreviousState
;
821 KeQueryPriorityThread(IN PKTHREAD Thread
)
823 ASSERT_THREAD(Thread
);
825 /* Return the current priority */
826 return Thread
->Priority
;
834 KeRevertToUserAffinityThread(VOID
)
838 PKTHREAD NextThread
, CurrentThread
= KeGetCurrentThread();
839 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
840 ASSERT(CurrentThread
->SystemAffinityActive
!= FALSE
);
842 /* Lock the Dispatcher Database */
843 OldIrql
= KiAcquireDispatcherLock();
845 /* Set the user affinity and processor and disable system affinity */
846 CurrentThread
->Affinity
= CurrentThread
->UserAffinity
;
847 CurrentThread
->IdealProcessor
= CurrentThread
->UserIdealProcessor
;
848 CurrentThread
->SystemAffinityActive
= FALSE
;
850 /* Get the current PRCB and check if it doesn't match this affinity */
851 Prcb
= KeGetCurrentPrcb();
852 if (!(Prcb
->SetMember
& CurrentThread
->Affinity
))
855 KiAcquirePrcbLock(Prcb
);
858 /* Check if there's no next thread scheduled */
859 if (!Prcb
->NextThread
)
861 /* Select a new thread and set it on standby */
862 NextThread
= KiSelectNextThread(Prcb
);
863 NextThread
->State
= Standby
;
864 Prcb
->NextThread
= NextThread
;
867 /* We need to dispatch a new thread */
869 CurrentThread
->WaitIrql
= OldIrql
;
870 KiDispatchThreadNoLock(Ready
);
871 KeLowerIrql(OldIrql
);
875 /* Release the PRCB lock */
876 KiReleasePrcbLock(Prcb
);
879 /* Unlock dispatcher database */
880 KiReleaseDispatcherLock(OldIrql
);
888 KeSetIdealProcessorThread(IN PKTHREAD Thread
,
891 CCHAR OldIdealProcessor
;
893 ASSERT(Processor
<= MAXIMUM_PROCESSORS
);
895 /* Lock the Dispatcher Database */
896 OldIrql
= KiAcquireDispatcherLock();
898 /* Save Old Ideal Processor */
899 OldIdealProcessor
= Thread
->UserIdealProcessor
;
901 /* Make sure a valid CPU was given */
902 if (Processor
< MAXIMUM_PROCESSORS
)
904 /* Check if the user ideal CPU is in the affinity */
905 if (Thread
->UserIdealProcessor
& AFFINITY_MASK(Processor
))
907 /* Set the ideal processor */
908 Thread
->IdealProcessor
= Processor
;
910 /* Check if system affinity is used */
911 if (!Thread
->SystemAffinityActive
)
913 /* It's not, so update the user CPU too */
914 Thread
->UserIdealProcessor
= Processor
;
919 /* Release dispatcher lock and return the old ideal CPU */
920 KiReleaseDispatcherLock(OldIrql
);
921 return OldIdealProcessor
;
929 KeSetSystemAffinityThread(IN KAFFINITY Affinity
)
934 ULONG AffinitySet
, NodeMask
;
936 PKTHREAD NextThread
, CurrentThread
= KeGetCurrentThread();
937 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
938 ASSERT((Affinity
& KeActiveProcessors
) != 0);
940 /* Lock the Dispatcher Database */
941 OldIrql
= KiAcquireDispatcherLock();
943 /* Restore the affinity and enable system affinity */
944 CurrentThread
->Affinity
= Affinity
;
945 CurrentThread
->SystemAffinityActive
= TRUE
;
947 /* Check if the ideal processor is part of the affinity */
949 if (!(Affinity
& AFFINITY_MASK(CurrentThread
->IdealProcessor
)))
951 /* It's not! Get the PRCB */
952 Prcb
= KiProcessorBlock
[CurrentThread
->IdealProcessor
];
954 /* Calculate the affinity set */
955 AffinitySet
= KeActiveProcessors
& Affinity
;
956 NodeMask
= Prcb
->ParentNode
->ProcessorMask
& AffinitySet
;
959 /* Use the Node set instead */
960 AffinitySet
= NodeMask
;
963 /* Calculate the ideal CPU from the affinity set */
964 BitScanReverse(&NodeMask
, AffinitySet
);
965 CurrentThread
->IdealProcessor
= (UCHAR
)NodeMask
;
969 /* Get the current PRCB and check if it doesn't match this affinity */
970 Prcb
= KeGetCurrentPrcb();
971 if (!(Prcb
->SetMember
& CurrentThread
->Affinity
))
974 KiAcquirePrcbLock(Prcb
);
977 /* Check if there's no next thread scheduled */
978 if (!Prcb
->NextThread
)
980 /* Select a new thread and set it on standby */
981 NextThread
= KiSelectNextThread(Prcb
);
982 NextThread
->State
= Standby
;
983 Prcb
->NextThread
= NextThread
;
986 /* We need to dispatch a new thread */
988 CurrentThread
->WaitIrql
= OldIrql
;
989 KiDispatchThreadNoLock(Ready
);
990 KeLowerIrql(OldIrql
);
994 /* Release the PRCB lock */
995 KiReleasePrcbLock(Prcb
);
998 /* Unlock dispatcher database */
999 KiReleaseDispatcherLock(OldIrql
);
1004 KeQueryBasePriorityThread(IN PKTHREAD Thread
)
1006 LONG BasePriorityIncrement
;
1010 /* Lock the Dispatcher Database */
1011 OldIrql
= KeAcquireDispatcherDatabaseLock();
1013 /* Get the Process */
1014 Process
= Thread
->ApcStatePointer
[0]->Process
;
1016 /* Calculate the BPI */
1017 BasePriorityIncrement
= Thread
->BasePriority
- Process
->BasePriority
;
1019 /* If saturation occured, return the SI instead */
1020 if (Thread
->Saturation
) BasePriorityIncrement
= (HIGH_PRIORITY
+ 1) / 2 *
1024 KeReleaseDispatcherDatabaseLock(OldIrql
);
1026 /* Return Increment */
1027 return BasePriorityIncrement
;
1035 KeSetBasePriorityThread(PKTHREAD Thread
,
1041 KPRIORITY CurrentBasePriority
;
1042 KPRIORITY BasePriority
;
1043 BOOLEAN Released
= FALSE
;
1044 LONG CurrentIncrement
;
1046 /* Lock the Dispatcher Database */
1047 OldIrql
= KeAcquireDispatcherDatabaseLock();
1049 /* Get the process and calculate current BP and BPI */
1050 Process
= Thread
->ApcStatePointer
[0]->Process
;
1051 CurrentBasePriority
= Thread
->BasePriority
;
1052 CurrentIncrement
= CurrentBasePriority
- Process
->BasePriority
;
1054 /* Change to use the SI if Saturation was used */
1055 if (Thread
->Saturation
) CurrentIncrement
= (HIGH_PRIORITY
+ 1) / 2 *
1058 /* Now check if saturation is being used for the new value */
1059 if (abs(Increment
) >= ((HIGH_PRIORITY
+ 1) / 2))
1061 /* Check if we need positive or negative saturation */
1062 Thread
->Saturation
= (Increment
> 0) ? 1 : -1;
1065 /* Normalize the Base Priority */
1066 BasePriority
= Process
->BasePriority
+ Increment
;
1067 if (Process
->BasePriority
>= LOW_REALTIME_PRIORITY
)
1069 /* Check if it's too low */
1070 if (BasePriority
< LOW_REALTIME_PRIORITY
)
1071 BasePriority
= LOW_REALTIME_PRIORITY
;
1073 /* Check if it's too high */
1074 if (BasePriority
> HIGH_PRIORITY
) BasePriority
= HIGH_PRIORITY
;
1076 /* We are at RTP, so use the raw BP */
1077 Priority
= BasePriority
;
1081 /* Check if it's entering RTP */
1082 if (BasePriority
>= LOW_REALTIME_PRIORITY
)
1083 BasePriority
= LOW_REALTIME_PRIORITY
- 1;
1085 /* Check if it's too low */
1086 if (BasePriority
<= LOW_PRIORITY
)
1089 /* If Saturation is used, then use the raw BP */
1090 if (Thread
->Saturation
)
1092 Priority
= BasePriority
;
1096 /* Calculate the new priority */
1097 Priority
= Thread
->Priority
+ (BasePriority
- CurrentBasePriority
)-
1098 Thread
->PriorityDecrement
;
1100 /* Make sure it won't enter RTP ranges */
1101 if (Priority
>= LOW_REALTIME_PRIORITY
)
1102 Priority
= LOW_REALTIME_PRIORITY
- 1;
1106 /* Finally set the new base priority */
1107 Thread
->BasePriority
= BasePriority
;
1109 /* Reset the decrements */
1110 Thread
->PriorityDecrement
= 0;
1112 /* If the priority will change, reset quantum and change it for real */
1113 if (Priority
!= Thread
->Priority
)
1115 Thread
->Quantum
= Thread
->QuantumReset
;
1116 KiSetPriorityThread(Thread
, Priority
, &Released
);
1119 /* Release Lock if needed */
1122 KeReleaseDispatcherDatabaseLock(OldIrql
);
1126 KeLowerIrql(OldIrql
);
1129 /* Return the Old Increment */
1130 return CurrentIncrement
;
1138 KeSetPriorityThread(PKTHREAD Thread
,
1141 KPRIORITY OldPriority
;
1142 BOOLEAN Released
= FALSE
;
1145 /* Lock the Dispatcher Database */
1146 OldIrql
= KeAcquireDispatcherDatabaseLock();
1148 /* Save the old Priority */
1149 OldPriority
= Thread
->Priority
;
1151 /* Reset the Quantum and Decrements */
1152 Thread
->Quantum
= Thread
->QuantumReset
;
1153 Thread
->PriorityDecrement
= 0;
1155 /* Set the new Priority */
1156 KiSetPriorityThread(Thread
, Priority
, &Released
);
1158 /* Release Lock if needed */
1161 KeReleaseDispatcherDatabaseLock(OldIrql
);
1165 KeLowerIrql(OldIrql
);
1168 /* Return Old Priority */
1175 * Sets thread's affinity
1179 KeSetAffinityThread(PKTHREAD Thread
,
1183 KAFFINITY OldAffinity
;
1186 DPRINT("KeSetAffinityThread(Thread %x, Affinity %x)\n", Thread
, Affinity
);
1188 OldIrql
= KeAcquireDispatcherDatabaseLock();
1190 /* Call the internal function */
1191 OldAffinity
= KiSetAffinityThread(Thread
, Affinity
, &Released
);
1193 /* Release Lock if needed */
1196 KeReleaseDispatcherDatabaseLock(OldIrql
);
1200 KeLowerIrql(OldIrql
);
1211 KeTerminateThread(IN KPRIORITY Increment
)
1213 PLIST_ENTRY
*ListHead
;
1214 PETHREAD Entry
, SavedEntry
;
1215 PETHREAD
*ThreadAddr
;
1216 KLOCK_QUEUE_HANDLE LockHandle
;
1217 PKTHREAD Thread
= KeGetCurrentThread();
1218 PKPROCESS Process
= Thread
->ApcState
.Process
;
1219 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
1221 /* Lock the process */
1222 KiAcquireProcessLock(Process
, &LockHandle
);
1224 /* Make sure we won't get Swapped */
1225 KiSetThreadSwapBusy(Thread
);
1227 /* Save the Kernel and User Times */
1228 Process
->KernelTime
+= Thread
->KernelTime
;
1229 Process
->UserTime
+= Thread
->UserTime
;
1231 /* Get the current entry and our Port */
1232 Entry
= (PETHREAD
)PspReaperListHead
.Flink
;
1233 ThreadAddr
= &((PETHREAD
)Thread
)->ReaperLink
;
1235 /* Add it to the reaper's list */
1238 /* Get the list head */
1239 ListHead
= &PspReaperListHead
.Flink
;
1241 /* Link ourselves */
1242 *ThreadAddr
= Entry
;
1245 /* Now try to do the exchange */
1246 Entry
= InterlockedCompareExchangePointer(ListHead
, ThreadAddr
, Entry
);
1248 /* Break out if the change was succesful */
1249 } while (Entry
!= SavedEntry
);
1251 /* Acquire the dispatcher lock */
1252 KiAcquireDispatcherLockAtDpcLevel();
1254 /* Check if the reaper wasn't active */
1257 /* Activate it as a work item, directly through its Queue */
1258 KiInsertQueue(&ExWorkerQueue
[HyperCriticalWorkQueue
].WorkerQueue
,
1259 &PspReaperWorkItem
.List
,
1263 /* Check the thread has an associated queue */
1266 /* Remove it from the list, and handle the queue */
1267 RemoveEntryList(&Thread
->QueueListEntry
);
1268 KiWakeQueue(Thread
->Queue
);
1271 /* Signal the thread */
1272 Thread
->DispatcherHeader
.SignalState
= TRUE
;
1273 if (IsListEmpty(&Thread
->DispatcherHeader
.WaitListHead
) != TRUE
)
1276 KiWaitTest((PVOID
)Thread
, Increment
);
1279 /* Remove the thread from the list */
1280 RemoveEntryList(&Thread
->ThreadListEntry
);
1282 /* Release the process lock */
1283 KiReleaseProcessLock(&LockHandle
);
1285 /* Set us as terminated, decrease the Process's stack count */
1286 Thread
->State
= Terminated
;
1288 /* Decrease stack count */
1289 ASSERT(Process
->StackCount
!= 0);
1290 ASSERT(Process
->State
== ProcessInMemory
);
1291 Process
->StackCount
--;
1292 if (!Process
->StackCount
)
1294 /* FIXME: Swap stacks */
1297 /* Rundown arch-specific parts */
1298 KiRundownThread(Thread
);
1300 /* Swap to a new thread */
1301 KiReleaseDispatcherLockFromDpcLevel();
1302 KiSwapThread(Thread
, KeGetCurrentPrcb());