Transcript 現代系統核心期末報告
現代系統核心期末報告
第四組
995202062
100522041
100522065
100522074
100522083
100522110
1
李宜庭
鍾珍慧
吳季衡
郭凱威
曾敬忠
葉奇鑫
100522016
100522056
100522069
100522080
100522106
100582015
蔡逸祥
薛浩哲
潘偉誠
林依汶
林宜姮
藍偉綺
報告章節目錄 (P.137~176)
Chapter 3 Windows行程和緒程
3.4
3.4.3
行程和緒程的建立過程
3.4.4
行程和緒程的結束處理
3.4.5
系統初始行程和緒程
3.5
Windows中的緒程排程
3.5.1
緒程優先層級
3.5.2
緒程狀態轉移
3.5.3
配量管理
3.5.4
優先層級排程和環境切換
3.6
行程和緒程執行狀態監視工具
3.6.1
ProcMon使用範例
3.6.2
ProcMon實作原理
3.7
2
Windows的行程和緒程管理
本章總結
報告章節目錄 (P.137~176)
Chapter 4 Windows記憶體管理
Chapter 4
4.1
3
Windows記憶體管理
記憶體管理概述
Chapter 3
Windows行程和緒程
4
3.4
•3.4.3
•3.4.4
•3.4.5
Windows的行程和緒程管理
行程和緒程的建立過程
行程和緒程的結束處理
系統初始行程和緒程
報告人:李宜庭
林宜媗
郭凱威
5
Windows 創建一個process的過程
建立一個執行體行程物件,即
EPROCESS 物件
建立一個初始Thread
為初始Thread建立一個stack
6
Windows 創建一個process的過程
完成這些工作以後,就可以開始參與系統的排程工作
了。然而,透過Windows API 函數創建的process也要
接受Windows 子系統的管理,系統在建立process過程
中,也必須和子系統溝通才行。
另外,還必需給process一塊個別的memory space 這
是Windows 建立process過程中不可或缺的步骤。
NtCreateProcess 只是簡單的對參數作一些處理的動作,
然後把建立process的任務交给NtCreateProcessEx 函
數
7
NtCreateProcessEx
NTSTATUS
NtCreateProcessEx(
__out PHANDLE ProcessHandle,
__in ACCESS_MASK DesiredAccess,
__in_opt POBJECT_ATTRIBUTES
ObjectAttributes,
__in HANDLE ParentProcess,
__in ULONG Flags,
__in_opt HANDLE SectionHandle,
__in_opt HANDLE DebugPort,
__in_opt HANDLE ExceptionPort,
__in ULONG JobMemberLevel
);
8
NtCreateProcessEx
NTSTATUS
NtCreateProcessEx(
__out PHANDLE ProcessHandle,
__in ACCESS_MASK DesiredAccess,
__in_opt POBJECT_ATTRIBUTES
ObjectAttributes,
__in HANDLE ParentProcess,
__in ULONG Flags,
__in_opt HANDLE SectionHandle,
__in_opt HANDLE DebugPort,
__in_opt HANDLE ExceptionPort,
__in ULONG JobMemberLevel
);
9
NtCreateProcessEx
NTSTATUS
NtCreateProcessEx(
__out PHANDLE ProcessHandle,
__in ACCESS_MASK DesiredAccess,
__in_opt POBJECT_ATTRIBUTES
ObjectAttributes,
__in HANDLE ParentProcess,
__in ULONG Flags,
__in_opt HANDLE SectionHandle,
__in_opt HANDLE DebugPort,
__in_opt HANDLE ExceptionPort,
__in ULONG JobMemberLevel
);
10
NtCreateProcessEx
NTSTATUS
NtCreateProcessEx(
__out PHANDLE ProcessHandle,
__in ACCESS_MASK DesiredAccess,
__in_opt POBJECT_ATTRIBUTES
ObjectAttributes,
__in HANDLE ParentProcess,
__in ULONG Flags,
__in_opt HANDLE SectionHandle,
__in_opt HANDLE DebugPort,
__in_opt HANDLE ExceptionPort,
__in ULONG JobMemberLevel
);
11
NtCreateProcessEx
NTSTATUS
NtCreateProcessEx(
__out PHANDLE ProcessHandle,
__in ACCESS_MASK DesiredAccess,
__in_opt POBJECT_ATTRIBUTES
ObjectAttributes,
__in HANDLE ParentProcess,
__in ULONG Flags,
__in_opt HANDLE SectionHandle,
__in_opt HANDLE DebugPort,
__in_opt HANDLE ExceptionPort,
__in ULONG JobMemberLevel
);
12
NtCreateProcessEx
NTSTATUS
NtCreateProcessEx(
__out PHANDLE ProcessHandle,
__in ACCESS_MASK DesiredAccess,
__in_opt POBJECT_ATTRIBUTES
ObjectAttributes,
__in HANDLE ParentProcess,
__in ULONG Flags,
__in_opt HANDLE SectionHandle,
__in_opt HANDLE DebugPort,
__in_opt HANDLE ExceptionPort,
__in ULONG JobMemberLevel
);
13
NtCreateProcessEx
NTSTATUS
NtCreateProcessEx(
__out PHANDLE ProcessHandle,
__in ACCESS_MASK DesiredAccess,
__in_opt POBJECT_ATTRIBUTES
ObjectAttributes,
__in HANDLE ParentProcess,
__in ULONG Flags,
__in_opt HANDLE SectionHandle,
__in_opt HANDLE DebugPort,
__in_opt HANDLE ExceptionPort,
__in ULONG JobMemberLevel
);
14
NtCreateProcessEx
NTSTATUS
NtCreateProcessEx(
__out PHANDLE ProcessHandle,
__in ACCESS_MASK DesiredAccess,
__in_opt POBJECT_ATTRIBUTES
ObjectAttributes,
__in HANDLE ParentProcess,
__in ULONG Flags,
__in_opt HANDLE SectionHandle,
__in_opt HANDLE DebugPort,
__in_opt HANDLE ExceptionPort,
__in ULONG JobMemberLevel
);
15
NtCreateProcessEx
NTSTATUS
NtCreateProcessEx(
__out PHANDLE ProcessHandle,
__in ACCESS_MASK DesiredAccess,
__in_opt POBJECT_ATTRIBUTES
ObjectAttributes,
__in HANDLE ParentProcess,
__in ULONG Flags,
__in_opt HANDLE SectionHandle,
__in_opt HANDLE DebugPort,
__in_opt HANDLE ExceptionPort,
__in ULONG JobMemberLevel
);
16
PspCreateProcess
其實,NtCreateProcessEx只是簡單的檢查了
ProcessHandle參數代表的控制代碼是否可寫
然後把真正的建立工作交給PspCreateProcess
PspCreateProcess是負責windos中建立所有process的
17
函式(包括system process)
只有三種函式會呼叫到它
NtCreateProcessEx
PsCreateSystemProcess
PspInitPhase0
if (ARGUMENT_PRESENT (ParentProcess))
NULL
非
NULL
Affinity = Parent->Pcb.Affinity;
WorkingSetMinimum =
PsMinimumWorkingSet;
Affinity = KeActiveProcessors;
18
WorkingSetMaximum =
PsMaximumWorkingSet;
Status = ObCreateObject
(PreviousMode,
PsProcessType,
ObjectAttributes,
PreviousMode,
NULL,
sizeof
(EPROCESS),
0,
0,
&Process);
19
if (ARGUMENT_PRESENT (SectionHandle))
對於系统process,此參數為NULL
if (Parent != PsInitialSystemProcess)
SectionObject = Parent>SectionObject;
if (SectionObject == NULL) {
Status =
STATUS_PROCESS_IS_TERMINATI
NG;
goto exit_and_deref;
}
若此參數不為NULL( 非系統process)
Status = ObReferenceObjectByHandle
(SectionHandle,
SECTION_MAP_EXECUTE,
MmSectionObjectType,
PreviousMode,
&SectionObject,
NULL);
新process物件的記憶體區段物件已經完成初始化。
20
21
if (Parent != NULL)
NULL
Process->ObjectTable =
CurrentProcess->ObjectTable;
22
不為NULL
Status =
STATUS_INSUFFICIENT_RESO
URCES;
KeInitializeProcess (&Process->Pcb,
NORMAL_BASE_PRIORITY, Affinity,
&DirectoryTableBase[0],
(BOOLEAN)(Process>DefaultHardErrorProcessing &
PROCESS_HARDERROR_ALIGNMENT_BIT));
Status = PspInitializeProcessSecurity (Parent, Process);
if (!NT_SUCCESS (Status)) {
goto exit_and_deref;
}
23
if (Parent != NULL)
NULL
不為NULL
Process->PriorityClass = Parent>PriorityClass;
Status =
MmInitializeHandBuiltProcess2
(Process);
24
Status = ObInitProcess
((Flags&PROCESS_CREATE_FLAG
S_INHERIT_HANDLES) ? Parent :
NULL, Process);
25
Process->UniqueProcessId =
ExCreateHandle (PspCidTable, &CidEntry);
if (SeDetailedAuditingWithToken (NULL)) {
SeAuditProcessCreation (Process);
}
26
if (Parent) {
Job = Parent->Job;
…
}
InsertTailList (&PsActiveProcessHead,
&Process->ActiveProcessLinks);
27
BasePriority = PspComputeQuantumAndPriority(Process,
PsProcessPriorityBackground,
&QuantumReset);
Process->GrantedAccess =
PROCESS_TERMINATE;
28
以上是建立並初始化一個行程物件的過程,經過
PspCreateProcess 函式以後,
新建process中並沒有任何Thread物件,所以其中
的程式碼並沒有真正被執行
接下來有請下一位講者
29
NtCreateThread
緒程的建立是從NtCreateThread函數開始
位於base\ntos\ps\create.c (77~169 行)
NTSTATUS
NtCreateThread(
__out PHANDLE ThreadHandle,
__in ACCESS_MASK DesiredAccess,
__in_opt POBJECT_ATTRIBUTES ObjectAttributes,
__in HANDLE ProcessHandle,
__out PCLIENT_ID ClientId,
__in PCONTEXT ThreadContext,
__in PINITIAL_TEB InitialTeb,
__in BOOLEAN CreateSuspended
);
NtCreateThread
NTSTATUS NtCreateThread(…)
1. 對於非kernel mode
{ //…
try {
傳遞過來的呼叫,
if (KeGetPreviousMode () != KernelMode) {
檢查參數是否可寫
ProbeForWriteHandle (ThreadHandle);
if (ARGUMENT_PRESENT (ClientId)) {
ProbeForWriteSmallStructure (ClientId, sizeof (CLIENT_ID), sizeof (ULONG));
}
if (ARGUMENT_PRESENT (ThreadContext) ) {
ProbeForReadSmallStructure (ThreadContext, sizeof (CONTEXT), CONTEXT_ALIGN);
} else {
return STATUS_INVALID_PARAMETER;
}
ProbeForReadSmallStructure (InitialTeb, sizeof (InitialTeb->OldInitialTeb),
sizeof (ULONG));
}
//...
}//…
}
NtCreateThread
NTSTATUS NtCreateThread(…)
2. 處理InitialTeb 參數,
{ //…
將它放到區域變數
try {
if (KeGetPreviousMode () != KernelMode) {
CapturedInitialTeb 中
//…
}
CapturedInitialTeb.OldInitialTeb = InitialTeb->OldInitialTeb;
if (CapturedInitialTeb.OldInitialTeb.OldStackBase == NULL &&
CapturedInitialTeb.OldInitialTeb.OldStackLimit == NULL) {
//
// Since the structure size here is less than 64k we don't need to reprobe
//
CapturedInitialTeb = *InitialTeb;
}
}
這些處理工作是在一個try 區塊中完成的,
//…
所以能夠捕捉發生在其中的異常,
}
保證核心的健壯性
NtCreateThread
NTSTATUS NtCreateThread(…)
3.NtCreateThread 呼叫
{ //...
真正建立緒程的函數
try {
//…
PspCreateThread
}//…
Status = PspCreateThread (ThreadHandle,
DesiredAccess,
ObjectAttributes,
ProcessHandle,
NULL,
ClientId,
ThreadContext,
&CapturedInitialTeb,
CreateSuspended,
NULL,
NULL);
return Status;
}
PspCreateThread
NTSTATUS
PspCreateThread(
OUT PHANDLE ThreadHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES
ObjectAttributes OPTIONAL,
IN HANDLE ProcessHandle,
IN PEPROCESS ProcessPointer,
OUT PCLIENT_ID ClientId OPTIONAL,
IN PCONTEXT ThreadContext OPTIONAL,
IN PINITIAL_TEB InitialTeb OPTIONAL,
IN BOOLEAN CreateSuspended,
IN PKSTART_ROUTINE StartRoutine OPTIONAL,
IN PVOID StartContext
);
ThreadHandle
如果thread建立成功,
會包含了所建立的
thread的控制代碼。
PspCreateThread
NTSTATUS
PspCreateThread(
OUT PHANDLE ThreadHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES
ObjectAttributes OPTIONAL,
IN HANDLE ProcessHandle,
IN PEPROCESS ProcessPointer,
OUT PCLIENT_ID ClientId OPTIONAL,
IN PCONTEXT ThreadContext OPTIONAL,
IN PINITIAL_TEB InitialTeb OPTIONAL,
IN BOOLEAN CreateSuspended,
IN PKSTART_ROUTINE StartRoutine OPTIONAL,
IN PVOID StartContext
);
DesiredAccess
包含對新緒程的存取權
限
PspCreateThread
NTSTATUS
PspCreateThread(
OUT PHANDLE ThreadHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES
ObjectAttributes OPTIONAL,
IN HANDLE ProcessHandle,
IN PEPROCESS ProcessPointer,
OUT PCLIENT_ID ClientId OPTIONAL,
IN PCONTEXT ThreadContext OPTIONAL,
IN PINITIAL_TEB InitialTeb OPTIONAL,
IN BOOLEAN CreateSuspended,
IN PKSTART_ROUTINE StartRoutine OPTIONAL,
IN PVOID StartContext
);
ObjectAttributes
一個optional pointer
(可為NULL) ,
指定新緒程物件的屬性。
PspCreateThread
NTSTATUS
PspCreateThread(
OUT PHANDLE ThreadHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES
ObjectAttributes OPTIONAL,
IN HANDLE ProcessHandle,
IN PEPROCESS ProcessPointer,
OUT PCLIENT_ID ClientId OPTIONAL,
IN PCONTEXT ThreadContext OPTIONAL,
IN PINITIAL_TEB InitialTeb OPTIONAL,
IN BOOLEAN CreateSuspended,
IN PKSTART_ROUTINE StartRoutine OPTIONAL,
IN PVOID StartContext
);
ProcessHandle
指向一個行程的控制代
碼,新緒程將執行在此
行程的環境中。
PspCreateThread
NTSTATUS
PspCreateThread(
OUT PHANDLE ThreadHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES
ObjectAttributes OPTIONAL,
IN HANDLE ProcessHandle,
IN PEPROCESS ProcessPointer,
OUT PCLIENT_ID ClientId OPTIONAL,
IN PCONTEXT ThreadContext OPTIONAL,
IN PINITIAL_TEB InitialTeb OPTIONAL,
IN BOOLEAN CreateSuspended,
IN PKSTART_ROUTINE StartRoutine OPTIONAL,
IN PVOID StartContext
);
ProcessPointer
指向所屬行程的
EPROCESS 物件,
當建立系統緒程時,
此參數指向全域的
PsInitialSystemProce
ss 物件,
其他情況下為NULL。
PspCreateThread
NTSTATUS
PspCreateThread(
OUT PHANDLE ThreadHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES
ObjectAttributes OPTIONAL,
IN HANDLE ProcessHandle,
IN PEPROCESS ProcessPointer,
OUT PCLIENT_ID ClientId OPTIONAL,
IN PCONTEXT ThreadContext OPTIONAL,
IN PINITIAL_TEB InitialTeb OPTIONAL,
IN BOOLEAN CreateSuspended,
IN PKSTART_ROUTINE StartRoutine OPTIONAL,
IN PVOID StartContext
);
ClientId
傳回新緒程的
CLIENT_ID結構。
包含Unique process
ID和Unique thread ID。
PspCreateThread
NTSTATUS
PspCreateThread(
OUT PHANDLE ThreadHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES
ObjectAttributes OPTIONAL,
IN HANDLE ProcessHandle,
IN PEPROCESS ProcessPointer,
OUT PCLIENT_ID ClientId OPTIONAL,
IN PCONTEXT ThreadContext OPTIONAL,
IN PINITIAL_TEB InitialTeb OPTIONAL,
IN BOOLEAN CreateSuspended,
IN PKSTART_ROUTINE StartRoutine OPTIONAL,
IN PVOID StartContext
);
ThreadContext
提供新緒程的執行環境。
代表使用者模式緒程的
初始執行環境。
如果該參數為NULL,
則說明此次呼叫將建立
一個系統緒程。
PspCreateThread
NTSTATUS
PspCreateThread(
OUT PHANDLE ThreadHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES
ObjectAttributes OPTIONAL,
IN HANDLE ProcessHandle,
IN PEPROCESS ProcessPointer,
OUT PCLIENT_ID ClientId OPTIONAL,
IN PCONTEXT ThreadContext OPTIONAL,
IN PINITIAL_TEB InitialTeb OPTIONAL,
IN BOOLEAN CreateSuspended,
IN PKSTART_ROUTINE StartRoutine OPTIONAL,
IN PVOID StartContext
);
InitialTeb
提供新緒程的TEB 結構
初始值。
PspCreateThread
NTSTATUS
PspCreateThread(
OUT PHANDLE ThreadHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES
ObjectAttributes OPTIONAL,
IN HANDLE ProcessHandle,
IN PEPROCESS ProcessPointer,
OUT PCLIENT_ID ClientId OPTIONAL,
IN PCONTEXT ThreadContext OPTIONAL,
IN PINITIAL_TEB InitialTeb OPTIONAL,
IN BOOLEAN CreateSuspended,
IN PKSTART_ROUTINE StartRoutine OPTIONAL,
IN PVOID StartContext
);
CreateSuspended
指明新緒程被建立起來
後是否被懸置。
若CreateSuspended
為TRUE,則新緒程建
立完成後並不立即執行,
之後必須要透過
NtResumeThread 函
式開始執行。
PspCreateThread
NTSTATUS
PspCreateThread(
OUT PHANDLE ThreadHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES
ObjectAttributes OPTIONAL,
IN HANDLE ProcessHandle,
IN PEPROCESS ProcessPointer,
OUT PCLIENT_ID ClientId OPTIONAL,
IN PCONTEXT ThreadContext OPTIONAL,
IN PINITIAL_TEB InitialTeb OPTIONAL,
IN BOOLEAN CreateSuspended,
IN PKSTART_ROUTINE StartRoutine OPTIONAL,
IN PVOID StartContext
);
StartRoutine
指定系統緒程啟動函式
的位址。
PspCreateThread
NTSTATUS
PspCreateThread(
OUT PHANDLE ThreadHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES
ObjectAttributes OPTIONAL,
IN HANDLE ProcessHandle,
IN PEPROCESS ProcessPointer,
OUT PCLIENT_ID ClientId OPTIONAL,
IN PCONTEXT ThreadContext OPTIONAL,
IN PINITIAL_TEB InitialTeb OPTIONAL,
IN BOOLEAN CreateSuspended,
IN PKSTART_ROUTINE StartRoutine OPTIONAL,
IN PVOID StartContext
);
StartContext
指定系統緒程啟動函式
的執行環境。
PspCreateThread
PspCreateThread 只可能會被以下兩個函式呼叫
NtCreateThread: 用在建立使用者緒程物件
PsCreateSystemThread: 用在建立系統緒程物件
在PsCreateThread函式的參數中,
ThreadContext 和InitialTeb : 針對使用者緒程的建
立操作
StartRoutine 和StartContext: 是針對系統緒程的建
立操作
PspCreateThread
1. 取得目前緒程物件,以及此次建立操作來自於核心模式還是使用者模式。
根據ProcessHandle 獲得相關的行程物件,放到區域變數Process 中
46
if (ProcessHandle
!= =NULL)
{
CurrentThread
PsGetCurrentThread
();
Status = ObReferenceObjectByHandle (ProcessHandle,
PROCESS_CREATE_THREAD,
if (StartRoutine != NULL)
{
PreviousMode =PsProcessType,
KernelMode;
PreviousMode,
} else {
&Process,
PreviousMode = KeGetPreviousModeByThread (&CurrentThread->Tcb);
NULL);
}
} else {
if (StartRoutine != NULL) {
ObReferenceObject (ProcessPointer);
Process = ProcessPointer;
Status = STATUS_SUCCESS;
} else {
Status = STATUS_INVALID_HANDLE;
}
}
PspCreateThread
2. 呼叫ObCreateObject 函式建立一個緒程物件ETHREAD,並初始化為零。
Status = ObCreateObject (PreviousMode,
PsThreadType,
ObjectAttributes,
PreviousMode,
NULL,
sizeof(ETHREAD),
0,
0,
&Thread);
RtlZeroMemory (Thread, sizeof (ETHREAD));
PspCreateThread
3.初始化一些基本欄位,包括RundownProtect、ThreadsProcess、Cid。
ExInitializeRundownProtection (&Thread->RundownProtect);
Thread->ThreadsProcess = Process;
Thread->Cid.UniqueProcess = Process->UniqueProcessId;
CidEntry.Object = Thread;
CidEntry.GrantedAccess = 0;
Thread->Cid.UniqueThread = ExCreateHandle (PspCidTable, &CidEntry);
4. 初始化新緒程物件ETHREAD 結構中的一些欄位,包括ReadClusterSize、
LpcReplySemaphore、LpcReplyChain、IrpList、PostBlockList 成員,
以及緒程鎖成員ThreadLock 和ActiveTimerListLock,
並初始化新緒程的計時器串列ActiveTimerListHead 成員。
PspCreateThread
5. 取得行程的RundownProtect ,以避免在建立過程中該行程被取消。
直到該緒程被插入到行程的緒程串列中(透過呼叫KeStartThread 函式)
PspCreateThread 才release RundownProtect
if (!ExAcquireRundownProtection (&Process->RundownProtect)) {
ObDereferenceObject (Thread);
return STATUS_PROCESS_IS_TERMINATING;
}
PspCreateThread
6-1. 如果此次建立的是user-mode thread ,
建立TEB,並且用InitialTeb 進行初始化。
利用ThreadContext中的程式指標(Eip)來設置緒程的 StartAddress 。
並且將ThreadContext 中的Eax 設置到緒程的Win32StartAddress 。
if (ARGUMENT_PRESENT (ThreadContext)) {
Status = MmCreateTeb (Process, InitialTeb, &Thread->Cid, &Teb);
//…
try {
Thread->StartAddress = (PVOID)CONTEXT_TO_PROGRAM_COUNTER(ThreadContext);
#if defined(_AMD64_)
Thread->Win32StartAddress = (PVOID)ThreadContext->Rdx;
#elif defined(_X86_)
Thread->Win32StartAddress = (PVOID)ThreadContext->Eax;
//…
}//…
}
PspCreateThread
6-2. 呼叫KeInitThread 函式,
初始化新緒程的屬性,包括Header、WaitBlock 等。
新緒程的ServiceTable以及與APC 和計時器相關的欄位
新緒程的核心stack
最後,KeInitThread 根據參數呼叫KiInitializeContextThread,完成
特定處理器相關的執行環境的初始化。
當這個函式返回時,新緒程的狀態是”已初始化(Initialized)”
if (NT_SUCCESS (Status)) {
Status = KeInitThread (&Thread->Tcb,
NULL,
PspUserThreadStartup,
(PKSTART_ROUTINE)NULL,
Thread->StartAddress,
ThreadContext,
Teb,
&Process->Pcb);
}
PspCreateThread
7. 如果此次建立的是kernel-mode thread ,
在CrossThreadFlags 標誌中設置系統緒程位元。
將緒程的啟位址設置為StartRoutine 。 最後呼叫KeInitThread 函式。
PS_SET_BITS (&Thread->CrossThreadFlags, PS_CROSS_THREAD_FLAGS_SYSTEM);
Thread->StartAddress = (PKSTART_ROUTINE) StartRoutine;
Status = KeInitThread (&Thread->Tcb,
NULL,
PspSystemThreadStartup,
StartRoutine,
StartContext,
NULL,
NULL,
&Process->Pcb);
PspCreateThread
8. 接下來鎖住行程,並確保此行程並不是在退出或終止過程中。
9. 行程的活動緒程數加1,並將新緒程加入到行程的緒程串列中。
接著呼叫KeStartThread 函式,
初始化剩餘的欄位,如優先層級等等。
新緒程就可以開始運行了
OldActiveThreads = Process->ActiveThreads++;
InsertTailList (&Process->ThreadListHead, &Thread->ThreadListEntry);
KeStartThread (&Thread->Tcb);
ExReleaseRundownProtection (&Process->RundownProtect);
PspCreateThread
10. 若這是process中的第一個Thread,則觸發該Process的建立通知
11. 檢查Thread的Process在是否再作業中
12. 通知那些接收Thread建立事件的callout routine。
PspCreateThread
13. 緒程物件的引用計數加2,針對目前的建立操作及回傳的緒程控制代碼。
14. 若CreateSuspended 為true,則呼叫KeSuspendThread。
if (CreateSuspended) {
try {
KeSuspendThread (&Thread->Tcb);
} except (…) { //…
}
// If deletion was started after we suspended then wake up the thread
if (Thread->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_TERMINATED) {
KeForceResumeThread (&Thread->Tcb);
}
}
15. 根據指定的期望存取權限,呼叫SeCreateAccessStateEx 建立存取狀態
結構(ACCESS_STATE)。
PspCreateThread
16. 呼叫ObInsertObject 把新緒程物件插入到目前process的控制代碼表中。
如果ObInsertObject呼叫失敗,終止此thread。
如果ObInsertObject呼叫成功,則設置ThreadHandle和ClientId。
Status = ObInsertObject (Thread,
AccessState,
DesiredAccess,
0,
NULL,
&LocalThreadHandle);
if (!NT_SUCCESS (Status)) {
PS_SET_BITS (&Thread->CrossThreadFlags,
PS_CROSS_THREAD_FLAGS_DEADTHREAD);
} else {
try {
*ThreadHandle = LocalThreadHandle;
if (ARGUMENT_PRESENT (ClientId)) {
*ClientId = Thread->Cid;
}
} //…
}
PspCreateThread
17. 設定Thread的建立時間。
18. 設置Thread的存取權限,即GrantedAccess 欄位(754~807 行)。
19. 呼叫KeReadyThread,使thread進入“ready”狀態,準備馬上執行
若此時process未在memory中,則thread的狀態為“transition”,等
待換入記憶體
KeReadyThread (&Thread->Tcb);
20. 引用計數減1,目前操作完成。 返回。
PspCreateThread
一旦PspCreateThread函式傳回,新Thread物
件的狀態已經完全設置好,可以被馬上執行。
因為Thread的建立是在Process已經建立完成
以後才做的動作,所以Thread建立是一個相對
簡單的過程。
接下來有請下一位講者
58
建立行程
先以上層之應用程式的角度來看
最常見的則是呼叫CreateProcess,當傳回成功則
代表行程已經建立
59
應用程式呼叫
CreateProcess(Cre
ateProcessW)
執行體層的行
程物件函式
(NtCreateProc
essEX)
Windows 子
系統打交道
回顧(執行體)
執行體是內核模組ntoskrnl.exe的上層部分,目的在
於提供一些可供上層應用程式或內核驅動程式直接
調用的功能和語意。
60
子系統DLL
NTDLL.DLL
系統服務
子系統服務
Windows
子系統
視窗管理
圖形介面
圖形驅
動程式
執行體API
記憶體
管理員
行程和
緒程管
理員
即插即
用管理
員
安全參
照監視
器
快取管
理員
本地程
序呼叫
(LPC)
組態管
理員
(登錄)
I/O管
理員
檔案
系統
網
路
物件管理員
核心 (或微核心)
硬體抽象層 (HAL)
圖2.3 Windows核心組成架構圖
61
使用者模式
核心模式
裝置驅
動程式
行程完整步驟(1/6)
Kernel32.dll
CreateProcess
function
Kernel32.dll
•動態鏈接庫文件
•控制著系統的內存管理、數
據的輸入輸出操作和中斷處
理
•當Windows啟動時,
kernel32.dll就會啟動
62
可執行檔
記憶體
區段
一段application與process的對話
好的,你等我…你一定要等我,
我現在就去建立
Hey,process你可以為我工作了嗎
噢,你怎麼這麼猴急,你才剛把
記憶體配置起來,我都還沒被
建立呢
63
行程完整步驟(2/6)
Kernel32.dll
ntdll.dll
Kernel
mode
64
CreateProcess
function
User mode
NtCreateProcessEX
function
透過處理器的陷阱機
制切換到kernel
mode
使用KiSystemService
獲得控制
NtCreateProcessEX
function
65
NtCreateProcessEX
function
執行行程邏輯
66
•
•
•
•
•
EPROCESS物件
初始化欄位
建立初始行程之空間
建立控制代碼表
設置EPROCESS與
KPROCESS中屬性
再續前緣
Hey,process,歷經千辛萬苦,總算
我也想~~~可是我沒有執行
建立妳了,可以為我工作了嗎
緒,怎麼能做事呢
ˊ<_ˋ
67
到目前為止,行程已經建立起來了
但是並無法做任何事情,因為緒程尚未建立
在建立緒程之前,必須先建立堆疊與執行環境
緒程的建立跟行程非常類似也是透過執行體的
NtcreateThread[link]來建立緒程
68
行程完整步驟(3/6)
NtCreateThread
function
執行緒程邏輯
69
•
•
•
•
ETHREAD物件
初始化欄位
產生緒程ID
建立TEB
爭吵的小倆口
Hey,pro…
閉嘴!我受夠你了,你總是不為
我著想,建立的thread要等到我
完全初始化後才可以為我所用
ˋ_ˊ
70
行程透過kernel32.dll中的BaseProcessStart函式啟
動第一個緒程
但是呢,他不會立刻執行而處於閒置狀態
等到行程完全初始化完成後才會真正開始執行
是一個非常淡定的緒程!
71
行程完整步驟(4/6)
對於子系統來說現在才正要開始
Kernel32.dll給子系統發送一個訊息
控制代碼
行程建立的ID
Csrss.exe
子系統行程(csrss.exe)接收到訊息後開始執行下一
•客戶端服務子系統
系列之動做
•用以控制 Windows 圖形
相關子系統
72
Csrss.exe
1.保留控制代碼
2.設定行程優先層級
3.子系統中分配一個內部行程區塊
4.設置例外port
5.設置偵錯port
6.初始化內部緒程
7.視窗工作行程count + 1
8.將行程插入至子系統清單中
9.分配記憶體供子系統使用
10.顯示應用程式啟動游標
73
行程完整步驟(5/6)
行程 finish
緒程 所需資源 finish
子系統已知道並登記了 行程跟緒程
現在即將要初始化thread
74
Thread 啟動流程
PspCreateThread[link]
call
KeInitThread[link]
call
KiInitializeContextThread[link]
設置
KiThreadStartup[link]
IRQL(IRQL(Interrupt
Request Level)
)Csrss.exe
•Windows定出32個IRQL
•Level高的不可被低的中斷
指
SoftwareIRQL
定
PASSIVE_LEVEL 0 // Passive release level
LOW_LEVEL 0 // Lowest interrupt level
APC_LEVEL 1 // APC interrupt level
DISPATCH_LEVEL 2 // Dispatch level
將IRQL 降低至APC_LEVEL
PspUserThreadStartup
75
APC
呼叫非同步系統呼叫時,執行緒可以立即繼續執行下
一步驟。
呼叫非同步系統呼叫時,會傳入一個非同步程序呼叫
(asynchronous procedure call,APC)給系統。
當非同步系統呼叫服務結束時,執行緒將被中斷而自
動執行非同步程序呼叫。
是一種軟體中斷
76
獲得目前
Thread與
Process物件
檢查建立過程
是否出錯
No
是否是Process
中的第一個
Thread
PspUserThreadStartup
執行流程
Yes
終止Thread,
通知偵錯器
YES
是否支援應
用程式預取
No
No
PspUserThreadStartup把
user mode APC插入到
Thread的使用者APC佇列
填充系統範圍的一個cookie值
77
Yes
通知快取管理
員預取映像檔
行程完整步驟(6/6)
PspUserThreadStartup 結束後回傳
PspUserThreadStartup
傳回
KiThreadStartup函式傳回到
user mode
APC被交付
LdrInitiallizeThunk被呼叫
LdrInitiallizeThunk傳回到使用者模式
APC發送器
Thread在使用者模式下執行
78
完美ending
^_^
79
3.4
•3.4.3
•3.4.4
•3.4.5
Windows的行程和緒程管理
行程和緒程的建立過程
行程和緒程的結束處理
系統初始行程和緒程
報告人:曾敬忠
80
Outline
1. Thread的結束處理
2. Process的結束處理
81
Introduction
重要觀念
在結束一個Process,必須要先將其中的Thread全部
結束。
82
Thread的結束處理
NtTerminateThrea
PsTerminateSyste
d
mThread
Call
Curr
ent
PspTerminateThread
ByPointer
Noncurrent
PspExitThread
PS_CROSS_THRE
AD_FLAGS_TERM
INATED
83
Kernel mode APC
指定 – PsExitSpecialApc
PspExitApcRundown
PspExitNormalApc
PsExitSpecialApc
->PspExitThread
Thread的結束處理
NtTerminateThread
if (Process == CurrentProcess) {
if (ProcessHandleSpecified) {
//
// Never Returns
//
84
Curre
nt
PspTerminateThr
eadByPointer
PspExitThread
PspTerminateThreadByPointer (Self, PS_CROSS_THR
ExitStatus, TRUE);
EAD_FLAGS_TE
}
RMINATED
}
PsTerminateSy
stemThread
Call
ObDereferenceObject
(Process);
NtTerminateTh
read
Noncurrent
Kernel mode APC
指定 –
PsExitSpecialApc
PspExitApcRundown
PspExitNormalApc
PsExitSpecialApc
->PspExitThread
Thread的結束處理
NtTerminateThread
for (
NtTerminateTh
read
Thread =
PsGetNextProcessThread
(Process, NULL);
Thread != NULL;
Thread =
PsGetNextProcessThread
(Process, Thread))
{
Call
Curre
nt
PspTerminateThr
eadByPointer
st = STATUS_SUCCESS;
if (Thread != Self) {
PspTerminateThreadByPointer
(Thread, ExitStatus, FALSE);
}
}
85
PsTerminateSy
stemThread
PspExitThread
PS_CROSS_THR
EAD_FLAGS_TE
RMINATED
Noncurrent
Kernel mode APC
指定 –
PsExitSpecialApc
PspExitApcRundown
PspExitNormalApc
PsExitSpecialApc
->PspExitThread
Thread的結束處理
PsTerminateSystemThread
{
NtTerminateTh
read
PETHREAD Thread =
PsGetCurrentThread();
Call
if (!IS_SYSTEM_THREAD
(Thread)) {
return
STATUS_INVALID_PARAMETE
R;
}
return
PspTerminateThreadByPointer
(Thread, ExitStatus, TRUE);
}
86
PsTerminateSy
stemThread
Curre
nt
PspTerminateThr
eadByPointer
PspExitThread
PS_CROSS_THR
EAD_FLAGS_TE
RMINATED
Noncurrent
Kernel mode APC
指定 –
PsExitSpecialApc
PspExitApcRundown
PspExitNormalApc
PsExitSpecialApc
->PspExitThread
Thread的結束處理
PspTerminateThreadByPointer
if (DirectTerminate && Thread ==
PsGetCurrentThread()) {
PS_SET_BITS (&Thread>CrossThreadFlags,
PS_CROSS_THREAD_FLAGS_TE
RMINATED);
PspExitThread (ExitStatus);
// Never Returns
87
}
PsTerminateSy
stemThread
Call
ASSERT (KeGetCurrentIrql() <
APC_LEVEL);
NtTerminateTh
read
Curre
nt
PspTerminateThr
eadByPointer
PspExitThread
PS_CROSS_THR
EAD_FLAGS_TE
RMINATED
Noncurrent
Kernel mode APC
指定 –
PsExitSpecialApc
PspExitApcRundown
PspExitNormalApc
PsExitSpecialApc
->PspExitThread
Thread的結束處理
PspTerminateThreadBy
88
Pointer
KeInitializeApc (
ExitApc,
PsGetKernelThread
(Thread),
OriginalApcEnvironment,
PsExitSpecialApc,
PspExitApcRundown,
PspExitNormalApc,
KernelMode,
ULongToPtr (ExitStatus));
NtTerminateTh
read
PsTerminateSy
stemThread
Call
Curre
nt
PspTerminateThr
eadByPointer
PspExitThread
PS_CROSS_THR
EAD_FLAGS_TE
RMINATED
Noncurrent
Kernel mode APC
指定 –
PsExitSpecialApc
PspExitApcRundown
PspExitNormalApc
PsExitSpecialApc
->PspExitThread
Thread的結束處理
PspExitThread
Thread =
先檢查目前的PROCESS和
THREAD
PsGetCurrentThread();
Process =
THREAD_TO_PROC
ESS(Thread);
判斷是否可終止目前的
THREAD
if (Process !=
PsGetCurrentProcess
ByThread (Thread))
PoRundownThread(T
關掉各種跨PROCESS的引用
hread);
89
Thread的結束處理
PERFINFO_THREAD
通知那些已註冊THREAD
_DELETE(Thread);
刪除事件的接收者
if(PspCreateThreadN
otifyRoutineCount != 0)
Process>ActiveThreads--;
THREAD - 1
if (Process>ActiveThreads == 0)
判斷是否為最後一個
90
Thread的結束處理
if (Process-
>DebugPort != NULL)
if
(KD_DEBUGGER_EN
ABLED)
91
有需要可以DEBUG
Thread的結束處理
TerminationPort
LpcRequestPort
向所有登記過要接收終止通知的
THREAD發送終止訊息
(TerminationPort->Port,
(PPORT_MESSAGE)&Cd
Msg);
LpcRequestPort (Process>ExceptionPort,
(PPORT_MESSAGE)&Cd 若ExceptionPort存在,也要發送終
Msg);
止訊息
if (Thread>Tcb.Win32Thread) {
(PspW32ThreadCallout)
(Thread,
PsW32ThreadCalloutExit);}
以上結束後,通知WIN子系統目前
THREAD結束
92
Thread的結束處理
if (LastThread &&
Process>Win32Process)
{(PspW32ProcessCall
out) (Process,
FALSE);}
IoCancelThreadIo
(Thread);
ExTimerRundown ();
若此為行程最後一個THREAD,同
時也通知WIN子系統目前行程結束
取消I/O THREAD
取消TIMER
93
Thread的結束處理
CmNotifyRunDown
(Thread);
KeRundownThread ();
LpcExitThread
(Thread);
清除所有未完成的登錄通知請求
執行kernel thread結束
釋放TEB,並呼叫LpcExitThread
去處理LpcReplyMessage
94
Thread的結束處理
Thread->ExitStatus =
95
ExitStatus;
KeQuerySystemTime
(&Thread->ExitTime);
if (LastThread)
PspExitProcess
(TRUE, Process);
KeForceResumeThre
ad (&Thread->Tcb);
設置時間和狀態
看是否為最後一個THREAD
若是則呼叫PspExitProcess
強制回復THREAD執行,處理可能
有的APC
Thread的結束處理
KeFlushQueueApc
96
(&Thread->Tcb,
UserMode);
if (Apc>RundownRoutine)
{(Apc>RundownRoutine)
(Apc);}
else {ExFreePool (Apc);}
if (LastThread) {
MmCleanProcessAddre
ssSpace (Process);}
在USER APC,如果發現有終止函式
(RundownRountine),則呼叫該函式
否則會丟棄這APC
如果這是PROCESS的最後一個
THREAD,會清除目前PROCESS的
位址空間
Thread的結束處理
KeTerminateThread
(0L);
Thread>Header.SignalState
= TRUE;
Thread->State =
Terminated;
呼叫KeTerminateThread
設置THREAD狀態為有信號之
狀態
設置其排程狀態為已終止
97
Process的結束處理
NtTerminateProcess
NtTerminateProcess
PspTerminateThreadB
yPointer (Thread,
ExitStatus, FALSE);
PspTerminateThreadByPointer
PspTerminateThreadB
yPointer (Self,
ExitStatus, TRUE);
終止所有process
98
Process的結束處理
PsTerminateProcess
PsTerminateProcess也
是完成Process終止工作
PsTerminateProcess
關機時候呼叫
呼叫
PspTerminateProcess
函式
PspTerminateProcess
用迴圈呼叫
PspTerminateThreadBy
Pointer以刪除Process
中所有Thread。
若Process中無Thread
則清除Process的控制代
碼表。
99
PspTerminateProcess
PspTerminateThreadByPointer
3.4
•3.4.3
•3.4.4
•3.4.5
Windows的行程和緒程管理
行程和緒程的建立過程
行程和緒程的結束處理
系統初始行程和緒程
報告人:曾敬忠
100
Outline
1. idle process and the idle thread of P0
processor
2. phase 0
3. phase 1
101
idle process and the idle thread of P0
processor
核心初始化分為第0階段和第1階段,用
InitializationPhase來標識, InitializationPhase0代
表phase0,InitializationPhase1代表phase1
進入核心的的入口是一個組合語言函式
_KiSystemStartup
102
核心初始化流程圖
103
idle process and the idle thread of P0
processor
_KiSystemStartup
KiInitializeKernel
KeInitializeProcess
104
KeInitializeThread
KeInitThread
KeStartThread
phase 0
ExpInitializeExecutive
PsInitSystem
PspInitPhase0
105
phase 1
106
Phase1InitializationDisca
rd
PsInitSystem
PspInitializeSystemDll
PspInitPhase1
Process及Thread
Idle process 只有一個
PsIdleProcess ID= 0
System process 只有一個
PsInitialSystemProcess ID= 4
zero page thread(零頁面緒程) 只有一個
idle thread 每個處理器中都有一個
其他處理器(非P0)會在階段1初始化過程中被啟動起
來,但是也會從_KiSystemStartup開始執行,完成初
始化後會轉到空閒迴圈,轉變成該處理器之idle
thread
107
Workitem
System process 容納了所有的系統THREAD,當
核心呼叫PsCreateSystemThread函式,如果沒有
指定的目標Process,那新的Thread會再System
process裡面執行。
System process中有一組系統輔助緒程,是用來執
行各項工作項目(WORKITEM),因此WIN的核心跟
驅動程式不需要建立THREAD,而是將他們工作包
成一個工作項目。
108
空閒迴圈(idle loop) = KiIdleLoop
1. 快速開一下中斷,又關上中斷,以便處理後續DPC
和THREAD檢查
2. 檢查目前處理器上是否有DPC(Deferred procedure
call)正在執行,如果DPC在等待,則清除軟體插斷,並
交付DPC
3. 檢查是否有一個Thread被選出來做為該處理器上執
行的下一個thread
如果有,分發該thread,使他執行
如果沒有,判斷是否該處理器已被標記上idle schedule
flag
成立,呼叫KiIdleSchedule,以找尋該處理器上執行的下一個
thread
不成立,回到空閒迴圈一開始。
109
3.5
•3.5.1
•3.5.2
•3.5.3
•3.5.4
Windows中的緒程排程
緒程優先層級
緒程狀態轉移
配量管理
優先層級排程和環境切換
報告人:蔡逸祥
110
以優先層級(priority level)為基礎的thread
scheduler。
可搶先(Preemptive)
動態變化
Windows內部使用32個優先層級別
即時類別: 16~31
動態類別: 1~15
系統類別: 0
111
在Windows平台上,使用者可以透過工作管理員
(task manager)來改變行程的優先層級
112
typedef struct _KPROCESS {
…
SCHAR BasePriority; //指定基本優先層級
…
} KPROCESS, *PKPROCESS, *PRKPROCESS;
typedef struct _KTHREAD {
…
SCHAR Priority; //定義動態優先層級
SCHAR BasePriority; //定義靜態優先層級
…
} KTHREAD, *PKTHREAD, *PRKTHREAD;
113
FORCEINLINE
SCHAR
KiComputeNewPriority ( IN PKTHREAD Thread, IN SCHAR
Adjustment )
{
SCHAR Priority;
/* 檢查是否為合理優先權 */
ASSERT((Thread->PriorityDecrement >= 0) && (Thread>PriorityDecrement <= Thread->Priority));
ASSERT((Thread->Priority < LOW_REALTIME_PRIORITY) ?
TRUE : (Thread->PriorityDecrement == 0));
114
/* 得到目前的優先權*/
Priority = Thread->Priority;
if (Priority < LOW_REALTIME_PRIORITY) {
/* 減去遞減值 加上調整值*/
Priority = Priority - Thread->PriorityDecrement - Adjustment;
/* 確定不低於base priority */
if (Priority < Thread->BasePriority) {
Priority = Thread->BasePriority;
}
Thread->PriorityDecrement = 0;
}
ASSERT((Thread->BasePriority == 0) || (Priority != 0));
return Priority;
}
115
從以上程式碼可發現
只針對非即時類別
新的優先權不會低於基本優先權
不會超越到即時類別的範圍(16~31)
116
ntpsapi.h(檔案路徑 public\sdk\inc\)中定義巨集
#define PROCESS_PRIORITY_CLASS_UNKNOWN
0
#define PROCESS_PRIORITY_CLASS_IDLE
1
#define PROCESS_PRIORITY_CLASS_NORMAL
2
#define PROCESS_PRIORITY_CLASS_HIGH
3
#define PROCESS_PRIORITY_CLASS_REALTIME 4
#define PROCESS_PRIORITY_CLASS_BELOW_NORMAL 5
#define PROCESS_PRIORITY_CLASS_ABOVE_NORMAL 6
psquery.c(檔案路徑 base\ntos\ps\psquery.c)中定全域變數
const KPRIORITY
PspPriorityTable[PROCESS_PRIORITY_CLASS_ABOVE_NORMA
L+1] = {8,4,8,13,24,6,10};
118
優先層級提升的典型情況
當一個I/O操作完成時
2. 一個緒程在等待了事件和旗號以後
3. 前台緒程從等待狀態中醒來時
4. 平衡集管理員系統緒程掃描出已進入就緒狀態4
秒鐘,但尚未被執行的緒程
1.
5.
119
這些緒程的優先層級會被提升至15,其用意在於避
免優先層級反轉(priority inversion)情形的長時間出
現。
視窗緒程因視窗的活動而醒來時
3.5
•3.5.1
•3.5.2
•3.5.3
•3.5.4
Windows中的緒程排程
緒程優先層級
緒程狀態轉移
配量管理
優先層級排程和環境切換
報告人:潘偉誠
120
KTHREAD的STATE欄位是反應緒程目前排程狀態
緒程的狀態轉移有可能是緒程本身的邏輯造成
也有些系統為了更有效管理可用資源而施予的
121
typedef enum _KTHREAD_STATE{
Initialized, //已初始化
Ready, //就緒
Running, //執行
Standby, //待命
Terminated, //已終止
Waiting, //等待
Transition, //轉移
DeferredReady, //延遲的就緒
GateWait //閘道等待
}KTHREAD_STATE;
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
3.5
•3.5.1
•3.5.2
•3.5.3
•3.5.4
Windows中的緒程排程
緒程優先層級
緒程狀態轉移
配量管理
優先層級排程和環境切換
報告人:薛浩哲
145
配量 Quantum
管理每個Thread能取的系統資源的時間與拿到的
資源量
KTHREAD (Kernel Thread)結構
Quantum: 紀錄該thread目前的配量還剩下多少時間
QuantumReset: 紀錄thread配量的重置值
QuantumReset
客戶端系統,預設值為6
伺服器系統,預設值為36
146
QuantumReset 與 Quantum decrement
Quantum decrement
CLOCK_QUANTUM_DECREMENT
代表一次CLOCK 中斷的Quantum減少量,值為3
WAIT_QUANTUM_DECREMENT
代表一個thread從等待狀態中醒來時的Quantum減少量,值
為1
若Quantum的值小於等於0時,則會觸Thread排程
QuantumReset
當thread從clock中斷後,獲得了執行權且分配到一
個 全 新 的 Quantum 時 , 此 Quantum 的 值 即 為
QuantumReset
147
Windows 分配處理器資源
臨時提升一個Thread的priority
例: 閘道物件
判別方式:
在Thread object中的 AdjustReason 欄位等於AdjustBoost
分配給Thread更大的Quantum
較常用於Server行程或前台行程的thread
148
Windows 建立新Thread流程
PspCreateProcess( )
call
PspComputeQuantumAndPriority( )
依Win32PrioritySeparation的值來決定取
陣列中的第幾項設為Quantum
PspForegroundQuantum[3]
將選擇的值Assign給
PspForegroundQuantum[3]
PspFixedQuantums[6]
PspInitPhase0( )
4選1
call
選擇這兩個陣列中其
中一個的前三個元素
或後三個元素
PspVaribleQuantums[6]
PsChangeQuantumTable( )
149
Server版與普通版(XP,WIN7)的差異
PspForegroundQuantum[3]
Server : {36, 36, 36}
Client: {6, 12, 18}
兩個版本的Win32PrioritySeparation都為2
Server: 前後台的Thread QuantumReset皆為36
Client: 前台的Thread QuantumReset為18 ,後台的
Thread QuantumReset為6
3.5
•3.5.1
•3.5.2
•3.5.3
•3.5.4
Windows中的緒程排程
緒程優先層級
緒程狀態轉移
配量管理
優先層級排程和環境切換
報告人:藍偉綺
151
系統當中有什麼?
全域的處理器陣列KiProcessorBlock
處理器陣列當中每一個元素對應於一個處理器的
KPRCB物件。
KiIdleSummary
全域變數
紀錄那些處理器是空閒的
在32位元系統中,KiIdleSummary為32位元
(DWORD),最多可支援32個處理器
152
KiIdleSummary
當一個處理器沒有找到合適的緒程來執行時,
會呼叫KiSetIdleSummary函式來設置
KiIdleSummary中相關位元。
同樣的,當一個空閒的處理器被分配了一個緒
程,則需要透過呼叫KiClearIdleSummary函式
來清除KiIdleSummary相關位元。
/base/ntos/ke/ki.h
153
KiIdleSummary
Thread->State = Standby;
/base/ntos/ke/ki.h
Thread->NextProcessor
= (UCHAR)Processor;
KiClearIdleSummary(AFFINITY_MASK(Processor));
TargetPrcb->NextThread = Thread;
當一個處理器沒有找到合適的緒程來執行時,
會呼叫KiSetIdleSummary函式來設置
#if defined(NT_UP)
KiIdleSummary
|= Mask;
&=
~Mask;
KiIdleSummary中相關位元。
#else
同樣的,當一個空閒的處理器被分配了一個
#if defined(_X86_)
#if InterlockedAnd((volatile
defined(_X86_)
LONG *)&KiIdleSummary, ~(LONG)Mask);
緒程,則需要透過呼叫KiClearIdleSummary
#else
InterlockedOr((volatile LONG *)&KiIdleSummary, (LONG)Mask);
函式來清除KiIdleSummary相關位元。
#else
InterlockedAnd64((volatile
LONG64 *)&KiIdleSummary, ~(LONG64)Mask);
#endif
InterlockedOr64((volatile LONG64 *)&KiIdleSummary, (LONG64)Mask);
KiDeferredReadyThread執行分配一個延遲就
#endif
緒的緒程到一個空閒處理器上時,便會執行
KiClearIdleSummary函式。
154
KPRCB資料結構
KiProcessorBlock
處理器1
處理器2
...
目前緒程
目前緒程
下一個緒程
下一個緒程
空閒緒程
空閒緒程
延遲就緒串列開頭
DeferredReadyListHead
就緒串列陣列:
...
延遲就緒串列開頭
DeferredReadyListHead
就緒串列陣列:
DispatcherReadyListHead
...
優先順序8
優先順序8
優先順序9
優先順序9
優先順序10
優先順序10
...
...
ReadySummary
就緒摘要
155
KiIdleSummary
空閒摘要
ReadySummary
就緒摘要
DispatcherReadyListHead
ReadySummary
由ReadySummary得知那些優先層級的序列
非空。
透過ReadySummary與
DispatcherReadyListHead兩項資訊,
KiSelectReadyThread 與
KiFindReadyThread可以快速找到滿足執行
條件的緒程。
156
關於緒程切換
主動放棄: 一個緒程主動放棄對於目前處理
器的執行權,該處理器的控制流就換轉移到
系統的緒程排程器。
等待的條件尚未滿足 則放棄目前處理器
(KeDelayExectIonThread、
KeWaitForSingleObject、
KeWaitForMultipleObjects函式執行)
被迫放棄: 緒程在執行過程中,由於系統某
些原因 迫使緒程必須放棄目前處理器的執
行權。
執行緒用完他目前的配量時,只要還存在優先層級大
157
於他的緒程 所以必須交出處理器的的執行權
KiSwapThread
NextThread存在
當一個緒程主動放棄執行權,會在核心函式中
if (CurrentPrcb->NextThread != NULL){
呼叫KiSwapThread,進而使得緒程排程器獲
CurrentPrcb->CurrentThread
= NewThread;
NewThread->State
= Running;
得控制權。
}
base\ntos\ke\thredsup.c
NextThread不存在從DispatcherReadyListHead挑選出一個緒程
if ((NewThread = KiSelectReadyThread(0, CurrentPrcb)) != NULL) {
CurrentPrcb->CurrentThread
= NewThread;
LONG_PTR
NewThread->State
= Running;
FASTCALL
KiSwapThread (
無適當緒程
IN PKTHREAD OldThread,
KiSetIdleSummary(CurrentPrcb->SetMember);
IN PKPRCB CurrentPrcb
)
158
呼叫此函數的緒程物件
目前處理器的KPRCB
五種呼叫KiSwapThread的情況
1. 緒程自願進入等待。
2. 緒程進入閘道等待 KeWaitForGate。
3. 緒程終止,完成中止處理事項以後,
159
KeTerminateThread呼叫KiSwapThread交還控制權給
緒程排程器。
4. 如果一個緒程呼叫KeRemoveQueue,但又不能馬上
獲得佇列中的項目,該緒程也會進入等待狀態,並且
呼叫KiSwapThread函是把控制權交給緒程排程器。
5. 當一個緒程附加到一個行程的位址空間中,若目標行
程尚未被換入記憶體,則儘管目前緒程是就緒的,但
是他不能繼續執行,所以將控制權交給緒程排程器。
等到將來行程換入記憶體以後再繼續執行。這種情形
發生在KiAttachProcess函式中。
自願放棄
KiSwapThread
等待物件或是延遲
執行
閘道等待
老緒程
緒程中止
不能從佇列物件中
提取項目
附加到非駐留的行
程中
160
新緒程
自願放棄的處理
sub
esp, 4*4
KiSwapThread會呼叫KiSwapContext函式來完
mov [esp+12], ebx
; save registers
成緒程切換。
mov [esp+8], esi
;
mov [esp+4], edi
;
KiSwapContext函式
mov [esp+0], ebp
;
mov base\ntos\ke\i386\ctxswap.asm
ebx, PCR[PcSelfPcr]
; set address of PCR
mov edi, ecx
; set old thread address
mov esi, edx
; set next thread address
movzx ecx, byte ptr [edi].ThWaitirql ; set APC interrupt bypass disable
call SwapContext
mov ebp, [esp+0]
mov edi, [esp+4]
mov esi, [esp+8]
mov ebx, [esp+12]
add esp, 4*4
161
; swap context
; restore registers
;
;
;
;
被迫放棄
緒程在執行過程中 由於系統某些原因 迫使緒程必須放棄
目前處理器的執行權。
KiDispatchInterrupt
老緒程
SwapContext
配量用完
被搶占
162
新緒程
被迫放棄
緒程被搶佔: KiDeferredReadyThread函式中,
一個緒程若搶占另一個正在執行的緒程,則自
己成為目標處理器的下一個緒程。
當目標處理器下一個時鐘中斷到來時,進行搶佔行為的緒程才有機會進行執行。
163
if ((Thread1 = TargetPrcb->NextThread) != NULL) {
ASSERT(Thread1->State == Standby);
if (ThreadPriority > Thread1->Priority) {
Thread1->Preempted = TRUE;
Thread->State = Standby;
TargetPrcb->NextThread = Thread;
Thread1->State = DeferredReady;
Thread1->DeferredProcessor = CurrentPrcb->Number;
KiReleaseTwoPrcbLocks(CurrentPrcb, TargetPrcb);
KiDeferredReadyThread(Thread1);
return;
}
被迫放棄
配量用完: 直接發生在時鐘中斷中。
緒程排程器並不是在時鐘中斷處理涵式中獲得
控制權,而是在KiDispatchInterrut函式中。
KiDispatchInterrut函式
DISPATCH_LEVEL軟體插斷的處理程式
同時也負責交付系統中的DPC物件。
Base\ntos\ke\i386\ctxswap.asm
164
KiDispatchInterrupt
檢查目前處理器上的DPC
和計時器串列不為空
判斷KPRCB
的
QuantumEn
d是否設定
是
清除此旗標並且執行
KiQuantumEnd切換
緒程,然後傳回
否
判斷目前處理器
的KPRCB物件中
的NextThread是
否已被選出
是
165
切換緒程
否
函式傳回
KiDispatchInterrupt
檢查QuantumEnd是否為0
kdi40: sti
; enable interrupts
cmp byte ptr [ebx].PcPrcbData.PbQuantumEnd, 0 ; quantum end requested
jne kdi90
; if neq, quantum end request
檢查是否KPRCB物件中的next thread是否被選出
cmp dword ptr [ebx].PcPrcbData.PbNextThread, 0 ; check if next thread
je
kdi70
; if eq, then no new thread
kdi70: stdRET _KiDispatchInterrupt
; return
不為0表示為搶占的情況
kdi90: mov byte ptr [ebx].PcPrcbData.PbQuantumEnd, 0 ; clear quantum end
indicator
stdCall _KiQuantumEnd
; process quantum end
stdRET _KiDispatchInterrupt ; return
166
if (OldIrql < DISPATCH_LEVEL) {
if (Prcb->NextThread != NULL) {
// If there is a new thread selected for execution, then switch
// context to the new thread.
KiAcquirePrcbLock(Prcb);
NewThread = Prcb->NextThread;
CurrentThread = Prcb->CurrentThread;
KiSetContextSwapBusy(CurrentThread);
Prcb->NextThread = NULL;
Prcb->CurrentThread
= NewThread;
NewThread->State = Running;
KxQueueReadyThread(CurrentThread,
Prcb);
CurrentThread->WaitIrql = OldIrql;
Pending = KiSwapContext(CurrentThread, NewThread);
if (Pending != FALSE) {
KeLowerIrql(APC_LEVEL);
KiDeliverApc(KernelMode,
NULL, NULL);
ASSERT(OldIrql == 0);
}
}
KiExitDispatcher
KiExitDispatcher也會導致緒程切換
為什麼會導致緒程切換?
當一個緒程在執行過程中進入到排程器的程式碼邏輯
中,為了回到緒程自身的程式碼邏輯中便會呼叫
KiExitDispatcher來結束排程器的程式碼邏輯。
Base\ntos\ke\waitsup.c
} else if ((Prcb->NextThread != NULL) &&
(Prcb->DpcRoutineActive == FALSE)) {
KiRequestSoftwareInterrupt(DISPATCH_LEVEL);
}
KeLowerIrql(OldIrql);
return;
167
緒程如何切換
KiSwapThread呼叫KiSwapContext。
KiSwapContext函式有包裝了SwapContext函式。
真正進行執行緒程切換的是組語函式
SwapContext。
SwapContext
base\ntos\ke\i386\ctxswap.asm
需要將處理中所有與緒程相關的狀態(暫存器)從老的緒程
環境變換到新的緒程環境中。
指令指標
堆疊指標(包含使用者堆疊和核心堆疊)
行程位址空間(分頁表目錄指標)
168
SwapContext函式流程
1. 等待將被切換過去的新緒程的SwapBusy欄位被清除
2.目前處理器上的緒程切換器+1
3. 原來緒程的例外串列開頭保存到堆疊中
4.根據需要保存輔助處理器的狀態
169
5.保存原來緒程的堆疊指標,保存到KTHREAD的KeneralStack欄位中
SwapContext函式流程
6.判斷CR0暫存
器與原來緒程
的CR0暫存器
是否匹配
否
重新載入新緒程的CR0暫存器
7.設置新緒程的堆疊指標
170
是
SwapContext函式流程
否
8.判斷新緒程是
否與原來的緒程
同屬於一個行程
維護行程物件的
ActiveProcessors
LDT是
否匹配
否
是
是
載入LDT並且更新IDT的INT 21
項
讓CR3暫存器指向新的目錄表
171
SwapContext函式流程
9. 清除原來緒程的SwapBusy欄位
10.設置目前處理器KPRCB的TEB,指向新的TEB,並且設置GDT中
的TEB項也指向新緒程的TEB
11. 調整初始的核心堆疊位址,並且設置到TSS的Esp0欄位
12.設置新行程的IOPM表的位置
172
SwapContext函式流程
13. 新緒程的環境切換次數+1
14. 恢復緒程的例外串列開頭
15.判斷目前是
否在一個DPC
中進行緒程切
換
是
呼叫BugCheck
否
173
SwapContext函式流程
16.判斷在新緒
程中是否有核
心模式的APC
正在等待處理
是
呼叫
HalRequestSoftwareInterrupt以
請求APC_LEVEL的軟體插斷
否
傳回
174
3.6
•3.6.1
•3.6.2
行程和緒程執行狀態監視工具
ProcMon使用範例
ProcMon實作原理
報告人:吳季衡
175
3.6.1 行程和緒程執行狀態監視工具
Windows中行程和緒程的管理機制
行程和緒程的狀態資訊
緒程是如何被排程的
176
ProcMon工具
可即時監視
查看哪些行程or緒程得到CPU的執行權
3.6.1 ProcMon使用範例
3.6.2 ProcMon實作原理
177
3.6.1 ProcMon使用範例
在Windows Server2003系統中
在特定時間點上的CPU使用率
可執行緒程的數量
178
可執行的緒程
在一段時間間隔內被真正執行或是
還在ready queue or deferred queue中排隊的緒程
滿足執行條件的緒程
可執行的緒程越多
CPU使用率越高
179
ProcMon
可將資料匯出至文字檔
支援Windows XP/Server
2003/Vista/Server2008/7 版本
可在多處理器or多核的系統上執行
180
樹狀檢視
ProcMon透過驅動程式KMonDrv.sys在kernel中收集
資訊
使用者選擇的時間點
狀態為執行的緒程
可
執
行
緒
程
集
合
181
狀態為就緒or延遲就緒的緒程
3.6
•3.6.1
•3.6.2
行程和緒程執行狀態監視工具
ProcMon使用範例
ProcMon實作原理
報告人:吳季衡
182
3.6.2 ProcMon 實作原理
user
mode
ProcMon.exe
載入
典型MFC程式
ProcMon.exe
在處理WM_TIMER
訊號的函式中
183
KMonDrv.sys
通知
驅動程式啟動緒程監視功能
驅動程式
register
1秒為間隔的timer
ProcMon向驅動
程式請求資料
發出
WM_TIMER
ProcMon解析資料
顯示於樹狀
圖中
KMonDrv
Windows核心無提供執行緒程變化通知
KMonDrv的做法
定期檢查每個CPU正在執行哪個緒程, 下個緒程, ready
queue & deferred ready queue有哪些緒程
KMonDrv的核心邏輯
初始化
定時收集資料
回應ProcMon的資料請求
184
KMonDrv的核心邏輯(1/3)
初始化階段
獲得每個CPU的KPRCB資料結構, 並建立一個查詢
timer
Timer的間隔
必須足夠小
也不能過小
分配一個合適大小的緩衝區以便將來存放收集到的緒
程資料
185
KMonDrv的核心邏輯(2/3)
定時收集資料
在timer的處理常式中收集資料
執行在DISPATCH_LEVEL層級上
存取每個CPU的KPRCB中的資料
必須得到KPRCB的spin lock(PrcbLock)
分別存取CurrentThread, NextThread, DispatcherReadyListHead,
DeferredReadyListHead成員
每個緒程依據其CLIENT_ID值在緩衝區佔據一項
若緩衝區已滿, 新緒程的資訊無法被加入至緩衝區
凡是已執行過的緒程, 便不再記錄
186
KMonDrv的核心邏輯(3/3)
回應ProcMon的資料請求
ProcMon和KMonDrv驅動程式透過Windows的標
準I/O介面進行通訊(回應自訂編碼的裝置控制I/O請
求)
KMonDrv
buffer
buffer
KMonDrv清空buffer
187
傳送給
ProcMon
ProcMon的問題
輪詢機制(polling)無法保證總是能獲得一個timer周期內
所有被執行或排隊過的緒程
Example
解決
核心日誌記錄器(a ETW provider)
可分析出一個系統中的緒程執行情況
Cswitch : 記錄每個CPU上發生的緒程切換資訊
Ready Thread : 記錄一個緒程進入延遲就緒狀態的資訊
WRK的核心程式碼
將緒程執行資訊記錄到一個緩衝區中, 給驅動程式讀取並顯示出來
188
Chapter 4
Windows記憶體管理
報告人:林依汶
190
CPU和記憶體的配合
儲存管理很重要
記憶體直接受處理器控制和管理
OS會依其所支援的硬體系統架構來選擇相關的記憶體
管理機制
記憶體管理元件的框架結構
在多行程環境中, 為了讓每個行程有獨立的位址空間,
Windows在處理器定址機制的基礎上用了大量的記憶
體管理技術來滿足各種需求
191
4.1
記憶體管理概述
•4.1.1
分頁式記憶體管理
•4.1.2 行程和緒程的結束處理
•4.1.3 系統初始行程和緒程
•4.1.4 Windows記憶體管理概述
報告人:林依汶
192
4.1 記憶體管理概述
記憶體(memory)
硬體(匯流排)
軟體(記憶體單元)
記憶體位址(Intel x86)
實體位址(Physical Address)
虛擬位址(Linear Address)
邏輯位址(Logical Address)
193
實體位址
記憶體儲存器的索引
系統的記憶體的真正位址
32bit or 36bit unsigned integer
194
虛擬位址
也稱線性位址
32bit系統上, 虛擬位址空間可達4GB
Intel x86晶片內有專門的電路把虛擬位址轉成實體
位址
195
邏輯位址
邏輯位址=區段基底位址+偏移量
區段(segment)
指定了整個位址空間中的一個基底位址和區段空間的大
小
偏移(offset)
指定了一個邏輯位址相對於區段基址的偏移量
偏移量不得超過邊界
Intel x86晶片內有專門的電路把邏輯位址轉成虛擬或
實體位址
196
位址空間的隔離性
需有效的管理所有實體記憶體
不同行程的位址空間應該是相互隔離的
隔離性使得每個行程有自己的私有位址空間
避免某個行程侵入到另個行程的位址空間
197