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