[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
FASTCALL
KiSwapContext(
IN PKTHREAD CurrentThread,
IN PKTHREAD NewThread
IN KIRQL WaitIrql,
IN PKTHREAD CurrentThread
);
VOID

View file

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

View file

@ -13,70 +13,20 @@
#include <ndk/asm.h>
.intel_syntax noprefix
#define Ready 1
#define Running 2
#define WrDispatchInt 0x1F
/* 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
.func @KiSwapContextInternal@0, @KiSwapContextInternal@0
@KiSwapContextInternal@0:
/* Set APC Bypass Disable and old thread pointer */
mov edx, edi
or dl, cl
/* Build switch frame */
sub esp, 2 * 4
mov ecx, esp
call @KiSwapContextEntry@8
mov ecx, 0xB00BFACA
jmp $
jmp @KiSwapContextEntry@8
.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
.func @KiSwapContext@8, @KiSwapContext@8
@KiSwapContext@8:
/* Save 4 registers */
sub esp, 4 * 4
@ -86,17 +36,8 @@
mov [esp+4], edi
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 */
movzx ecx, byte ptr [edi+KTHREAD_WAIT_IRQL]
or dl, cl
/* Do the swap with the registers correctly setup */
call @KiSwapContextInternal@0
@ -112,10 +53,21 @@
ret
.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
.func @KiRetireDpcListInDpcStack@8, @KiRetireDpcListInDpcStack@8
@KiRetireDpcListInDpcStack@8:
/* Switch stacks and retire DPCs */
mov eax, esp
mov esp, edx
@ -140,20 +92,6 @@ _Ki386SetupAndExitToV86Mode@4:
jmp $
.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
@Ki386BiosCallReturnAddress@4:

View file

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

View file

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

View file

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