[NTOS]: Optimize new context switching code to avoid wasted cycles.

svn path=/trunk/; revision=49523
This commit is contained in:
Sir Richard 2010-11-08 11:56:22 +00:00
parent 44eef5b073
commit e8c269c0c4
6 changed files with 24 additions and 89 deletions

View file

@ -298,8 +298,8 @@ KeReadStateThread(IN PKTHREAD Thread);
BOOLEAN BOOLEAN
FASTCALL FASTCALL
KiSwapContext( KiSwapContext(
IN PKTHREAD CurrentThread, IN KIRQL WaitIrql,
IN PKTHREAD NewThread IN PKTHREAD CurrentThread
); );
VOID VOID

View file

@ -534,7 +534,7 @@ KiQuantumEnd(VOID)
Thread->WaitIrql = APC_LEVEL; Thread->WaitIrql = APC_LEVEL;
/* Swap threads */ /* Swap threads */
KiSwapContext(Thread, NextThread); KiSwapContext(APC_LEVEL, Thread);
/* Lower IRQL back to DISPATCH_LEVEL */ /* Lower IRQL back to DISPATCH_LEVEL */
KeLowerIrql(DISPATCH_LEVEL); KeLowerIrql(DISPATCH_LEVEL);

View file

@ -13,70 +13,20 @@
#include <ndk/asm.h> #include <ndk/asm.h>
.intel_syntax noprefix .intel_syntax noprefix
#define Ready 1
#define Running 2
#define WrDispatchInt 0x1F
/* FUNCTIONS ****************************************************************/ /* FUNCTIONS ****************************************************************/
/*++
* KiSwapContextInternal
*
* The KiSwapContextInternal routine switches context to another thread.
*
* Params:
* ESI - Pointer to the KTHREAD to which the caller wishes to
* switch to.
* EDI - Pointer to the KTHREAD to which the caller wishes to
* switch from.
*
* Returns:
* None.
*
* Remarks:
* Absolutely all registers except ESP can be trampled here for maximum code flexibility.
*
*--*/
.globl @KiSwapContextInternal@0 .globl @KiSwapContextInternal@0
.func @KiSwapContextInternal@0, @KiSwapContextInternal@0 .func @KiSwapContextInternal@0, @KiSwapContextInternal@0
@KiSwapContextInternal@0: @KiSwapContextInternal@0:
/* Set APC Bypass Disable and old thread pointer */
mov edx, edi
or dl, cl
/* Build switch frame */ /* Build switch frame */
sub esp, 2 * 4 sub esp, 2 * 4
mov ecx, esp mov ecx, esp
call @KiSwapContextEntry@8 jmp @KiSwapContextEntry@8
mov ecx, 0xB00BFACA
jmp $
.endfunc .endfunc
/*++
* KiSwapContext
*
* The KiSwapContext routine switches context to another thread.
*
* Params:
* TargetThread - Pointer to the KTHREAD to which the caller wishes to
* switch to.
*
* Returns:
* The WaitStatus of the Target Thread.
*
* Remarks:
* This is a wrapper around KiSwapContextInternal which will save all the
* non-volatile registers so that the Internal function can use all of
* them. It will also save the old current thread and set the new one.
*
* The calling thread does not return after KiSwapContextInternal until
* another thread switches to IT.
*
*--*/
.globl @KiSwapContext@8 .globl @KiSwapContext@8
.func @KiSwapContext@8, @KiSwapContext@8 .func @KiSwapContext@8, @KiSwapContext@8
@KiSwapContext@8: @KiSwapContext@8:
/* Save 4 registers */ /* Save 4 registers */
sub esp, 4 * 4 sub esp, 4 * 4
@ -86,17 +36,8 @@
mov [esp+4], edi mov [esp+4], edi
mov [esp+0], ebp mov [esp+0], ebp
/* Get the current KPCR */
mov ebx, fs:[KPCR_SELF]
/* Get the Current Thread */
mov edi, ecx
/* Get the New Thread */
mov esi, edx
/* Get the wait IRQL */ /* Get the wait IRQL */
movzx ecx, byte ptr [edi+KTHREAD_WAIT_IRQL] or dl, cl
/* Do the swap with the registers correctly setup */ /* Do the swap with the registers correctly setup */
call @KiSwapContextInternal@0 call @KiSwapContextInternal@0
@ -112,10 +53,21 @@
ret ret
.endfunc .endfunc
.globl @KiSwitchThreads@8
.func @KiSwitchThreads@8, @KiSwitchThreads@8
@KiSwitchThreads@8:
/* Load the new kernel stack and switch OS to new thread */
mov esp, edx
call @KiSwapContextExit@8
/* Now we're on the new thread. Return to the caller to restore registers */
add esp, 2 * 4
ret
.endfunc
.globl @KiRetireDpcListInDpcStack@8 .globl @KiRetireDpcListInDpcStack@8
.func @KiRetireDpcListInDpcStack@8, @KiRetireDpcListInDpcStack@8 .func @KiRetireDpcListInDpcStack@8, @KiRetireDpcListInDpcStack@8
@KiRetireDpcListInDpcStack@8: @KiRetireDpcListInDpcStack@8:
/* Switch stacks and retire DPCs */ /* Switch stacks and retire DPCs */
mov eax, esp mov eax, esp
mov esp, edx mov esp, edx
@ -140,20 +92,6 @@ _Ki386SetupAndExitToV86Mode@4:
jmp $ jmp $
.endfunc .endfunc
.globl @KiSwitchThreads@8
.func @KiSwitchThreads@8, @KiSwitchThreads@8
@KiSwitchThreads@8:
/* Load the new kernel stack and switch OS to new thread */
mov esp, [edx+KTHREAD_KERNEL_STACK]
mov edx, esp
call @KiSwapContextExit@8
/* Now we're on the new thread. Return to the caller to restore registers */
add esp, 2 * 4
ret
.endfunc
.globl @Ki386BiosCallReturnAddress@4 .globl @Ki386BiosCallReturnAddress@4
@Ki386BiosCallReturnAddress@4: @Ki386BiosCallReturnAddress@4:

