7459450aa842b3d47e74e8c8f866845fbd9ce3e7
[reactos.git] / reactos / ntoskrnl / ke / kthread.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ke/kthread.c
5 * PURPOSE: Microkernel thread support
6 *
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
8 * David Welch (welch@cwcom.net)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* FIXME: NDK */
18 #define MAXIMUM_SUSPEND_COUNT 0x7F
19 #define THREAD_ALERT_INCREMENT 2
20
21 extern EX_WORK_QUEUE ExWorkerQueue[MaximumWorkQueue];
22
23 /*
24 * PURPOSE: List of threads associated with each priority level
25 */
26 LIST_ENTRY PriorityListHead[MAXIMUM_PRIORITY];
27 static ULONG PriorityListMask = 0;
28 ULONG IdleProcessorMask = 0;
29 extern PETHREAD PspReaperList;
30
31 /* FUNCTIONS *****************************************************************/
32
33 STATIC
34 VOID
35 KiRequestReschedule(CCHAR Processor)
36 {
37 PKPCR Pcr;
38
39 Pcr = (PKPCR)(KPCR_BASE + Processor * PAGE_SIZE);
40 Pcr->Prcb->QuantumEnd = TRUE;
41 KiIpiSendRequest(1 << Processor, IPI_DPC);
42 }
43
44 STATIC
45 VOID
46 KiInsertIntoThreadList(KPRIORITY Priority,
47 PKTHREAD Thread)
48 {
49 ASSERT(Ready == Thread->State);
50 ASSERT(Thread->Priority == Priority);
51
52 if (Priority >= MAXIMUM_PRIORITY || Priority < LOW_PRIORITY) {
53
54 DPRINT1("Invalid thread priority (%d)\n", Priority);
55 KEBUGCHECK(0);
56 }
57
58 InsertTailList(&PriorityListHead[Priority], &Thread->WaitListEntry);
59 PriorityListMask |= (1 << Priority);
60 }
61
62 STATIC
63 VOID
64 KiRemoveFromThreadList(PKTHREAD Thread)
65 {
66 ASSERT(Ready == Thread->State);
67 RemoveEntryList(&Thread->WaitListEntry);
68 if (IsListEmpty(&PriorityListHead[(ULONG)Thread->Priority])) {
69
70 PriorityListMask &= ~(1 << Thread->Priority);
71 }
72 }
73
74 STATIC
75 PKTHREAD
76 KiScanThreadList(KPRIORITY Priority,
77 KAFFINITY Affinity)
78 {
79 PKTHREAD current;
80 ULONG Mask;
81
82 Mask = (1 << Priority);
83
84 if (PriorityListMask & Mask) {
85
86 LIST_FOR_EACH(current, &PriorityListHead[Priority], KTHREAD, WaitListEntry) {
87
88 if (current->State != Ready) {
89
90 DPRINT1("%d/%d\n", &current, current->State);
91 }
92
93 ASSERT(current->State == Ready);
94
95 if (current->Affinity & Affinity) {
96
97 KiRemoveFromThreadList(current);
98 return(current);
99 }
100 }
101 }
102
103 return(NULL);
104 }
105
106 VOID
107 STDCALL
108 KiDispatchThreadNoLock(ULONG NewThreadStatus)
109 {
110 KPRIORITY CurrentPriority;
111 PKTHREAD Candidate;
112 ULONG Affinity;
113 PKTHREAD CurrentThread = KeGetCurrentThread();
114
115 DPRINT("KiDispatchThreadNoLock() %d/%d/%d/%d\n", KeGetCurrentProcessorNumber(),
116 CurrentThread, NewThreadStatus, CurrentThread->State);
117
118 CurrentThread->State = (UCHAR)NewThreadStatus;
119
120 if (NewThreadStatus == Ready) {
121
122 KiInsertIntoThreadList(CurrentThread->Priority,
123 CurrentThread);
124 }
125
126 Affinity = 1 << KeGetCurrentProcessorNumber();
127
128 for (CurrentPriority = HIGH_PRIORITY; CurrentPriority >= LOW_PRIORITY; CurrentPriority--) {
129
130 Candidate = KiScanThreadList(CurrentPriority, Affinity);
131
132 if (Candidate == CurrentThread) {
133
134 Candidate->State = Running;
135 KeReleaseDispatcherDatabaseLockFromDpcLevel();
136 return;
137 }
138
139 if (Candidate != NULL) {
140
141 PKTHREAD OldThread;
142 PKTHREAD IdleThread;
143
144 DPRINT("Scheduling %x(%d)\n",Candidate, CurrentPriority);
145
146 Candidate->State = Running;
147
148 OldThread = CurrentThread;
149 CurrentThread = Candidate;
150 IdleThread = KeGetCurrentPrcb()->IdleThread;
151
152 if (OldThread == IdleThread) {
153
154 IdleProcessorMask &= ~Affinity;
155
156 } else if (CurrentThread == IdleThread) {
157
158 IdleProcessorMask |= Affinity;
159 }
160
161 MmUpdatePageDir(PsGetCurrentProcess(),((PETHREAD)CurrentThread)->ThreadsProcess, sizeof(EPROCESS));
162
163 /* Special note for Filip: This will release the Dispatcher DB Lock ;-) -- Alex */
164 DPRINT("You are : %x, swapping to: %x\n", OldThread, CurrentThread);
165 KiArchContextSwitch(CurrentThread);
166 DPRINT("You are : %x, swapped from: %x\n", OldThread, CurrentThread);
167 return;
168 }
169 }
170
171 DPRINT1("CRITICAL: No threads are ready (CPU%d)\n", KeGetCurrentProcessorNumber());
172 KEBUGCHECK(0);
173 }
174
175 VOID
176 STDCALL
177 KiBlockThread(PNTSTATUS Status,
178 UCHAR Alertable,
179 ULONG WaitMode,
180 UCHAR WaitReason)
181 {
182 PKTHREAD Thread = KeGetCurrentThread();
183 PKWAIT_BLOCK WaitBlock;
184
185 if (Thread->ApcState.KernelApcPending) {
186
187 DPRINT("Dispatching Thread as ready (APC!)\n");
188
189 /* Remove Waits */
190 WaitBlock = Thread->WaitBlockList;
191 do {
192 RemoveEntryList (&WaitBlock->WaitListEntry);
193 WaitBlock = WaitBlock->NextWaitBlock;
194 } while (WaitBlock != Thread->WaitBlockList);
195 Thread->WaitBlockList = NULL;
196
197 /* Dispatch it and return status */
198 KiDispatchThreadNoLock (Ready);
199 if (Status != NULL) *Status = STATUS_KERNEL_APC;
200
201 } else {
202
203 /* Set the Thread Data as Requested */
204 DPRINT("Dispatching Thread as blocked: %d\n", Thread->WaitStatus);
205 Thread->Alertable = Alertable;
206 Thread->WaitMode = (UCHAR)WaitMode;
207 Thread->WaitReason = WaitReason;
208
209 /* Dispatch it and return status */
210 KiDispatchThreadNoLock(Waiting);
211 DPRINT("Dispatching Thread as blocked: %d\n", Thread->WaitStatus);
212 if (Status != NULL) *Status = Thread->WaitStatus;
213 }
214
215 DPRINT("Releasing Dispatcher Lock\n");
216 KfLowerIrql(Thread->WaitIrql);
217 }
218
219 VOID
220 STDCALL
221 KiDispatchThread(ULONG NewThreadStatus)
222 {
223 KIRQL OldIrql;
224
225 if (KeGetCurrentPrcb()->IdleThread == NULL) {
226 return;
227 }
228
229 OldIrql = KeAcquireDispatcherDatabaseLock();
230 KiDispatchThreadNoLock(NewThreadStatus);
231 KeLowerIrql(OldIrql);
232 }
233
234 VOID
235 STDCALL
236 KiUnblockThread(PKTHREAD Thread,
237 PNTSTATUS WaitStatus,
238 KPRIORITY Increment)
239 {
240 if (Terminated == Thread->State) {
241
242 DPRINT("Can't unblock thread 0x%x because it's terminating\n",
243 Thread);
244
245 } else if (Ready == Thread->State ||
246 Running == Thread->State) {
247
248 DPRINT("Can't unblock thread 0x%x because it's %s\n",
249 Thread, (Thread->State == Ready ? "ready" : "running"));
250
251 } else {
252
253 LONG Processor;
254 KAFFINITY Affinity;
255
256 /* FIXME: This propably isn't the right way to do it... */
257 /* No it's not... i'll fix it later-- Alex */
258 if (Thread->Priority < LOW_REALTIME_PRIORITY &&
259 Thread->BasePriority < LOW_REALTIME_PRIORITY - 2) {
260
261 if (!Thread->PriorityDecrement && !Thread->DisableBoost) {
262
263 Thread->Priority = Thread->BasePriority + Increment;
264 Thread->PriorityDecrement = Increment;
265 }
266
267 /* Also decrease quantum */
268 Thread->Quantum--;
269
270 } else {
271
272 Thread->Quantum = Thread->QuantumReset;
273 }
274
275 if (WaitStatus != NULL) {
276
277 Thread->WaitStatus = *WaitStatus;
278 }
279
280 Thread->State = Ready;
281 KiInsertIntoThreadList(Thread->Priority, Thread);
282 Processor = KeGetCurrentProcessorNumber();
283 Affinity = Thread->Affinity;
284
285 if (!(IdleProcessorMask & (1 << Processor) & Affinity) &&
286 (IdleProcessorMask & ~(1 << Processor) & Affinity)) {
287
288 LONG i;
289
290 for (i = 0; i < KeNumberProcessors - 1; i++) {
291
292 Processor++;
293
294 if (Processor >= KeNumberProcessors) {
295
296 Processor = 0;
297 }
298
299 if (IdleProcessorMask & (1 << Processor) & Affinity) {
300 #if 0
301 /* FIXME:
302 * Reschedule the threads on an other processor
303 */
304 KeReleaseDispatcherDatabaseLockFromDpcLevel();
305 KiRequestReschedule(Processor);
306 KeAcquireDispatcherDatabaseLockAtDpcLevel();
307 #endif
308 break;
309 }
310 }
311 }
312 }
313 }
314
315 VOID
316 STDCALL
317 KiAdjustQuantumThread(IN PKTHREAD Thread)
318 {
319 KPRIORITY Priority;
320
321 /* Don't adjust for RT threads */
322 if ((Thread->Priority < LOW_REALTIME_PRIORITY) &&
323 Thread->BasePriority < LOW_REALTIME_PRIORITY - 2)
324 {
325 /* Decrease Quantum by one and see if we've ran out */
326 if (--Thread->Quantum <= 0)
327 {
328 /* Return quantum */
329 Thread->Quantum = Thread->QuantumReset;
330
331 /* Calculate new Priority */
332 Priority = Thread->Priority - (Thread->PriorityDecrement + 1);
333
334 /* Normalize it if we've gone too low */
335 if (Priority < Thread->BasePriority) Priority = Thread->BasePriority;
336
337 /* Reset the priority decrement, we've done it */
338 Thread->PriorityDecrement = 0;
339
340 /* Set the new priority, if needed */
341 if (Priority != Thread->Priority)
342 {
343 /*
344 * FIXME: This should be a call to KiSetPriorityThread but
345 * due to the current ""scheduler"" in ROS, it can't be done
346 * cleanly since it actualyl dispatches threads instead.
347 */
348 Thread->Priority = Priority;
349 }
350 else
351 {
352 /* FIXME: Priority hasn't changed, find a new thread */
353 }
354 }
355 }
356
357 /* Nothing to do... */
358 return;
359 }
360
361
362 VOID
363 STDCALL
364 KiSuspendThreadKernelRoutine(PKAPC Apc,
365 PKNORMAL_ROUTINE* NormalRoutine,
366 PVOID* NormalContext,
367 PVOID* SystemArgument1,
368 PVOID* SystemArguemnt2)
369 {
370 }
371
372 VOID
373 STDCALL
374 KiSuspendThreadNormalRoutine(PVOID NormalContext,
375 PVOID SystemArgument1,
376 PVOID SystemArgument2)
377 {
378 PKTHREAD CurrentThread = KeGetCurrentThread();
379
380 /* Non-alertable kernel-mode suspended wait */
381 DPRINT("Waiting...\n");
382 KeWaitForSingleObject(&CurrentThread->SuspendSemaphore,
383 Suspended,
384 KernelMode,
385 FALSE,
386 NULL);
387 DPRINT("Done Waiting\n");
388 }
389
390 #ifdef KeGetCurrentThread
391 #undef KeGetCurrentThread
392 #endif
393 /*
394 * @implemented
395 */
396 PKTHREAD
397 STDCALL
398 KeGetCurrentThread(VOID)
399 {
400 #ifdef CONFIG_SMP
401 ULONG Flags;
402 PKTHREAD Thread;
403 Ke386SaveFlags(Flags);
404 Ke386DisableInterrupts();
405 Thread = KeGetCurrentPrcb()->CurrentThread;
406 Ke386RestoreFlags(Flags);
407 return Thread;
408 #else
409 return(KeGetCurrentPrcb()->CurrentThread);
410 #endif
411 }
412
413 VOID
414 STDCALL
415 KeSetPreviousMode(ULONG Mode)
416 {
417 PsGetCurrentThread()->Tcb.PreviousMode = (UCHAR)Mode;
418 }
419
420 /*
421 * @implemented
422 */
423 KPROCESSOR_MODE
424 STDCALL
425 KeGetPreviousMode(VOID)
426 {
427 return (ULONG)PsGetCurrentThread()->Tcb.PreviousMode;
428 }
429
430 BOOLEAN
431 STDCALL
432 KeDisableThreadApcQueueing(IN PKTHREAD Thread)
433 {
434 KIRQL OldIrql;
435 BOOLEAN PreviousState;
436
437 /* Lock the Dispatcher Database */
438 OldIrql = KeAcquireDispatcherDatabaseLock();
439
440 /* Save old state */
441 PreviousState = Thread->ApcQueueable;
442
443 /* Disable it now */
444 Thread->ApcQueueable = FALSE;
445
446 /* Release the Lock */
447 KeReleaseDispatcherDatabaseLock(OldIrql);
448
449 /* Return old state */
450 return PreviousState;
451 }
452
453 VOID
454 STDCALL
455 KeRundownThread(VOID)
456 {
457 KIRQL OldIrql;
458 PKTHREAD Thread = KeGetCurrentThread();
459 PLIST_ENTRY NextEntry, ListHead;
460 PKMUTANT Mutant;
461 DPRINT("KeRundownThread: %x\n", Thread);
462
463 /* Optimized path if nothing is on the list at the moment */
464 if (IsListEmpty(&Thread->MutantListHead)) return;
465
466 /* Lock the Dispatcher Database */
467 OldIrql = KeAcquireDispatcherDatabaseLock();
468
469 /* Get the List Pointers */
470 ListHead = &Thread->MutantListHead;
471 NextEntry = ListHead->Flink;
472 while (NextEntry != ListHead)
473 {
474 /* Get the Mutant */
475 Mutant = CONTAINING_RECORD(NextEntry, KMUTANT, MutantListEntry);
476 DPRINT1("Mutant: %p. Type, Size %x %x\n", Mutant, Mutant->Header.Type, Mutant->Header.Size);
477
478 /* Make sure it's not terminating with APCs off */
479 if (Mutant->ApcDisable)
480 {
481 /* Bugcheck the system */
482 KEBUGCHECKEX(0,//THREAD_TERMINATE_HELD_MUTEX,
483 (ULONG_PTR)Thread,
484 (ULONG_PTR)Mutant,
485 0,
486 0);
487 }
488
489 /* Now we can remove it */
490 RemoveEntryList(&Mutant->MutantListEntry);
491
492 /* Unconditionally abandon it */
493 DPRINT("Abandonning the Mutant\n");
494 Mutant->Header.SignalState = 1;
495 Mutant->Abandoned = TRUE;
496 Mutant->OwnerThread = NULL;
497
498 /* Check if the Wait List isn't empty */
499 DPRINT("Checking whether to wake the Mutant\n");
500 if (!IsListEmpty(&Mutant->Header.WaitListHead))
501 {
502 /* Wake the Mutant */
503 DPRINT("Waking the Mutant\n");
504 KiWaitTest(&Mutant->Header, MUTANT_INCREMENT);
505 }
506
507 /* Move on */
508 NextEntry = NextEntry->Flink;
509 }
510
511 /* Release the Lock */
512 KeReleaseDispatcherDatabaseLock(OldIrql);
513 }
514
515 ULONG
516 STDCALL
517 KeResumeThread(PKTHREAD Thread)
518 {
519 ULONG PreviousCount;
520 KIRQL OldIrql;
521
522 DPRINT("KeResumeThread (Thread %p called). %x, %x\n", Thread,
523 Thread->SuspendCount, Thread->FreezeCount);
524
525 /* Lock the Dispatcher */
526 OldIrql = KeAcquireDispatcherDatabaseLock();
527
528 /* Save the Old Count */
529 PreviousCount = Thread->SuspendCount;
530
531 /* Check if it existed */
532 if (PreviousCount) {
533
534 Thread->SuspendCount--;
535
536 /* Decrease the current Suspend Count and Check Freeze Count */
537 if ((!Thread->SuspendCount) && (!Thread->FreezeCount)) {
538
539 /* Signal the Suspend Semaphore */
540 Thread->SuspendSemaphore.Header.SignalState++;
541 KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT);
542 }
543 }
544
545 /* Release Lock and return the Old State */
546 KeReleaseDispatcherDatabaseLock(OldIrql);
547 return PreviousCount;
548 }
549
550 VOID
551 FASTCALL
552 KiInsertQueueApc(PKAPC Apc,
553 KPRIORITY PriorityBoost);
554
555 /*
556 * Used by the debugging code to freeze all the process's threads
557 * while the debugger is examining their state.
558 */
559 VOID
560 STDCALL
561 KeFreezeAllThreads(PKPROCESS Process)
562 {
563 KIRQL OldIrql;
564 PKTHREAD Current;
565 PKTHREAD CurrentThread = KeGetCurrentThread();
566
567 /* Acquire Lock */
568 OldIrql = KeAcquireDispatcherDatabaseLock();
569
570 /* If someone is already trying to free us, try again */
571 while (CurrentThread->FreezeCount)
572 {
573 /* Release and re-acquire the lock so the APC will go through */
574 KeReleaseDispatcherDatabaseLock(OldIrql);
575 OldIrql = KeAcquireDispatcherDatabaseLock();
576 }
577
578 /* Enter a critical region */
579 KeEnterCriticalRegion();
580
581 /* Loop the Process's Threads */
582 LIST_FOR_EACH(Current, &Process->ThreadListHead, KTHREAD, ThreadListEntry)
583 {
584 /* Make sure it's not ours */
585 if (Current != CurrentThread)
586 {
587 /* Should be bother inserting the APC? */
588 if (Current->ApcQueueable)
589 {
590 /* Make sure it wasn't already frozen, and that it's not suspended */
591 if (!(++Current->FreezeCount) && !(Current->SuspendCount))
592 {
593 /* Did we already insert it? */
594 if (!Current->SuspendApc.Inserted)
595 {
596 /* Insert the APC */
597 Current->SuspendApc.Inserted = TRUE;
598 KiInsertQueueApc(&Current->SuspendApc, IO_NO_INCREMENT);
599 }
600 else
601 {
602 /* Unsignal the Semaphore, the APC already got inserted */
603 Current->SuspendSemaphore.Header.SignalState--;
604 }
605 }
606 }
607 }
608 }
609
610 /* Release the lock */
611 KeReleaseDispatcherDatabaseLock(OldIrql);
612 }
613
614 NTSTATUS
615 STDCALL
616 KeSuspendThread(PKTHREAD Thread)
617 {
618 ULONG PreviousCount;
619 KIRQL OldIrql;
620
621 DPRINT("KeSuspendThread (Thread %p called). %x, %x\n", Thread, Thread->SuspendCount, Thread->FreezeCount);
622
623 /* Lock the Dispatcher */
624 OldIrql = KeAcquireDispatcherDatabaseLock();
625
626 /* Save the Old Count */
627 PreviousCount = Thread->SuspendCount;
628
629 /* Handle the maximum */
630 if (PreviousCount == MAXIMUM_SUSPEND_COUNT)
631 {
632 /* Raise an exception */
633 KeReleaseDispatcherDatabaseLock(OldIrql);
634 RtlRaiseStatus(STATUS_SUSPEND_COUNT_EXCEEDED);
635 }
636
637 /* Should we bother to queue at all? */
638 if (Thread->ApcQueueable)
639 {
640 /* Increment the suspend count */
641 Thread->SuspendCount++;
642
643 /* Check if we should suspend it */
644 if (!PreviousCount && !Thread->FreezeCount)
645 {
646 /* Is the APC already inserted? */
647 if (!Thread->SuspendApc.Inserted)
648 {
649 /* Not inserted, insert it */
650 Thread->SuspendApc.Inserted = TRUE;
651 KiInsertQueueApc(&Thread->SuspendApc, IO_NO_INCREMENT);
652 }
653 else
654 {
655 /* Unsignal the Semaphore, the APC already got inserted */
656 Thread->SuspendSemaphore.Header.SignalState--;
657 }
658 }
659 }
660
661 /* Release Lock and return the Old State */
662 KeReleaseDispatcherDatabaseLock(OldIrql);
663 return PreviousCount;
664 }
665
666 ULONG
667 STDCALL
668 KeForceResumeThread(IN PKTHREAD Thread)
669 {
670 KIRQL OldIrql;
671 ULONG PreviousCount;
672
673 /* Lock the Dispatcher Database and the APC Queue */
674 OldIrql = KeAcquireDispatcherDatabaseLock();
675
676 /* Save the old Suspend Count */
677 PreviousCount = Thread->SuspendCount + Thread->FreezeCount;
678
679 /* If the thread is suspended, wake it up!!! */
680 if (PreviousCount) {
681
682 /* Unwait it completely */
683 Thread->SuspendCount = 0;
684 Thread->FreezeCount = 0;
685
686 /* Signal and satisfy */
687 Thread->SuspendSemaphore.Header.SignalState++;
688 KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT);
689 }
690
691 /* Release Lock and return the Old State */
692 KeReleaseDispatcherDatabaseLock(OldIrql);
693 return PreviousCount;
694 }
695
696 ULONG
697 STDCALL
698 KeAlertResumeThread(IN PKTHREAD Thread)
699 {
700 ULONG PreviousCount;
701 KIRQL OldIrql;
702
703 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
704
705 /* Lock the Dispatcher Database and the APC Queue */
706 OldIrql = KeAcquireDispatcherDatabaseLock();
707 KiAcquireSpinLock(&Thread->ApcQueueLock);
708
709 /* Return if Thread is already alerted. */
710 if (Thread->Alerted[KernelMode] == FALSE) {
711
712 /* If it's Blocked, unblock if it we should */
713 if (Thread->State == Waiting && Thread->Alertable) {
714
715 DPRINT("Aborting Wait\n");
716 KiAbortWaitThread(Thread, STATUS_ALERTED, THREAD_ALERT_INCREMENT);
717
718 } else {
719
720 /* If not, simply Alert it */
721 Thread->Alerted[KernelMode] = TRUE;
722 }
723 }
724
725 /* Save the old Suspend Count */
726 PreviousCount = Thread->SuspendCount;
727
728 /* If the thread is suspended, decrease one of the suspend counts */
729 if (PreviousCount) {
730
731 /* Decrease count. If we are now zero, unwait it completely */
732 if (--Thread->SuspendCount) {
733
734 /* Signal and satisfy */
735 Thread->SuspendSemaphore.Header.SignalState++;
736 KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT);
737 }
738 }
739
740 /* Release Locks and return the Old State */
741 KiReleaseSpinLock(&Thread->ApcQueueLock);
742 KeReleaseDispatcherDatabaseLock(OldIrql);
743 return PreviousCount;
744 }
745
746 BOOLEAN
747 STDCALL
748 KeAlertThread(PKTHREAD Thread,
749 KPROCESSOR_MODE AlertMode)
750 {
751 KIRQL OldIrql;
752 BOOLEAN PreviousState;
753
754 /* Acquire the Dispatcher Database Lock */
755 OldIrql = KeAcquireDispatcherDatabaseLock();
756
757 /* Save the Previous State */
758 PreviousState = Thread->Alerted[AlertMode];
759
760 /* Return if Thread is already alerted. */
761 if (PreviousState == FALSE) {
762
763 /* If it's Blocked, unblock if it we should */
764 if (Thread->State == Waiting &&
765 (AlertMode == KernelMode || Thread->WaitMode == AlertMode) &&
766 Thread->Alertable) {
767
768 DPRINT("Aborting Wait\n");
769 KiAbortWaitThread(Thread, STATUS_ALERTED, THREAD_ALERT_INCREMENT);
770
771 } else {
772
773 /* If not, simply Alert it */
774 Thread->Alerted[AlertMode] = TRUE;
775 }
776 }
777
778 /* Release the Dispatcher Lock */
779 KeReleaseDispatcherDatabaseLock(OldIrql);
780
781 /* Return the old state */
782 return PreviousState;
783 }
784
785 /*
786 * @unimplemented
787 */
788 VOID
789 STDCALL
790 KeCapturePersistentThreadState(IN PVOID CurrentThread,
791 IN ULONG Setting1,
792 IN ULONG Setting2,
793 IN ULONG Setting3,
794 IN ULONG Setting4,
795 IN ULONG Setting5,
796 IN PVOID ThreadState)
797 {
798 UNIMPLEMENTED;
799 }
800
801 /*
802 * FUNCTION: Initialize the microkernel state of the thread
803 */
804 VOID
805 STDCALL
806 KeInitializeThread(PKPROCESS Process,
807 PKTHREAD Thread,
808 PKSYSTEM_ROUTINE SystemRoutine,
809 PKSTART_ROUTINE StartRoutine,
810 PVOID StartContext,
811 PCONTEXT Context,
812 PVOID Teb,
813 PVOID KernelStack)
814 {
815 /* Initalize the Dispatcher Header */
816 DPRINT("Initializing Dispatcher Header for New Thread: %x in Process: %x\n", Thread, Process);
817 KeInitializeDispatcherHeader(&Thread->DispatcherHeader,
818 ThreadObject,
819 sizeof(KTHREAD),
820 FALSE);
821
822 DPRINT("Thread Header Created. SystemRoutine: %x, StartRoutine: %x with Context: %x\n",
823 SystemRoutine, StartRoutine, StartContext);
824 DPRINT("UserMode Information. Context: %x, Teb: %x\n", Context, Teb);
825
826 /* Initialize the Mutant List */
827 InitializeListHead(&Thread->MutantListHead);
828
829 /* Setup the Service Descriptor Table for Native Calls */
830 Thread->ServiceTable = KeServiceDescriptorTable;
831
832 /* Setup APC Fields */
833 InitializeListHead(&Thread->ApcState.ApcListHead[0]);
834 InitializeListHead(&Thread->ApcState.ApcListHead[1]);
835 Thread->ApcState.Process = Process;
836 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState;
837 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState;
838 Thread->ApcStateIndex = OriginalApcEnvironment;
839 KeInitializeSpinLock(&Thread->ApcQueueLock);
840
841 /* Initialize the Suspend APC */
842 KeInitializeApc(&Thread->SuspendApc,
843 Thread,
844 OriginalApcEnvironment,
845 KiSuspendThreadKernelRoutine,
846 NULL,
847 KiSuspendThreadNormalRoutine,
848 KernelMode,
849 NULL);
850
851 /* Initialize the Suspend Semaphore */
852 KeInitializeSemaphore(&Thread->SuspendSemaphore, 0, 128);
853
854 /* FIXME OPTIMIZATION OF DOOM. DO NOT ENABLE FIXME */
855 #if 0
856 Thread->WaitBlock[3].Object = (PVOID)&Thread->Timer;
857 Thread->WaitBlock[3].Thread = Thread;
858 Thread->WaitBlock[3].WaitKey = STATUS_TIMEOUT;
859 Thread->WaitBlock[3].WaitType = WaitAny;
860 Thread->WaitBlock[3].NextWaitBlock = NULL;
861 InsertTailList(&Thread->Timer.Header.WaitListHead,
862 &Thread->WaitBlock[3].WaitListEntry);
863 #endif
864 KeInitializeTimer(&Thread->Timer);
865
866 /* Set the TEB */
867 Thread->Teb = Teb;
868
869 /* Set the Thread Stacks */
870 Thread->InitialStack = (PCHAR)KernelStack + MM_STACK_SIZE;
871 Thread->StackBase = (PCHAR)KernelStack + MM_STACK_SIZE;
872 Thread->StackLimit = (ULONG_PTR)KernelStack;
873 Thread->KernelStackResident = TRUE;
874
875 /*
876 * Establish the pde's for the new stack and the thread structure within the
877 * address space of the new process. They are accessed while taskswitching or
878 * while handling page faults. At this point it isn't possible to call the
879 * page fault handler for the missing pde's.
880 */
881 MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread->StackLimit, MM_STACK_SIZE);
882 MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread, sizeof(ETHREAD));
883
884 /* Initalize the Thread Context */
885 DPRINT("Initializing the Context for the thread: %x\n", Thread);
886 KiArchInitThreadWithContext(Thread,
887 SystemRoutine,
888 StartRoutine,
889 StartContext,
890 Context);
891
892 /* Setup scheduler Fields based on Parent */
893 DPRINT("Thread context created, setting Scheduler Data\n");
894 Thread->BasePriority = Process->BasePriority;
895 Thread->Quantum = Process->QuantumReset;
896 Thread->QuantumReset = Process->QuantumReset;
897 Thread->Affinity = Process->Affinity;
898 Thread->Priority = Process->BasePriority;
899 Thread->UserAffinity = Process->Affinity;
900 Thread->DisableBoost = Process->DisableBoost;
901 Thread->AutoAlignment = Process->AutoAlignment;
902 Thread->Iopl = Process->Iopl;
903
904 /* Set the Thread to initalized */
905 Thread->State = Initialized;
906
907 /*
908 * Insert the Thread into the Process's Thread List
909 * Note, this is the KTHREAD Thread List. It is removed in
910 * ke/kthread.c!KeTerminateThread.
911 */
912 InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry);
913 DPRINT("Thread initalized\n");
914 }
915
916
917 /*
918 * @implemented
919 */
920 KPRIORITY
921 STDCALL
922 KeQueryPriorityThread (IN PKTHREAD Thread)
923 {
924 return Thread->Priority;
925 }
926
927 /*
928 * @implemented
929 */
930 ULONG
931 STDCALL
932 KeQueryRuntimeThread(IN PKTHREAD Thread,
933 OUT PULONG UserTime)
934 {
935 /* Return the User Time */
936 *UserTime = Thread->UserTime;
937
938 /* Return the Kernel Time */
939 return Thread->KernelTime;
940 }
941
942 /*
943 * @implemented
944 */
945 BOOLEAN
946 STDCALL
947 KeSetKernelStackSwapEnable(IN BOOLEAN Enable)
948 {
949 PKTHREAD Thread = KeGetCurrentThread();
950 BOOLEAN PreviousState;
951 KIRQL OldIrql;
952
953 /* Lock the Dispatcher Database */
954 OldIrql = KeAcquireDispatcherDatabaseLock();
955
956 /* Save Old State */
957 PreviousState = Thread->EnableStackSwap;
958
959 /* Set New State */
960 Thread->EnableStackSwap = Enable;
961
962 /* No, Release Lock */
963 KeReleaseDispatcherDatabaseLock(OldIrql);
964
965 /* Return Old State */
966 return PreviousState;
967 }
968
969 /*
970 * @implemented
971 */
972 VOID
973 STDCALL
974 KeRevertToUserAffinityThread(VOID)
975 {
976 PKTHREAD CurrentThread = KeGetCurrentThread();
977 KIRQL OldIrql;
978
979 ASSERT(CurrentThread->SystemAffinityActive != FALSE);
980
981 /* Lock the Dispatcher Database */
982 OldIrql = KeAcquireDispatcherDatabaseLock();
983
984 /* Return to User Affinity */
985 CurrentThread->Affinity = CurrentThread->UserAffinity;
986
987 /* Disable System Affinity */
988 CurrentThread->SystemAffinityActive = FALSE;
989
990 /* Check if we need to Dispatch a New thread */
991 if (CurrentThread->Affinity & (1 << KeGetCurrentProcessorNumber())) {
992
993 /* No, just release */
994 KeReleaseDispatcherDatabaseLock(OldIrql);
995
996 } else {
997
998 /* We need to dispatch a new thread */
999 CurrentThread->WaitIrql = OldIrql;
1000 KiDispatchThreadNoLock(Ready);
1001 KeLowerIrql(OldIrql);
1002 }
1003 }
1004
1005 /*
1006 * @implemented
1007 */
1008 CCHAR
1009 STDCALL
1010 KeSetIdealProcessorThread(IN PKTHREAD Thread,
1011 IN CCHAR Processor)
1012 {
1013 CCHAR PreviousIdealProcessor;
1014 KIRQL OldIrql;
1015
1016 /* Lock the Dispatcher Database */
1017 OldIrql = KeAcquireDispatcherDatabaseLock();
1018
1019 /* Save Old Ideal Processor */
1020 PreviousIdealProcessor = Thread->IdealProcessor;
1021
1022 /* Set New Ideal Processor */
1023 Thread->IdealProcessor = Processor;
1024
1025 /* Release Lock */
1026 KeReleaseDispatcherDatabaseLock(OldIrql);
1027
1028 /* Return Old Ideal Processor */
1029 return PreviousIdealProcessor;
1030 }
1031
1032 /*
1033 * @implemented
1034 */
1035 VOID
1036 STDCALL
1037 KeSetSystemAffinityThread(IN KAFFINITY Affinity)
1038 {
1039 PKTHREAD CurrentThread = KeGetCurrentThread();
1040 KIRQL OldIrql;
1041
1042 ASSERT(Affinity & ((1 << KeNumberProcessors) - 1));
1043
1044 /* Lock the Dispatcher Database */
1045 OldIrql = KeAcquireDispatcherDatabaseLock();
1046
1047 /* Set the System Affinity Specified */
1048 CurrentThread->Affinity = Affinity;
1049
1050 /* Enable System Affinity */
1051 CurrentThread->SystemAffinityActive = TRUE;
1052
1053 /* Check if we need to Dispatch a New thread */
1054 if (Affinity & (1 << KeGetCurrentProcessorNumber())) {
1055
1056 /* No, just release */
1057 KeReleaseDispatcherDatabaseLock(OldIrql);
1058
1059 } else {
1060
1061 /* We need to dispatch a new thread */
1062 CurrentThread->WaitIrql = OldIrql;
1063 KiDispatchThreadNoLock(Ready);
1064 KeLowerIrql(OldIrql);
1065 }
1066 }
1067
1068 LONG
1069 STDCALL
1070 KeQueryBasePriorityThread(IN PKTHREAD Thread)
1071 {
1072 LONG BasePriorityIncrement;
1073 KIRQL OldIrql;
1074 PKPROCESS Process;
1075
1076 /* Lock the Dispatcher Database */
1077 OldIrql = KeAcquireDispatcherDatabaseLock();
1078
1079 /* Get the Process */
1080 Process = Thread->ApcStatePointer[0]->Process;
1081
1082 /* Calculate the BPI */
1083 BasePriorityIncrement = Thread->BasePriority - Process->BasePriority;
1084
1085 /* If saturation occured, return the SI instead */
1086 if (Thread->Saturation) BasePriorityIncrement = (HIGH_PRIORITY + 1) / 2 *
1087 Thread->Saturation;
1088
1089 /* Release Lock */
1090 KeReleaseDispatcherDatabaseLock(OldIrql);
1091
1092 /* Return Increment */
1093 return BasePriorityIncrement;
1094 }
1095
1096 VOID
1097 STDCALL
1098 KiSetPriorityThread(PKTHREAD Thread,
1099 KPRIORITY Priority,
1100 PBOOLEAN Released)
1101 {
1102 KPRIORITY OldPriority = Thread->Priority;
1103 ULONG Mask;
1104 int i;
1105 PKPCR Pcr;
1106 DPRINT("Changing prio to : %lx\n", Priority);
1107
1108 /* Check if priority changed */
1109 if (OldPriority != Priority)
1110 {
1111 /* Set it */
1112 Thread->Priority = Priority;
1113
1114 /* Choose action based on thread's state */
1115 if (Thread->State == Ready)
1116 {
1117 /* Remove it from the current queue */
1118 KiRemoveFromThreadList(Thread);
1119
1120 /* Re-insert it at its current priority */
1121 KiInsertIntoThreadList(Priority, Thread);
1122
1123 /* Check if the old priority was lower */
1124 if (KeGetCurrentThread()->Priority < Priority)
1125 {
1126 /* Dispatch it immediately */
1127 KiDispatchThreadNoLock(Ready);
1128 *Released = TRUE;
1129 return;
1130 }
1131 }
1132 else if (Thread->State == Running)
1133 {
1134 /* Check if the new priority is lower */
1135 if (Priority < OldPriority)
1136 {
1137 /* Check for threads with a higher priority */
1138 Mask = ~((1 << (Priority + 1)) - 1);
1139 if (PriorityListMask & Mask)
1140 {
1141 /* Found a thread, is it us? */
1142 if (Thread == KeGetCurrentThread())
1143 {
1144 /* Dispatch us */
1145 KiDispatchThreadNoLock(Ready);
1146 *Released = TRUE;
1147 return;
1148 }
1149 else
1150 {
1151 /* Loop every CPU */
1152 for (i = 0; i < KeNumberProcessors; i++)
1153 {
1154 /* Get the PCR for this CPU */
1155 Pcr = (PKPCR)(KPCR_BASE + i * PAGE_SIZE);
1156
1157 /* Reschedule if the new one is already on a CPU */
1158 if (Pcr->Prcb->CurrentThread == Thread)
1159 {
1160 KeReleaseDispatcherDatabaseLockFromDpcLevel();
1161 KiRequestReschedule(i);
1162 *Released = TRUE;
1163 return;
1164 }
1165 }
1166 }
1167 }
1168 }
1169 }
1170 }
1171
1172 /* Return to caller */
1173 return;
1174 }
1175
1176 /*
1177 * Sets thread's base priority relative to the process' base priority
1178 * Should only be passed in THREAD_PRIORITY_ constants in pstypes.h
1179 *
1180 * @implemented
1181 */
1182 LONG
1183 STDCALL
1184 KeSetBasePriorityThread (PKTHREAD Thread,
1185 LONG Increment)
1186 {
1187 KIRQL OldIrql;
1188 PKPROCESS Process;
1189 KPRIORITY Priority;
1190 KPRIORITY CurrentBasePriority;
1191 KPRIORITY BasePriority;
1192 BOOLEAN Released = FALSE;
1193 LONG CurrentIncrement;
1194
1195 /* Lock the Dispatcher Database */
1196 OldIrql = KeAcquireDispatcherDatabaseLock();
1197
1198 /* Get the process and calculate current BP and BPI */
1199 Process = Thread->ApcStatePointer[0]->Process;
1200 CurrentBasePriority = Thread->BasePriority;
1201 CurrentIncrement = CurrentBasePriority - Process->BasePriority;
1202
1203 /* Change to use the SI if Saturation was used */
1204 if (Thread->Saturation) CurrentIncrement = (HIGH_PRIORITY + 1) / 2 *
1205 Thread->Saturation;
1206
1207 /* Now check if saturation is being used for the new value */
1208 if (abs(Increment) >= ((HIGH_PRIORITY + 1) / 2))
1209 {
1210 /* Check if we need positive or negative saturation */
1211 Thread->Saturation = (Increment > 0) ? 1 : -1;
1212 }
1213
1214 /* Normalize the Base Priority */
1215 BasePriority = Process->BasePriority + Increment;
1216 if (Process->BasePriority >= LOW_REALTIME_PRIORITY)
1217 {
1218 /* Check if it's too low */
1219 if (BasePriority < LOW_REALTIME_PRIORITY)
1220 BasePriority = LOW_REALTIME_PRIORITY;
1221
1222 /* Check if it's too high */
1223 if (BasePriority > HIGH_PRIORITY) BasePriority = HIGH_PRIORITY;
1224
1225 /* We are at RTP, so use the raw BP */
1226 Priority = BasePriority;
1227 }
1228 else
1229 {
1230 /* Check if it's entering RTP */
1231 if (BasePriority >= LOW_REALTIME_PRIORITY)
1232 BasePriority = LOW_REALTIME_PRIORITY - 1;
1233
1234 /* Check if it's too low */
1235 if (BasePriority <= LOW_PRIORITY)
1236 BasePriority = 1;
1237
1238 /* If Saturation is used, then use the raw BP */
1239 if (Thread->Saturation)
1240 {
1241 Priority = BasePriority;
1242 }
1243 else
1244 {
1245 /* Calculate the new priority */
1246 Priority = Thread->Priority + (BasePriority - CurrentBasePriority)-
1247 Thread->PriorityDecrement;
1248
1249 /* Make sure it won't enter RTP ranges */
1250 if (Priority >= LOW_REALTIME_PRIORITY)
1251 Priority = LOW_REALTIME_PRIORITY - 1;
1252 }
1253 }
1254
1255 /* Finally set the new base priority */
1256 Thread->BasePriority = BasePriority;
1257
1258 /* Reset the decrements */
1259 Thread->DecrementCount = 0;
1260 Thread->PriorityDecrement = 0;
1261
1262 /* If the priority will change, reset quantum and change it for real */
1263 if (Priority != Thread->Priority)
1264 {
1265 Thread->Quantum = Thread->QuantumReset;
1266 KiSetPriorityThread(Thread, Priority, &Released);
1267 }
1268
1269 /* Release Lock if needed */
1270 if (!Released)
1271 {
1272 KeReleaseDispatcherDatabaseLock(OldIrql);
1273 }
1274 else
1275 {
1276 KeLowerIrql(OldIrql);
1277 }
1278
1279 /* Return the Old Increment */
1280 return CurrentIncrement;
1281 }
1282
1283 /*
1284 * @implemented
1285 */
1286 KPRIORITY
1287 STDCALL
1288 KeSetPriorityThread(PKTHREAD Thread,
1289 KPRIORITY Priority)
1290 {
1291 KPRIORITY OldPriority;
1292 BOOLEAN Released = FALSE;
1293 KIRQL OldIrql;
1294
1295 /* Lock the Dispatcher Database */
1296 OldIrql = KeAcquireDispatcherDatabaseLock();
1297
1298 /* Save the old Priority */
1299 OldPriority = Thread->Priority;
1300
1301 /* Reset the Quantum and Decrements */
1302 Thread->Quantum = Thread->QuantumReset;
1303 Thread->DecrementCount = 0;
1304 Thread->PriorityDecrement = 0;
1305
1306 /* Set the new Priority */
1307 KiSetPriorityThread(Thread, Priority, &Released);
1308
1309 /* Release Lock if needed */
1310 if (!Released)
1311 {
1312 KeReleaseDispatcherDatabaseLock(OldIrql);
1313 }
1314 else
1315 {
1316 KeLowerIrql(OldIrql);
1317 }
1318
1319 /* Return Old Priority */
1320 return OldPriority;
1321 }
1322
1323 /*
1324 * @implemented
1325 *
1326 * Sets thread's affinity
1327 */
1328 NTSTATUS
1329 STDCALL
1330 KeSetAffinityThread(PKTHREAD Thread,
1331 KAFFINITY Affinity)
1332 {
1333 KIRQL OldIrql;
1334 LONG i;
1335 PKPCR Pcr;
1336 KAFFINITY ProcessorMask;
1337
1338 DPRINT("KeSetAffinityThread(Thread %x, Affinity %x)\n", Thread, Affinity);
1339
1340 /* Verify correct affinity */
1341 if ((Affinity & Thread->ApcStatePointer[0]->Process->Affinity) !=
1342 Affinity || !Affinity)
1343 {
1344 KEBUGCHECK(INVALID_AFFINITY_SET);
1345 }
1346
1347 OldIrql = KeAcquireDispatcherDatabaseLock();
1348
1349 Thread->UserAffinity = Affinity;
1350
1351 if (Thread->SystemAffinityActive == FALSE) {
1352
1353 Thread->Affinity = Affinity;
1354
1355 if (Thread->State == Running) {
1356
1357 ProcessorMask = 1 << KeGetCurrentKPCR()->Number;
1358 if (Thread == KeGetCurrentThread()) {
1359
1360 if (!(Affinity & ProcessorMask)) {
1361
1362 KiDispatchThreadNoLock(Ready);
1363 KeLowerIrql(OldIrql);
1364 return STATUS_SUCCESS;
1365 }
1366
1367 } else {
1368
1369 for (i = 0; i < KeNumberProcessors; i++) {
1370
1371 Pcr = (PKPCR)(KPCR_BASE + i * PAGE_SIZE);
1372 if (Pcr->Prcb->CurrentThread == Thread) {
1373
1374 if (!(Affinity & ProcessorMask)) {
1375
1376 KeReleaseDispatcherDatabaseLockFromDpcLevel();
1377 KiRequestReschedule(i);
1378 KeLowerIrql(OldIrql);
1379 return STATUS_SUCCESS;
1380 }
1381
1382 break;
1383 }
1384 }
1385
1386 ASSERT (i < KeNumberProcessors);
1387 }
1388 }
1389 }
1390
1391 KeReleaseDispatcherDatabaseLock(OldIrql);
1392 return STATUS_SUCCESS;
1393 }
1394
1395 /*
1396 * @implemented
1397 */
1398 /* The Increment Argument seems to be ignored by NT and always 0 when called */
1399 VOID
1400 STDCALL
1401 KeTerminateThread(IN KPRIORITY Increment)
1402 {
1403 KIRQL OldIrql;
1404 PKTHREAD Thread = KeGetCurrentThread();
1405
1406 /* Lock the Dispatcher Database and the APC Queue */
1407 DPRINT("Terminating\n");
1408 OldIrql = KeAcquireDispatcherDatabaseLock();
1409
1410 /* Remove the thread from the list */
1411 RemoveEntryList(&Thread->ThreadListEntry);
1412
1413 /* Insert into the Reaper List */
1414 DPRINT("List: %p\n", PspReaperList);
1415 ((PETHREAD)Thread)->ReaperLink = PspReaperList;
1416 PspReaperList = (PETHREAD)Thread;
1417 DPRINT("List: %p\n", PspReaperList);
1418
1419 /* Check if it's active */
1420 if (PspReaping == FALSE) {
1421
1422 /* Activate it. We use the internal function for speed, and use the Hyper Critical Queue */
1423 PspReaping = TRUE;
1424 DPRINT("Terminating\n");
1425 KiInsertQueue(&ExWorkerQueue[HyperCriticalWorkQueue].WorkerQueue,
1426 &PspReaperWorkItem.List,
1427 FALSE);
1428 }
1429
1430 /* Handle Kernel Queues */
1431 if (Thread->Queue) {
1432
1433 DPRINT("Waking Queue\n");
1434 RemoveEntryList(&Thread->QueueListEntry);
1435 KiWakeQueue(Thread->Queue);
1436 }
1437
1438 /* Signal the thread */
1439 Thread->DispatcherHeader.SignalState = TRUE;
1440 if (IsListEmpty(&Thread->DispatcherHeader.WaitListHead) != TRUE) {
1441
1442 /* Satisfy waits */
1443 KiWaitTest((PVOID)Thread, Increment);
1444 }
1445
1446 /* Find a new Thread */
1447 KiDispatchThreadNoLock(Terminated);
1448 }
1449
1450 /*
1451 * FUNCTION: Tests whether there are any pending APCs for the current thread
1452 * and if so the APCs will be delivered on exit from kernel mode
1453 */
1454 BOOLEAN
1455 STDCALL
1456 KeTestAlertThread(IN KPROCESSOR_MODE AlertMode)
1457 {
1458 KIRQL OldIrql;
1459 PKTHREAD Thread = KeGetCurrentThread();
1460 BOOLEAN OldState;
1461
1462 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
1463
1464 /* Lock the Dispatcher Database and the APC Queue */
1465 OldIrql = KeAcquireDispatcherDatabaseLock();
1466 KiAcquireSpinLock(&Thread->ApcQueueLock);
1467
1468 /* Save the old State */
1469 OldState = Thread->Alerted[AlertMode];
1470
1471 /* If the Thread is Alerted, Clear it */
1472 if (OldState) {
1473
1474 Thread->Alerted[AlertMode] = FALSE;
1475
1476 } else if ((AlertMode != KernelMode) && (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))) {
1477
1478 /* If the mode is User and the Queue isn't empty, set Pending */
1479 Thread->ApcState.UserApcPending = TRUE;
1480 }
1481
1482 /* Release Locks and return the Old State */
1483 KiReleaseSpinLock(&Thread->ApcQueueLock);
1484 KeReleaseDispatcherDatabaseLock(OldIrql);
1485 return OldState;
1486 }
1487
1488 VOID
1489 KiServiceCheck (VOID)
1490 {
1491 PKTHREAD Thread = KeGetCurrentThread();
1492
1493 /* Check if we need to inialize Win32 for this Thread */
1494 if (Thread->ServiceTable != KeServiceDescriptorTableShadow) {
1495
1496 /* We do. Initialize it and save the new table */
1497 Thread->ServiceTable = KeServiceDescriptorTableShadow;
1498 PsInitWin32Thread((PETHREAD)Thread);
1499 }
1500 }
1501
1502 /*
1503 *
1504 * NOT EXPORTED
1505 */
1506 NTSTATUS
1507 STDCALL
1508 NtAlertResumeThread(IN HANDLE ThreadHandle,
1509 OUT PULONG SuspendCount)
1510 {
1511 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1512 PETHREAD Thread;
1513 NTSTATUS Status;
1514 ULONG PreviousState;
1515
1516 /* Check if parameters are valid */
1517 if(PreviousMode != KernelMode) {
1518
1519 _SEH_TRY {
1520
1521 ProbeForWriteUlong(SuspendCount);
1522
1523 } _SEH_HANDLE {
1524
1525 Status = _SEH_GetExceptionCode();
1526
1527 } _SEH_END;
1528 }
1529
1530 /* Reference the Object */
1531 Status = ObReferenceObjectByHandle(ThreadHandle,
1532 THREAD_SUSPEND_RESUME,
1533 PsThreadType,
1534 PreviousMode,
1535 (PVOID*)&Thread,
1536 NULL);
1537
1538 /* Check for Success */
1539 if (NT_SUCCESS(Status)) {
1540
1541 /* Call the Kernel Function */
1542 PreviousState = KeAlertResumeThread(&Thread->Tcb);
1543
1544 /* Dereference Object */
1545 ObDereferenceObject(Thread);
1546
1547 if (SuspendCount) {
1548
1549 _SEH_TRY {
1550
1551 *SuspendCount = PreviousState;
1552
1553 } _SEH_HANDLE {
1554
1555 Status = _SEH_GetExceptionCode();
1556
1557 } _SEH_END;
1558 }
1559 }
1560
1561 /* Return status */
1562 return Status;
1563 }
1564
1565 /*
1566 * @implemented
1567 *
1568 * EXPORTED
1569 */
1570 NTSTATUS
1571 STDCALL
1572 NtAlertThread (IN HANDLE ThreadHandle)
1573 {
1574 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1575 PETHREAD Thread;
1576 NTSTATUS Status;
1577
1578 /* Reference the Object */
1579 Status = ObReferenceObjectByHandle(ThreadHandle,
1580 THREAD_SUSPEND_RESUME,
1581 PsThreadType,
1582 PreviousMode,
1583 (PVOID*)&Thread,
1584 NULL);
1585
1586 /* Check for Success */
1587 if (NT_SUCCESS(Status)) {
1588
1589 /*
1590 * Do an alert depending on the processor mode. If some kmode code wants to
1591 * enforce a umode alert it should call KeAlertThread() directly. If kmode
1592 * code wants to do a kmode alert it's sufficient to call it with Zw or just
1593 * use KeAlertThread() directly
1594 */
1595 KeAlertThread(&Thread->Tcb, PreviousMode);
1596
1597 /* Dereference Object */
1598 ObDereferenceObject(Thread);
1599 }
1600
1601 /* Return status */
1602 return Status;
1603 }
1604
1605 NTSTATUS
1606 STDCALL
1607 NtDelayExecution(IN BOOLEAN Alertable,
1608 IN PLARGE_INTEGER DelayInterval)
1609 {
1610 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1611 LARGE_INTEGER SafeInterval;
1612 NTSTATUS Status;
1613
1614 /* Check if parameters are valid */
1615 if(PreviousMode != KernelMode) {
1616
1617 Status = STATUS_SUCCESS;
1618
1619 _SEH_TRY {
1620
1621 /* make a copy on the kernel stack and let DelayInterval point to it so
1622 we don't need to wrap KeDelayExecutionThread in SEH! */
1623 SafeInterval = ProbeForReadLargeInteger(DelayInterval);
1624 DelayInterval = &SafeInterval;
1625
1626 } _SEH_HANDLE {
1627
1628 Status = _SEH_GetExceptionCode();
1629 } _SEH_END;
1630
1631 if (!NT_SUCCESS(Status))
1632 {
1633 return Status;
1634 }
1635 }
1636
1637 /* Call the Kernel Function */
1638 Status = KeDelayExecutionThread(PreviousMode,
1639 Alertable,
1640 DelayInterval);
1641
1642 /* Return Status */
1643 return Status;
1644 }