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