View file

@ -309,7 +309,7 @@ KiIdleLoop(VOID)
NewThread->State = Running; NewThread->State = Running;
/* Switch away from the idle thread */ /* Switch away from the idle thread */
KiSwapContext(OldThread, NewThread); KiSwapContext(APC_LEVEL, OldThread);
/* We are back in the idle thread -- disable interrupts again */ /* We are back in the idle thread -- disable interrupts again */
_enable(); _enable();
@ -416,9 +416,6 @@ KiSwapContextEntry(IN PKSWITCHFRAME SwitchFrame,
PKTHREAD OldThread, NewThread; PKTHREAD OldThread, NewThread;
ULONG Cr0, NewCr0; ULONG Cr0, NewCr0;
/* Switch threads, check for APC disable */
ASSERT(OldThreadAndApcFlag &~ 1);
/* Save APC bypass disable */ /* Save APC bypass disable */
SwitchFrame->ApcBypassDisable = OldThreadAndApcFlag & 3; SwitchFrame->ApcBypassDisable = OldThreadAndApcFlag & 3;
SwitchFrame->ExceptionList = Pcr->NtTib.ExceptionList; SwitchFrame->ExceptionList = Pcr->NtTib.ExceptionList;
@ -451,7 +448,7 @@ KiSwapContextEntry(IN PKSWITCHFRAME SwitchFrame,
/* Now enable interrupts and do the switch */ /* Now enable interrupts and do the switch */
_enable(); _enable();
KiSwitchThreads(OldThread, NewThread); KiSwitchThreads(OldThread, NewThread->KernelStack);
} }
VOID VOID
@ -509,8 +506,8 @@ KiDispatchInterrupt(VOID)
/* Make the old thread ready */ /* Make the old thread ready */
KxQueueReadyThread(OldThread, Prcb); KxQueueReadyThread(OldThread, Prcb);
/* Swap to the new thread. FIXME: APC Bypass */ /* Swap to the new thread */
KiSwapContext(OldThread, NewThread); KiSwapContext(APC_LEVEL, OldThread);
} }
} }

View file

@ -387,7 +387,7 @@ KiSwapThread(IN PKTHREAD CurrentThread,
WaitIrql = CurrentThread->WaitIrql; WaitIrql = CurrentThread->WaitIrql;
/* Swap contexts */ /* Swap contexts */
ApcState = KiSwapContext(CurrentThread, NextThread); ApcState = KiSwapContext(WaitIrql, CurrentThread);
/* Get the wait status */ /* Get the wait status */
WaitStatus = CurrentThread->WaitStatus; WaitStatus = CurrentThread->WaitStatus;
@ -754,7 +754,7 @@ NtYieldExecution(VOID)
ASSERT(OldIrql <= DISPATCH_LEVEL); ASSERT(OldIrql <= DISPATCH_LEVEL);
/* Swap to new thread */ /* Swap to new thread */
KiSwapContext(Thread, NextThread); KiSwapContext(APC_LEVEL, Thread);
Status = STATUS_SUCCESS; Status = STATUS_SUCCESS;
} }
else else

View file

@ -249,7 +249,7 @@ KiExitDispatcher(IN KIRQL OldIrql)
Thread->WaitIrql = OldIrql; Thread->WaitIrql = OldIrql;
/* Swap threads and check if APCs were pending */ /* Swap threads and check if APCs were pending */
PendingApc = KiSwapContext(Thread, NextThread); PendingApc = KiSwapContext(OldIrql, Thread);
if (PendingApc) if (PendingApc)
{ {
/* Lower only to APC */ /* Lower only to APC */