b473e476335eece78c179ff74c30b37182a6ccf0
[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) / sizeof(LONG),
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 * @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->PriorityDecrement = 0;
1260
1261 /* If the priority will change, reset quantum and change it for real */
1262 if (Priority != Thread->Priority)
1263 {
1264 Thread->Quantum = Thread->QuantumReset;
1265 KiSetPriorityThread(Thread, Priority, &Released);
1266 }
1267
1268 /* Release Lock if needed */
1269 if (!Released)
1270 {
1271 KeReleaseDispatcherDatabaseLock(OldIrql);
1272 }
1273 else
1274 {
1275 KeLowerIrql(OldIrql);
1276 }
1277
1278 /* Return the Old Increment */
1279 return CurrentIncrement;
1280 }
1281
1282 /*
1283 * @implemented
1284 */
1285 KPRIORITY
1286 STDCALL
1287 KeSetPriorityThread(PKTHREAD Thread,
1288 KPRIORITY Priority)
1289 {
1290 KPRIORITY OldPriority;
1291 BOOLEAN Released = FALSE;
1292 KIRQL OldIrql;
1293
1294 /* Lock the Dispatcher Database */
1295 OldIrql = KeAcquireDispatcherDatabaseLock();
1296
1297 /* Save the old Priority */
1298 OldPriority = Thread->Priority;
1299
1300 /* Reset the Quantum and Decrements */
1301 Thread->Quantum = Thread->QuantumReset;
1302 Thread->PriorityDecrement = 0;
1303
1304 /* Set the new Priority */
1305 KiSetPriorityThread(Thread, Priority, &Released);
1306
1307 /* Release Lock if needed */
1308 if (!Released)
1309 {
1310 KeReleaseDispatcherDatabaseLock(OldIrql);
1311 }
1312 else
1313 {
1314 KeLowerIrql(OldIrql);
1315 }
1316
1317 /* Return Old Priority */
1318 return OldPriority;
1319 }
1320
1321 /*
1322 * @implemented
1323 *
1324 * Sets thread's affinity
1325 */
1326 NTSTATUS
1327 STDCALL
1328 KeSetAffinityThread(PKTHREAD Thread,
1329 KAFFINITY Affinity)
1330 {
1331 KIRQL OldIrql;
1332 LONG i;
1333 PKPCR Pcr;
1334 KAFFINITY ProcessorMask;
1335
1336 DPRINT("KeSetAffinityThread(Thread %x, Affinity %x)\n", Thread, Affinity);
1337
1338 /* Verify correct affinity */
1339 if ((Affinity & Thread->ApcStatePointer[0]->Process->Affinity) !=
1340 Affinity || !Affinity)
1341 {
1342 KEBUGCHECK(INVALID_AFFINITY_SET);
1343 }
1344
1345 OldIrql = KeAcquireDispatcherDatabaseLock();
1346
1347 Thread->UserAffinity = Affinity;
1348
1349 if (Thread->SystemAffinityActive == FALSE) {
1350
1351 Thread->Affinity = Affinity;
1352
1353 if (Thread->State == Running) {
1354
1355 ProcessorMask = 1 << KeGetCurrentProcessorNumber();
1356 if (Thread == KeGetCurrentThread()) {
1357
1358 if (!(Affinity & ProcessorMask)) {
1359
1360 KiDispatchThreadNoLock(Ready);
1361 KeLowerIrql(OldIrql);
1362 return STATUS_SUCCESS;
1363 }
1364
1365 } else {
1366
1367 for (i = 0; i < KeNumberProcessors; i++) {
1368
1369 Pcr = (PKPCR)(KPCR_BASE + i * PAGE_SIZE);
1370 if (Pcr->Prcb->CurrentThread == Thread) {
1371
1372 if (!(Affinity & ProcessorMask)) {
1373
1374 KeReleaseDispatcherDatabaseLockFromDpcLevel();
1375 KiRequestReschedule(i);
1376 KeLowerIrql(OldIrql);
1377 return STATUS_SUCCESS;
1378 }
1379
1380 break;
1381 }
1382 }
1383
1384 ASSERT (i < KeNumberProcessors);
1385 }
1386 }
1387 }
1388
1389 KeReleaseDispatcherDatabaseLock(OldIrql);
1390 return STATUS_SUCCESS;
1391 }
1392
1393 /*
1394 * @implemented
1395 */
1396 /* The Increment Argument seems to be ignored by NT and always 0 when called */
1397 VOID
1398 STDCALL
1399 KeTerminateThread(IN KPRIORITY Increment)
1400 {
1401 KIRQL OldIrql;
1402 PKTHREAD Thread = KeGetCurrentThread();
1403
1404 /* Lock the Dispatcher Database and the APC Queue */
1405 DPRINT("Terminating\n");
1406 OldIrql = KeAcquireDispatcherDatabaseLock();
1407
1408 /* Remove the thread from the list */
1409 RemoveEntryList(&Thread->ThreadListEntry);
1410
1411 /* Insert into the Reaper List */
1412 DPRINT("List: %p\n", PspReaperList);
1413 ((PETHREAD)Thread)->ReaperLink = PspReaperList;
1414 PspReaperList = (PETHREAD)Thread;
1415 DPRINT("List: %p\n", PspReaperList);
1416
1417 /* Check if it's active */
1418 if (PspReaping == FALSE) {
1419
1420 /* Activate it. We use the internal function for speed, and use the Hyper Critical Queue */
1421 PspReaping = TRUE;
1422 DPRINT("Terminating\n");
1423 KiInsertQueue(&ExWorkerQueue[HyperCriticalWorkQueue].WorkerQueue,
1424 &PspReaperWorkItem.List,
1425 FALSE);
1426 }
1427
1428 /* Handle Kernel Queues */
1429 if (Thread->Queue) {
1430
1431 DPRINT("Waking Queue\n");
1432 RemoveEntryList(&Thread->QueueListEntry);
1433 KiWakeQueue(Thread->Queue);
1434 }
1435
1436 /* Signal the thread */
1437 Thread->DispatcherHeader.SignalState = TRUE;
1438 if (IsListEmpty(&Thread->DispatcherHeader.WaitListHead) != TRUE) {
1439
1440 /* Satisfy waits */
1441 KiWaitTest((PVOID)Thread, Increment);
1442 }
1443
1444 /* Find a new Thread */
1445 KiDispatchThreadNoLock(Terminated);
1446 }
1447
1448 /*
1449 * FUNCTION: Tests whether there are any pending APCs for the current thread
1450 * and if so the APCs will be delivered on exit from kernel mode
1451 */
1452 BOOLEAN
1453 STDCALL
1454 KeTestAlertThread(IN KPROCESSOR_MODE AlertMode)
1455 {
1456 KIRQL OldIrql;
1457 PKTHREAD Thread = KeGetCurrentThread();
1458 BOOLEAN OldState;
1459
1460 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
1461
1462 /* Lock the Dispatcher Database and the APC Queue */
1463 OldIrql = KeAcquireDispatcherDatabaseLock();
1464 KiAcquireSpinLock(&Thread->ApcQueueLock);
1465
1466 /* Save the old State */
1467 OldState = Thread->Alerted[AlertMode];
1468
1469 /* If the Thread is Alerted, Clear it */
1470 if (OldState) {
1471
1472 Thread->Alerted[AlertMode] = FALSE;
1473
1474 } else if ((AlertMode != KernelMode) && (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))) {
1475
1476 /* If the mode is User and the Queue isn't empty, set Pending */
1477 Thread->ApcState.UserApcPending = TRUE;
1478 }
1479
1480 /* Release Locks and return the Old State */
1481 KiReleaseSpinLock(&Thread->ApcQueueLock);
1482 KeReleaseDispatcherDatabaseLock(OldIrql);
1483 return OldState;
1484 }
1485
1486 VOID
1487 KiServiceCheck (VOID)
1488 {
1489 PKTHREAD Thread = KeGetCurrentThread();
1490
1491 /* Check if we need to inialize Win32 for this Thread */
1492 if (Thread->ServiceTable != KeServiceDescriptorTableShadow) {
1493
1494 /* We do. Initialize it and save the new table */
1495 Thread->ServiceTable = KeServiceDescriptorTableShadow;
1496 PsInitWin32Thread((PETHREAD)Thread);
1497 }
1498 }
1499
1500 /*
1501 *
1502 * NOT EXPORTED
1503 */
1504 NTSTATUS
1505 STDCALL
1506 NtAlertResumeThread(IN HANDLE ThreadHandle,
1507 OUT PULONG SuspendCount)
1508 {
1509 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1510 PETHREAD Thread;
1511 NTSTATUS Status;
1512 ULONG PreviousState;
1513
1514 /* Check if parameters are valid */
1515 if(PreviousMode != KernelMode) {
1516
1517 _SEH_TRY {
1518
1519 ProbeForWriteUlong(SuspendCount);
1520
1521 } _SEH_HANDLE {
1522
1523 Status = _SEH_GetExceptionCode();
1524
1525 } _SEH_END;
1526 }
1527
1528 /* Reference the Object */
1529 Status = ObReferenceObjectByHandle(ThreadHandle,
1530 THREAD_SUSPEND_RESUME,
1531 PsThreadType,
1532 PreviousMode,
1533 (PVOID*)&Thread,
1534 NULL);
1535
1536 /* Check for Success */
1537 if (NT_SUCCESS(Status)) {
1538
1539 /* Call the Kernel Function */
1540 PreviousState = KeAlertResumeThread(&Thread->Tcb);
1541
1542 /* Dereference Object */
1543 ObDereferenceObject(Thread);
1544
1545 if (SuspendCount) {
1546
1547 _SEH_TRY {
1548
1549 *SuspendCount = PreviousState;
1550
1551 } _SEH_HANDLE {
1552
1553 Status = _SEH_GetExceptionCode();
1554
1555 } _SEH_END;
1556 }
1557 }
1558
1559 /* Return status */
1560 return Status;
1561 }
1562
1563 /*
1564 * @implemented
1565 *
1566 * EXPORTED
1567 */
1568 NTSTATUS
1569 STDCALL
1570 NtAlertThread (IN HANDLE ThreadHandle)
1571 {
1572 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1573 PETHREAD Thread;
1574 NTSTATUS Status;
1575
1576 /* Reference the Object */
1577 Status = ObReferenceObjectByHandle(ThreadHandle,
1578 THREAD_SUSPEND_RESUME,
1579 PsThreadType,
1580 PreviousMode,
1581 (PVOID*)&Thread,
1582 NULL);
1583
1584 /* Check for Success */
1585 if (NT_SUCCESS(Status)) {
1586
1587 /*
1588 * Do an alert depending on the processor mode. If some kmode code wants to
1589 * enforce a umode alert it should call KeAlertThread() directly. If kmode
1590 * code wants to do a kmode alert it's sufficient to call it with Zw or just
1591 * use KeAlertThread() directly
1592 */
1593 KeAlertThread(&Thread->Tcb, PreviousMode);
1594
1595 /* Dereference Object */
1596 ObDereferenceObject(Thread);
1597 }
1598
1599 /* Return status */
1600 return Status;
1601 }
1602
1603 NTSTATUS
1604 STDCALL
1605 NtDelayExecution(IN BOOLEAN Alertable,
1606 IN PLARGE_INTEGER DelayInterval)
1607 {
1608 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1609 LARGE_INTEGER SafeInterval;
1610 NTSTATUS Status;
1611
1612 /* Check if parameters are valid */
1613 if(PreviousMode != KernelMode) {
1614
1615 Status = STATUS_SUCCESS;
1616
1617 _SEH_TRY {
1618
1619 /* make a copy on the kernel stack and let DelayInterval point to it so
1620 we don't need to wrap KeDelayExecutionThread in SEH! */
1621 SafeInterval = ProbeForReadLargeInteger(DelayInterval);
1622 DelayInterval = &SafeInterval;
1623
1624 } _SEH_HANDLE {
1625
1626 Status = _SEH_GetExceptionCode();
1627 } _SEH_END;
1628
1629 if (!NT_SUCCESS(Status))
1630 {
1631 return Status;
1632 }
1633 }
1634
1635 /* Call the Kernel Function */
1636 Status = KeDelayExecutionThread(PreviousMode,
1637 Alertable,
1638 DelayInterval);
1639
1640 /* Return Status */
1641 return Status;
1642 }