From 8a59fecfa5196e643ccea45ddd2b355b90c626cb Mon Sep 17 00:00:00 2001 From: Sir Richard Date: Fri, 5 Nov 2010 15:58:34 +0000 Subject: [PATCH] [NTOS]: Implement the idle loop in C. svn path=/trunk/; revision=49485 --- reactos/ntoskrnl/ke/i386/ctxswitch.S | 123 --------------------------- reactos/ntoskrnl/ke/i386/thrdini.c | 62 +++++++++++++- 2 files changed, 60 insertions(+), 125 deletions(-) diff --git a/reactos/ntoskrnl/ke/i386/ctxswitch.S b/reactos/ntoskrnl/ke/i386/ctxswitch.S index 716db3b3b11..518d05da460 100644 --- a/reactos/ntoskrnl/ke/i386/ctxswitch.S +++ b/reactos/ntoskrnl/ke/i386/ctxswitch.S @@ -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 diff --git a/reactos/ntoskrnl/ke/i386/thrdini.c b/reactos/ntoskrnl/ke/i386/thrdini.c index 219e2883922..2fdcc6505fe 100644 --- a/reactos/ntoskrnl/ke/i386/thrdini.c +++ b/reactos/ntoskrnl/ke/i386/thrdini.c @@ -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 */ - -