mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 01:25:41 +00:00
[NTOS]: Implement the idle loop in C.
svn path=/trunk/; revision=49485
This commit is contained in:
parent
c3f5d851e3
commit
8a59fecfa5
2 changed files with 60 additions and 125 deletions
|
@ -498,129 +498,6 @@ QuantumEnd:
|
||||||
ret
|
ret
|
||||||
.endfunc
|
.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 ****/
|
/* FIXFIX: Move to C code ****/
|
||||||
.globl _Ki386SetupAndExitToV86Mode@4
|
.globl _Ki386SetupAndExitToV86Mode@4
|
||||||
.func Ki386SetupAndExitToV86Mode@4
|
.func Ki386SetupAndExitToV86Mode@4
|
||||||
|
|
|
@ -249,6 +249,64 @@ KiInitializeContextThread(IN PKTHREAD Thread,
|
||||||
Thread->KernelStack = (PVOID)CtxSwitchFrame;
|
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 */
|
/* EOF */
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue