[NTOS]
[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 /* Make sure that we are in the right page directory (ReactOS Mm Hack) */
814 MiSyncForProcessAttach(Thread, (PEPROCESS)Process);
815
816 /* Enter SEH to avoid crashes due to user mode */
817 Status = STATUS_SUCCESS;
818 _SEH2_TRY
819 {
820 /* Initalize the Thread Context */
821 KiInitializeContextThread(Thread,
822 SystemRoutine,
823 StartRoutine,
824 StartContext,
825 Context);
826 }
827 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
828 {
829 /* Set failure status */
830 Status = STATUS_UNSUCCESSFUL;
831
832 /* Check if a stack was allocated */
833 if (AllocatedStack)
834 {
835 /* Delete the stack */
836 MmDeleteKernelStack((PVOID)Thread->StackBase, FALSE);
837 Thread->InitialStack = NULL;
838 }
839 }
840 _SEH2_END;
841
842 /* Set the Thread to initalized */
843 Thread->State = Initialized;
844 return Status;
845 }
846
847 VOID
848 NTAPI
849 KeInitializeThread(IN PKPROCESS Process,
850 IN OUT PKTHREAD Thread,
851 IN PKSYSTEM_ROUTINE SystemRoutine,
852 IN PKSTART_ROUTINE StartRoutine,
853 IN PVOID StartContext,
854 IN PCONTEXT Context,
855 IN PVOID Teb,
856 IN PVOID KernelStack)
857 {
858 /* Initialize and start the thread on success */
859 if (NT_SUCCESS(KeInitThread(Thread,
860 KernelStack,
861 SystemRoutine,
862 StartRoutine,
863 StartContext,
864 Context,
865 Teb,
866 Process)))
867 {
868 /* Start it */
869 KeStartThread(Thread);
870 }
871 }
872
873 VOID
874 NTAPI
875 KeUninitThread(IN PKTHREAD Thread)
876 {
877 /* Delete the stack */
878 MmDeleteKernelStack((PVOID)Thread->StackBase, FALSE);
879 Thread->InitialStack = NULL;
880 }
881
882 /* PUBLIC FUNCTIONS **********************************************************/
883
884 /*
885 * @unimplemented
886 */
887 VOID
888 NTAPI
889 KeCapturePersistentThreadState(IN PVOID CurrentThread,
890 IN ULONG Setting1,
891 IN ULONG Setting2,
892 IN ULONG Setting3,
893 IN ULONG Setting4,
894 IN ULONG Setting5,
895 IN PVOID ThreadState)
896 {
897 UNIMPLEMENTED;
898 }
899
900 /*
901 * @implemented
902 */
903 #undef KeGetCurrentThread
904 PKTHREAD
905 NTAPI
906 KeGetCurrentThread(VOID)
907 {
908 /* Return the current thread on this PCR */
909 return _KeGetCurrentThread();
910 }
911
912 /*
913 * @implemented
914 */
915 #undef KeGetPreviousMode
916 UCHAR
917 NTAPI
918 KeGetPreviousMode(VOID)
919 {
920 /* Return the previous mode of this thread */
921 return _KeGetPreviousMode();
922 }
923
924 /*
925 * @implemented
926 */
927 ULONG
928 NTAPI
929 KeQueryRuntimeThread(IN PKTHREAD Thread,
930 OUT PULONG UserTime)
931 {
932 ASSERT_THREAD(Thread);
933
934 /* Return the User Time */
935 *UserTime = Thread->UserTime;
936
937 /* Return the Kernel Time */
938 return Thread->KernelTime;
939 }
940
941 /*
942 * @implemented
943 */
944 BOOLEAN
945 NTAPI
946 KeSetKernelStackSwapEnable(IN BOOLEAN Enable)
947 {
948 BOOLEAN PreviousState;
949 PKTHREAD Thread = KeGetCurrentThread();
950
951 /* Save Old State */
952 PreviousState = Thread->EnableStackSwap;
953
954 /* Set New State */
955 Thread->EnableStackSwap = Enable;
956
957 /* Return Old State */
958 return PreviousState;
959 }
960
961 /*
962 * @implemented
963 */
964 KPRIORITY
965 NTAPI
966 KeQueryPriorityThread(IN PKTHREAD Thread)
967 {
968 ASSERT_THREAD(Thread);
969
970 /* Return the current priority */
971 return Thread->Priority;
972 }
973
974 /*
975 * @implemented
976 */
977 VOID
978 NTAPI
979 KeRevertToUserAffinityThread(VOID)
980 {
981 KIRQL OldIrql;
982 PKPRCB Prcb;
983 PKTHREAD NextThread, CurrentThread = KeGetCurrentThread();
984 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
985 ASSERT(CurrentThread->SystemAffinityActive != FALSE);
986
987 /* Lock the Dispatcher Database */
988 OldIrql = KiAcquireDispatcherLock();
989
990 /* Set the user affinity and processor and disable system affinity */
991 CurrentThread->Affinity = CurrentThread->UserAffinity;
992 CurrentThread->IdealProcessor = CurrentThread->UserIdealProcessor;
993 CurrentThread->SystemAffinityActive = FALSE;
994
995 /* Get the current PRCB and check if it doesn't match this affinity */
996 Prcb = KeGetCurrentPrcb();
997 if (!(Prcb->SetMember & CurrentThread->Affinity))
998 {
999 /* Lock the PRCB */
1000 KiAcquirePrcbLock(Prcb);
1001
1002 /* Check if there's no next thread scheduled */
1003 if (!Prcb->NextThread)
1004 {
1005 /* Select a new thread and set it on standby */
1006 NextThread = KiSelectNextThread(Prcb);
1007 NextThread->State = Standby;
1008 Prcb->NextThread = NextThread;
1009 }
1010
1011 /* Release the PRCB lock */
1012 KiReleasePrcbLock(Prcb);
1013 }
1014
1015 /* Unlock dispatcher database */
1016 KiReleaseDispatcherLock(OldIrql);
1017 }
1018
1019 /*
1020 * @implemented
1021 */
1022 UCHAR
1023 NTAPI
1024 KeSetIdealProcessorThread(IN PKTHREAD Thread,
1025 IN UCHAR Processor)
1026 {
1027 CCHAR OldIdealProcessor;
1028 KIRQL OldIrql;
1029 ASSERT(Processor <= MAXIMUM_PROCESSORS);
1030
1031 /* Lock the Dispatcher Database */
1032 OldIrql = KiAcquireDispatcherLock();
1033
1034 /* Save Old Ideal Processor */
1035 OldIdealProcessor = Thread->UserIdealProcessor;
1036
1037 /* Make sure a valid CPU was given */
1038 if (Processor < KeNumberProcessors)
1039 {
1040 /* Check if the user ideal CPU is in the affinity */
1041 if (Thread->Affinity & AFFINITY_MASK(Processor))
1042 {
1043 /* Set the ideal processor */
1044 Thread->IdealProcessor = Processor;
1045
1046 /* Check if system affinity is used */
1047 if (!Thread->SystemAffinityActive)
1048 {
1049 /* It's not, so update the user CPU too */
1050 Thread->UserIdealProcessor = Processor;
1051 }
1052 }
1053 }
1054
1055 /* Release dispatcher lock and return the old ideal CPU */
1056 KiReleaseDispatcherLock(OldIrql);
1057 return OldIdealProcessor;
1058 }
1059
1060 /*
1061 * @implemented
1062 */
1063 VOID
1064 NTAPI
1065 KeSetSystemAffinityThread(IN KAFFINITY Affinity)
1066 {
1067 KIRQL OldIrql;
1068 PKPRCB Prcb;
1069 PKTHREAD NextThread, CurrentThread = KeGetCurrentThread();
1070 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
1071 ASSERT((Affinity & KeActiveProcessors) != 0);
1072
1073 /* Lock the Dispatcher Database */
1074 OldIrql = KiAcquireDispatcherLock();
1075
1076 /* Restore the affinity and enable system affinity */
1077 CurrentThread->Affinity = Affinity;
1078 CurrentThread->SystemAffinityActive = TRUE;
1079
1080 /* Check if the ideal processor is part of the affinity */
1081 #ifdef CONFIG_SMP
1082 if (!(Affinity & AFFINITY_MASK(CurrentThread->IdealProcessor)))
1083 {
1084 ULONG AffinitySet, NodeMask;
1085
1086 /* It's not! Get the PRCB */
1087 Prcb = KiProcessorBlock[CurrentThread->IdealProcessor];
1088
1089 /* Calculate the affinity set */
1090 AffinitySet = KeActiveProcessors & Affinity;
1091 NodeMask = Prcb->ParentNode->ProcessorMask & AffinitySet;
1092 if (NodeMask)
1093 {
1094 /* Use the Node set instead */
1095 AffinitySet = NodeMask;
1096 }
1097
1098 /* Calculate the ideal CPU from the affinity set */
1099 BitScanReverse(&NodeMask, AffinitySet);
1100 CurrentThread->IdealProcessor = (UCHAR)NodeMask;
1101 }
1102 #endif
1103
1104 /* Get the current PRCB and check if it doesn't match this affinity */
1105 Prcb = KeGetCurrentPrcb();
1106 if (!(Prcb->SetMember & CurrentThread->Affinity))
1107 {
1108 /* Lock the PRCB */
1109 KiAcquirePrcbLock(Prcb);
1110
1111 /* Check if there's no next thread scheduled */
1112 if (!Prcb->NextThread)
1113 {
1114 /* Select a new thread and set it on standby */
1115 NextThread = KiSelectNextThread(Prcb);
1116 NextThread->State = Standby;
1117 Prcb->NextThread = NextThread;
1118 }
1119
1120 /* Release the PRCB lock */
1121 KiReleasePrcbLock(Prcb);
1122 }
1123
1124 /* Unlock dispatcher database */
1125 KiReleaseDispatcherLock(OldIrql);
1126 }
1127
1128 /*
1129 * @implemented
1130 */
1131 LONG
1132 NTAPI
1133 KeSetBasePriorityThread(IN PKTHREAD Thread,
1134 IN LONG Increment)
1135 {
1136 KIRQL OldIrql;
1137 KPRIORITY OldBasePriority, Priority, BasePriority;
1138 LONG OldIncrement;
1139 PKPROCESS Process;
1140 ASSERT_THREAD(Thread);
1141 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
1142
1143 /* Get the process */
1144 Process = Thread->ApcState.Process;
1145
1146 /* Lock the Dispatcher Database */
1147 OldIrql = KiAcquireDispatcherLock();
1148
1149 /* Lock the thread */
1150 KiAcquireThreadLock(Thread);
1151
1152 /* Save the old base priority and increment */
1153 OldBasePriority = Thread->BasePriority;
1154 OldIncrement = OldBasePriority - Process->BasePriority;
1155
1156 /* If priority saturation happened, use the saturated increment */
1157 if (Thread->Saturation) OldIncrement = (HIGH_PRIORITY + 1) / 2 *
1158 Thread->Saturation;
1159
1160 /* Reset the saturation value */
1161 Thread->Saturation = 0;
1162
1163 /* Now check if saturation is being used for the new value */
1164 if (abs(Increment) >= ((HIGH_PRIORITY + 1) / 2))
1165 {
1166 /* Check if we need positive or negative saturation */
1167 Thread->Saturation = (Increment > 0) ? 1 : -1;
1168 }
1169
1170 /* Normalize the Base Priority */
1171 BasePriority = Process->BasePriority + Increment;
1172 if (Process->BasePriority >= LOW_REALTIME_PRIORITY)
1173 {
1174 /* Check if it's too low */
1175 if (BasePriority < LOW_REALTIME_PRIORITY)
1176 {
1177 /* Set it to the lowest real time level */
1178 BasePriority = LOW_REALTIME_PRIORITY;
1179 }
1180
1181 /* Check if it's too high */
1182 if (BasePriority > HIGH_PRIORITY) BasePriority = HIGH_PRIORITY;
1183
1184 /* We are at real time, so use the raw base priority */
1185 Priority = BasePriority;
1186 }
1187 else
1188 {
1189 /* Check if it's entering the real time range */
1190 if (BasePriority >= LOW_REALTIME_PRIORITY)
1191 {
1192 /* Set it to the highest dynamic level */
1193 BasePriority = LOW_REALTIME_PRIORITY - 1;
1194 }
1195
1196 /* Check if it's too low and normalize it */
1197 if (BasePriority <= LOW_PRIORITY) BasePriority = 1;
1198
1199 /* Check if Saturation is used */
1200 if (Thread->Saturation)
1201 {
1202 /* Use the raw base priority */
1203 Priority = BasePriority;
1204 }
1205 else
1206 {
1207 /* Otherwise, calculate the new priority */
1208 Priority = KiComputeNewPriority(Thread, 0);
1209 Priority += (BasePriority - OldBasePriority);
1210
1211 /* Check if it entered the real-time range */
1212 if (Priority >= LOW_REALTIME_PRIORITY)
1213 {
1214 /* Normalize it down to the highest dynamic priority */
1215 Priority = LOW_REALTIME_PRIORITY - 1;
1216 }
1217 else if (Priority <= LOW_PRIORITY)
1218 {
1219 /* It went too low, normalize it */
1220 Priority = 1;
1221 }
1222 }
1223 }
1224
1225 /* Finally set the new base priority */
1226 Thread->BasePriority = (SCHAR)BasePriority;
1227
1228 /* Reset the decrements */
1229 Thread->PriorityDecrement = 0;
1230
1231 /* Check if we're changing priority after all */
1232 if (Priority != Thread->Priority)
1233 {
1234 /* Reset the quantum and do the actual priority modification */
1235 Thread->Quantum = Thread->QuantumReset;
1236 KiSetPriorityThread(Thread, Priority);
1237 }
1238
1239 /* Release thread lock */
1240 KiReleaseThreadLock(Thread);
1241
1242 /* Release the dispatcher database and return old increment */
1243 KiReleaseDispatcherLock(OldIrql);
1244 return OldIncrement;
1245 }
1246
1247 /*
1248 * @implemented
1249 */
1250 KAFFINITY
1251 NTAPI
1252 KeSetAffinityThread(IN PKTHREAD Thread,
1253 IN KAFFINITY Affinity)
1254 {
1255 KIRQL OldIrql;
1256 KAFFINITY OldAffinity;
1257 ASSERT_THREAD(Thread);
1258 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
1259
1260 /* Lock the dispatcher database */
1261 OldIrql = KiAcquireDispatcherLock();
1262
1263 /* Call the internal function */
1264 OldAffinity = KiSetAffinityThread(Thread, Affinity);
1265
1266 /* Release the dispatcher database and return old affinity */
1267 KiReleaseDispatcherLock(OldIrql);
1268 return OldAffinity;
1269 }
1270
1271 /*
1272 * @implemented
1273 */
1274 KPRIORITY
1275 NTAPI
1276 KeSetPriorityThread(IN PKTHREAD Thread,
1277 IN KPRIORITY Priority)
1278 {
1279 KIRQL OldIrql;
1280 KPRIORITY OldPriority;
1281 ASSERT_THREAD(Thread);
1282 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
1283 ASSERT((Priority <= HIGH_PRIORITY) && (Priority >= LOW_PRIORITY));
1284 ASSERT(KeIsExecutingDpc() == FALSE);
1285
1286 /* Lock the Dispatcher Database */
1287 OldIrql = KiAcquireDispatcherLock();
1288
1289 /* Lock the thread */
1290 KiAcquireThreadLock(Thread);
1291
1292 /* Save the old Priority and reset decrement */
1293 OldPriority = Thread->Priority;
1294 Thread->PriorityDecrement = 0;
1295
1296 /* Make sure that an actual change is being done */
1297 if (Priority != Thread->Priority)
1298 {
1299 /* Reset the quantum */
1300 Thread->Quantum = Thread->QuantumReset;
1301
1302 /* Check if priority is being set too low and normalize if so */
1303 if ((Thread->BasePriority != 0) && !(Priority)) Priority = 1;
1304
1305 /* Set the new Priority */
1306 KiSetPriorityThread(Thread, Priority);
1307 }
1308
1309 /* Release thread lock */
1310 KiReleaseThreadLock(Thread);
1311
1312 /* Release the dispatcher database */
1313 KiReleaseDispatcherLock(OldIrql);
1314
1315 /* Return Old Priority */
1316 return OldPriority;
1317 }
1318
1319 /*
1320 * @implemented
1321 */
1322 VOID
1323 NTAPI
1324 KeTerminateThread(IN KPRIORITY Increment)
1325 {
1326 PLIST_ENTRY *ListHead;
1327 PETHREAD Entry, SavedEntry;
1328 PETHREAD *ThreadAddr;
1329 KLOCK_QUEUE_HANDLE LockHandle;
1330 PKTHREAD Thread = KeGetCurrentThread();
1331 PKPROCESS Process = Thread->ApcState.Process;
1332 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
1333
1334 /* Lock the process */
1335 KiAcquireProcessLock(Process, &LockHandle);
1336
1337 /* Make sure we won't get Swapped */
1338 KiSetThreadSwapBusy(Thread);
1339
1340 /* Save the Kernel and User Times */
1341 Process->KernelTime += Thread->KernelTime;
1342 Process->UserTime += Thread->UserTime;
1343
1344 /* Get the current entry and our Port */
1345 Entry = (PETHREAD)PspReaperListHead.Flink;
1346 ThreadAddr = &((PETHREAD)Thread)->ReaperLink;
1347
1348 /* Add it to the reaper's list */
1349 do
1350 {
1351 /* Get the list head */
1352 ListHead = &PspReaperListHead.Flink;
1353
1354 /* Link ourselves */
1355 *ThreadAddr = Entry;
1356 SavedEntry = Entry;
1357
1358 /* Now try to do the exchange */
1359 Entry = InterlockedCompareExchangePointer((PVOID*)ListHead,
1360 ThreadAddr,
1361 Entry);
1362
1363 /* Break out if the change was succesful */
1364 } while (Entry != SavedEntry);
1365
1366 /* Acquire the dispatcher lock */
1367 KiAcquireDispatcherLockAtDpcLevel();
1368
1369 /* Check if the reaper wasn't active */
1370 if (!Entry)
1371 {
1372 /* Activate it as a work item, directly through its Queue */
1373 KiInsertQueue(&ExWorkerQueue[HyperCriticalWorkQueue].WorkerQueue,
1374 &PspReaperWorkItem.List,
1375 FALSE);
1376 }
1377
1378 /* Check the thread has an associated queue */
1379 if (Thread->Queue)
1380 {
1381 /* Remove it from the list, and handle the queue */
1382 RemoveEntryList(&Thread->QueueListEntry);
1383 KiActivateWaiterQueue(Thread->Queue);
1384 }
1385
1386 /* Signal the thread */
1387 Thread->DispatcherHeader.SignalState = TRUE;
1388 if (!IsListEmpty(&Thread->DispatcherHeader.WaitListHead))
1389 {
1390 /* Unwait the threads */
1391 KxUnwaitThread(&Thread->DispatcherHeader, Increment);
1392 }
1393
1394 /* Remove the thread from the list */
1395 RemoveEntryList(&Thread->ThreadListEntry);
1396
1397 /* Release the process lock */
1398 KiReleaseProcessLockFromDpcLevel(&LockHandle);
1399
1400 /* Set us as terminated, decrease the Process's stack count */
1401 Thread->State = Terminated;
1402
1403 /* Decrease stack count */
1404 ASSERT(Process->StackCount != 0);
1405 ASSERT(Process->State == ProcessInMemory);
1406 Process->StackCount--;
1407 if (!(Process->StackCount) && !(IsListEmpty(&Process->ThreadListHead)))
1408 {
1409 /* FIXME: Swap stacks */
1410 }
1411
1412 /* Rundown arch-specific parts */
1413 KiRundownThread(Thread);
1414
1415 /* Swap to a new thread */
1416 KiReleaseDispatcherLockFromDpcLevel();
1417 KiSwapThread(Thread, KeGetCurrentPrcb());
1418 }