Comments in italics are mine and express my own views, thoughts and opinions
Windows Internals by M. Russinovich, D. Solomon and A. Ionescu:
Processor mode doesn’t affect thread scheduling (p. 414)
Preemption can be before a quantum ends and in that case the preempted thread is pushed at the front of a ready queue (pp. 414 - 415)
Clock interval extension of quanta for interrupted threads (pp. 416 - 417)
Context Switching (p. 418) - just noticed (never paid attention to before) that WinDbg shows empty context for the preempted thread:
x86 W2K3:
0: kd> kL
ChildEBP RetAddr
ba3a2a44 80833ed1 nt!KiSwapContext+0x26
ba3a2a70 80829c14 nt!KiSwapThread+0x2e5
ba3a2ab8 b9c5674d nt!KeWaitForSingleObject+0x346
[...]
0: kd> r
Last set context:
eax=00000000 ebx=00000000 ecx=00000000 edx=00000000 esi=00000000 edi=00000000
eip=8088f77e esp=ba3a2a38 ebp=ba3a2a70 iopl=0 nv up di pl nz na po nc
cs=0008 ss=0010 ds=0000 es=0000 fs=0000 gs=0000 efl=00000000
nt!KiSwapContext+0×26:
8088f77e 8b2c24 mov ebp,dword ptr [esp] ss:0010:ba3a2a38=ba3a2a70
0: kd> uf nt!KiSwapContext
nt!KiSwapContext:
8088f758 sub esp,10h
8088f75b mov dword ptr [esp+0Ch],ebx
8088f75f mov dword ptr [esp+8],esi
8088f763 mov dword ptr [esp+4],edi
8088f767 mov dword ptr [esp],ebp
8088f76a mov ebx,dword ptr fs:[1Ch]
8088f771 mov edi,ecx
8088f773 mov esi,edx
8088f775 movzx ecx,byte ptr [edi+4Eh]
8088f779 call nt!SwapContext (8088f880)
8088f77e mov ebp,dword ptr [esp]
8088f781 mov edi,dword ptr [esp+4]
8088f785 mov esi,dword ptr [esp+8]
8088f789 mov ebx,dword ptr [esp+0Ch]
8088f78d add esp,10h
8088f790 ret
x64 W2K8:
1: kd> kL
*** Stack trace for last set context - .thread/.cxr resets it
Child-SP RetAddr Call Site
fffffa60`02ddc7c0 fffff800`0187a6fa nt!KiSwapContext+0x7f
fffffa60`02ddc900 fffff800`0186f35b nt!KiSwapThread+0x13a
fffffa60`02ddc970 fffff800`01ad9e57 nt!KeWaitForSingleObject+0x2cb
fffffa60`02ddca00 fffff800`01ad9219 nt!AlpcpReceiveMessagePort+0x287
fffffa60`02ddca60 fffff800`01ada58a nt!AlpcpReceiveMessage+0x245
fffffa60`02ddcb00 fffff800`01877ef3 nt!NtAlpcSendWaitReceivePort+0x1da
fffffa60`02ddcbb0 00000000`7747756a nt!KiSystemServiceCopyEnd+0x13
00000000`0020f5a8 00000000`00000000 ntdll!ZwAlpcSendWaitReceivePort+0xa
1: kd> r
Last set context:
rax=0000000000000000 rbx=0000000000000000 rcx=0000000000000000
rdx=0000000000000000 rsi=0000000000000000 rdi=0000000000000000
rip=fffff8000187ac7f rsp=fffffa6002ddc7c0 rbp=fffffa80047ca290
r8=0000000000000000 r9=0000000000000000 r10=0000000000000000
r11=0000000000000000 r12=0000000000000000 r13=0000000000000000
r14=0000000000000000 r15=0000000000000000
iopl=0 nv up di pl nz na pe nc
cs=0000 ss=0000 ds=0000 es=0000 fs=0000 gs=0000 efl=00000000
nt!KiSwapContext+0×7f:
fffff800`0187ac7f 488d8c2400010000 lea rcx,[rsp+100h]
1: kd> uf nt!KiSwapContext
nt!KiSwapContext:
fffff800`0187ac00 sub rsp,138h
fffff800`0187ac07 lea rax,[rsp+100h]
fffff800`0187ac0f movaps xmmword ptr [rsp+30h],xmm6
fffff800`0187ac14 movaps xmmword ptr [rsp+40h],xmm7
fffff800`0187ac19 movaps xmmword ptr [rsp+50h],xmm8
fffff800`0187ac1f movaps xmmword ptr [rsp+60h],xmm9
fffff800`0187ac25 movaps xmmword ptr [rsp+70h],xmm10
fffff800`0187ac2b movdqa xmmword ptr [rax-80h],xmm11
fffff800`0187ac31 movdqa xmmword ptr [rax-70h],xmm12
fffff800`0187ac37 movdqa xmmword ptr [rax-60h],xmm13
fffff800`0187ac3d movdqa xmmword ptr [rax-50h],xmm14
fffff800`0187ac43 movdqa xmmword ptr [rax-40h],xmm15
fffff800`0187ac49 mov qword ptr [rax],rbx
fffff800`0187ac4c mov qword ptr [rax+8],rdi
fffff800`0187ac50 mov qword ptr [rax+10h],rsi
fffff800`0187ac54 mov qword ptr [rax+18h],r12
fffff800`0187ac58 mov qword ptr [rax+20h],r13
fffff800`0187ac5c mov qword ptr [rax+28h],r14
fffff800`0187ac60 mov qword ptr [rax+30h],r15
fffff800`0187ac64 mov rbx,qword ptr gs:[20h]
fffff800`0187ac6d mov rdi,rcx
fffff800`0187ac70 mov rsi,rdx
fffff800`0187ac73 movzx ecx,byte ptr [rdi+156h]
fffff800`0187ac7a call nt!SwapContext (fffff800`0187af50)
fffff800`0187ac7f lea rcx,[rsp+100h]
fffff800`0187ac87 movdqa xmm6,xmmword ptr [rsp+30h]
fffff800`0187ac8d movdqa xmm7,xmmword ptr [rsp+40h]
fffff800`0187ac93 movdqa xmm8,xmmword ptr [rsp+50h]
fffff800`0187ac9a movdqa xmm9,xmmword ptr [rsp+60h]
fffff800`0187aca1 movdqa xmm10,xmmword ptr [rsp+70h]
fffff800`0187aca8 movdqa xmm11,xmmword ptr [rcx-80h]
fffff800`0187acae movdqa xmm12,xmmword ptr [rcx-70h]
fffff800`0187acb4 movdqa xmm13,xmmword ptr [rcx-60h]
fffff800`0187acba movdqa xmm14,xmmword ptr [rcx-50h]
fffff800`0187acc0 movdqa xmm15,xmmword ptr [rcx-40h]
fffff800`0187acc6 mov rbx,qword ptr [rcx]
fffff800`0187acc9 mov rdi,qword ptr [rcx+8]
fffff800`0187accd mov rsi,qword ptr [rcx+10h]
fffff800`0187acd1 mov r12,qword ptr [rcx+18h]
fffff800`0187acd5 mov r13,qword ptr [rcx+20h]
fffff800`0187acd9 mov r14,qword ptr [rcx+28h]
fffff800`0187acdd mov r15,qword ptr [rcx+30h]
fffff800`0187ace1 add rsp,138h
fffff800`0187ace8 ret
We also see that if there is an attempt to switch from a DPC we get a bugcheck
1: kd> uf nt!SwapContext
nt!SwapContext:
fffff800`0187af50 sub rsp,38h
fffff800`0187af54 mov qword ptr [rsp+30h],rbp
fffff800`0187af59 mov byte ptr [rsp+28h],cl
fffff800`0187af5d cmp byte ptr [rsi+95h],0
fffff800`0187af64 jne nt!SwapContext+0x1cb (fffff800`0187b11b)
[...]
nt!SwapContext+0x1b2:
fffff800`0187b102 xor r9,r9
fffff800`0187b105 mov qword ptr [rsp+20h],r9
fffff800`0187b10a mov r8,rsi
fffff800`0187b10d mov rdx,rdi
fffff800`0187b110 mov ecx,0B8h
fffff800`0187b115 call nt!KeBugCheckEx (fffff800`01878450)
fffff800`0187b11a ret
It happens infrequently: http://www.dumpanalysis.org/blog/index.php/2008/03/12/bug-check-frequencies/
Idle process and threads can have NULL fields (pp. 418 - 419) - on x64 W2K8:
1: kd> !process poi(PsIdleProcess)
PROCESS fffff800019970c0
SessionId: none Cid: 0000 Peb: 00000000 ParentCid: 0000
DirBase: 00124000 ObjectTable: fffff88000000080 HandleCount: 551.
Image: Idle
VadRoot fffffa8003b97c70 Vads 1 Clone 0 Private 1. Modified 0. Locked 0.
DeviceMap 0000000000000000
Token fffff88000003330
ElapsedTime 00:00:00.000
UserTime 00:00:00.000
KernelTime 00:00:00.000
QuotaPoolUsage[PagedPool] 0
QuotaPoolUsage[NonPagedPool] 0
Working Set Sizes (now,min,max) (6, 50, 450) (24KB, 200KB, 1800KB)
PeakWorkingSetSize 6
VirtualSize 0 Mb
PeakVirtualSize 0 Mb
PageFaultCount 1
MemoryPriority BACKGROUND
BasePriority 0
CommitCharge 0
THREAD fffff80001996b80 Cid 0000.0000 Teb: 0000000000000000 Win32Thread: 0000000000000000 RUNNING on processor 0
Not impersonating
DeviceMap fffff88000007310
Owning Process fffff800019970c0 Image: Idle
Attached Process fffffa8003bf1040 Image: System
Wait Start TickCount 16846 Ticks: 1721 (0:00:00:26.847)
Context Switch Count 229608
UserTime 00:00:00.000
KernelTime 00:04:13.532
Win32 Start Address nt!KiIdleLoop (0xfffff8000187c880)
Stack Init fffff80002bdadb0 Current fffff80002bdad40
Base fffff80002bdb000 Limit fffff80002bd5000 Call 0
Priority 16 BasePriority 0 PriorityDecrement 0 IoPriority 0 PagePriority 0
Child-SP RetAddr Call Site
fffff800`02bdad80 fffff800`01a49860 nt!KiIdleLoop+0x11b
fffff800`02bdadb0 00000000`00000000 nt!zzz_AsmCodeRange_End+0x4
THREAD fffffa60005f5d40 Cid 0000.0000 Teb: 0000000000000000 Win32Thread: 0000000000000000 RUNNING on processor 1
Not impersonating
DeviceMap fffff88000007310
Owning Process fffff800019970c0 Image: Idle
Attached Process fffffa8003bf1040 Image: System
Wait Start TickCount 0 Ticks: 18567 (0:00:04:49.647)
Context Switch Count 241262
UserTime 00:00:00.000
KernelTime 00:04:23.501
Win32 Start Address nt!KiIdleLoop (0xfffff8000187c880)
Stack Init fffffa600191bdb0 Current fffffa600191bd40
Base fffffa600191c000 Limit fffffa6001916000 Call 0
Priority 16 BasePriority 0 PriorityDecrement 0 IoPriority 0 PagePriority 0
Child-SP RetAddr Call Site
fffffa60`0191bcd8 fffffa60`00f07685 intelppm!C1Halt+0x2
fffffa60`0191bce0 fffff800`0187cb83 intelppm!C1Idle+0x9
fffffa60`0191bd10 fffff800`0187c8a1 nt!PoIdle+0x183
fffffa60`0191bd80 fffff800`01a49860 nt!KiIdleLoop+0x21
fffffa60`0191bdb0 00000000`fffffa60 nt!zzz_AsmCodeRange_End+0x4
fffffa60`005efd00 00000000`00000000 0xfffffa60
MMCSS (MultiMedia Class Schedular Service) and priority boosts in Vista (p. 420)
Priority boosts never go beyond level 15 (p. 421) - looks like addition of velocities in relativity, where v1 > c/2, v2 > c/2 but v1+v2 < c (where c is the speed of light) :-)
Priority boosts for low prioroty _ERESOURCE owners (pp. 422 - 423)