- Fix KiDispatchException to unmask KI_EXCEPTION_INTERNAL when setting the exception...
[reactos.git] / reactos / ntoskrnl / ke / thrdschd.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/thrdschd.c
5 * PURPOSE: Kernel Thread Scheduler (Affinity, Priority, Scheduling)
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS *******************************************************************/
16
17 ULONG KiIdleSummary;
18 ULONG KiIdleSMTSummary;
19
20 /* FUNCTIONS *****************************************************************/
21
22 VOID
23 FASTCALL
24 KiQueueReadyThread(IN PKTHREAD Thread,
25 IN PKPRCB Prcb)
26 {
27 /* Call the macro. We keep the API for compatibility with ASM code */
28 KxQueueReadyThread(Thread, Prcb);
29 }
30
31 VOID
32 NTAPI
33 KiDeferredReadyThread(IN PKTHREAD Thread)
34 {
35 PKPRCB Prcb;
36 BOOLEAN Preempted;
37 ULONG Processor = 0;
38 KPRIORITY OldPriority;
39 PKTHREAD NextThread;
40
41 /* Sanity checks */
42 ASSERT(Thread->State == DeferredReady);
43 ASSERT((Thread->Priority >= 0) && (Thread->Priority <= HIGH_PRIORITY));
44
45 /* Check if we have any adjusts to do */
46 if (Thread->AdjustReason == AdjustBoost)
47 {
48 /* Lock the thread */
49 KiAcquireThreadLock(Thread);
50
51 /* Check if the priority is low enough to qualify for boosting */
52 if ((Thread->Priority <= Thread->AdjustIncrement) &&
53 (Thread->Priority < (LOW_REALTIME_PRIORITY - 3)) &&
54 !(Thread->DisableBoost))
55 {
56 /* Calculate the new priority based on the adjust increment */
57 OldPriority = min(Thread->AdjustIncrement + 1,
58 LOW_REALTIME_PRIORITY - 1);
59
60 /* Make sure we're not decreasing outside of the priority range */
61 ASSERT((Thread->PriorityDecrement >= 0) &&
62 (Thread->PriorityDecrement <= Thread->Priority));
63
64 /* Calculate the new priority decrement based on the boost */
65 Thread->PriorityDecrement += ((SCHAR)OldPriority - Thread->Priority);
66
67 /* Again verify that this decrement is valid */
68 ASSERT((Thread->PriorityDecrement >= 0) &&
69 (Thread->PriorityDecrement <= OldPriority));
70
71 /* Set the new priority */
72 Thread->Priority = (SCHAR)OldPriority;
73 }
74
75 /* We need 4 quanta, make sure we have them, then decrease by one */
76 if (Thread->Quantum < 4) Thread->Quantum = 4;
77 Thread->Quantum--;
78
79 /* Make sure the priority is still valid */
80 ASSERT((Thread->Priority >= 0) && (Thread->Priority <= HIGH_PRIORITY));
81
82 /* Release the lock and clear the adjust reason */
83 KiReleaseThreadLock(Thread);
84 Thread->AdjustReason = AdjustNone;
85 }
86 else if (Thread->AdjustReason == AdjustUnwait)
87 {
88 /* Acquire the thread lock and check if this is a real-time thread */
89 KiAcquireThreadLock(Thread);
90 if (Thread->Priority < LOW_REALTIME_PRIORITY)
91 {
92 /* It's not real time, but is it time critical? */
93 if (Thread->BasePriority >= (LOW_REALTIME_PRIORITY - 2))
94 {
95 /* It is, so simply reset its quantum */
96 Thread->Quantum = Thread->QuantumReset;
97 }
98 else
99 {
100 /* Has the priority been adjusted previously? */
101 if (!(Thread->PriorityDecrement) && (Thread->AdjustIncrement))
102 {
103 /* Yes, reset its quantum */
104 Thread->Quantum = Thread->QuantumReset;
105 }
106
107 /* Wait code already handles quantum adjustment during APCs */
108 if (Thread->WaitStatus != STATUS_KERNEL_APC)
109 {
110 /* Decrease the quantum by one and check if we're out */
111 if (--Thread->Quantum <= 0)
112 {
113 /* We are, reset the quantum and get a new priority */
114 Thread->Quantum = Thread->QuantumReset;
115 Thread->Priority = KiComputeNewPriority(Thread, 1);
116 }
117 }
118 }
119
120 /* Now check if we have no decrement and boosts are enabled */
121 if (!(Thread->PriorityDecrement) && !(Thread->DisableBoost))
122 {
123 /* Make sure we have an increment */
124 ASSERT(Thread->AdjustIncrement >= 0);
125
126 /* Calculate the new priority after the increment */
127 OldPriority = Thread->BasePriority + Thread->AdjustIncrement;
128
129 /* Check if this new priority is higher */
130 if (OldPriority > Thread->Priority)
131 {
132 /* Make sure we don't go into the real time range */
133 if (OldPriority >= LOW_REALTIME_PRIORITY)
134 {
135 /* Normalize it back down one notch */
136 OldPriority = LOW_REALTIME_PRIORITY - 1;
137 }
138
139 /* Check if the priority is higher then the boosted base */
140 if (OldPriority > (Thread->BasePriority +
141 Thread->AdjustIncrement))
142 {
143 /* Setup a priority decrement to nullify the boost */
144 Thread->PriorityDecrement = ((SCHAR)OldPriority -
145 Thread->BasePriority -
146 Thread->AdjustIncrement);
147 }
148
149 /* Make sure that the priority decrement is valid */
150 ASSERT((Thread->PriorityDecrement >= 0) &&
151 (Thread->PriorityDecrement <= OldPriority));
152
153 /* Set this new priority */
154 Thread->Priority = (SCHAR)OldPriority;
155 }
156 }
157 }
158 else
159 {
160 /* It's a real-time thread, so just reset its quantum */
161 Thread->Quantum = Thread->QuantumReset;
162 }
163
164 /* Make sure the priority makes sense */
165 ASSERT((Thread->Priority >= 0) && (Thread->Priority <= HIGH_PRIORITY));
166
167 /* Release the thread lock and reset the adjust reason */
168 KiReleaseThreadLock(Thread);
169 Thread->AdjustReason = AdjustNone;
170 }
171
172 /* Clear thread preemption status and save current values */
173 Preempted = Thread->Preempted;
174 OldPriority = Thread->Priority;
175 Thread->Preempted = FALSE;
176
177 /* Queue the thread on CPU 0 and get the PRCB */
178 Thread->NextProcessor = 0;
179 Prcb = KiProcessorBlock[0];
180
181 /* Check if we have an idle summary */
182 if (KiIdleSummary)
183 {
184 /* Clear it and set this thread as the next one */
185 KiIdleSummary = 0;
186 Thread->State = Standby;
187 Prcb->NextThread = Thread;
188 return;
189 }
190
191 /* Set the CPU number */
192 Thread->NextProcessor = (UCHAR)Processor;
193
194 /* Get the next scheduled thread */
195 NextThread = Prcb->NextThread;
196 if (NextThread)
197 {
198 /* Sanity check */
199 ASSERT(NextThread->State == Standby);
200
201 /* Check if priority changed */
202 if (OldPriority > NextThread->Priority)
203 {
204 /* Preempt the thread */
205 NextThread->Preempted = TRUE;
206
207 /* Put this one as the next one */
208 Thread->State = Standby;
209 Prcb->NextThread = Thread;
210
211 /* Set it in deferred ready mode */
212 NextThread->State = DeferredReady;
213 NextThread->DeferredProcessor = Prcb->Number;
214 KiReleasePrcbLock(Prcb);
215 KiDeferredReadyThread(NextThread);
216 return;
217 }
218 }
219 else
220 {
221 /* Set the next thread as the current thread */
222 NextThread = Prcb->CurrentThread;
223 if (OldPriority > NextThread->Priority)
224 {
225 /* Preempt it if it's already running */
226 if (NextThread->State == Running) NextThread->Preempted = TRUE;
227
228 /* Set the thread on standby and as the next thread */
229 Thread->State = Standby;
230 Prcb->NextThread = Thread;
231
232 /* Release the lock */
233 KiReleasePrcbLock(Prcb);
234
235 /* Check if we're running on another CPU */
236 if (KeGetCurrentProcessorNumber() != Thread->NextProcessor)
237 {
238 /* We are, send an IPI */
239 KiIpiSendRequest(AFFINITY_MASK(Thread->NextProcessor), IPI_DPC);
240 }
241 return;
242 }
243 }
244
245 /* Sanity check */
246 ASSERT((OldPriority >= 0) && (OldPriority <= HIGH_PRIORITY));
247
248 /* Set this thread as ready */
249 Thread->State = Ready;
250 Thread->WaitTime = KeTickCount.LowPart;
251
252 /* Insert this thread in the appropriate order */
253 Preempted ? InsertHeadList(&Prcb->DispatcherReadyListHead[OldPriority],
254 &Thread->WaitListEntry) :
255 InsertTailList(&Prcb->DispatcherReadyListHead[OldPriority],
256 &Thread->WaitListEntry);
257
258 /* Update the ready summary */
259 Prcb->ReadySummary |= PRIORITY_MASK(OldPriority);
260
261 /* Sanity check */
262 ASSERT(OldPriority == Thread->Priority);
263
264 /* Release the lock */
265 KiReleasePrcbLock(Prcb);
266 }
267
268 VOID
269 KiInsertIntoThreadList(KPRIORITY Priority,
270 PKTHREAD Thread)
271 {
272 ASSERT(Ready == Thread->State);
273 ASSERT(Thread->Priority == Priority);
274
275 if (Priority >= MAXIMUM_PRIORITY || Priority < LOW_PRIORITY) {
276
277 DPRINT1("Invalid thread priority (%d)\n", Priority);
278 KEBUGCHECK(0);
279 }
280
281 InsertTailList(&KeGetCurrentPrcb()->DispatcherReadyListHead[Priority], &Thread->WaitListEntry);
282 KeGetCurrentPrcb()->ReadySummary |= (1 << Priority);
283 }
284
285 VOID
286 KiRemoveFromThreadList(PKTHREAD Thread)
287 {
288 ASSERT(Ready == Thread->State);
289 RemoveEntryList(&Thread->WaitListEntry);
290 if (IsListEmpty(&KeGetCurrentPrcb()->DispatcherReadyListHead[Thread->Priority])) {
291
292 KeGetCurrentPrcb()->ReadySummary &= ~(1 << Thread->Priority);
293 }
294 }
295
296 PKTHREAD
297 KiScanThreadList(KPRIORITY Priority,
298 KAFFINITY Affinity)
299 {
300 PKTHREAD current;
301 ULONG Mask;
302
303 Mask = (1 << Priority);
304
305 if (KeGetCurrentPrcb()->ReadySummary & Mask) {
306
307 LIST_FOR_EACH(current, &KeGetCurrentPrcb()->DispatcherReadyListHead[Priority], KTHREAD, WaitListEntry) {
308
309 if (current->State != Ready) {
310
311 DPRINT1("%p/%d\n", current, current->State);
312 }
313
314 ASSERT(current->State == Ready);
315
316 if (current->Affinity & Affinity) {
317
318 KiRemoveFromThreadList(current);
319 return(current);
320 }
321 }
322 }
323
324 return(NULL);
325 }
326
327 BOOLEAN
328 STDCALL
329 KiDispatchThreadNoLock(ULONG NewThreadStatus)
330 {
331 KPRIORITY CurrentPriority;
332 PKTHREAD Candidate;
333 ULONG Affinity;
334 PKTHREAD CurrentThread = KeGetCurrentThread();
335 BOOLEAN ApcState;
336
337 DPRINT("KiDispatchThreadNoLock() %d/%d/%d/%d\n", KeGetCurrentProcessorNumber(),
338 CurrentThread, NewThreadStatus, CurrentThread->State);
339
340 CurrentThread->State = (UCHAR)NewThreadStatus;
341
342 if (NewThreadStatus == Ready) {
343
344 KiInsertIntoThreadList(CurrentThread->Priority,
345 CurrentThread);
346 }
347
348 Affinity = 1 << KeGetCurrentProcessorNumber();
349
350 for (CurrentPriority = HIGH_PRIORITY; CurrentPriority >= LOW_PRIORITY; CurrentPriority--) {
351
352 Candidate = KiScanThreadList(CurrentPriority, Affinity);
353
354 if (Candidate == CurrentThread) {
355
356 Candidate->State = Running;
357 KiReleaseDispatcherLockFromDpcLevel();
358 return FALSE;
359 }
360
361 if (Candidate != NULL) {
362
363 PKTHREAD OldThread;
364 PKTHREAD IdleThread;
365
366 DPRINT("Scheduling %x(%d)\n",Candidate, CurrentPriority);
367
368 Candidate->State = Running;
369
370 OldThread = CurrentThread;
371 CurrentThread = Candidate;
372 IdleThread = KeGetCurrentPrcb()->IdleThread;
373
374 if (OldThread == IdleThread) {
375
376 KiIdleSummary &= ~Affinity;
377
378 } else if (CurrentThread == IdleThread) {
379
380 KiIdleSummary |= Affinity;
381 }
382
383 MmUpdatePageDir((PEPROCESS)PsGetCurrentProcess(),((PETHREAD)CurrentThread)->ThreadsProcess, sizeof(EPROCESS));
384
385 /* Special note for Filip: This will release the Dispatcher DB Lock ;-) -- Alex */
386 DPRINT("You are : %x, swapping to: %x.\n", OldThread, CurrentThread);
387 KeGetCurrentPrcb()->CurrentThread = CurrentThread;
388 ApcState = KiSwapContext(OldThread, CurrentThread);
389 DPRINT("You are : %x, swapped from: %x\n", OldThread, CurrentThread);
390 return ApcState;
391 }
392 }
393
394 DPRINT1("CRITICAL: No threads are ready (CPU%d)\n", KeGetCurrentProcessorNumber());
395 KEBUGCHECK(0);
396 return FALSE;
397 }
398
399 VOID
400 STDCALL
401 KiDispatchThread(ULONG NewThreadStatus)
402 {
403 KIRQL OldIrql;
404
405 if (KeGetCurrentPrcb()->IdleThread == NULL) {
406 return;
407 }
408
409 OldIrql = KiAcquireDispatcherLock();
410 KiDispatchThreadNoLock(NewThreadStatus);
411 KeLowerIrql(OldIrql);
412 }
413
414 PKTHREAD
415 FASTCALL
416 KiSelectNextThread(IN PKPRCB Prcb)
417 {
418 PKTHREAD Thread;
419
420 /* Select a ready thread */
421 Thread = KiSelectReadyThread(0, Prcb);
422 if (!Thread)
423 {
424 /* Didn't find any, get the current idle thread */
425 Thread = Prcb->IdleThread;
426
427 /* Enable idle scheduling */
428 InterlockedOr((PLONG) &KiIdleSummary, Prcb->SetMember);
429 Prcb->IdleSchedule = TRUE;
430
431 /* FIXME: SMT support */
432 }
433
434 /* Sanity checks and return the thread */
435 ASSERT(Thread != NULL);
436 ASSERT((Thread->BasePriority == 0) || (Thread->Priority != 0));
437 return Thread;
438 }
439
440 NTSTATUS
441 FASTCALL
442 KiSwapThread(IN PKTHREAD CurrentThread,
443 IN PKPRCB Prcb)
444 {
445 BOOLEAN ApcState = FALSE;
446 KIRQL WaitIrql;
447 LONG_PTR WaitStatus;
448 PKTHREAD NextThread;
449 #ifdef NEW_SCHEDULER
450 PEPROCESS HackOfDoom = PsGetCurrentProcess();
451 #endif
452 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
453
454 /* Acquire the PRCB lock */
455 KiAcquirePrcbLock(Prcb);
456
457 /* Get the next thread */
458 NextThread = Prcb->NextThread;
459 if (NextThread)
460 {
461 /* Already got a thread, set it up */
462 Prcb->NextThread = NULL;
463 Prcb->CurrentThread = NextThread;
464 NextThread->State = Running;
465 }
466 else
467 {
468 #ifdef NEW_SCHEDULER
469 /* Try to find a ready thread */
470 NextThread = KiSelectReadyThread(0, Prcb);
471 if (NextThread)
472 {
473 /* Switch to it */
474 Prcb->CurrentThread = NextThread;
475 NextThread->State = Running;
476 }
477 else
478 {
479 /* Set the idle summary */
480 InterlockedOr((PLONG)&KiIdleSummary, Prcb->SetMember);
481
482 /* Schedule the idle thread */
483 NextThread = Prcb->IdleThread;
484 Prcb->CurrentThread = NextThread;
485 NextThread->State = Running;
486 }
487 #else
488 /* Find a new thread to run */
489 ApcState = KiDispatchThreadNoLock(Waiting);
490 #endif
491 }
492
493 /* Sanity check and release the PRCB */
494 ASSERT(CurrentThread != Prcb->IdleThread);
495 KiReleasePrcbLock(Prcb);
496
497 /* Save the wait IRQL */
498 WaitIrql = CurrentThread->WaitIrql;
499
500 #ifdef NEW_SCHEDULER
501 /* REACTOS Mm Hack of Doom */
502 MmUpdatePageDir(HackOfDoom,((PETHREAD)NextThread)->ThreadsProcess, sizeof(EPROCESS));
503
504 /* Swap contexts */
505 ApcState = KiSwapContext(CurrentThread, NextThread);
506 #endif
507
508 /* Get the wait status */
509 WaitStatus = CurrentThread->WaitStatus;
510
511 /* Check if we need to deliver APCs */
512 if (ApcState)
513 {
514 /* Lower to APC_LEVEL */
515 KeLowerIrql(APC_LEVEL);
516
517 /* Deliver APCs */
518 KiDeliverApc(KernelMode, NULL, NULL);
519 ASSERT(WaitIrql == 0);
520 }
521
522 /* Lower IRQL back to what it was and return the wait status */
523 KeLowerIrql(WaitIrql);
524 return WaitStatus;
525 }
526
527 VOID
528 NTAPI
529 KiReadyThread(IN PKTHREAD Thread)
530 {
531 IN PKPROCESS Process = Thread->ApcState.Process;
532
533 /* Check if the process is paged out */
534 if (Process->State != ProcessInMemory)
535 {
536 /* We don't page out processes in ROS */
537 KEBUGCHECK(0);
538 }
539 else if (!Thread->KernelStackResident)
540 {
541 /* Increase the stack count */
542 ASSERT(Process->StackCount != MAXULONG_PTR);
543 Process->StackCount++;
544
545 /* Set the thread to transition */
546 ASSERT(Thread->State != Transition);
547 Thread->State = Transition;
548
549 /* The stack is always resident in ROS */
550 KEBUGCHECK(0);
551 }
552 else
553 {
554 /* Insert the thread on the deferred ready list */
555 #ifdef NEW_SCHEDULER
556 KiInsertDeferredReadyList(Thread);
557 #else
558 /* Insert the thread into the thread list */
559 Thread->State = Ready;
560 KiInsertIntoThreadList(Thread->Priority, Thread);
561 #endif
562 }
563 }
564
565 VOID
566 NTAPI
567 KiAdjustQuantumThread(IN PKTHREAD Thread)
568 {
569 PKPRCB Prcb = KeGetCurrentPrcb();
570 PKTHREAD NextThread;
571
572 /* Acquire thread and PRCB lock */
573 KiAcquireThreadLock(Thread);
574 KiAcquirePrcbLock(Prcb);
575
576 /* Don't adjust for RT threads */
577 if ((Thread->Priority < LOW_REALTIME_PRIORITY) &&
578 (Thread->BasePriority < (LOW_REALTIME_PRIORITY - 2)))
579 {
580 /* Decrease Quantum by one and see if we've ran out */
581 if (--Thread->Quantum <= 0)
582 {
583 /* Return quantum */
584 Thread->Quantum = Thread->QuantumReset;
585
586 /* Calculate new Priority */
587 Thread->Priority = KiComputeNewPriority(Thread, 1);
588
589 #ifdef NEW_SCHEDULER
590 /* Check if there's no next thread scheduled */
591 if (!Prcb->NextThread)
592 {
593 /* Select a ready thread and check if we found one */
594 NextThread = KiSelectReadyThread(Thread->Priority, Prcb);
595 if (NextThread)
596 {
597 /* Set it on standby and switch to it */
598 NextThread->State = Standby;
599 Prcb->NextThread = NextThread;
600 }
601 }
602 else
603 {
604 /* This thread can be preempted again */
605 Thread->Preempted = FALSE;
606 }
607 #else
608 /* We need to dispatch a new thread */
609 NextThread = NULL;
610 KiDispatchThread(Ready);
611 #endif
612 }
613 }
614
615 /* Release locks */
616 KiReleasePrcbLock(Prcb);
617 KiReleaseThreadLock(Thread);
618 KiExitDispatcher(Thread->WaitIrql);
619 }
620
621 VOID
622 FASTCALL
623 KiSetPriorityThread(IN PKTHREAD Thread,
624 IN KPRIORITY Priority)
625 {
626 PKPRCB Prcb;
627 ULONG Processor;
628 BOOLEAN RequestInterrupt = FALSE;
629 KPRIORITY OldPriority;
630 PKTHREAD NewThread;
631 ASSERT((Priority >= 0) && (Priority <= HIGH_PRIORITY));
632
633 /* Check if priority changed */
634 if (Thread->Priority != Priority)
635 {
636 /* Loop priority setting in case we need to start over */
637 for (;;)
638 {
639 /* Choose action based on thread's state */
640 if (Thread->State == Ready)
641 {
642 /* Make sure we're not on the ready queue */
643 if (!Thread->ProcessReadyQueue)
644 {
645 /* Get the PRCB for the thread and lock it */
646 Processor = Thread->NextProcessor;
647 Prcb = KiProcessorBlock[Processor];
648 KiAcquirePrcbLock(Prcb);
649
650 /* Make sure the thread is still ready and on this CPU */
651 if ((Thread->State == Ready) &&
652 (Thread->NextProcessor == Prcb->Number))
653 {
654 #ifdef NEW_SCHEDULER
655 /* Sanity check */
656 ASSERT((Prcb->ReadySummary &
657 PRIORITY_MASK(Thread->Priority)));
658
659 /* Remove it from the current queue */
660 if (RemoveEntryList(&Thread->WaitListEntry))
661 {
662 /* Update the ready summary */
663 Prcb->ReadySummary ^= PRIORITY_MASK(Thread->
664 Priority);
665 }
666 #else
667 KiRemoveFromThreadList(Thread);
668 #endif
669
670 /* Update priority */
671 Thread->Priority = (SCHAR)Priority;
672
673 /* Re-insert it at its current priority */
674 #ifndef NEW_SCHEDULER
675 KiInsertIntoThreadList(Priority, Thread);
676 //KiDispatchThreadNoLock(Ready);
677 #else
678 KiInsertDeferredReadyList(Thread);
679 #endif
680
681 /* Release the PRCB Lock */
682 KiReleasePrcbLock(Prcb);
683 }
684 else
685 {
686 /* Release the lock and loop again */
687 KiReleasePrcbLock(Prcb);
688 continue;
689 }
690 }
691 else
692 {
693 /* It's already on the ready queue, just update priority */
694 Thread->Priority = (SCHAR)Priority;
695 }
696 }
697 else if (Thread->State == Standby)
698 {
699 /* Get the PRCB for the thread and lock it */
700 Processor = Thread->NextProcessor;
701 Prcb = KiProcessorBlock[Processor];
702 KiAcquirePrcbLock(Prcb);
703
704 /* Check if we're still the next thread to run */
705 if (Thread == Prcb->NextThread)
706 {
707 /* Get the old priority and update ours */
708 OldPriority = Thread->Priority;
709 Thread->Priority = (SCHAR)Priority;
710
711 /* Check if there was a change */
712 if (Priority < OldPriority)
713 {
714 /* Find a new thread */
715 NewThread = KiSelectReadyThread(Priority + 1, Prcb);
716 if (NewThread)
717 {
718 /* Found a new one, set it on standby */
719 NewThread->State = Standby;
720 Prcb->NextThread = NewThread;
721
722 /* Dispatch our thread */
723 KiInsertDeferredReadyList(Thread);
724 }
725 }
726
727 /* Release the PRCB lock */
728 KiReleasePrcbLock(Prcb);
729 }
730 else
731 {
732 /* Release the lock and try again */
733 KiReleasePrcbLock(Prcb);
734 continue;
735 }
736 }
737 else if (Thread->State == Running)
738 {
739 /* Get the PRCB for the thread and lock it */
740 Processor = Thread->NextProcessor;
741 Prcb = KiProcessorBlock[Processor];
742 KiAcquirePrcbLock(Prcb);
743
744 /* Check if we're still the current thread running */
745 if (Thread == Prcb->CurrentThread)
746 {
747 /* Get the old priority and update ours */
748 OldPriority = Thread->Priority;
749 Thread->Priority = (SCHAR)Priority;
750
751 /* Check if there was a change and there's no new thread */
752 if ((Priority < OldPriority) && !(Prcb->NextThread))
753 {
754 #ifdef NEW_SCHEDULER
755 /* Find a new thread */
756 NewThread = KiSelectReadyThread(Priority + 1, Prcb);
757 if (NewThread)
758 {
759 /* Found a new one, set it on standby */
760 NewThread->State = Standby;
761 Prcb->NextThread = NewThread;
762
763 /* Request an interrupt */
764 RequestInterrupt = TRUE;
765 }
766 #else
767 /* Check for threads with a higher priority */
768 if (KeGetCurrentPrcb()->ReadySummary & ~((1 << (Priority + 1)) - 1))
769 {
770 /* Found a thread, is it us? */
771 if (Thread == KeGetCurrentThread())
772 {
773 /* Dispatch us */
774 //KiDispatchThreadNoLock(Ready);
775 return;
776 }
777 }
778 #endif
779 }
780
781 /* Release the lock and check if we need an interrupt */
782 KiReleasePrcbLock(Prcb);
783 if (RequestInterrupt)
784 {
785 /* Check if we're running on another CPU */
786 if (KeGetCurrentProcessorNumber() != Processor)
787 {
788 /* We are, send an IPI */
789 KiIpiSendRequest(AFFINITY_MASK(Processor), IPI_DPC);
790 }
791 }
792 }
793 else
794 {
795 /* Thread changed, release lock and restart */
796 KiReleasePrcbLock(Prcb);
797 continue;
798 }
799 }
800 else if (Thread->State == DeferredReady)
801 {
802 /* FIXME: TODO */
803 DPRINT1("Deferred state not yet supported\n");
804 KEBUGCHECK(0);
805 }
806 else
807 {
808 /* Any other state, just change priority */
809 Thread->Priority = (SCHAR)Priority;
810 }
811
812 /* If we got here, then thread state was consistent, so bail out */
813 break;
814 }
815 }
816 }
817
818 KAFFINITY
819 FASTCALL
820 KiSetAffinityThread(IN PKTHREAD Thread,
821 IN KAFFINITY Affinity)
822 {
823 KAFFINITY OldAffinity;
824
825 /* Get the current affinity */
826 OldAffinity = Thread->UserAffinity;
827
828 /* Make sure that the affinity is valid */
829 if (((Affinity & Thread->ApcState.Process->Affinity) != (Affinity)) ||
830 (!Affinity))
831 {
832 /* Bugcheck the system */
833 KeBugCheck(INVALID_AFFINITY_SET);
834 }
835
836 /* Update the new affinity */
837 Thread->UserAffinity = Affinity;
838
839 /* Check if system affinity is disabled */
840 if (!Thread->SystemAffinityActive)
841 {
842 /* FIXME: TODO */
843 DPRINT1("Affinity support disabled!\n");
844 }
845
846 /* Return the old affinity */
847 return OldAffinity;
848 }
849
850 /*
851 * @implemented
852 */
853 NTSTATUS
854 NTAPI
855 NtYieldExecution(VOID)
856 {
857 #ifdef NEW_SCHEDULER
858 NTSTATUS Status = STATUS_NO_YIELD_PERFORMED;
859 KIRQL OldIrql;
860 PKPRCB Prcb = KeGetCurrentPrcb();
861 PKTHREAD Thread = KeGetCurrentThread(), NextThread;
862
863 /* Fail if there's no ready summary */
864 if (!Prcb->ReadySummary) return Status;
865
866 /* Raise IRQL to synch */
867 OldIrql = KeRaiseIrqlToSynchLevel();
868
869 /* Now check if there's still a ready summary */
870 if (Prcb->ReadySummary)
871 {
872 /* Acquire thread and PRCB lock */
873 KiAcquireThreadLock(Thread);
874 KiAcquirePrcbLock(Prcb);
875
876 /* Find a new thread to run if none was selected */
877 if (!Prcb->NextThread) Prcb->NextThread = KiSelectReadyThread(1, Prcb);
878
879 /* Make sure we still have a next thread to schedule */
880 NextThread = Prcb->NextThread;
881 if (NextThread)
882 {
883 /* Reset quantum and recalculate priority */
884 Thread->Quantum = Thread->QuantumReset;
885 Thread->Priority = KiComputeNewPriority(Thread, 1);
886
887 /* Release the thread lock */
888 KiReleaseThreadLock(Thread);
889
890 /* Set context swap busy */
891 KiSetThreadSwapBusy(Thread);
892
893 /* Set the new thread as running */
894 Prcb->NextThread = NULL;
895 Prcb->CurrentThread = NextThread;
896 NextThread->State = Running;
897
898 /* Setup a yield wait and queue the thread */
899 Thread->WaitReason = WrYieldExecution;
900 KxQueueReadyThread(Thread, Prcb);
901
902 /* Make it wait at APC_LEVEL */
903 Thread->WaitIrql = APC_LEVEL;
904
905 /* Sanity check */
906 ASSERT(OldIrql <= DISPATCH_LEVEL);
907
908 /* Swap to new thread */
909 KiSwapContext(Thread, NextThread);
910 Status = STATUS_SUCCESS;
911 }
912 else
913 {
914 /* Release the PRCB and thread lock */
915 KiReleasePrcbLock(Prcb);
916 KiReleaseThreadLock(Thread);
917 }
918 }
919
920 /* Lower IRQL and return */
921 KeLowerIrql(OldIrql);
922 return Status;
923 #else
924 KiDispatchThread(Ready);
925 return STATUS_SUCCESS;
926 #endif
927 }
928