Author: sir_richard Date: Fri Nov 5 15:58:34 2010 New Revision: 49485
URL: http://svn.reactos.org/svn/reactos?rev=49485&view=rev Log: [NTOS]: Implement the idle loop in C.
Modified: trunk/reactos/ntoskrnl/ke/i386/ctxswitch.S trunk/reactos/ntoskrnl/ke/i386/thrdini.c
Modified: trunk/reactos/ntoskrnl/ke/i386/ctxswitch.S URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/ctxswitch.... ============================================================================== --- trunk/reactos/ntoskrnl/ke/i386/ctxswitch.S [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/ke/i386/ctxswitch.S [iso-8859-1] Fri Nov 5 15:58:34 2010 @@ -498,129 +498,6 @@ 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
Modified: trunk/reactos/ntoskrnl/ke/i386/thrdini.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/thrdini.c?... ============================================================================== --- trunk/reactos/ntoskrnl/ke/i386/thrdini.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/ke/i386/thrdini.c [iso-8859-1] Fri Nov 5 15:58:34 2010 @@ -249,6 +249,64 @@ 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 */ - -