ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

thrdschd.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         ReactOS Kernel
00003  * LICENSE:         GPL - See COPYING in the top level directory
00004  * FILE:            ntoskrnl/ke/thrdschd.c
00005  * PURPOSE:         Kernel Thread Scheduler (Affinity, Priority, Scheduling)
00006  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
00007  */
00008 
00009 /* INCLUDES ******************************************************************/
00010 
00011 #include <ntoskrnl.h>
00012 #define NDEBUG
00013 #include <debug.h>
00014 
00015 #ifdef _WIN64
00016 # define InterlockedOrSetMember(Destination, SetMember) \
00017     InterlockedOr64((PLONG64)Destination, SetMember);
00018 #else
00019 # define InterlockedOrSetMember(Destination, SetMember) \
00020     InterlockedOr((PLONG)Destination, SetMember);
00021 #endif
00022 
00023 /* GLOBALS *******************************************************************/
00024 
00025 ULONG_PTR KiIdleSummary;
00026 ULONG_PTR KiIdleSMTSummary;
00027 
00028 /* FUNCTIONS *****************************************************************/
00029 
00030 PKTHREAD
00031 FASTCALL
00032 KiIdleSchedule(IN PKPRCB Prcb)
00033 {
00034     /* FIXME: TODO */
00035     ASSERTMSG("SMP: Not yet implemented\n", FALSE);
00036     return NULL;
00037 }
00038 
00039 VOID
00040 FASTCALL
00041 KiProcessDeferredReadyList(IN PKPRCB Prcb)
00042 {
00043     PSINGLE_LIST_ENTRY ListEntry;
00044     PKTHREAD Thread;
00045 
00046     /* Make sure there is something on the ready list */
00047     ASSERT(Prcb->DeferredReadyListHead.Next != NULL);
00048 
00049     /* Get the first entry and clear the list */
00050     ListEntry = Prcb->DeferredReadyListHead.Next;
00051     Prcb->DeferredReadyListHead.Next = NULL;
00052 
00053     /* Start processing loop */
00054     do
00055     {
00056         /* Get the thread and advance to the next entry */
00057         Thread = CONTAINING_RECORD(ListEntry, KTHREAD, SwapListEntry);
00058         ListEntry = ListEntry->Next;
00059 
00060         /* Make the thread ready */
00061         KiDeferredReadyThread(Thread);
00062     } while (ListEntry != NULL);
00063 
00064     /* Make sure the ready list is still empty */
00065     ASSERT(Prcb->DeferredReadyListHead.Next == NULL);
00066 }
00067 
00068 VOID
00069 FASTCALL
00070 KiQueueReadyThread(IN PKTHREAD Thread,
00071                    IN PKPRCB Prcb)
00072 {
00073     /* Call the macro. We keep the API for compatibility with ASM code */
00074     KxQueueReadyThread(Thread, Prcb);
00075 }
00076 
00077 VOID
00078 FASTCALL
00079 KiDeferredReadyThread(IN PKTHREAD Thread)
00080 {
00081     PKPRCB Prcb;
00082     BOOLEAN Preempted;
00083     ULONG Processor = 0;
00084     KPRIORITY OldPriority;
00085     PKTHREAD NextThread;
00086 
00087     /* Sanity checks */
00088     ASSERT(Thread->State == DeferredReady);
00089     ASSERT((Thread->Priority >= 0) && (Thread->Priority <= HIGH_PRIORITY));
00090 
00091     /* Check if we have any adjusts to do */
00092     if (Thread->AdjustReason == AdjustBoost)
00093     {
00094         /* Lock the thread */
00095         KiAcquireThreadLock(Thread);
00096 
00097         /* Check if the priority is low enough to qualify for boosting */
00098         if ((Thread->Priority <= Thread->AdjustIncrement) &&
00099             (Thread->Priority < (LOW_REALTIME_PRIORITY - 3)) &&
00100             !(Thread->DisableBoost))
00101         {
00102             /* Calculate the new priority based on the adjust increment */
00103             OldPriority = min(Thread->AdjustIncrement + 1,
00104                               LOW_REALTIME_PRIORITY - 3);
00105 
00106             /* Make sure we're not decreasing outside of the priority range */
00107             ASSERT((Thread->PriorityDecrement >= 0) &&
00108                    (Thread->PriorityDecrement <= Thread->Priority));
00109 
00110             /* Calculate the new priority decrement based on the boost */
00111             Thread->PriorityDecrement += ((SCHAR)OldPriority - Thread->Priority);
00112 
00113             /* Again verify that this decrement is valid */
00114             ASSERT((Thread->PriorityDecrement >= 0) &&
00115                    (Thread->PriorityDecrement <= OldPriority));
00116 
00117             /* Set the new priority */
00118             Thread->Priority = (SCHAR)OldPriority;
00119         }
00120 
00121         /* We need 4 quanta, make sure we have them, then decrease by one */
00122         if (Thread->Quantum < 4) Thread->Quantum = 4;
00123         Thread->Quantum--;
00124 
00125         /* Make sure the priority is still valid */
00126         ASSERT((Thread->Priority >= 0) && (Thread->Priority <= HIGH_PRIORITY));
00127 
00128         /* Release the lock and clear the adjust reason */
00129         KiReleaseThreadLock(Thread);
00130         Thread->AdjustReason = AdjustNone;
00131     }
00132     else if (Thread->AdjustReason == AdjustUnwait)
00133     {
00134         /* Acquire the thread lock and check if this is a real-time thread */
00135         KiAcquireThreadLock(Thread);
00136         if (Thread->Priority < LOW_REALTIME_PRIORITY)
00137         {
00138             /* It's not real time, but is it time critical? */
00139             if (Thread->BasePriority >= (LOW_REALTIME_PRIORITY - 2))
00140             {
00141                 /* It is, so simply reset its quantum */
00142                 Thread->Quantum = Thread->QuantumReset;
00143             }
00144             else
00145             {
00146                 /* Has the priority been adjusted previously? */
00147                 if (!(Thread->PriorityDecrement) && (Thread->AdjustIncrement))
00148                 {
00149                     /* Yes, reset its quantum */
00150                     Thread->Quantum = Thread->QuantumReset;
00151                 }
00152 
00153                 /* Wait code already handles quantum adjustment during APCs */
00154                 if (Thread->WaitStatus != STATUS_KERNEL_APC)
00155                 {
00156                     /* Decrease the quantum by one and check if we're out */
00157                     if (--Thread->Quantum <= 0)
00158                     {
00159                         /* We are, reset the quantum and get a new priority */
00160                         Thread->Quantum = Thread->QuantumReset;
00161                         Thread->Priority = KiComputeNewPriority(Thread, 1);
00162                     }
00163                 }
00164             }
00165 
00166             /* Now check if we have no decrement and boosts are enabled */
00167             if (!(Thread->PriorityDecrement) && !(Thread->DisableBoost))
00168             {
00169                 /* Make sure we have an increment */
00170                 ASSERT(Thread->AdjustIncrement >= 0);
00171 
00172                 /* Calculate the new priority after the increment */
00173                 OldPriority = Thread->BasePriority + Thread->AdjustIncrement;
00174 
00175                 /* Check if this new priority is higher */
00176                 if (OldPriority > Thread->Priority)
00177                 {
00178                     /* Make sure we don't go into the real time range */
00179                     if (OldPriority >= LOW_REALTIME_PRIORITY)
00180                     {
00181                         /* Normalize it back down one notch */
00182                         OldPriority = LOW_REALTIME_PRIORITY - 1;
00183                     }
00184 
00185                     /* Check if the priority is higher then the boosted base */
00186                     if (OldPriority > (Thread->BasePriority +
00187                                        Thread->AdjustIncrement))
00188                     {
00189                         /* Setup a priority decrement to nullify the boost  */
00190                         Thread->PriorityDecrement = ((SCHAR)OldPriority -
00191                                                     Thread->BasePriority -
00192                                                     Thread->AdjustIncrement);
00193                     }
00194 
00195                     /* Make sure that the priority decrement is valid */
00196                     ASSERT((Thread->PriorityDecrement >= 0) &&
00197                            (Thread->PriorityDecrement <= OldPriority));
00198 
00199                     /* Set this new priority */
00200                     Thread->Priority = (SCHAR)OldPriority;
00201                 }
00202             }
00203         }
00204         else
00205         {
00206             /* It's a real-time thread, so just reset its quantum */
00207             Thread->Quantum = Thread->QuantumReset;
00208         }
00209 
00210         /* Make sure the priority makes sense */
00211         ASSERT((Thread->Priority >= 0) && (Thread->Priority <= HIGH_PRIORITY));
00212 
00213         /* Release the thread lock and reset the adjust reason */
00214         KiReleaseThreadLock(Thread);
00215         Thread->AdjustReason = AdjustNone;
00216     }
00217 
00218     /* Clear thread preemption status and save current values */
00219     Preempted = Thread->Preempted;
00220     OldPriority = Thread->Priority;
00221     Thread->Preempted = FALSE;
00222 
00223     /* Queue the thread on CPU 0 and get the PRCB and lock it */
00224     Thread->NextProcessor = 0;
00225     Prcb = KiProcessorBlock[0];
00226     KiAcquirePrcbLock(Prcb);
00227 
00228     /* Check if we have an idle summary */
00229     if (KiIdleSummary)
00230     {
00231         /* Clear it and set this thread as the next one */
00232         KiIdleSummary = 0;
00233         Thread->State = Standby;
00234         Prcb->NextThread = Thread;
00235 
00236         /* Unlock the PRCB and return */
00237         KiReleasePrcbLock(Prcb);
00238         return;
00239     }
00240 
00241     /* Set the CPU number */
00242     Thread->NextProcessor = (UCHAR)Processor;
00243 
00244     /* Get the next scheduled thread */
00245     NextThread = Prcb->NextThread;
00246     if (NextThread)
00247     {
00248         /* Sanity check */
00249         ASSERT(NextThread->State == Standby);
00250 
00251         /* Check if priority changed */
00252         if (OldPriority > NextThread->Priority)
00253         {
00254             /* Preempt the thread */
00255             NextThread->Preempted = TRUE;
00256 
00257             /* Put this one as the next one */
00258             Thread->State = Standby;
00259             Prcb->NextThread = Thread;
00260 
00261             /* Set it in deferred ready mode */
00262             NextThread->State = DeferredReady;
00263             NextThread->DeferredProcessor = Prcb->Number;
00264             KiReleasePrcbLock(Prcb);
00265             KiDeferredReadyThread(NextThread);
00266             return;
00267         }
00268     }
00269     else
00270     {
00271         /* Set the next thread as the current thread */
00272         NextThread = Prcb->CurrentThread;
00273         if (OldPriority > NextThread->Priority)
00274         {
00275             /* Preempt it if it's already running */
00276             if (NextThread->State == Running) NextThread->Preempted = TRUE;
00277 
00278             /* Set the thread on standby and as the next thread */
00279             Thread->State = Standby;
00280             Prcb->NextThread = Thread;
00281 
00282             /* Release the lock */
00283             KiReleasePrcbLock(Prcb);
00284 
00285             /* Check if we're running on another CPU */
00286             if (KeGetCurrentProcessorNumber() != Thread->NextProcessor)
00287             {
00288                 /* We are, send an IPI */
00289                 KiIpiSend(AFFINITY_MASK(Thread->NextProcessor), IPI_DPC);
00290             }
00291             return;
00292         }
00293     }
00294 
00295     /* Sanity check */
00296     ASSERT((OldPriority >= 0) && (OldPriority <= HIGH_PRIORITY));
00297 
00298     /* Set this thread as ready */
00299     Thread->State = Ready;
00300     Thread->WaitTime = KeTickCount.LowPart;
00301 
00302     /* Insert this thread in the appropriate order */
00303     Preempted ? InsertHeadList(&Prcb->DispatcherReadyListHead[OldPriority],
00304                                &Thread->WaitListEntry) :
00305                 InsertTailList(&Prcb->DispatcherReadyListHead[OldPriority],
00306                                &Thread->WaitListEntry);
00307 
00308     /* Update the ready summary */
00309     Prcb->ReadySummary |= PRIORITY_MASK(OldPriority);
00310 
00311     /* Sanity check */
00312     ASSERT(OldPriority == Thread->Priority);
00313 
00314     /* Release the lock */
00315     KiReleasePrcbLock(Prcb);
00316 }
00317 
00318 PKTHREAD
00319 FASTCALL
00320 KiSelectNextThread(IN PKPRCB Prcb)
00321 {
00322     PKTHREAD Thread;
00323 
00324     /* Select a ready thread */
00325     Thread = KiSelectReadyThread(0, Prcb);
00326     if (!Thread)
00327     {
00328         /* Didn't find any, get the current idle thread */
00329         Thread = Prcb->IdleThread;
00330 
00331         /* Enable idle scheduling */
00332         InterlockedOrSetMember(&KiIdleSummary, Prcb->SetMember);
00333         Prcb->IdleSchedule = TRUE;
00334 
00335         /* FIXME: SMT support */
00336         ASSERTMSG("SMP: Not yet implemented\n", FALSE);
00337     }
00338 
00339     /* Sanity checks and return the thread */
00340     ASSERT(Thread != NULL);
00341     ASSERT((Thread->BasePriority == 0) || (Thread->Priority != 0));
00342     return Thread;
00343 }
00344 
00345 LONG_PTR
00346 FASTCALL
00347 KiSwapThread(IN PKTHREAD CurrentThread,
00348              IN PKPRCB Prcb)
00349 {
00350     BOOLEAN ApcState = FALSE;
00351     KIRQL WaitIrql;
00352     LONG_PTR WaitStatus;
00353     PKTHREAD NextThread;
00354     ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
00355 
00356     /* Acquire the PRCB lock */
00357     KiAcquirePrcbLock(Prcb);
00358 
00359     /* Get the next thread */
00360     NextThread = Prcb->NextThread;
00361     if (NextThread)
00362     {
00363         /* Already got a thread, set it up */
00364         Prcb->NextThread = NULL;
00365         Prcb->CurrentThread = NextThread;
00366         NextThread->State = Running;
00367     }
00368     else
00369     {
00370         /* Try to find a ready thread */
00371         NextThread = KiSelectReadyThread(0, Prcb);
00372         if (NextThread)
00373         {
00374             /* Switch to it */
00375             Prcb->CurrentThread = NextThread;
00376             NextThread->State = Running;
00377         }
00378         else
00379         {
00380             /* Set the idle summary */
00381             InterlockedOrSetMember(&KiIdleSummary, Prcb->SetMember);
00382 
00383             /* Schedule the idle thread */
00384             NextThread = Prcb->IdleThread;
00385             Prcb->CurrentThread = NextThread;
00386             NextThread->State = Running;
00387         }
00388     }
00389 
00390     /* Sanity check and release the PRCB */
00391     ASSERT(CurrentThread != Prcb->IdleThread);
00392     KiReleasePrcbLock(Prcb);
00393 
00394     /* Save the wait IRQL */
00395     WaitIrql = CurrentThread->WaitIrql;
00396 
00397     /* Swap contexts */
00398     ApcState = KiSwapContext(WaitIrql, CurrentThread);
00399 
00400     /* Get the wait status */
00401     WaitStatus = CurrentThread->WaitStatus;
00402 
00403     /* Check if we need to deliver APCs */
00404     if (ApcState)
00405     {
00406         /* Lower to APC_LEVEL */
00407         KeLowerIrql(APC_LEVEL);
00408 
00409         /* Deliver APCs */
00410         KiDeliverApc(KernelMode, NULL, NULL);
00411         ASSERT(WaitIrql == 0);
00412     }
00413 
00414     /* Lower IRQL back to what it was and return the wait status */
00415     KeLowerIrql(WaitIrql);
00416     return WaitStatus;
00417 }
00418 
00419 VOID
00420 NTAPI
00421 KiReadyThread(IN PKTHREAD Thread)
00422 {
00423     IN PKPROCESS Process = Thread->ApcState.Process;
00424 
00425     /* Check if the process is paged out */
00426     if (Process->State != ProcessInMemory)
00427     {
00428         /* We don't page out processes in ROS */
00429         ASSERT(FALSE);
00430     }
00431     else if (!Thread->KernelStackResident)
00432     {
00433         /* Increase the stack count */
00434         ASSERT(Process->StackCount != MAXULONG_PTR);
00435         Process->StackCount++;
00436 
00437         /* Set the thread to transition */
00438         ASSERT(Thread->State != Transition);
00439         Thread->State = Transition;
00440 
00441         /* The stack is always resident in ROS */
00442         ASSERT(FALSE);
00443     }
00444     else
00445     {
00446         /* Insert the thread on the deferred ready list */
00447         KiInsertDeferredReadyList(Thread);
00448     }
00449 }
00450 
00451 VOID
00452 NTAPI
00453 KiAdjustQuantumThread(IN PKTHREAD Thread)
00454 {
00455     PKPRCB Prcb = KeGetCurrentPrcb();
00456     PKTHREAD NextThread;
00457 
00458     /* Acquire thread and PRCB lock */
00459     KiAcquireThreadLock(Thread);
00460     KiAcquirePrcbLock(Prcb);
00461 
00462     /* Don't adjust for RT threads */
00463     if ((Thread->Priority < LOW_REALTIME_PRIORITY) &&
00464         (Thread->BasePriority < (LOW_REALTIME_PRIORITY - 2)))
00465     {
00466         /* Decrease Quantum by one and see if we've ran out */
00467         if (--Thread->Quantum <= 0)
00468         {
00469             /* Return quantum */
00470             Thread->Quantum = Thread->QuantumReset;
00471 
00472             /* Calculate new Priority */
00473             Thread->Priority = KiComputeNewPriority(Thread, 1);
00474 
00475             /* Check if there's no next thread scheduled */
00476             if (!Prcb->NextThread)
00477             {
00478                 /* Select a ready thread and check if we found one */
00479                 NextThread = KiSelectReadyThread(Thread->Priority, Prcb);
00480                 if (NextThread)
00481                 {
00482                     /* Set it on standby and switch to it */
00483                     NextThread->State = Standby;
00484                     Prcb->NextThread = NextThread;
00485                 }
00486             }
00487             else
00488             {
00489                 /* This thread can be preempted again */
00490                 Thread->Preempted = FALSE;
00491             }
00492         }
00493     }
00494 
00495     /* Release locks */
00496     KiReleasePrcbLock(Prcb);
00497     KiReleaseThreadLock(Thread);
00498     KiExitDispatcher(Thread->WaitIrql);
00499 }
00500 
00501 VOID
00502 FASTCALL
00503 KiSetPriorityThread(IN PKTHREAD Thread,
00504                     IN KPRIORITY Priority)
00505 {
00506     PKPRCB Prcb;
00507     ULONG Processor;
00508     BOOLEAN RequestInterrupt = FALSE;
00509     KPRIORITY OldPriority;
00510     PKTHREAD NewThread;
00511     ASSERT((Priority >= 0) && (Priority <= HIGH_PRIORITY));
00512 
00513     /* Check if priority changed */
00514     if (Thread->Priority != Priority)
00515     {
00516         /* Loop priority setting in case we need to start over */
00517         for (;;)
00518         {
00519             /* Choose action based on thread's state */
00520             if (Thread->State == Ready)
00521             {
00522                 /* Make sure we're not on the ready queue */
00523                 if (!Thread->ProcessReadyQueue)
00524                 {
00525                     /* Get the PRCB for the thread and lock it */
00526                     Processor = Thread->NextProcessor;
00527                     Prcb = KiProcessorBlock[Processor];
00528                     KiAcquirePrcbLock(Prcb);
00529 
00530                     /* Make sure the thread is still ready and on this CPU */
00531                     if ((Thread->State == Ready) &&
00532                         (Thread->NextProcessor == Prcb->Number))
00533                     {
00534                         /* Sanity check */
00535                         ASSERT((Prcb->ReadySummary &
00536                                 PRIORITY_MASK(Thread->Priority)));
00537 
00538                         /* Remove it from the current queue */
00539                         if (RemoveEntryList(&Thread->WaitListEntry))
00540                         {
00541                             /* Update the ready summary */
00542                             Prcb->ReadySummary ^= PRIORITY_MASK(Thread->
00543                                                                 Priority);
00544                         }
00545 
00546                         /* Update priority */
00547                         Thread->Priority = (SCHAR)Priority;
00548 
00549                         /* Re-insert it at its current priority */
00550                         KiInsertDeferredReadyList(Thread);
00551 
00552                         /* Release the PRCB Lock */
00553                         KiReleasePrcbLock(Prcb);
00554                     }
00555                     else
00556                     {
00557                         /* Release the lock and loop again */
00558                         KiReleasePrcbLock(Prcb);
00559                         continue;
00560                     }
00561                 }
00562                 else
00563                 {
00564                     /* It's already on the ready queue, just update priority */
00565                     Thread->Priority = (SCHAR)Priority;
00566                 }
00567             }
00568             else if (Thread->State == Standby)
00569             {
00570                 /* Get the PRCB for the thread and lock it */
00571                 Processor = Thread->NextProcessor;
00572                 Prcb = KiProcessorBlock[Processor];
00573                 KiAcquirePrcbLock(Prcb);
00574 
00575                 /* Check if we're still the next thread to run */
00576                 if (Thread == Prcb->NextThread)
00577                 {
00578                     /* Get the old priority and update ours */
00579                     OldPriority = Thread->Priority;
00580                     Thread->Priority = (SCHAR)Priority;
00581 
00582                     /* Check if there was a change */
00583                     if (Priority < OldPriority)
00584                     {
00585                         /* Find a new thread */
00586                         NewThread = KiSelectReadyThread(Priority + 1, Prcb);
00587                         if (NewThread)
00588                         {
00589                             /* Found a new one, set it on standby */
00590                             NewThread->State = Standby;
00591                             Prcb->NextThread = NewThread;
00592 
00593                             /* Dispatch our thread */
00594                             KiInsertDeferredReadyList(Thread);
00595                         }
00596                     }
00597 
00598                     /* Release the PRCB lock */
00599                     KiReleasePrcbLock(Prcb);
00600                 }
00601                 else
00602                 {
00603                     /* Release the lock and try again */
00604                     KiReleasePrcbLock(Prcb);
00605                     continue;
00606                 }
00607             }
00608             else if (Thread->State == Running)
00609             {
00610                 /* Get the PRCB for the thread and lock it */
00611                 Processor = Thread->NextProcessor;
00612                 Prcb = KiProcessorBlock[Processor];
00613                 KiAcquirePrcbLock(Prcb);
00614 
00615                 /* Check if we're still the current thread running */
00616                 if (Thread == Prcb->CurrentThread)
00617                 {
00618                     /* Get the old priority and update ours */
00619                     OldPriority = Thread->Priority;
00620                     Thread->Priority = (SCHAR)Priority;
00621 
00622                     /* Check if there was a change and there's no new thread */
00623                     if ((Priority < OldPriority) && !(Prcb->NextThread))
00624                     {
00625                         /* Find a new thread */
00626                         NewThread = KiSelectReadyThread(Priority + 1, Prcb);
00627                         if (NewThread)
00628                         {
00629                             /* Found a new one, set it on standby */
00630                             NewThread->State = Standby;
00631                             Prcb->NextThread = NewThread;
00632 
00633                             /* Request an interrupt */
00634                             RequestInterrupt = TRUE;
00635                         }
00636                     }
00637 
00638                     /* Release the lock and check if we need an interrupt */
00639                     KiReleasePrcbLock(Prcb);
00640                     if (RequestInterrupt)
00641                     {
00642                         /* Check if we're running on another CPU */
00643                         if (KeGetCurrentProcessorNumber() != Processor)
00644                         {
00645                             /* We are, send an IPI */
00646                             KiIpiSend(AFFINITY_MASK(Processor), IPI_DPC);
00647                         }
00648                     }
00649                 }
00650                 else
00651                 {
00652                     /* Thread changed, release lock and restart */
00653                     KiReleasePrcbLock(Prcb);
00654                     continue;
00655                 }
00656             }
00657             else if (Thread->State == DeferredReady)
00658             {
00659                 /* FIXME: TODO */
00660                 DPRINT1("Deferred state not yet supported\n");
00661                 ASSERT(FALSE);
00662             }
00663             else
00664             {
00665                 /* Any other state, just change priority */
00666                 Thread->Priority = (SCHAR)Priority;
00667             }
00668 
00669             /* If we got here, then thread state was consistent, so bail out */
00670             break;
00671         }
00672     }
00673 }
00674 
00675 KAFFINITY
00676 FASTCALL
00677 KiSetAffinityThread(IN PKTHREAD Thread,
00678                     IN KAFFINITY Affinity)
00679 {
00680     KAFFINITY OldAffinity;
00681 
00682     /* Get the current affinity */
00683     OldAffinity = Thread->UserAffinity;
00684 
00685     /* Make sure that the affinity is valid */
00686     if (((Affinity & Thread->ApcState.Process->Affinity) != (Affinity)) ||
00687         (!Affinity))
00688     {
00689         /* Bugcheck the system */
00690         KeBugCheck(INVALID_AFFINITY_SET);
00691     }
00692 
00693     /* Update the new affinity */
00694     Thread->UserAffinity = Affinity;
00695 
00696     /* Check if system affinity is disabled */
00697     if (!Thread->SystemAffinityActive)
00698     {
00699         /* FIXME: TODO */
00700         DPRINT1("Affinity support disabled!\n");
00701     }
00702 
00703     /* Return the old affinity */
00704     return OldAffinity;
00705 }
00706 
00707 //
00708 // This macro exists because NtYieldExecution locklessly attempts to read from
00709 // the KPRCB's ready summary, and the usual way of going through KeGetCurrentPrcb
00710 // would require getting fs:1C first (or gs), and then doing another dereference.
00711 // In an attempt to minimize the amount of instructions and potential race/tear
00712 // that could happen, Windows seems to define this as a macro that directly acceses
00713 // the ready summary through a single fs: read by going through the KPCR's PrcbData.
00714 //
00715 // See http://research.microsoft.com/en-us/collaboration/global/asia-pacific/
00716 //     programs/trk_case4_process-thread_management.pdf
00717 //
00718 // We need this per-arch because sometimes it's Prcb and sometimes PrcbData, and
00719 // because on x86 it's FS, and on x64 it's GS (not sure what it is on ARM/PPC).
00720 //
00721 #ifdef _M_IX86
00722 #define KiGetCurrentReadySummary() __readfsdword(FIELD_OFFSET(KIPCR, PrcbData.ReadySummary))
00723 #elif _M_AMD64
00724 #define KiGetCurrentReadySummary() __readgsdword(FIELD_OFFSET(KIPCR, Prcb.ReadySummary))
00725 #else
00726 #error Implement me!
00727 #endif
00728 
00729 /*
00730  * @implemented
00731  */
00732 NTSTATUS
00733 NTAPI
00734 NtYieldExecution(VOID)
00735 {
00736     NTSTATUS Status;
00737     KIRQL OldIrql;
00738     PKPRCB Prcb;
00739     PKTHREAD Thread, NextThread;
00740 
00741     /* NB: No instructions (other than entry code) should preceed this line */
00742 
00743     /* Fail if there's no ready summary */
00744     if (!KiGetCurrentReadySummary()) return STATUS_NO_YIELD_PERFORMED;
00745 
00746     /* Now get the current thread, set the status... */
00747     Status = STATUS_NO_YIELD_PERFORMED;
00748     Thread = KeGetCurrentThread();
00749 
00750     /* Raise IRQL to synch and get the KPRCB now */
00751     OldIrql = KeRaiseIrqlToSynchLevel();
00752     Prcb = KeGetCurrentPrcb();
00753 
00754     /* Now check if there's still a ready summary */
00755     if (Prcb->ReadySummary)
00756     {
00757         /* Acquire thread and PRCB lock */
00758         KiAcquireThreadLock(Thread);
00759         KiAcquirePrcbLock(Prcb);
00760 
00761         /* Find a new thread to run if none was selected */
00762         if (!Prcb->NextThread) Prcb->NextThread = KiSelectReadyThread(1, Prcb);
00763 
00764         /* Make sure we still have a next thread to schedule */
00765         NextThread = Prcb->NextThread;
00766         if (NextThread)
00767         {
00768             /* Reset quantum and recalculate priority */
00769             Thread->Quantum = Thread->QuantumReset;
00770             Thread->Priority = KiComputeNewPriority(Thread, 1);
00771 
00772             /* Release the thread lock */
00773             KiReleaseThreadLock(Thread);
00774 
00775             /* Set context swap busy */
00776             KiSetThreadSwapBusy(Thread);
00777 
00778             /* Set the new thread as running */
00779             Prcb->NextThread = NULL;
00780             Prcb->CurrentThread = NextThread;
00781             NextThread->State = Running;
00782 
00783             /* Setup a yield wait and queue the thread */
00784             Thread->WaitReason = WrYieldExecution;
00785             KxQueueReadyThread(Thread, Prcb);
00786 
00787             /* Make it wait at APC_LEVEL */
00788             Thread->WaitIrql = APC_LEVEL;
00789 
00790             /* Sanity check */
00791             ASSERT(OldIrql <= DISPATCH_LEVEL);
00792 
00793             /* Swap to new thread */
00794             KiSwapContext(APC_LEVEL, Thread);
00795             Status = STATUS_SUCCESS;
00796         }
00797         else
00798         {
00799             /* Release the PRCB and thread lock */
00800             KiReleasePrcbLock(Prcb);
00801             KiReleaseThreadLock(Thread);
00802         }
00803     }
00804 
00805     /* Lower IRQL and return */
00806     KeLowerIrql(OldIrql);
00807     return Status;
00808 }

Generated on Sun May 27 2012 04:37:33 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.