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