1 /*
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)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 extern EX_WORK_QUEUE ExWorkerQueue[MaximumWorkQueue];
16 extern LIST_ENTRY PspReaperListHead;
17
18 /* FUNCTIONS *****************************************************************/
19
20 UCHAR
21 NTAPI
KeFindNextRightSetAffinity(IN UCHAR Number,IN KAFFINITY Set)22 KeFindNextRightSetAffinity(IN UCHAR Number,
23 IN KAFFINITY Set)
24 {
25 KAFFINITY Bit;
26 ULONG Result;
27 ASSERT(Set != 0);
28
29 /* Calculate the mask */
30 Bit = (AFFINITY_MASK(Number) - 1) & Set;
31
32 /* If it's 0, use the one we got */
33 if (!Bit) Bit = Set;
34
35 /* Now find the right set and return it */
36 BitScanReverseAffinity(&Result, Bit);
37 return (UCHAR)Result;
38 }
39
40 BOOLEAN
41 NTAPI
KeReadStateThread(IN PKTHREAD Thread)42 KeReadStateThread(IN PKTHREAD Thread)
43 {
44 ASSERT_THREAD(Thread);
45
46 /* Return signal state */
47 return (BOOLEAN)Thread->Header.SignalState;
48 }
49
50 KPRIORITY
51 NTAPI
KeQueryBasePriorityThread(IN PKTHREAD Thread)52 KeQueryBasePriorityThread(IN PKTHREAD Thread)
53 {
54 LONG BaseIncrement;
55 KIRQL OldIrql;
56 PKPROCESS Process;
57 ASSERT_THREAD(Thread);
58 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
59
60 /* Raise IRQL to synch level */
61 OldIrql = KeRaiseIrqlToSynchLevel();
62
63 /* Lock the thread */
64 KiAcquireThreadLock(Thread);
65
66 /* Get the Process */
67 Process = Thread->ApcStatePointer[0]->Process;
68
69 /* Calculate the base increment */
70 BaseIncrement = Thread->BasePriority - Process->BasePriority;
71
72 /* If saturation occured, return the saturation increment instead */
73 if (Thread->Saturation) BaseIncrement = (HIGH_PRIORITY + 1) / 2 *
74 Thread->Saturation;
75
76 /* Release thread lock */
77 KiReleaseThreadLock(Thread);
78
79 /* Lower IRQl and return Increment */
80 KeLowerIrql(OldIrql);
81 return BaseIncrement;
82 }
83
84 BOOLEAN
85 NTAPI
KeSetDisableBoostThread(IN OUT PKTHREAD Thread,IN BOOLEAN Disable)86 KeSetDisableBoostThread(IN OUT PKTHREAD Thread,
87 IN BOOLEAN Disable)
88 {
89 ASSERT_THREAD(Thread);
90
91 /* Check if we're enabling or disabling */
92 if (Disable)
93 {
94 /* Set the bit */
95 return InterlockedBitTestAndSet(&Thread->ThreadFlags, 1);
96 }
97 else
98 {
99 /* Remove the bit */
100 return InterlockedBitTestAndReset(&Thread->ThreadFlags, 1);
101 }
102 }
103
104 VOID
105 NTAPI
KeReadyThread(IN PKTHREAD Thread)106 KeReadyThread(IN PKTHREAD Thread)
107 {
108 KIRQL OldIrql;
109 ASSERT_THREAD(Thread);
110 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
111
112 /* Lock the Dispatcher Database */
113 OldIrql = KiAcquireDispatcherLock();
114
115 /* Make the thread ready */
116 KiReadyThread(Thread);
117
118 /* Unlock dispatcher database */
119 KiReleaseDispatcherLock(OldIrql);
120 }
121
122 ULONG
123 NTAPI
KeAlertResumeThread(IN PKTHREAD Thread)124 KeAlertResumeThread(IN PKTHREAD Thread)
125 {
126 ULONG PreviousCount;
127 KLOCK_QUEUE_HANDLE ApcLock;
128 ASSERT_THREAD(Thread);
129 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
130
131 /* Lock the Dispatcher Database and the APC Queue */
132 KiAcquireApcLockRaiseToSynch(Thread, &ApcLock);
133 KiAcquireDispatcherLockAtSynchLevel();
134
135 /* Return if Thread is already alerted. */
136 if (!Thread->Alerted[KernelMode])
137 {
138 /* If it's Blocked, unblock if it we should */
139 if ((Thread->State == Waiting) && (Thread->Alertable))
140 {
141 /* Abort the wait */
142 KiUnwaitThread(Thread, STATUS_ALERTED, THREAD_ALERT_INCREMENT);
143 }
144 else
145 {
146 /* If not, simply Alert it */
147 Thread->Alerted[KernelMode] = TRUE;
148 }
149 }
150
151 /* Save the old Suspend Count */
152 PreviousCount = Thread->SuspendCount;
153
154 /* If the thread is suspended, decrease one of the suspend counts */
155 if (PreviousCount)
156 {
157 /* Decrease count. If we are now zero, unwait it completely */
158 Thread->SuspendCount--;
159 if (!(Thread->SuspendCount) && !(Thread->FreezeCount))
160 {
161 /* Signal and satisfy */
162 Thread->SuspendSemaphore.Header.SignalState++;
163 KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT);
164 }
165 }
166
167 /* Release Locks and return the Old State */
168 KiReleaseDispatcherLockFromSynchLevel();
169 KiReleaseApcLockFromSynchLevel(&ApcLock);
170 KiExitDispatcher(ApcLock.OldIrql);
171 return PreviousCount;
172 }
173
174 BOOLEAN
175 NTAPI
KeAlertThread(IN PKTHREAD Thread,IN KPROCESSOR_MODE AlertMode)176 KeAlertThread(IN PKTHREAD Thread,
177 IN KPROCESSOR_MODE AlertMode)
178 {
179 BOOLEAN PreviousState;
180 KLOCK_QUEUE_HANDLE ApcLock;
181 ASSERT_THREAD(Thread);
182 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
183
184 /* Lock the Dispatcher Database and the APC Queue */
185 KiAcquireApcLockRaiseToSynch(Thread, &ApcLock);
186 KiAcquireDispatcherLockAtSynchLevel();
187
188 /* Save the Previous State */
189 PreviousState = Thread->Alerted[AlertMode];
190
191 /* Check if it's already alerted */
192 if (!PreviousState)
193 {
194 /* Check if the thread is alertable, and blocked in the given mode */
195 if ((Thread->State == Waiting) &&
196 (Thread->Alertable) &&
197 (AlertMode <= Thread->WaitMode))
198 {
199 /* Abort the wait to alert the thread */
200 KiUnwaitThread(Thread, STATUS_ALERTED, THREAD_ALERT_INCREMENT);
201 }
202 else
203 {
204 /* Otherwise, merely set the alerted state */
205 Thread->Alerted[AlertMode] = TRUE;
206 }
207 }
208
209 /* Release the Dispatcher Lock */
210 KiReleaseDispatcherLockFromSynchLevel();
211 KiReleaseApcLockFromSynchLevel(&ApcLock);
212 KiExitDispatcher(ApcLock.OldIrql);
213
214 /* Return the old state */
215 return PreviousState;
216 }
217
218 VOID
219 NTAPI
KeBoostPriorityThread(IN PKTHREAD Thread,IN KPRIORITY Increment)220 KeBoostPriorityThread(IN PKTHREAD Thread,
221 IN KPRIORITY Increment)
222 {
223 KIRQL OldIrql;
224 KPRIORITY Priority;
225 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
226
227 /* Lock the Dispatcher Database */
228 OldIrql = KiAcquireDispatcherLock();
229
230 /* Only threads in the dynamic range get boosts */
231 if (Thread->Priority < LOW_REALTIME_PRIORITY)
232 {
233 /* Lock the thread */
234 KiAcquireThreadLock(Thread);
235
236 /* Check again, and make sure there's not already a boost */
237 if ((Thread->Priority < LOW_REALTIME_PRIORITY) &&
238 !(Thread->PriorityDecrement))
239 {
240 /* Compute the new priority and see if it's higher */
241 Priority = Thread->BasePriority + Increment;
242 if (Priority > Thread->Priority)
243 {
244 if (Priority >= LOW_REALTIME_PRIORITY)
245 {
246 Priority = LOW_REALTIME_PRIORITY - 1;
247 }
248
249 /* Reset the quantum */
250 Thread->Quantum = Thread->QuantumReset;
251
252 /* Set the new Priority */
253 KiSetPriorityThread(Thread, Priority);
254 }
255 }
256
257 /* Release thread lock */
258 KiReleaseThreadLock(Thread);
259 }
260
261 /* Release the dispatcher lokc */
262 KiReleaseDispatcherLock(OldIrql);
263 }
264
265 ULONG
266 NTAPI
KeForceResumeThread(IN PKTHREAD Thread)267 KeForceResumeThread(IN PKTHREAD Thread)
268 {
269 KLOCK_QUEUE_HANDLE ApcLock;
270 ULONG PreviousCount;
271 ASSERT_THREAD(Thread);
272 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
273
274 /* Lock the APC Queue */
275 KiAcquireApcLockRaiseToSynch(Thread, &ApcLock);
276
277 /* Save the old Suspend Count */
278 PreviousCount = Thread->SuspendCount + Thread->FreezeCount;
279
280 /* If the thread is suspended, wake it up!!! */
281 if (PreviousCount)
282 {
283 /* Unwait it completely */
284 Thread->SuspendCount = 0;
285 Thread->FreezeCount = 0;
286
287 /* Lock the dispatcher */
288 KiAcquireDispatcherLockAtSynchLevel();
289
290 /* Signal and satisfy */
291 Thread->SuspendSemaphore.Header.SignalState++;
292 KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT);
293
294 /* Release the dispatcher */
295 KiReleaseDispatcherLockFromSynchLevel();
296 }
297
298 /* Release Lock and return the Old State */
299 KiReleaseApcLockFromSynchLevel(&ApcLock);
300 KiExitDispatcher(ApcLock.OldIrql);
301 return PreviousCount;
302 }
303
304 VOID
305 NTAPI
KeFreezeAllThreads(VOID)306 KeFreezeAllThreads(VOID)
307 {
308 KLOCK_QUEUE_HANDLE LockHandle, ApcLock;
309 PKTHREAD Current, CurrentThread = KeGetCurrentThread();
310 PKPROCESS Process = CurrentThread->ApcState.Process;
311 PLIST_ENTRY ListHead, NextEntry;
312 LONG OldCount;
313 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
314
315 /* Lock the process */
316 KiAcquireProcessLockRaiseToSynch(Process, &LockHandle);
317
318 /* If someone is already trying to free us, try again */
319 while (CurrentThread->FreezeCount)
320 {
321 /* Release and re-acquire the process lock so the APC will go through */
322 KiReleaseProcessLock(&LockHandle);
323 KiAcquireProcessLockRaiseToSynch(Process, &LockHandle);
324 }
325
326 /* Enter a critical region */
327 KeEnterCriticalRegion();
328
329 /* Loop the Process's Threads */
330 ListHead = &Process->ThreadListHead;
331 NextEntry = ListHead->Flink;
332 do
333 {
334 /* Get the current thread */
335 Current = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry);
336
337 /* Lock it */
338 KiAcquireApcLockAtSynchLevel(Current, &ApcLock);
339
340 /* Make sure it's not ours, and check if APCs are enabled */
341 if ((Current != CurrentThread) && (Current->ApcQueueable))
342 {
343 /* Sanity check */
344 OldCount = Current->SuspendCount;
345 ASSERT(OldCount != MAXIMUM_SUSPEND_COUNT);
346
347 /* Increase the freeze count */
348 Current->FreezeCount++;
349
350 /* Make sure it wasn't already suspended */
351 if (!(OldCount) && !(Current->SuspendCount))
352 {
353 /* Did we already insert it? */
354 if (!Current->SuspendApc.Inserted)
355 {
356 /* Insert the APC */
357 Current->SuspendApc.Inserted = TRUE;
358 KiInsertQueueApc(&Current->SuspendApc, IO_NO_INCREMENT);
359 }
360 else
361 {
362 /* Lock the dispatcher */
363 KiAcquireDispatcherLockAtSynchLevel();
364
365 /* Unsignal the semaphore, the APC was already inserted */
366 Current->SuspendSemaphore.Header.SignalState--;
367
368 /* Release the dispatcher */
369 KiReleaseDispatcherLockFromSynchLevel();
370 }
371 }
372 }
373
374 /* Release the APC lock */
375 KiReleaseApcLockFromSynchLevel(&ApcLock);
376
377 /* Move to the next thread */
378 NextEntry = NextEntry->Flink;
379 } while (NextEntry != ListHead);
380
381 /* Release the process lock and exit the dispatcher */
382 KiReleaseProcessLockFromSynchLevel(&LockHandle);
383 KiExitDispatcher(LockHandle.OldIrql);
384 }
385
386 ULONG
387 NTAPI
KeResumeThread(IN PKTHREAD Thread)388 KeResumeThread(IN PKTHREAD Thread)
389 {
390 KLOCK_QUEUE_HANDLE ApcLock;
391 ULONG PreviousCount;
392 ASSERT_THREAD(Thread);
393 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
394
395 /* Lock the APC Queue */
396 KiAcquireApcLockRaiseToSynch(Thread, &ApcLock);
397
398 /* Save the Old Count */
399 PreviousCount = Thread->SuspendCount;
400
401 /* Check if it existed */
402 if (PreviousCount)
403 {
404 /* Decrease the suspend count */
405 Thread->SuspendCount--;
406
407 /* Check if the thrad is still suspended or not */
408 if ((!Thread->SuspendCount) && (!Thread->FreezeCount))
409 {
410 /* Acquire the dispatcher lock */
411 KiAcquireDispatcherLockAtSynchLevel();
412
413 /* Signal the Suspend Semaphore */
414 Thread->SuspendSemaphore.Header.SignalState++;
415 KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT);
416
417 /* Release the dispatcher lock */
418 KiReleaseDispatcherLockFromSynchLevel();
419 }
420 }
421
422 /* Release APC Queue lock and return the Old State */
423 KiReleaseApcLockFromSynchLevel(&ApcLock);
424 KiExitDispatcher(ApcLock.OldIrql);
425 return PreviousCount;
426 }
427
428 VOID
429 NTAPI
KeRundownThread(VOID)430 KeRundownThread(VOID)
431 {
432 KIRQL OldIrql;
433 PKTHREAD Thread = KeGetCurrentThread();
434 PLIST_ENTRY NextEntry, ListHead;
435 PKMUTANT Mutant;
436 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
437
438 /* Optimized path if nothing is on the list at the moment */
439 if (IsListEmpty(&Thread->MutantListHead)) return;
440
441 /* Lock the Dispatcher Database */
442 OldIrql = KiAcquireDispatcherLock();
443
444 /* Get the List Pointers */
445 ListHead = &Thread->MutantListHead;
446 NextEntry = ListHead->Flink;
447 while (NextEntry != ListHead)
448 {
449 /* Get the Mutant */
450 Mutant = CONTAINING_RECORD(NextEntry, KMUTANT, MutantListEntry);
451 ASSERT_MUTANT(Mutant);
452
453 /* Make sure it's not terminating with APCs off */
454 if (Mutant->ApcDisable)
455 {
456 /* Bugcheck the system */
457 KeBugCheckEx(THREAD_TERMINATE_HELD_MUTEX,
458 (ULONG_PTR)Thread,
459 (ULONG_PTR)Mutant,
460 0,
461 0);
462 }
463
464 /* Now we can remove it */
465 RemoveEntryList(&Mutant->MutantListEntry);
466
467 /* Unconditionally abandon it */
468 Mutant->Header.SignalState = 1;
469 Mutant->Abandoned = TRUE;
470 Mutant->OwnerThread = NULL;
471
472 /* Check if the Wait List isn't empty */
473 if (!IsListEmpty(&Mutant->Header.WaitListHead))
474 {
475 /* Wake the Mutant */
476 KiWaitTest(&Mutant->Header, MUTANT_INCREMENT);
477 }
478
479 /* Move on */
480 NextEntry = Thread->MutantListHead.Flink;
481 }
482
483 /* Release the Lock */
484 KiReleaseDispatcherLock(OldIrql);
485 }
486
487 VOID
488 NTAPI
KeStartThread(IN OUT PKTHREAD Thread)489 KeStartThread(IN OUT PKTHREAD Thread)
490 {
491 KLOCK_QUEUE_HANDLE LockHandle;
492 #ifdef CONFIG_SMP
493 PKNODE Node;
494 PKPRCB NodePrcb;
495 KAFFINITY Set, Mask;
496 #endif
497 UCHAR IdealProcessor = 0;
498 PKPROCESS Process = Thread->ApcState.Process;
499
500 /* Setup static fields from parent */
501 Thread->DisableBoost = Process->DisableBoost;
502 #if defined(_M_IX86)
503 Thread->Iopl = Process->Iopl;
504 #endif
505 Thread->Quantum = Process->QuantumReset;
506 Thread->QuantumReset = Process->QuantumReset;
507 Thread->SystemAffinityActive = FALSE;
508
509 /* Lock the process */
510 KiAcquireProcessLockRaiseToSynch(Process, &LockHandle);
511
512 /* Setup volatile data */
513 Thread->Priority = Process->BasePriority;
514 Thread->BasePriority = Process->BasePriority;
515 Thread->Affinity = Process->Affinity;
516 Thread->UserAffinity = Process->Affinity;
517
518 #ifdef CONFIG_SMP
519 /* Get the KNODE and its PRCB */
520 Node = KeNodeBlock[Process->IdealNode];
521 NodePrcb = KiProcessorBlock[Process->ThreadSeed];
522
523 /* Calculate affinity mask */
524 #ifdef _M_ARM
525 DbgBreakPoint();
526 Set = 0;
527 #else
528 Set = ~NodePrcb->MultiThreadProcessorSet;
529 #endif
530 Mask = Node->ProcessorMask & Process->Affinity;
531 Set &= Mask;
532 if (Set) Mask = Set;
533
534 /* Get the new thread seed */
535 IdealProcessor = KeFindNextRightSetAffinity(Process->ThreadSeed, Mask);
536 Process->ThreadSeed = IdealProcessor;
537
538 /* Sanity check */
539 ASSERT((Thread->UserAffinity & AFFINITY_MASK(IdealProcessor)));
540 #endif
541
542 /* Set the Ideal Processor */
543 Thread->IdealProcessor = IdealProcessor;
544 Thread->UserIdealProcessor = IdealProcessor;
545
546 /* Lock the Dispatcher Database */
547 KiAcquireDispatcherLockAtSynchLevel();
548
549 /* Insert the thread into the process list */
550 InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry);
551
552 /* Increase the stack count */
553 ASSERT(Process->StackCount != MAXULONG_PTR);
554 Process->StackCount++;
555
556 /* Release locks and return */
557 KiReleaseDispatcherLockFromSynchLevel();
558 KiReleaseProcessLock(&LockHandle);
559 }
560
561 VOID
562 NTAPI
KiSuspendRundown(IN PKAPC Apc)563 KiSuspendRundown(IN PKAPC Apc)
564 {
565 /* Does nothing */
566 UNREFERENCED_PARAMETER(Apc);
567 }
568
569 VOID
570 NTAPI
KiSuspendNop(IN PKAPC Apc,IN PKNORMAL_ROUTINE * NormalRoutine,IN PVOID * NormalContext,IN PVOID * SystemArgument1,IN PVOID * SystemArgument2)571 KiSuspendNop(IN PKAPC Apc,
572 IN PKNORMAL_ROUTINE *NormalRoutine,
573 IN PVOID *NormalContext,
574 IN PVOID *SystemArgument1,
575 IN PVOID *SystemArgument2)
576 {
577 /* Does nothing */
578 UNREFERENCED_PARAMETER(Apc);
579 UNREFERENCED_PARAMETER(NormalRoutine);
580 UNREFERENCED_PARAMETER(NormalContext);
581 UNREFERENCED_PARAMETER(SystemArgument1);
582 UNREFERENCED_PARAMETER(SystemArgument2);
583 }
584
585 VOID
586 NTAPI
KiSuspendThread(IN PVOID NormalContext,IN PVOID SystemArgument1,IN PVOID SystemArgument2)587 KiSuspendThread(IN PVOID NormalContext,
588 IN PVOID SystemArgument1,
589 IN PVOID SystemArgument2)
590 {
591 /* Non-alertable kernel-mode suspended wait */
592 KeWaitForSingleObject(&KeGetCurrentThread()->SuspendSemaphore,
593 Suspended,
594 KernelMode,
595 FALSE,
596 NULL);
597 }
598
599 ULONG
600 NTAPI
KeSuspendThread(PKTHREAD Thread)601 KeSuspendThread(PKTHREAD Thread)
602 {
603 KLOCK_QUEUE_HANDLE ApcLock;
604 ULONG PreviousCount;
605 ASSERT_THREAD(Thread);
606 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
607
608 /* Lock the APC Queue */
609 KiAcquireApcLockRaiseToSynch(Thread, &ApcLock);
610
611 /* Save the Old Count */
612 PreviousCount = Thread->SuspendCount;
613
614 /* Handle the maximum */
615 if (PreviousCount == MAXIMUM_SUSPEND_COUNT)
616 {
617 /* Raise an exception */
618 KiReleaseApcLock(&ApcLock);
619 RtlRaiseStatus(STATUS_SUSPEND_COUNT_EXCEEDED);
620 }
621
622 /* Should we bother to queue at all? */
623 if (Thread->ApcQueueable)
624 {
625 /* Increment the suspend count */
626 Thread->SuspendCount++;
627
628 /* Check if we should suspend it */
629 if (!(PreviousCount) && !(Thread->FreezeCount))
630 {
631 /* Is the APC already inserted? */
632 if (!Thread->SuspendApc.Inserted)
633 {
634 /* Not inserted, insert it */
635 Thread->SuspendApc.Inserted = TRUE;
636 KiInsertQueueApc(&Thread->SuspendApc, IO_NO_INCREMENT);
637 }
638 else
639 {
640 /* Lock the dispatcher */
641 KiAcquireDispatcherLockAtSynchLevel();
642
643 /* Unsignal the semaphore, the APC was already inserted */
644 Thread->SuspendSemaphore.Header.SignalState--;
645
646 /* Release the dispatcher */
647 KiReleaseDispatcherLockFromSynchLevel();
648 }
649 }
650 }
651
652 /* Release Lock and return the Old State */
653 KiReleaseApcLockFromSynchLevel(&ApcLock);
654 KiExitDispatcher(ApcLock.OldIrql);
655 return PreviousCount;
656 }
657
658 VOID
659 NTAPI
KeThawAllThreads(VOID)660 KeThawAllThreads(VOID)
661 {
662 KLOCK_QUEUE_HANDLE LockHandle, ApcLock;
663 PKTHREAD Current, CurrentThread = KeGetCurrentThread();
664 PKPROCESS Process = CurrentThread->ApcState.Process;
665 PLIST_ENTRY ListHead, NextEntry;
666 LONG OldCount;
667 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
668
669 /* Lock the process */
670 KiAcquireProcessLockRaiseToSynch(Process, &LockHandle);
671
672 /* Loop the Process's Threads */
673 ListHead = &Process->ThreadListHead;
674 NextEntry = ListHead->Flink;
675 do
676 {
677 /* Get the current thread */
678 Current = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry);
679
680 /* Lock it */
681 KiAcquireApcLockAtSynchLevel(Current, &ApcLock);
682
683 /* Make sure we are frozen */
684 OldCount = Current->FreezeCount;
685 if (OldCount)
686 {
687 /* Decrease the freeze count */
688 Current->FreezeCount--;
689
690 /* Check if both counts are zero now */
691 if (!(Current->SuspendCount) && (!Current->FreezeCount))
692 {
693 /* Lock the dispatcher */
694 KiAcquireDispatcherLockAtSynchLevel();
695
696 /* Signal the suspend semaphore and wake it */
697 Current->SuspendSemaphore.Header.SignalState++;
698 KiWaitTest(&Current->SuspendSemaphore, 0);
699
700 /* Unlock the dispatcher */
701 KiReleaseDispatcherLockFromSynchLevel();
702 }
703 }
704
705 /* Release the APC lock */
706 KiReleaseApcLockFromSynchLevel(&ApcLock);
707
708 /* Go to the next one */
709 NextEntry = NextEntry->Flink;
710 } while (NextEntry != ListHead);
711
712 /* Release the process lock and exit the dispatcher */
713 KiReleaseProcessLockFromSynchLevel(&LockHandle);
714 KiExitDispatcher(LockHandle.OldIrql);
715
716 /* Leave the critical region */
717 KeLeaveCriticalRegion();
718 }
719
720 BOOLEAN
721 NTAPI
KeTestAlertThread(IN KPROCESSOR_MODE AlertMode)722 KeTestAlertThread(IN KPROCESSOR_MODE AlertMode)
723 {
724 PKTHREAD Thread = KeGetCurrentThread();
725 BOOLEAN OldState;
726 KLOCK_QUEUE_HANDLE ApcLock;
727 ASSERT_THREAD(Thread);
728 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
729
730 /* Lock the Dispatcher Database and the APC Queue */
731 KiAcquireApcLockRaiseToSynch(Thread, &ApcLock);
732
733 /* Save the old State */
734 OldState = Thread->Alerted[AlertMode];
735
736 /* Check the Thread is alerted */
737 if (OldState)
738 {
739 /* Disable alert for this mode */
740 Thread->Alerted[AlertMode] = FALSE;
741 }
742 else if ((AlertMode != KernelMode) &&
743 (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode])))
744 {
745 /* If the mode is User and the Queue isn't empty, set Pending */
746 Thread->ApcState.UserApcPending = TRUE;
747 }
748
749 /* Release Locks and return the Old State */
750 KiReleaseApcLock(&ApcLock);
751 return OldState;
752 }
753
754 NTSTATUS
755 NTAPI
KeInitThread(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)756 KeInitThread(IN OUT PKTHREAD Thread,
757 IN PVOID KernelStack,
758 IN PKSYSTEM_ROUTINE SystemRoutine,
759 IN PKSTART_ROUTINE StartRoutine,
760 IN PVOID StartContext,
761 IN PCONTEXT Context,
762 IN PVOID Teb,
763 IN PKPROCESS Process)
764 {
765 BOOLEAN AllocatedStack = FALSE;
766 ULONG i;
767 PKWAIT_BLOCK TimerWaitBlock;
768 PKTIMER Timer;
769 NTSTATUS Status;
770
771 /* Initialize the Dispatcher Header */
772 Thread->Header.Type = ThreadObject;
773 Thread->Header.ThreadControlFlags = 0;
774 Thread->Header.DebugActive = FALSE;
775 Thread->Header.SignalState = 0;
776 InitializeListHead(&(Thread->Header.WaitListHead));
777
778 /* Initialize the Mutant List */
779 InitializeListHead(&Thread->MutantListHead);
780
781 /* Initialize the wait blocks */
782 for (i = 0; i< (THREAD_WAIT_OBJECTS + 1); i++)
783 {
784 /* Put our pointer */
785 Thread->WaitBlock[i].Thread = Thread;
786 }
787
788 /* Set swap settings */
789 Thread->EnableStackSwap = TRUE;
790 Thread->IdealProcessor = 1;
791 Thread->SwapBusy = FALSE;
792 Thread->KernelStackResident = TRUE;
793 Thread->AdjustReason = AdjustNone;
794
795 /* Initialize the lock */
796 KeInitializeSpinLock(&Thread->ThreadLock);
797
798 /* Setup the Service Descriptor Table for Native Calls */
799 Thread->ServiceTable = KeServiceDescriptorTable;
800
801 /* Setup APC Fields */
802 InitializeListHead(&Thread->ApcState.ApcListHead[KernelMode]);
803 InitializeListHead(&Thread->ApcState.ApcListHead[UserMode]);
804 Thread->ApcState.Process = Process;
805 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState;
806 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState;
807 Thread->ApcStateIndex = OriginalApcEnvironment;
808 Thread->ApcQueueable = TRUE;
809 KeInitializeSpinLock(&Thread->ApcQueueLock);
810
811 /* Initialize the Suspend APC */
812 KeInitializeApc(&Thread->SuspendApc,
813 Thread,
814 OriginalApcEnvironment,
815 KiSuspendNop,
816 KiSuspendRundown,
817 KiSuspendThread,
818 KernelMode,
819 NULL);
820
821 /* Initialize the Suspend Semaphore */
822 KeInitializeSemaphore(&Thread->SuspendSemaphore, 0, 2);
823
824 /* Setup the timer */
825 Timer = &Thread->Timer;
826 KeInitializeTimer(Timer);
827 TimerWaitBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
828 TimerWaitBlock->Object = Timer;
829 TimerWaitBlock->WaitKey = STATUS_TIMEOUT;
830 TimerWaitBlock->WaitType = WaitAny;
831 TimerWaitBlock->NextWaitBlock = NULL;
832
833 /* Link the two wait lists together */
834 TimerWaitBlock->WaitListEntry.Flink = &Timer->Header.WaitListHead;
835 TimerWaitBlock->WaitListEntry.Blink = &Timer->Header.WaitListHead;
836
837 /* Set the TEB and process */
838 Thread->Teb = Teb;
839 Thread->Process = Process;
840
841 /* Check if we have a kernel stack */
842 if (!KernelStack)
843 {
844 /* We don't, allocate one */
845 KernelStack = MmCreateKernelStack(FALSE, 0);
846 if (!KernelStack) return STATUS_INSUFFICIENT_RESOURCES;
847
848 /* Remember for later */
849 AllocatedStack = TRUE;
850 }
851
852 /* Set the Thread Stacks */
853 Thread->InitialStack = KernelStack;
854 Thread->StackBase = KernelStack;
855 Thread->StackLimit = (ULONG_PTR)KernelStack - KERNEL_STACK_SIZE;
856 Thread->KernelStackResident = TRUE;
857
858 /* Enter SEH to avoid crashes due to user mode */
859 Status = STATUS_SUCCESS;
860 _SEH2_TRY
861 {
862 /* Initialize the Thread Context */
863 KiInitializeContextThread(Thread,
864 SystemRoutine,
865 StartRoutine,
866 StartContext,
867 Context);
868 }
869 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
870 {
871 /* Set failure status */
872 Status = STATUS_UNSUCCESSFUL;
873
874 /* Check if a stack was allocated */
875 if (AllocatedStack)
876 {
877 /* Delete the stack */
878 MmDeleteKernelStack((PVOID)Thread->StackBase, FALSE);
879 Thread->InitialStack = NULL;
880 }
881 }
882 _SEH2_END;
883
884 /* Set the Thread to initialized */
885 Thread->State = Initialized;
886 return Status;
887 }
888
889 VOID
890 NTAPI
KeInitializeThread(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)891 KeInitializeThread(IN PKPROCESS Process,
892 IN OUT PKTHREAD Thread,
893 IN PKSYSTEM_ROUTINE SystemRoutine,
894 IN PKSTART_ROUTINE StartRoutine,
895 IN PVOID StartContext,
896 IN PCONTEXT Context,
897 IN PVOID Teb,
898 IN PVOID KernelStack)
899 {
900 /* Initialize and start the thread on success */
901 if (NT_SUCCESS(KeInitThread(Thread,
902 KernelStack,
903 SystemRoutine,
904 StartRoutine,
905 StartContext,
906 Context,
907 Teb,
908 Process)))
909 {
910 /* Start it */
911 KeStartThread(Thread);
912 }
913 }
914
915 VOID
916 NTAPI
KeUninitThread(IN PKTHREAD Thread)917 KeUninitThread(IN PKTHREAD Thread)
918 {
919 /* Delete the stack */
920 MmDeleteKernelStack((PVOID)Thread->StackBase, FALSE);
921 Thread->InitialStack = NULL;
922 }
923
924 /* PUBLIC FUNCTIONS **********************************************************/
925
926 /*
927 * @unimplemented
928 */
929 VOID
930 NTAPI
KeCapturePersistentThreadState(IN PVOID CurrentThread,IN ULONG Setting1,IN ULONG Setting2,IN ULONG Setting3,IN ULONG Setting4,IN ULONG Setting5,IN PVOID ThreadState)931 KeCapturePersistentThreadState(IN PVOID CurrentThread,
932 IN ULONG Setting1,
933 IN ULONG Setting2,
934 IN ULONG Setting3,
935 IN ULONG Setting4,
936 IN ULONG Setting5,
937 IN PVOID ThreadState)
938 {
939 UNIMPLEMENTED;
940 }
941
942 /*
943 * @implemented
944 */
945 #undef KeGetCurrentThread
946 PKTHREAD
947 NTAPI
KeGetCurrentThread(VOID)948 KeGetCurrentThread(VOID)
949 {
950 /* Return the current thread on this PCR */
951 return _KeGetCurrentThread();
952 }
953
954 /*
955 * @implemented
956 */
957 #undef KeGetPreviousMode
958 UCHAR
959 NTAPI
KeGetPreviousMode(VOID)960 KeGetPreviousMode(VOID)
961 {
962 /* Return the previous mode of this thread */
963 return _KeGetPreviousMode();
964 }
965
966 /*
967 * @implemented
968 */
969 ULONG
970 NTAPI
KeQueryRuntimeThread(IN PKTHREAD Thread,OUT PULONG UserTime)971 KeQueryRuntimeThread(IN PKTHREAD Thread,
972 OUT PULONG UserTime)
973 {
974 ASSERT_THREAD(Thread);
975
976 /* Return the User Time */
977 *UserTime = Thread->UserTime;
978
979 /* Return the Kernel Time */
980 return Thread->KernelTime;
981 }
982
983 /*
984 * @implemented
985 */
986 BOOLEAN
987 NTAPI
KeSetKernelStackSwapEnable(IN BOOLEAN Enable)988 KeSetKernelStackSwapEnable(IN BOOLEAN Enable)
989 {
990 BOOLEAN PreviousState;
991 PKTHREAD Thread = KeGetCurrentThread();
992
993 /* Save Old State */
994 PreviousState = Thread->EnableStackSwap;
995
996 /* Set New State */
997 Thread->EnableStackSwap = Enable;
998
999 /* Return Old State */
1000 return PreviousState;
1001 }
1002
1003 /*
1004 * @implemented
1005 */
1006 KPRIORITY
1007 NTAPI
KeQueryPriorityThread(IN PKTHREAD Thread)1008 KeQueryPriorityThread(IN PKTHREAD Thread)
1009 {
1010 ASSERT_THREAD(Thread);
1011
1012 /* Return the current priority */
1013 return Thread->Priority;
1014 }
1015
1016 /*
1017 * @implemented
1018 */
1019 VOID
1020 NTAPI
KeRevertToUserAffinityThread(VOID)1021 KeRevertToUserAffinityThread(VOID)
1022 {
1023 KIRQL OldIrql;
1024 PKPRCB Prcb;
1025 PKTHREAD NextThread, CurrentThread = KeGetCurrentThread();
1026 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
1027 ASSERT(CurrentThread->SystemAffinityActive != FALSE);
1028
1029 /* Lock the Dispatcher Database */
1030 OldIrql = KiAcquireDispatcherLock();
1031
1032 /* Set the user affinity and processor and disable system affinity */
1033 CurrentThread->Affinity = CurrentThread->UserAffinity;
1034 CurrentThread->IdealProcessor = CurrentThread->UserIdealProcessor;
1035 CurrentThread->SystemAffinityActive = FALSE;
1036
1037 /* Get the current PRCB and check if it doesn't match this affinity */
1038 Prcb = KeGetCurrentPrcb();
1039 if (!(Prcb->SetMember & CurrentThread->Affinity))
1040 {
1041 /* Lock the PRCB */
1042 KiAcquirePrcbLock(Prcb);
1043
1044 /* Check if there's no next thread scheduled */
1045 if (!Prcb->NextThread)
1046 {
1047 /* Select a new thread and set it on standby */
1048 NextThread = KiSelectNextThread(Prcb);
1049 NextThread->State = Standby;
1050 Prcb->NextThread = NextThread;
1051 }
1052
1053 /* Release the PRCB lock */
1054 KiReleasePrcbLock(Prcb);
1055 }
1056
1057 /* Unlock dispatcher database */
1058 KiReleaseDispatcherLock(OldIrql);
1059 }
1060
1061 /*
1062 * @implemented
1063 */
1064 UCHAR
1065 NTAPI
KeSetIdealProcessorThread(IN PKTHREAD Thread,IN UCHAR Processor)1066 KeSetIdealProcessorThread(IN PKTHREAD Thread,
1067 IN UCHAR Processor)
1068 {
1069 CCHAR OldIdealProcessor;
1070 KIRQL OldIrql;
1071 ASSERT(Processor <= MAXIMUM_PROCESSORS);
1072
1073 /* Lock the Dispatcher Database */
1074 OldIrql = KiAcquireDispatcherLock();
1075
1076 /* Save Old Ideal Processor */
1077 OldIdealProcessor = Thread->UserIdealProcessor;
1078
1079 /* Make sure a valid CPU was given */
1080 if (Processor < KeNumberProcessors)
1081 {
1082 /* Check if the user ideal CPU is in the affinity */
1083 if (Thread->Affinity & AFFINITY_MASK(Processor))
1084 {
1085 /* Set the ideal processor */
1086 Thread->IdealProcessor = Processor;
1087
1088 /* Check if system affinity is used */
1089 if (!Thread->SystemAffinityActive)
1090 {
1091 /* It's not, so update the user CPU too */
1092 Thread->UserIdealProcessor = Processor;
1093 }
1094 }
1095 }
1096
1097 /* Release dispatcher lock and return the old ideal CPU */
1098 KiReleaseDispatcherLock(OldIrql);
1099 return OldIdealProcessor;
1100 }
1101
1102 /*
1103 * @implemented
1104 */
1105 VOID
1106 NTAPI
KeSetSystemAffinityThread(IN KAFFINITY Affinity)1107 KeSetSystemAffinityThread(IN KAFFINITY Affinity)
1108 {
1109 KIRQL OldIrql;
1110 PKPRCB Prcb;
1111 PKTHREAD NextThread, CurrentThread = KeGetCurrentThread();
1112 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
1113 ASSERT((Affinity & KeActiveProcessors) != 0);
1114
1115 /* Lock the Dispatcher Database */
1116 OldIrql = KiAcquireDispatcherLock();
1117
1118 /* Restore the affinity and enable system affinity */
1119 CurrentThread->Affinity = Affinity;
1120 CurrentThread->SystemAffinityActive = TRUE;
1121
1122 /* Check if the ideal processor is part of the affinity */
1123 #ifdef CONFIG_SMP
1124 if (!(Affinity & AFFINITY_MASK(CurrentThread->IdealProcessor)))
1125 {
1126 KAFFINITY AffinitySet, NodeMask;
1127 ULONG IdealProcessor;
1128
1129 /* It's not! Get the PRCB */
1130 Prcb = KiProcessorBlock[CurrentThread->IdealProcessor];
1131
1132 /* Calculate the affinity set */
1133 AffinitySet = KeActiveProcessors & Affinity;
1134 NodeMask = Prcb->ParentNode->ProcessorMask & AffinitySet;
1135 if (NodeMask)
1136 {
1137 /* Use the Node set instead */
1138 AffinitySet = NodeMask;
1139 }
1140
1141 /* Calculate the ideal CPU from the affinity set */
1142 BitScanReverseAffinity(&IdealProcessor, AffinitySet);
1143 CurrentThread->IdealProcessor = (UCHAR)IdealProcessor;
1144 }
1145 #endif
1146
1147 /* Get the current PRCB and check if it doesn't match this affinity */
1148 Prcb = KeGetCurrentPrcb();
1149 if (!(Prcb->SetMember & CurrentThread->Affinity))
1150 {
1151 /* Lock the PRCB */
1152 KiAcquirePrcbLock(Prcb);
1153
1154 /* Check if there's no next thread scheduled */
1155 if (!Prcb->NextThread)
1156 {
1157 /* Select a new thread and set it on standby */
1158 NextThread = KiSelectNextThread(Prcb);
1159 NextThread->State = Standby;
1160 Prcb->NextThread = NextThread;
1161 }
1162
1163 /* Release the PRCB lock */
1164 KiReleasePrcbLock(Prcb);
1165 }
1166
1167 /* Unlock dispatcher database */
1168 KiReleaseDispatcherLock(OldIrql);
1169 }
1170
1171 /*
1172 * @implemented
1173 */
1174 LONG
1175 NTAPI
KeSetBasePriorityThread(IN PKTHREAD Thread,IN LONG Increment)1176 KeSetBasePriorityThread(IN PKTHREAD Thread,
1177 IN LONG Increment)
1178 {
1179 KIRQL OldIrql;
1180 KPRIORITY OldBasePriority, Priority, BasePriority;
1181 LONG OldIncrement;
1182 PKPROCESS Process;
1183 ASSERT_THREAD(Thread);
1184 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
1185
1186 /* Get the process */
1187 Process = Thread->ApcState.Process;
1188
1189 /* Lock the Dispatcher Database */
1190 OldIrql = KiAcquireDispatcherLock();
1191
1192 /* Lock the thread */
1193 KiAcquireThreadLock(Thread);
1194
1195 /* Save the old base priority and increment */
1196 OldBasePriority = Thread->BasePriority;
1197 OldIncrement = OldBasePriority - Process->BasePriority;
1198
1199 /* If priority saturation happened, use the saturated increment */
1200 if (Thread->Saturation) OldIncrement = (HIGH_PRIORITY + 1) / 2 *
1201 Thread->Saturation;
1202
1203 /* Reset the saturation value */
1204 Thread->Saturation = 0;
1205
1206 /* Now check if saturation is being used for the new value */
1207 if (abs(Increment) >= ((HIGH_PRIORITY + 1) / 2))
1208 {
1209 /* Check if we need positive or negative saturation */
1210 Thread->Saturation = (Increment > 0) ? 1 : -1;
1211 }
1212
1213 /* Normalize the Base Priority */
1214 BasePriority = Process->BasePriority + Increment;
1215 if (Process->BasePriority >= LOW_REALTIME_PRIORITY)
1216 {
1217 /* Check if it's too low */
1218 if (BasePriority < LOW_REALTIME_PRIORITY)
1219 {
1220 /* Set it to the lowest real time level */
1221 BasePriority = LOW_REALTIME_PRIORITY;
1222 }
1223
1224 /* Check if it's too high */
1225 if (BasePriority > HIGH_PRIORITY) BasePriority = HIGH_PRIORITY;
1226
1227 /* We are at real time, so use the raw base priority */
1228 Priority = BasePriority;
1229 }
1230 else
1231 {
1232 /* Check if it's entering the real time range */
1233 if (BasePriority >= LOW_REALTIME_PRIORITY)
1234 {
1235 /* Set it to the highest dynamic level */
1236 BasePriority = LOW_REALTIME_PRIORITY - 1;
1237 }
1238
1239 /* Check if it's too low and normalize it */
1240 if (BasePriority <= LOW_PRIORITY) BasePriority = 1;
1241
1242 /* Check if Saturation is used */
1243 if (Thread->Saturation)
1244 {
1245 /* Use the raw base priority */
1246 Priority = BasePriority;
1247 }
1248 else
1249 {
1250 /* Otherwise, calculate the new priority */
1251 Priority = KiComputeNewPriority(Thread, 0);
1252 Priority += (BasePriority - OldBasePriority);
1253
1254 /* Check if it entered the real-time range */
1255 if (Priority >= LOW_REALTIME_PRIORITY)
1256 {
1257 /* Normalize it down to the highest dynamic priority */
1258 Priority = LOW_REALTIME_PRIORITY - 1;
1259 }
1260 else if (Priority <= LOW_PRIORITY)
1261 {
1262 /* It went too low, normalize it */
1263 Priority = 1;
1264 }
1265 }
1266 }
1267
1268 /* Finally set the new base priority */
1269 Thread->BasePriority = (SCHAR)BasePriority;
1270
1271 /* Reset the decrements */
1272 Thread->PriorityDecrement = 0;
1273
1274 /* Check if we're changing priority after all */
1275 if (Priority != Thread->Priority)
1276 {
1277 /* Reset the quantum and do the actual priority modification */
1278 Thread->Quantum = Thread->QuantumReset;
1279 KiSetPriorityThread(Thread, Priority);
1280 }
1281
1282 /* Release thread lock */
1283 KiReleaseThreadLock(Thread);
1284
1285 /* Release the dispatcher database and return old increment */
1286 KiReleaseDispatcherLock(OldIrql);
1287 return OldIncrement;
1288 }
1289
1290 /*
1291 * @implemented
1292 */
1293 KAFFINITY
1294 NTAPI
KeSetAffinityThread(IN PKTHREAD Thread,IN KAFFINITY Affinity)1295 KeSetAffinityThread(IN PKTHREAD Thread,
1296 IN KAFFINITY Affinity)
1297 {
1298 KIRQL OldIrql;
1299 KAFFINITY OldAffinity;
1300 ASSERT_THREAD(Thread);
1301 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
1302
1303 /* Lock the dispatcher database */
1304 OldIrql = KiAcquireDispatcherLock();
1305
1306 /* Call the internal function */
1307 OldAffinity = KiSetAffinityThread(Thread, Affinity);
1308
1309 /* Release the dispatcher database and return old affinity */
1310 KiReleaseDispatcherLock(OldIrql);
1311 return OldAffinity;
1312 }
1313
1314 /*
1315 * @implemented
1316 */
1317 KPRIORITY
1318 NTAPI
KeSetPriorityThread(IN PKTHREAD Thread,IN KPRIORITY Priority)1319 KeSetPriorityThread(IN PKTHREAD Thread,
1320 IN KPRIORITY Priority)
1321 {
1322 KIRQL OldIrql;
1323 KPRIORITY OldPriority;
1324 ASSERT_THREAD(Thread);
1325 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
1326 ASSERT((Priority <= HIGH_PRIORITY) && (Priority >= LOW_PRIORITY));
1327 ASSERT(KeIsExecutingDpc() == FALSE);
1328
1329 /* Lock the Dispatcher Database */
1330 OldIrql = KiAcquireDispatcherLock();
1331
1332 /* Lock the thread */
1333 KiAcquireThreadLock(Thread);
1334
1335 /* Save the old Priority and reset decrement */
1336 OldPriority = Thread->Priority;
1337 Thread->PriorityDecrement = 0;
1338
1339 /* Make sure that an actual change is being done */
1340 if (Priority != Thread->Priority)
1341 {
1342 /* Reset the quantum */
1343 Thread->Quantum = Thread->QuantumReset;
1344
1345 /* Check if priority is being set too low and normalize if so */
1346 if ((Thread->BasePriority != 0) && !(Priority)) Priority = 1;
1347
1348 /* Set the new Priority */
1349 KiSetPriorityThread(Thread, Priority);
1350 }
1351
1352 /* Release thread lock */
1353 KiReleaseThreadLock(Thread);
1354
1355 /* Release the dispatcher database */
1356 KiReleaseDispatcherLock(OldIrql);
1357
1358 /* Return Old Priority */
1359 return OldPriority;
1360 }
1361
1362 /*
1363 * @implemented
1364 */
1365 VOID
1366 NTAPI
KeTerminateThread(IN KPRIORITY Increment)1367 KeTerminateThread(IN KPRIORITY Increment)
1368 {
1369 PLIST_ENTRY *ListHead;
1370 PETHREAD Entry, SavedEntry;
1371 PETHREAD *ThreadAddr;
1372 KLOCK_QUEUE_HANDLE LockHandle;
1373 PKTHREAD Thread = KeGetCurrentThread();
1374 PKPROCESS Process = Thread->ApcState.Process;
1375 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
1376
1377 /* Lock the process */
1378 KiAcquireProcessLockRaiseToSynch(Process, &LockHandle);
1379
1380 /* Make sure we won't get Swapped */
1381 KiSetThreadSwapBusy(Thread);
1382
1383 /* Save the Kernel and User Times */
1384 Process->KernelTime += Thread->KernelTime;
1385 Process->UserTime += Thread->UserTime;
1386
1387 /* Get the current entry and our Port */
1388 Entry = (PETHREAD)PspReaperListHead.Flink;
1389 ThreadAddr = &((PETHREAD)Thread)->ReaperLink;
1390
1391 /* Add it to the reaper's list */
1392 do
1393 {
1394 /* Get the list head */
1395 ListHead = &PspReaperListHead.Flink;
1396
1397 /* Link ourselves */
1398 *ThreadAddr = Entry;
1399 SavedEntry = Entry;
1400
1401 /* Now try to do the exchange */
1402 Entry = InterlockedCompareExchangePointer((PVOID*)ListHead,
1403 ThreadAddr,
1404 Entry);
1405
1406 /* Break out if the change was succesful */
1407 } while (Entry != SavedEntry);
1408
1409 /* Acquire the dispatcher lock */
1410 KiAcquireDispatcherLockAtSynchLevel();
1411
1412 /* Check if the reaper wasn't active */
1413 if (!Entry)
1414 {
1415 /* Activate it as a work item, directly through its Queue */
1416 KiInsertQueue(&ExWorkerQueue[HyperCriticalWorkQueue].WorkerQueue,
1417 &PspReaperWorkItem.List,
1418 FALSE);
1419 }
1420
1421 /* Check the thread has an associated queue */
1422 if (Thread->Queue)
1423 {
1424 /* Remove it from the list, and handle the queue */
1425 RemoveEntryList(&Thread->QueueListEntry);
1426 KiActivateWaiterQueue(Thread->Queue);
1427 }
1428
1429 /* Signal the thread */
1430 Thread->Header.SignalState = TRUE;
1431 if (!IsListEmpty(&Thread->Header.WaitListHead))
1432 {
1433 /* Unwait the threads */
1434 KxUnwaitThread(&Thread->Header, Increment);
1435 }
1436
1437 /* Remove the thread from the list */
1438 RemoveEntryList(&Thread->ThreadListEntry);
1439
1440 /* Release the process lock */
1441 KiReleaseProcessLockFromSynchLevel(&LockHandle);
1442
1443 /* Set us as terminated, decrease the Process's stack count */
1444 Thread->State = Terminated;
1445
1446 /* Decrease stack count */
1447 ASSERT(Process->StackCount != 0);
1448 ASSERT(Process->State == ProcessInMemory);
1449 Process->StackCount--;
1450 if (!(Process->StackCount) && !(IsListEmpty(&Process->ThreadListHead)))
1451 {
1452 /* FIXME: Swap stacks */
1453 }
1454
1455 /* Rundown arch-specific parts */
1456 KiRundownThread(Thread);
1457
1458 /* Swap to a new thread */
1459 KiReleaseDispatcherLockFromSynchLevel();
1460 KiSwapThread(Thread, KeGetCurrentPrcb());
1461 }
1462