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 */
-
-