5cb0e1e339896a07f1a8cd81955be9ae5bfcb01b
[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",
477 Mutant,
478 Mutant->Header.Type,
479 Mutant->Header.Size);
480
481 /* Make sure it's not terminating with APCs off */
482 if (Mutant->ApcDisable)
483 {
484 /* Bugcheck the system */
485 KEBUGCHECKEX(0,//THREAD_TERMINATE_HELD_MUTEX,
486 (ULONG_PTR)Thread,
487 (ULONG_PTR)Mutant,
488 0,
489 0);
490 }
491
492 /* Now we can remove it */
493 RemoveEntryList(&Mutant->MutantListEntry);
494
495 /* Unconditionally abandon it */
496 DPRINT("Abandonning the Mutant\n");
497 Mutant->Header.SignalState = 1;
498 Mutant->Abandoned = TRUE;
499 Mutant->OwnerThread = NULL;
500
501 /* Check if the Wait List isn't empty */
502 DPRINT("Checking whether to wake the Mutant\n");
503 if (!IsListEmpty(&Mutant->Header.WaitListHead))
504 {
505 /* Wake the Mutant */
506 DPRINT("Waking the Mutant\n");
507 KiWaitTest(&Mutant->Header, MUTANT_INCREMENT);
508 }
509
510 /* Move on */
511 NextEntry = NextEntry->Flink;
512 }
513
514 /* Release the Lock */
515 KeReleaseDispatcherDatabaseLock(OldIrql);
516 }
517
518 ULONG
519 STDCALL
520 KeResumeThread(PKTHREAD Thread)
521 {
522 ULONG PreviousCount;
523 KIRQL OldIrql;
524
525 DPRINT("KeResumeThread (Thread %p called). %x, %x\n", Thread,
526 Thread->SuspendCount, Thread->FreezeCount);
527
528 /* Lock the Dispatcher */
529 OldIrql = KeAcquireDispatcherDatabaseLock();
530
531 /* Save the Old Count */
532 PreviousCount = Thread->SuspendCount;
533
534 /* Check if it existed */
535 if (PreviousCount) {
536
537 Thread->SuspendCount--;
538
539 /* Decrease the current Suspend Count and Check Freeze Count */
540 if ((!Thread->SuspendCount) && (!Thread->FreezeCount)) {
541
542 /* Signal the Suspend Semaphore */
543 Thread->SuspendSemaphore.Header.SignalState++;
544 KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT);
545 }
546 }
547
548 /* Release Lock and return the Old State */
549 KeReleaseDispatcherDatabaseLock(OldIrql);
550 return PreviousCount;
551 }
552
553 VOID
554 FASTCALL
555 KiInsertQueueApc(PKAPC Apc,
556 KPRIORITY PriorityBoost);
557
558 /*
559 * Used by the debugging code to freeze all the process's threads
560 * while the debugger is examining their state.
561 */
562 VOID
563 STDCALL
564 KeFreezeAllThreads(PKPROCESS Process)
565 {
566 KIRQL OldIrql;
567 PKTHREAD Current;
568 PKTHREAD CurrentThread = KeGetCurrentThread();
569
570 /* Acquire Lock */
571 OldIrql = KeAcquireDispatcherDatabaseLock();
572
573 /* If someone is already trying to free us, try again */
574 while (CurrentThread->FreezeCount)
575 {
576 /* Release and re-acquire the lock so the APC will go through */
577 KeReleaseDispatcherDatabaseLock(OldIrql);
578 OldIrql = KeAcquireDispatcherDatabaseLock();
579 }
580
581 /* Enter a critical region */
582 KeEnterCriticalRegion();
583
584 /* Loop the Process's Threads */
585 LIST_FOR_EACH(Current, &Process->ThreadListHead, KTHREAD, ThreadListEntry)
586 {
587 /* Make sure it's not ours */
588 if (Current != CurrentThread)
589 {
590 /* Should be bother inserting the APC? */
591 if (Current->ApcQueueable)
592 {
593 /* Make sure it wasn't already frozen, and that it's not suspended */
594 if (!(++Current->FreezeCount) && !(Current->SuspendCount))
595 {
596 /* Did we already insert it? */
597 if (!Current->SuspendApc.Inserted)
598 {
599 /* Insert the APC */
600 Current->SuspendApc.Inserted = TRUE;
601 KiInsertQueueApc(&Current->SuspendApc, IO_NO_INCREMENT);
602 }
603 else
604 {
605 /* Unsignal the Semaphore, the APC already got inserted */
606 Current->SuspendSemaphore.Header.SignalState--;
607 }
608 }
609 }
610 }
611 }
612
613 /* Release the lock */
614 KeReleaseDispatcherDatabaseLock(OldIrql);
615 }
616
617 NTSTATUS
618 STDCALL
619 KeSuspendThread(PKTHREAD Thread)
620 {
621 ULONG PreviousCount;
622 KIRQL OldIrql;
623
624 DPRINT("KeSuspendThread (Thread %p called). %x, %x\n", Thread, Thread->SuspendCount, Thread->FreezeCount);
625
626 /* Lock the Dispatcher */
627 OldIrql = KeAcquireDispatcherDatabaseLock();
628
629 /* Save the Old Count */
630 PreviousCount = Thread->SuspendCount;
631
632 /* Handle the maximum */
633 if (PreviousCount == MAXIMUM_SUSPEND_COUNT)
634 {
635 /* Raise an exception */
636 KeReleaseDispatcherDatabaseLock(OldIrql);
637 RtlRaiseStatus(STATUS_SUSPEND_COUNT_EXCEEDED);
638 }
639
640 /* Should we bother to queue at all? */
641 if (Thread->ApcQueueable)
642 {
643 /* Increment the suspend count */
644 Thread->SuspendCount++;
645
646 /* Check if we should suspend it */
647 if (!PreviousCount && !Thread->FreezeCount)
648 {
649 /* Is the APC already inserted? */
650 if (!Thread->SuspendApc.Inserted)
651 {
652 /* Not inserted, insert it */
653 Thread->SuspendApc.Inserted = TRUE;
654 KiInsertQueueApc(&Thread->SuspendApc, IO_NO_INCREMENT);
655 }
656 else
657 {
658 /* Unsignal the Semaphore, the APC already got inserted */
659 Thread->SuspendSemaphore.Header.SignalState--;
660 }
661 }
662 }
663
664 /* Release Lock and return the Old State */
665 KeReleaseDispatcherDatabaseLock(OldIrql);
666 return PreviousCount;
667 }
668
669 ULONG
670 STDCALL
671 KeForceResumeThread(IN PKTHREAD Thread)
672 {
673 KIRQL OldIrql;
674 ULONG PreviousCount;
675
676 /* Lock the Dispatcher Database and the APC Queue */
677 OldIrql = KeAcquireDispatcherDatabaseLock();
678
679 /* Save the old Suspend Count */
680 PreviousCount = Thread->SuspendCount + Thread->FreezeCount;
681
682 /* If the thread is suspended, wake it up!!! */
683 if (PreviousCount) {
684
685 /* Unwait it completely */
686 Thread->SuspendCount = 0;
687 Thread->FreezeCount = 0;
688
689 /* Signal and satisfy */
690 Thread->SuspendSemaphore.Header.SignalState++;
691 KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT);
692 }
693
694 /* Release Lock and return the Old State */
695 KeReleaseDispatcherDatabaseLock(OldIrql);
696 return PreviousCount;
697 }
698
699 ULONG
700 STDCALL
701 KeAlertResumeThread(IN PKTHREAD Thread)
702 {
703 ULONG PreviousCount;
704 KIRQL OldIrql;
705
706 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
707
708 /* Lock the Dispatcher Database and the APC Queue */
709 OldIrql = KeAcquireDispatcherDatabaseLock();
710 KiAcquireSpinLock(&Thread->ApcQueueLock);
711
712 /* Return if Thread is already alerted. */
713 if (Thread->Alerted[KernelMode] == FALSE) {
714
715 /* If it's Blocked, unblock if it we should */
716 if (Thread->State == Waiting && Thread->Alertable) {
717
718 DPRINT("Aborting Wait\n");
719 KiAbortWaitThread(Thread, STATUS_ALERTED, THREAD_ALERT_INCREMENT);
720
721 } else {
722
723 /* If not, simply Alert it */
724 Thread->Alerted[KernelMode] = TRUE;
725 }
726 }
727
728 /* Save the old Suspend Count */
729 PreviousCount = Thread->SuspendCount;
730
731 /* If the thread is suspended, decrease one of the suspend counts */
732 if (PreviousCount) {
733
734 /* Decrease count. If we are now zero, unwait it completely */
735 if (--Thread->SuspendCount) {
736
737 /* Signal and satisfy */
738 Thread->SuspendSemaphore.Header.SignalState++;
739 KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT);
740 }
741 }
742
743 /* Release Locks and return the Old State */
744 KiReleaseSpinLock(&Thread->ApcQueueLock);
745 KeReleaseDispatcherDatabaseLock(OldIrql);
746 return PreviousCount;
747 }
748
749 BOOLEAN
750 STDCALL
751 KeAlertThread(PKTHREAD Thread,
752 KPROCESSOR_MODE AlertMode)
753 {
754 KIRQL OldIrql;
755 BOOLEAN PreviousState;
756
757 /* Acquire the Dispatcher Database Lock */
758 OldIrql = KeAcquireDispatcherDatabaseLock();
759
760 /* Save the Previous State */
761 PreviousState = Thread->Alerted[AlertMode];
762
763 /* Return if Thread is already alerted. */
764 if (PreviousState == FALSE) {
765
766 /* If it's Blocked, unblock if it we should */
767 if (Thread->State == Waiting &&
768 (AlertMode == KernelMode || Thread->WaitMode == AlertMode) &&
769 Thread->Alertable) {
770
771 DPRINT("Aborting Wait\n");
772 KiAbortWaitThread(Thread, STATUS_ALERTED, THREAD_ALERT_INCREMENT);
773
774 } else {
775
776 /* If not, simply Alert it */
777 Thread->Alerted[AlertMode] = TRUE;
778 }
779 }
780
781 /* Release the Dispatcher Lock */
782 KeReleaseDispatcherDatabaseLock(OldIrql);
783
784 /* Return the old state */
785 return PreviousState;
786 }
787
788 /*
789 * @unimplemented
790 */
791 VOID
792 STDCALL
793 KeCapturePersistentThreadState(IN PVOID CurrentThread,
794 IN ULONG Setting1,
795 IN ULONG Setting2,
796 IN ULONG Setting3,
797 IN ULONG Setting4,
798 IN ULONG Setting5,
799 IN PVOID ThreadState)
800 {
801 UNIMPLEMENTED;
802 }
803
804 /*
805 * FUNCTION: Initialize the microkernel state of the thread
806 */
807 VOID
808 STDCALL
809 KeInitializeThread(PKPROCESS Process,
810 PKTHREAD Thread,
811 PKSYSTEM_ROUTINE SystemRoutine,
812 PKSTART_ROUTINE StartRoutine,
813 PVOID StartContext,
814 PCONTEXT Context,
815 PVOID Teb,
816 PVOID KernelStack)
817 {
818 /* Initalize the Dispatcher Header */
819 DPRINT("Initializing Dispatcher Header for New Thread: %x in Process: %x\n", Thread, Process);
820 KeInitializeDispatcherHeader(&Thread->DispatcherHeader,
821 ThreadObject,
822 sizeof(KTHREAD),
823 FALSE);
824
825 DPRINT("Thread Header Created. SystemRoutine: %x, StartRoutine: %x with Context: %x\n",
826 SystemRoutine, StartRoutine, StartContext);
827 DPRINT("UserMode Information. Context: %x, Teb: %x\n", Context, Teb);
828
829 /* Initialize the Mutant List */
830 InitializeListHead(&Thread->MutantListHead);
831
832 /* Setup the Service Descriptor Table for Native Calls */
833 Thread->ServiceTable = KeServiceDescriptorTable;
834
835 /* Setup APC Fields */
836 InitializeListHead(&Thread->ApcState.ApcListHead[0]);
837 InitializeListHead(&Thread->ApcState.ApcListHead[1]);
838 Thread->ApcState.Process = Process;
839 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState;
840 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState;
841 Thread->ApcStateIndex = OriginalApcEnvironment;
842 KeInitializeSpinLock(&Thread->ApcQueueLock);
843
844 /* Initialize the Suspend APC */
845 KeInitializeApc(&Thread->SuspendApc,
846 Thread,
847 OriginalApcEnvironment,
848 KiSuspendThreadKernelRoutine,
849 NULL,
850 KiSuspendThreadNormalRoutine,
851 KernelMode,
852 NULL);
853
854 /* Initialize the Suspend Semaphore */
855 KeInitializeSemaphore(&Thread->SuspendSemaphore, 0, 128);
856
857 /* FIXME OPTIMIZATION OF DOOM. DO NOT ENABLE FIXME */
858 #if 0
859 Thread->WaitBlock[3].Object = (PVOID)&Thread->Timer;
860 Thread->WaitBlock[3].Thread = Thread;
861 Thread->WaitBlock[3].WaitKey = STATUS_TIMEOUT;
862 Thread->WaitBlock[3].WaitType = WaitAny;
863 Thread->WaitBlock[3].NextWaitBlock = NULL;
864 InsertTailList(&Thread->Timer.Header.WaitListHead,
865 &Thread->WaitBlock[3].WaitListEntry);
866 #endif
867 KeInitializeTimer(&Thread->Timer);
868
869 /* Set the TEB */
870 Thread->Teb = Teb;
871
872 /* Set the Thread Stacks */
873 Thread->InitialStack = (PCHAR)KernelStack + MM_STACK_SIZE;
874 Thread->StackBase = (PCHAR)KernelStack + MM_STACK_SIZE;
875 Thread->StackLimit = (ULONG_PTR)KernelStack;
876 Thread->KernelStackResident = TRUE;
877
878 /*
879 * Establish the pde's for the new stack and the thread structure within the
880 * address space of the new process. They are accessed while taskswitching or
881 * while handling page faults. At this point it isn't possible to call the
882 * page fault handler for the missing pde's.
883 */
884 MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread->StackLimit, MM_STACK_SIZE);
885 MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread, sizeof(ETHREAD));
886
887 /* Initalize the Thread Context */
888 DPRINT("Initializing the Context for the thread: %x\n", Thread);
889 KiArchInitThreadWithContext(Thread,
890 SystemRoutine,
891 StartRoutine,
892 StartContext,
893 Context);
894
895 /* Setup scheduler Fields based on Parent */
896 DPRINT("Thread context created, setting Scheduler Data\n");
897 Thread->BasePriority = Process->BasePriority;
898 Thread->Quantum = Process->QuantumReset;
899 Thread->QuantumReset = Process->QuantumReset;
900 Thread->Affinity = Process->Affinity;
901 Thread->Priority = Process->BasePriority;
902 Thread->UserAffinity = Process->Affinity;
903 Thread->DisableBoost = Process->DisableBoost;
904 Thread->AutoAlignment = Process->AutoAlignment;
905 Thread->Iopl = Process->Iopl;
906
907 /* Set the Thread to initalized */
908 Thread->State = Initialized;
909
910 /*
911 * Insert the Thread into the Process's Thread List
912 * Note, this is the KTHREAD Thread List. It is removed in
913 * ke/kthread.c!KeTerminateThread.
914 */
915 InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry);
916 DPRINT("Thread initalized\n");
917 }
918
919
920 /*
921 * @implemented
922 */
923 KPRIORITY
924 STDCALL
925 KeQueryPriorityThread (IN PKTHREAD Thread)
926 {
927 return Thread->Priority;
928 }
929
930 /*
931 * @implemented
932 */
933 ULONG
934 STDCALL
935 KeQueryRuntimeThread(IN PKTHREAD Thread,
936 OUT PULONG UserTime)
937 {
938 /* Return the User Time */
939 *UserTime = Thread->UserTime;
940
941 /* Return the Kernel Time */
942 return Thread->KernelTime;
943 }
944
945 /*
946 * @implemented
947 */
948 BOOLEAN
949 STDCALL
950 KeSetKernelStackSwapEnable(IN BOOLEAN Enable)
951 {
952 PKTHREAD Thread = KeGetCurrentThread();
953 BOOLEAN PreviousState;
954 KIRQL OldIrql;
955
956 /* Lock the Dispatcher Database */
957 OldIrql = KeAcquireDispatcherDatabaseLock();
958
959 /* Save Old State */
960 PreviousState = Thread->EnableStackSwap;
961
962 /* Set New State */
963 Thread->EnableStackSwap = Enable;
964
965 /* No, Release Lock */
966 KeReleaseDispatcherDatabaseLock(OldIrql);
967
968 /* Return Old State */
969 return PreviousState;
970 }
971
972 /*
973 * @implemented
974 */
975 VOID
976 STDCALL
977 KeRevertToUserAffinityThread(VOID)
978 {
979 PKTHREAD CurrentThread = KeGetCurrentThread();
980 KIRQL OldIrql;
981
982 ASSERT(CurrentThread->SystemAffinityActive != FALSE);
983
984 /* Lock the Dispatcher Database */
985 OldIrql = KeAcquireDispatcherDatabaseLock();
986
987 /* Return to User Affinity */
988 CurrentThread->Affinity = CurrentThread->UserAffinity;
989
990 /* Disable System Affinity */
991 CurrentThread->SystemAffinityActive = FALSE;
992
993 /* Check if we need to Dispatch a New thread */
994 if (CurrentThread->Affinity & (1 << KeGetCurrentProcessorNumber())) {
995
996 /* No, just release */
997 KeReleaseDispatcherDatabaseLock(OldIrql);
998
999 } else {
1000
1001 /* We need to dispatch a new thread */
1002 CurrentThread->WaitIrql = OldIrql;
1003 KiDispatchThreadNoLock(Ready);
1004 KeLowerIrql(OldIrql);
1005 }
1006 }
1007
1008 /*
1009 * @implemented
1010 */
1011 CCHAR
1012 STDCALL
1013 KeSetIdealProcessorThread(IN PKTHREAD Thread,
1014 IN CCHAR Processor)
1015 {
1016 CCHAR PreviousIdealProcessor;
1017 KIRQL OldIrql;
1018
1019 /* Lock the Dispatcher Database */
1020 OldIrql = KeAcquireDispatcherDatabaseLock();
1021
1022 /* Save Old Ideal Processor */
1023 PreviousIdealProcessor = Thread->IdealProcessor;
1024
1025 /* Set New Ideal Processor */
1026 Thread->IdealProcessor = Processor;
1027
1028 /* Release Lock */
1029 KeReleaseDispatcherDatabaseLock(OldIrql);
1030
1031 /* Return Old Ideal Processor */
1032 return PreviousIdealProcessor;
1033 }
1034
1035 /*
1036 * @implemented
1037 */
1038 VOID
1039 STDCALL
1040 KeSetSystemAffinityThread(IN KAFFINITY Affinity)
1041 {
1042 PKTHREAD CurrentThread = KeGetCurrentThread();
1043 KIRQL OldIrql;
1044
1045 ASSERT(Affinity & ((1 << KeNumberProcessors) - 1));
1046
1047 /* Lock the Dispatcher Database */
1048 OldIrql = KeAcquireDispatcherDatabaseLock();
1049
1050 /* Set the System Affinity Specified */
1051 CurrentThread->Affinity = Affinity;
1052
1053 /* Enable System Affinity */
1054 CurrentThread->SystemAffinityActive = TRUE;
1055
1056 /* Check if we need to Dispatch a New thread */
1057 if (Affinity & (1 << KeGetCurrentProcessorNumber())) {
1058
1059 /* No, just release */
1060 KeReleaseDispatcherDatabaseLock(OldIrql);
1061
1062 } else {
1063
1064 /* We need to dispatch a new thread */
1065 CurrentThread->WaitIrql = OldIrql;
1066 KiDispatchThreadNoLock(Ready);
1067 KeLowerIrql(OldIrql);
1068 }
1069 }
1070
1071 LONG
1072 STDCALL
1073 KeQueryBasePriorityThread(IN PKTHREAD Thread)
1074 {
1075 LONG BasePriorityIncrement;
1076 KIRQL OldIrql;
1077 PKPROCESS Process;
1078
1079 /* Lock the Dispatcher Database */
1080 OldIrql = KeAcquireDispatcherDatabaseLock();
1081
1082 /* Get the Process */
1083 Process = Thread->ApcStatePointer[0]->Process;
1084
1085 /* Calculate the BPI */
1086 BasePriorityIncrement = Thread->BasePriority - Process->BasePriority;
1087
1088 /* If saturation occured, return the SI instead */
1089 if (Thread->Saturation) BasePriorityIncrement = (HIGH_PRIORITY + 1) / 2 *
1090 Thread->Saturation;
1091
1092 /* Release Lock */
1093 KeReleaseDispatcherDatabaseLock(OldIrql);
1094
1095 /* Return Increment */
1096 return BasePriorityIncrement;
1097 }
1098
1099 VOID
1100 STDCALL
1101 KiSetPriorityThread(PKTHREAD Thread,
1102 KPRIORITY Priority,
1103 PBOOLEAN Released)
1104 {
1105 KPRIORITY OldPriority = Thread->Priority;
1106 ULONG Mask;
1107 int i;
1108 PKPCR Pcr;
1109 DPRINT("Changing prio to : %lx\n", Priority);
1110
1111 /* Check if priority changed */
1112 if (OldPriority != Priority)
1113 {
1114 /* Set it */
1115 Thread->Priority = Priority;
1116
1117 /* Choose action based on thread's state */
1118 if (Thread->State == Ready)
1119 {
1120 /* Remove it from the current queue */
1121 KiRemoveFromThreadList(Thread);
1122
1123 /* Re-insert it at its current priority */
1124 KiInsertIntoThreadList(Priority, Thread);
1125
1126 /* Check if the old priority was lower */
1127 if (KeGetCurrentThread()->Priority < Priority)
1128 {
1129 /* Dispatch it immediately */
1130 KiDispatchThreadNoLock(Ready);
1131 *Released = TRUE;
1132 return;
1133 }
1134 }
1135 else if (Thread->State == Running)
1136 {
1137 /* Check if the new priority is lower */
1138 if (Priority < OldPriority)
1139 {
1140 /* Check for threads with a higher priority */
1141 Mask = ~((1 << (Priority + 1)) - 1);
1142 if (PriorityListMask & Mask)
1143 {
1144 /* Found a thread, is it us? */
1145 if (Thread == KeGetCurrentThread())
1146 {
1147 /* Dispatch us */
1148 KiDispatchThreadNoLock(Ready);
1149 *Released = TRUE;
1150 return;
1151 }
1152 else
1153 {
1154 /* Loop every CPU */
1155 for (i = 0; i < KeNumberProcessors; i++)
1156 {
1157 /* Get the PCR for this CPU */
1158 Pcr = (PKPCR)(KPCR_BASE + i * PAGE_SIZE);
1159
1160 /* Reschedule if the new one is already on a CPU */
1161 if (Pcr->Prcb->CurrentThread == Thread)
1162 {
1163 KeReleaseDispatcherDatabaseLockFromDpcLevel();
1164 KiRequestReschedule(i);
1165 *Released = TRUE;
1166 return;
1167 }
1168 }
1169 }
1170 }
1171 }
1172 }
1173 }
1174
1175 /* Return to caller */
1176 return;
1177 }
1178
1179 /*
1180 * Sets thread's base priority relative to the process' base priority
1181 * Should only be passed in THREAD_PRIORITY_ constants in pstypes.h
1182 *
1183 * @implemented
1184 */
1185 LONG
1186 STDCALL
1187 KeSetBasePriorityThread (PKTHREAD Thread,
1188 LONG Increment)
1189 {
1190 KIRQL OldIrql;
1191 PKPROCESS Process;
1192 KPRIORITY Priority;
1193 KPRIORITY CurrentBasePriority;
1194 KPRIORITY BasePriority;
1195 BOOLEAN Released = FALSE;
1196 LONG CurrentIncrement;
1197
1198 /* Lock the Dispatcher Database */
1199 OldIrql = KeAcquireDispatcherDatabaseLock();
1200
1201 /* Get the process and calculate current BP and BPI */
1202 Process = Thread->ApcStatePointer[0]->Process;
1203 CurrentBasePriority = Thread->BasePriority;
1204 CurrentIncrement = CurrentBasePriority - Process->BasePriority;
1205
1206 /* Change to use the SI if Saturation was used */
1207 if (Thread->Saturation) CurrentIncrement = (HIGH_PRIORITY + 1) / 2 *
1208 Thread->Saturation;
1209
1210 /* Now check if saturation is being used for the new value */
1211 if (abs(Increment) >= ((HIGH_PRIORITY + 1) / 2))
1212 {
1213 /* Check if we need positive or negative saturation */
1214 Thread->Saturation = (Increment > 0) ? 1 : -1;
1215 }
1216
1217 /* Normalize the Base Priority */
1218 BasePriority = Process->BasePriority + Increment;
1219 if (Process->BasePriority >= LOW_REALTIME_PRIORITY)
1220 {
1221 /* Check if it's too low */
1222 if (BasePriority < LOW_REALTIME_PRIORITY)
1223 BasePriority = LOW_REALTIME_PRIORITY;
1224
1225 /* Check if it's too high */
1226 if (BasePriority > HIGH_PRIORITY) BasePriority = HIGH_PRIORITY;
1227
1228 /* We are at RTP, so use the raw BP */
1229 Priority = BasePriority;
1230 }
1231 else
1232 {
1233 /* Check if it's entering RTP */
1234 if (BasePriority >= LOW_REALTIME_PRIORITY)
1235 BasePriority = LOW_REALTIME_PRIORITY - 1;
1236
1237 /* Check if it's too low */
1238 if (BasePriority <= LOW_PRIORITY)
1239 BasePriority = 1;
1240
1241 /* If Saturation is used, then use the raw BP */
1242 if (Thread->Saturation)
1243 {
1244 Priority = BasePriority;
1245 }
1246 else
1247 {
1248 /* Calculate the new priority */
1249 Priority = Thread->Priority + (BasePriority - CurrentBasePriority)-
1250 Thread->PriorityDecrement;
1251
1252 /* Make sure it won't enter RTP ranges */
1253 if (Priority >= LOW_REALTIME_PRIORITY)
1254 Priority = LOW_REALTIME_PRIORITY - 1;
1255 }
1256 }
1257
1258 /* Finally set the new base priority */
1259 Thread->BasePriority = BasePriority;
1260
1261 /* Reset the decrements */
1262 Thread->PriorityDecrement = 0;
1263
1264 /* If the priority will change, reset quantum and change it for real */
1265 if (Priority != Thread->Priority)
1266 {
1267 Thread->Quantum = Thread->QuantumReset;
1268 KiSetPriorityThread(Thread, Priority, &Released);
1269 }
1270
1271 /* Release Lock if needed */
1272 if (!Released)
1273 {
1274 KeReleaseDispatcherDatabaseLock(OldIrql);
1275 }
1276 else
1277 {
1278 KeLowerIrql(OldIrql);
1279 }
1280
1281 /* Return the Old Increment */
1282 return CurrentIncrement;
1283 }
1284
1285 /*
1286 * @implemented
1287 */
1288 KPRIORITY
1289 STDCALL
1290 KeSetPriorityThread(PKTHREAD Thread,
1291 KPRIORITY Priority)
1292 {
1293 KPRIORITY OldPriority;
1294 BOOLEAN Released = FALSE;
1295 KIRQL OldIrql;
1296
1297 /* Lock the Dispatcher Database */
1298 OldIrql = KeAcquireDispatcherDatabaseLock();
1299
1300 /* Save the old Priority */
1301 OldPriority = Thread->Priority;
1302
1303 /* Reset the Quantum and Decrements */
1304 Thread->Quantum = Thread->QuantumReset;
1305 Thread->PriorityDecrement = 0;
1306
1307 /* Set the new Priority */
1308 KiSetPriorityThread(Thread, Priority, &Released);
1309
1310 /* Release Lock if needed */
1311 if (!Released)
1312 {
1313 KeReleaseDispatcherDatabaseLock(OldIrql);
1314 }
1315 else
1316 {
1317 KeLowerIrql(OldIrql);
1318 }
1319
1320 /* Return Old Priority */
1321 return OldPriority;
1322 }
1323
1324 /*
1325 * @implemented
1326 *
1327 * Sets thread's affinity
1328 */
1329 NTSTATUS
1330 STDCALL
1331 KeSetAffinityThread(PKTHREAD Thread,
1332 KAFFINITY Affinity)
1333 {
1334 KIRQL OldIrql;
1335 LONG i;
1336 PKPCR Pcr;
1337 KAFFINITY ProcessorMask;
1338
1339 DPRINT("KeSetAffinityThread(Thread %x, Affinity %x)\n", Thread, Affinity);
1340
1341 /* Verify correct affinity */
1342 if ((Affinity & Thread->ApcStatePointer[0]->Process->Affinity) !=
1343 Affinity || !Affinity)
1344 {
1345 KEBUGCHECK(INVALID_AFFINITY_SET);
1346 }
1347
1348 OldIrql = KeAcquireDispatcherDatabaseLock();
1349
1350 Thread->UserAffinity = Affinity;
1351
1352 if (Thread->SystemAffinityActive == FALSE) {
1353
1354 Thread->Affinity = Affinity;
1355
1356 if (Thread->State == Running) {
1357
1358 ProcessorMask = 1 << KeGetCurrentProcessorNumber();
1359 if (Thread == KeGetCurrentThread()) {
1360
1361 if (!(Affinity & ProcessorMask)) {
1362
1363 KiDispatchThreadNoLock(Ready);
1364 KeLowerIrql(OldIrql);
1365 return STATUS_SUCCESS;
1366 }
1367
1368 } else {
1369
1370 for (i = 0; i < KeNumberProcessors; i++) {
1371
1372 Pcr = (PKPCR)(KPCR_BASE + i * PAGE_SIZE);
1373 if (Pcr->Prcb->CurrentThread == Thread) {
1374
1375 if (!(Affinity & ProcessorMask)) {
1376
1377 KeReleaseDispatcherDatabaseLockFromDpcLevel();
1378 KiRequestReschedule(i);
1379 KeLowerIrql(OldIrql);
1380 return STATUS_SUCCESS;
1381 }
1382
1383 break;
1384 }
1385 }
1386
1387 ASSERT (i < KeNumberProcessors);
1388 }
1389 }
1390 }
1391
1392 KeReleaseDispatcherDatabaseLock(OldIrql);
1393 return STATUS_SUCCESS;
1394 }
1395
1396 /*
1397 * @implemented
1398 */
1399 /* The Increment Argument seems to be ignored by NT and always 0 when called */
1400 VOID
1401 STDCALL
1402 KeTerminateThread(IN KPRIORITY Increment)
1403 {
1404 KIRQL OldIrql;
1405 PKTHREAD Thread = KeGetCurrentThread();
1406
1407 /* Lock the Dispatcher Database and the APC Queue */
1408 DPRINT("Terminating\n");
1409 OldIrql = KeAcquireDispatcherDatabaseLock();
1410
1411 /* Remove the thread from the list */
1412 RemoveEntryList(&Thread->ThreadListEntry);
1413
1414 /* Insert into the Reaper List */
1415 DPRINT("List: %p\n", PspReaperList);
1416 ((PETHREAD)Thread)->ReaperLink = PspReaperList;
1417 PspReaperList = (PETHREAD)Thread;
1418 DPRINT("List: %p\n", PspReaperList);
1419
1420 /* Check if it's active */
1421 if (PspReaping == FALSE) {
1422
1423 /* Activate it. We use the internal function for speed, and use the Hyper Critical Queue */
1424 PspReaping = TRUE;
1425 DPRINT("Terminating\n");
1426 KiInsertQueue(&ExWorkerQueue[HyperCriticalWorkQueue].WorkerQueue,
1427 &PspReaperWorkItem.List,
1428 FALSE);
1429 }
1430
1431 /* Handle Kernel Queues */
1432 if (Thread->Queue) {
1433
1434 DPRINT("Waking Queue\n");
1435 RemoveEntryList(&Thread->QueueListEntry);
1436 KiWakeQueue(Thread->Queue);
1437 }
1438
1439 /* Signal the thread */
1440 Thread->DispatcherHeader.SignalState = TRUE;
1441 if (IsListEmpty(&Thread->DispatcherHeader.WaitListHead) != TRUE) {
1442
1443 /* Satisfy waits */
1444 KiWaitTest((PVOID)Thread, Increment);
1445 }
1446
1447 /* Find a new Thread */
1448 KiDispatchThreadNoLock(Terminated);
1449 }
1450
1451 /*
1452 * FUNCTION: Tests whether there are any pending APCs for the current thread
1453 * and if so the APCs will be delivered on exit from kernel mode
1454 */
1455 BOOLEAN
1456 STDCALL
1457 KeTestAlertThread(IN KPROCESSOR_MODE AlertMode)
1458 {
1459 KIRQL OldIrql;
1460 PKTHREAD Thread = KeGetCurrentThread();
1461 BOOLEAN OldState;
1462
1463 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
1464
1465 /* Lock the Dispatcher Database and the APC Queue */
1466 OldIrql = KeAcquireDispatcherDatabaseLock();
1467 KiAcquireSpinLock(&Thread->ApcQueueLock);
1468
1469 /* Save the old State */
1470 OldState = Thread->Alerted[AlertMode];
1471
1472 /* If the Thread is Alerted, Clear it */
1473 if (OldState) {
1474
1475 Thread->Alerted[AlertMode] = FALSE;
1476
1477 } else if ((AlertMode != KernelMode) && (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))) {
1478
1479 /* If the mode is User and the Queue isn't empty, set Pending */
1480 Thread->ApcState.UserApcPending = TRUE;
1481 }
1482
1483 /* Release Locks and return the Old State */
1484 KiReleaseSpinLock(&Thread->ApcQueueLock);
1485 KeReleaseDispatcherDatabaseLock(OldIrql);
1486 return OldState;
1487 }
1488
1489 VOID
1490 KiServiceCheck (VOID)
1491 {
1492 PKTHREAD Thread = KeGetCurrentThread();
1493
1494 /* Check if we need to inialize Win32 for this Thread */
1495 if (Thread->ServiceTable != KeServiceDescriptorTableShadow) {
1496
1497 /* We do. Initialize it and save the new table */
1498 Thread->ServiceTable = KeServiceDescriptorTableShadow;
1499 PsInitWin32Thread((PETHREAD)Thread);
1500 }
1501 }
1502
1503 /*
1504 *
1505 * NOT EXPORTED
1506 */
1507 NTSTATUS
1508 STDCALL
1509 NtAlertResumeThread(IN HANDLE ThreadHandle,
1510 OUT PULONG SuspendCount)
1511 {
1512 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1513 PETHREAD Thread;
1514 NTSTATUS Status;
1515 ULONG PreviousState;
1516
1517 /* Check if parameters are valid */
1518 if(PreviousMode != KernelMode) {
1519
1520 _SEH_TRY {
1521
1522 ProbeForWriteUlong(SuspendCount);
1523
1524 } _SEH_HANDLE {
1525
1526 Status = _SEH_GetExceptionCode();
1527
1528 } _SEH_END;
1529 }
1530
1531 /* Reference the Object */
1532 Status = ObReferenceObjectByHandle(ThreadHandle,
1533 THREAD_SUSPEND_RESUME,
1534 PsThreadType,
1535 PreviousMode,
1536 (PVOID*)&Thread,
1537 NULL);
1538
1539 /* Check for Success */
1540 if (NT_SUCCESS(Status)) {
1541
1542 /* Call the Kernel Function */
1543 PreviousState = KeAlertResumeThread(&Thread->Tcb);
1544
1545 /* Dereference Object */
1546 ObDereferenceObject(Thread);
1547
1548 if (SuspendCount) {
1549
1550 _SEH_TRY {
1551
1552 *SuspendCount = PreviousState;
1553
1554 } _SEH_HANDLE {
1555
1556 Status = _SEH_GetExceptionCode();
1557
1558 } _SEH_END;
1559 }
1560 }
1561
1562 /* Return status */
1563 return Status;
1564 }
1565
1566 /*
1567 * @implemented
1568 *
1569 * EXPORTED
1570 */
1571 NTSTATUS
1572 STDCALL
1573 NtAlertThread (IN HANDLE ThreadHandle)
1574 {
1575 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1576 PETHREAD Thread;
1577 NTSTATUS Status;
1578
1579 /* Reference the Object */
1580 Status = ObReferenceObjectByHandle(ThreadHandle,
1581 THREAD_SUSPEND_RESUME,
1582 PsThreadType,
1583 PreviousMode,
1584 (PVOID*)&Thread,
1585 NULL);
1586
1587 /* Check for Success */
1588 if (NT_SUCCESS(Status)) {
1589
1590 /*
1591 * Do an alert depending on the processor mode. If some kmode code wants to
1592 * enforce a umode alert it should call KeAlertThread() directly. If kmode
1593 * code wants to do a kmode alert it's sufficient to call it with Zw or just
1594 * use KeAlertThread() directly
1595 */
1596 KeAlertThread(&Thread->Tcb, PreviousMode);
1597
1598 /* Dereference Object */
1599 ObDereferenceObject(Thread);
1600 }
1601
1602 /* Return status */
1603 return Status;
1604 }
1605
1606 NTSTATUS
1607 STDCALL
1608 NtDelayExecution(IN BOOLEAN Alertable,
1609 IN PLARGE_INTEGER DelayInterval)
1610 {
1611 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1612 LARGE_INTEGER SafeInterval;
1613 NTSTATUS Status;
1614
1615 /* Check if parameters are valid */
1616 if(PreviousMode != KernelMode) {
1617
1618 Status = STATUS_SUCCESS;
1619
1620 _SEH_TRY {
1621
1622 /* make a copy on the kernel stack and let DelayInterval point to it so
1623 we don't need to wrap KeDelayExecutionThread in SEH! */
1624 SafeInterval = ProbeForReadLargeInteger(DelayInterval);
1625 DelayInterval = &SafeInterval;
1626
1627 } _SEH_HANDLE {
1628
1629 Status = _SEH_GetExceptionCode();
1630 } _SEH_END;
1631
1632 if (!NT_SUCCESS(Status))
1633 {
1634 return Status;
1635 }
1636 }
1637
1638 /* Call the Kernel Function */
1639 Status = KeDelayExecutionThread(PreviousMode,
1640 Alertable,
1641 DelayInterval);
1642
1643 /* Return Status */
1644 return Status;
1645 }