[NTOS]: Implement the idle loop in C.

svn path=/trunk/; revision=49485
This commit is contained in:
Sir Richard 2010-11-05 15:58:34 +00:00
parent c3f5d851e3
commit 8a59fecfa5
2 changed files with 60 additions and 125 deletions

View file

@ -498,129 +498,6 @@ QuantumEnd:
ret
.endfunc
.globl @KiIdleLoop@0
.func @KiIdleLoop@0, @KiIdleLoop@0
@KiIdleLoop@0:
/* Set EBX */
mov ebx, fs:[KPCR_SELF]
/* Jump into mainline code */
jmp MainLoop
CpuIdle:
/* Call the CPU's idle function */
lea ecx, [ebx+KPCR_PRCB_POWER_STATE_IDLE_FUNCTION]
call [ecx]
MainLoop:
/* Cycle interrupts for 1 cycle */
sti
nop
nop
cli
/* Check if we have to deliver DPCs, timers, or deferred threads */
mov eax, [ebx+KPCR_PRCB_DPC_QUEUE_DEPTH]
or eax, [ebx+KPCR_PRCB_TIMER_REQUEST]
#ifdef CONFIG_SMP
or eax, [ebx+KPCR_PRCB_DEFERRED_READY_LIST_HEAD]
#endif
jz CheckSchedule
mov cl, DISPATCH_LEVEL
call @HalClearSoftwareInterrupt@4
/* Handle the above */
lea ecx, [ebx+KPCR_PRCB_DATA]
call @KiRetireDpcList@4
CheckSchedule:
/* Check if a next thread is queued */
cmp dword ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
#ifdef CONFIG_SMP
jz NoNextThread
#else
jz CpuIdle
#endif
#ifdef CONFIG_SMP
/* There is, raise IRQL to synch level */
call _KeRaiseIrqlToSynchLevel@0
#endif
sti
/* Set the current thread to ready */
mov edi, [ebx+KPCR_CURRENT_THREAD]
#ifdef CONFIG_SMP
mov byte ptr [edi+KTHREAD_SWAP_BUSY], 1
/* Acquire the PRCB Lock */
lock bts dword ptr [ebx+KPCR_PRCB_PRCB_LOCK], 0
jnb CheckNext
lea ecx, [ebx+KPCR_PRCB_PRCB_LOCK]
call @KefAcquireSpinLockAtDpcLevel@4
#endif
CheckNext:
/* Check if the next thread is the current */
mov esi, [ebx+KPCR_PRCB_NEXT_THREAD]
#ifdef CONFIG_SMP
cmp esi, edi
jz SameThread
#endif
/* Clear the next thread and set this one instead */
and dword ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
mov [ebx+KPCR_CURRENT_THREAD], esi
/* Set the thread as running */
mov byte ptr [esi+KTHREAD_STATE_], Running
#ifdef CONFIG_SMP
/* Disable the idle scheduler and release the PRCB lock */
and byte ptr [ebx+KPCR_PRCB_IDLE_SCHEDULE], 0
and dword ptr [ebx+KPCR_PRCB_PRCB_LOCK], 0
#endif
SwapContext:
/* Swap context at APC_LEVEL */
mov ecx, APC_LEVEL
call @KiSwapContextInternal@0
#ifdef CONFIG_SMP
/* Lower to DPC level */
mov ecx, DISPATCH_LEVEL
call @KfLowerIrql@4
#endif
jmp MainLoop
#ifdef CONFIG_SMP
SameThread:
/* Clear the next thread, and put the thread as ready after lock release */
and dword ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
and dword ptr [ebx+KPCR_PRCB_PRCB_LOCK], 0
and byte ptr [edi+KTHREAD_STATE_], Ready
jmp MainLoop
NoNextThread:
/* Check if the idle scheduler is enabled */
cmp byte ptr [ebx+KPCR_PRCB_IDLE_SCHEDULE], 0
jz CpuIdle
/* It is, so call the scheduler */
lea ecx, [ebx+KPCR_PRCB_DATA]
call @KiIdleSchedule@4
test eax, eax
/* Get new thread pointers and either swap or idle loop again */
mov esi, eax
mov edi, [ebx+KPCR_PRCB_IDLE_THREAD]
jnz SwapContext
jmp MainLoop
#endif
.endfunc
/* FIXFIX: Move to C code ****/
.globl _Ki386SetupAndExitToV86Mode@4
.func Ki386SetupAndExitToV86Mode@4

View file

@ -249,6 +249,64 @@ KiInitializeContextThread(IN PKTHREAD Thread,
Thread->KernelStack = (PVOID)CtxSwitchFrame;
}
VOID
FASTCALL
KiIdleLoop(VOID)
{
PKPRCB Prcb = KeGetCurrentPrcb();
PKTHREAD OldThread, NewThread;
/* Initialize the idle loop: disable interrupts */
_enable();
__asm__("nop; nop");
_disable();
/* Now loop forever */
while (TRUE)
{
/* Check for pending timers, pending DPCs, or pending ready threads */
if ((Prcb->DpcData[0].DpcQueueDepth) ||
(Prcb->TimerRequest) ||
(Prcb->DeferredReadyListHead.Next))
{
/* Quiesce the DPC software interrupt */
HalClearSoftwareInterrupt(DISPATCH_LEVEL);
/* Handle it */
KiRetireDpcList(Prcb);
}
/* Check if a new thread is scheduled for execution */
if (Prcb->NextThread)
{
/* Enable interupts */
_enable();
/* Capture current thread data */
OldThread = Prcb->CurrentThread;
NewThread = Prcb->NextThread;
/* Set new thread data */
Prcb->NextThread = NULL;
Prcb->CurrentThread = NewThread;
/* The thread is now running */
NewThread->State = Running;
/* Switch away from the idle thread */
KiSwapContext(OldThread, NewThread);
/* We are back in the idle thread -- disable interrupts again */
_enable();
__asm__("nop");
_disable();
}
else
{
/* Continue staying idle. Note the HAL returns with interrupts on */
Prcb->PowerState.IdleFunction(&Prcb->PowerState);
}
}
}
/* EOF */