reactos操作系统实现(39)
到底一个线程是怎么样创建的呢?又是怎么样放到就绪队列呢? #001 NTSTATUS #002 NTAPI #003 PspCreateThread(OUT PHANDLE ThreadHandle, #004 IN ACCESS_MASK DesiredAccess, #005 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, #006 IN HANDLE ProcessHandle, #007 IN PEPROCESS TargetProcess, #008 OUT PCLIENT_ID ClientId, #009 IN PCONTEXT ThreadContext, #010 IN PINITIAL_TEB InitialTeb, #011 IN BOOLEAN CreateSuspended, #012 IN PKSTART_ROUTINE StartRoutine OPTIONAL, #013 IN PVOID StartContext OPTIONAL) #014 { #015 HANDLE hThread; #016 PEPROCESS Process; #017 PETHREAD Thread; #018 PTEB TebBase = NULL;
获取当前处理器的模式,比如内核模式、用户模式、最大模式。 #019 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); #020 NTSTATUS Status,AccessStatus; #021 HANDLE_TABLE_ENTRY CidEntry; #022 ACCESS_STATE LocalAccessState; #023 PACCESS_STATE AccessState = &LocalAccessState; #024 AUX_ACCESS_DATA AuxData; #025 BOOLEAN Result,SdAllocated; #026 PSECURITY_DESCRIPTOR SecurityDescriptor; #027 SECURITY_SUBJECT_CONTEXT SubjectContext;
判断代码是否可以执行。 #028 PAGED_CODE(); #029 PSTRACE(PS_THREAD_DEBUG, #030 "ThreadContext: %p TargetProcess: %p ProcessHandle: %p/n", #031 ThreadContext,TargetProcess,ProcessHandle); #032
当从函数PsCreateSystemThread里调用时,当前肯定是运行在内核模式,也就是通过是否有回调函数StartRoutine来判断的。 #033 /* If we were called from PsCreateSystemThread,then we're kernel mode */ #034 if (StartRoutine) PreviousMode = KernelMode; #035
获取线程所属的进程结构。 #036 /* Reference the Process by handle or pointer,depending on what we got */ #037 if (ProcessHandle) #038 {
通过进程句柄到对象 #039 /* Normal thread or System Thread */ #040 Status = ObReferenceObjectByHandle(ProcessHandle, #041 PROCESS_CREATE_THREAD, #042 PsProcessType, #043 PreviousMode, #044 (PVOID*)&Process, #045 NULL); #046 PSREFTRACE(Process); #047 } #048 else #049 {
获取系统线程的进程对象,或者普通线程的进程有问题。 #050 /* System thread inside System Process,or Normal Thread with a bug */ #051 if (StartRoutine) #052 { #053 /* Reference the Process by Pointer */ #054 ObReferenceObject(TargetProcess); #055 Process = TargetProcess; #056 Status = STATUS_SUCCESS; #057 } #058 else #059 { #060 /* Fake ObReference returning this */ #061 Status = STATUS_INVALID_HANDLE; #062 } #063 } #064 #065 /* Check for success */ #066 if (!NT_SUCCESS(Status)) return Status; #067
如果不是内核模式,不让创建线程。 #068 /* Also make sure that User-Mode isn't trying to create a system thread */ #069 if ((PreviousMode != KernelMode) && (Process == PsInitialSystemProcess)) #070 { #071 /* Fail */ #072 ObDereferenceObject(Process); #073 return STATUS_INVALID_HANDLE; #074 } #075
创建一个线程对象。 #076 /* Create Thread Object */ #077 Status = ObCreateObject(PreviousMode, #078 PsThreadType, #079 ObjectAttributes, #080 PreviousMode, #081 NULL, #082 sizeof(ETHREAD), #083 0, #084 0, #085 (PVOID*)&Thread); #086 if (!NT_SUCCESS(Status)) #087 { #088 /* We failed; dereference the process and exit */ #089 ObDereferenceObject(Process); #090 return Status; #091 } #092
初始化线程对象。 #093 /* Zero the Object entirely */ #094 RtlZeroMemory(Thread,sizeof(ETHREAD)); #095 #096 /* Initialize rundown protection */ #097 ExInitializeRundownProtection(&Thread->RundownProtect); #098
设置线程退出码。 #099 /* Initialize exit code */ #100 Thread->ExitStatus = STATUS_PENDING; #101
设置线程的进程ID。 #102 /* Set the Process CID */ #103 Thread->ThreadsProcess = Process; #104 Thread->Cid.UniqueProcess = Process->UniqueProcessId; #105
创建线程的ID。 #106 /* Create Cid Handle */ #107 CidEntry.Object = Thread; #108 CidEntry.GrantedAccess = 0; #109 Thread->Cid.UniqueThread = ExCreateHandle(PspCidTable,&CidEntry); #110 if (!Thread->Cid.UniqueThread) #111 { #112 /* We couldn't create the CID,dereference the thread and fail */ #113 ObDereferenceObject(Thread); #114 return STATUS_INSUFFICIENT_RESOURCES; #115 }
保存读取的族大小。 #116 #117 /* Save the read cluster size */ #118 Thread->ReadClusterSize = MmReadClusterSize; #119
初始化LPC信号量。 #120 /* Initialize the LPC Reply Semaphore */ #121 KeInitializeSemaphore(&Thread->LpcReplySemaphore,1); #122
初始化线程的列表和锁。 #123 /* Initialize the list heads and locks */ #124 InitializeListHead(&Thread->LpcReplyChain); #125 InitializeListHead(&Thread->IrpList); #126 InitializeListHead(&Thread->PostBlockList); #127 InitializeListHead(&Thread->ActiveTimerListHead); #128 KeInitializeSpinLock(&Thread->ActiveTimerListLock); #129 #130 /* Acquire rundown protection */ #131 if (!ExAcquireRundownProtection (&Process->RundownProtect)) #132 { #133 /* Fail */ #134 ObDereferenceObject(Thread); #135 return STATUS_PROCESS_IS_TERMINATING; #136 } #137
初始化线程的TEB环境块。 #138 /* Now let the kernel initialize the context */ #139 if (ThreadContext) #140 { #141 /* User-mode Thread,create Teb */ #142 TebBase = MmCreateTeb(Process,&Thread->Cid,InitialTeb); #143 if (!TebBase) #144 { #145 /* Failed to create the TEB. Release rundown and dereference */ #146 ExReleaseRundownProtection(&Process->RundownProtect); #147 ObDereferenceObject(Thread); #148 return STATUS_INSUFFICIENT_RESOURCES; #149 } #150 #151 /* Set the Start Addresses */ #152 #if defined(_M_IX86) #153 Thread->StartAddress = (PVOID)ThreadContext->Eip; #154 Thread->Win32StartAddress = (PVOID)ThreadContext->Eax; #155 #elif defined(_M_PPC) #156 Thread->StartAddress = (PVOID)ThreadContext->Dr0; #157 Thread->Win32StartAddress = (PVOID)ThreadContext->Gpr3; #158 #elif defined(_M_MIPS) #159 Thread->StartAddress = (PVOID)ThreadContext->Psr; #160 Thread->Win32StartAddress = (PVOID)ThreadContext->IntA0; #161 #elif defined(_M_ARM) #162 Thread->StartAddress = (PVOID)ThreadContext->Pc; #163 Thread->Win32StartAddress = (PVOID)ThreadContext->R0; #164 #elif defined(_M_AMD64) #165 Thread->StartAddress = (PVOID)ThreadContext->Rip; #166 Thread->Win32StartAddress = (PVOID)ThreadContext->Rax; #167 #else #168 #error Unknown architecture #169 #endif #170 #171 /* Let the kernel intialize the Thread */ #172 Status = KeInitThread(&Thread->Tcb, #173 NULL, #174 PspUserThreadStartup, #175 NULL, #176 Thread->StartAddress, #177 ThreadContext, #178 TebBase, #179 &Process->Pcb); #180 } #181 else #182 {
创建系统线程。 #183 /* System Thread */ #184 Thread->StartAddress = StartRoutine; #185 PspSetCrossThreadFlag(Thread,CT_SYSTEM_THREAD_BIT); #186 #187 /* Let the kernel intialize the Thread */ #188 Status = KeInitThread(&Thread->Tcb, #189 NULL, #190 PspSystemThreadStartup, #191 StartRoutine, #192 StartContext, #193 NULL, #194 NULL, #195 &Process->Pcb); #196 } #197
初始化线程失败,就清除分配的资源。 #198 /* Check if we failed */ #199 if (!NT_SUCCESS(Status)) #200 { #201 /* Delete the TEB if we had done */ #202 if (TebBase) MmDeleteTeb(Process,TebBase); #203 #204 /* Release rundown and dereference */ #205 ExReleaseRundownProtection(&Process->RundownProtect); #206 ObDereferenceObject(Thread); #207 return Status; #208 } #209
检查进程是否已经删除。 #210 /* Lock the process */ #211 KeEnterCriticalRegion(); #212 ExAcquirePushLockExclusive(&Process->ProcessLock); #213 #214 /* Make sure the proces didn't just die on us */ #215 if (Process->ProcessDelete) goto Quickie; #216 #217 /* Check if the thread was ours,terminated and it was user mode */ #218 if ((Thread->Terminated) && #219 (ThreadContext) && #220 (Thread->ThreadsProcess == Process)) #221 { #222 /* Cleanup,we don't want to start it up and context switch */ #223 goto Quickie; #224 } #225
把新创建的线程放到进程的线程列表里。 #226 /* #227 * Insert the Thread into the Process's Thread List #228 * Note,this is the ETHREAD Thread List. It is removed in #229 * ps/kill.c!PspExitThread. #230 */ #231 InsertTailList(&Process->ThreadListHead,&Thread->ThreadListEntry); #232 Process->ActiveThreads++; #233
设置启动线程。 #234 /* Start the thread */ #235 KeStartThread(&Thread->Tcb); #236 #237 /* Release the process lock */ #238 ExReleasePushLockExclusive(&Process->ProcessLock); #239 KeLeaveCriticalRegion(); #240 #241 /* Release rundown */ #242 ExReleaseRundownProtection(&Process->RundownProtect); #243 #244 /* Notify WMI */ #245 //WmiTraceProcess(Process,TRUE); #246 //WmiTraceThread(Thread,InitialTeb,TRUE); #247
通知线程创建。 #248 /* Notify Thread Creation */ #249 PspRunCreateThreadNotifyRoutines(Thread,TRUE); #250 #251 /* Reference ourselves as a keep-alive */ #252 ObReferenceObjectEx(Thread,2); #253
检查是否需要挂起线程执行。 #254 /* Suspend the Thread if we have to */ #255 if (CreateSuspended) KeSuspendThread(&Thread->Tcb); #256
终止线程的执行。 #257 /* Check if we were already terminated */ #258 if (Thread->Terminated) KeForceResumeThread(&Thread->Tcb); #259 #260 /* Create an access state */ #261 Status = SeCreateAccessStateEx(NULL, #262 ThreadContext ? #263 PsGetCurrentProcess() : Process, #264 &LocalAccessState, #265 &AuxData, #266 DesiredAccess, #267 &PsThreadType->TypeInfo.GenericMapping); #268 if (!NT_SUCCESS(Status)) #269 { #270 /* Access state failed,thread is dead */ #271 PspSetCrossThreadFlag(Thread,CT_DEAD_THREAD_BIT); #272 #273 /* If we were suspended,wake it up */ #274 if (CreateSuspended) KeResumeThread(&Thread->Tcb); #275 #276 /* Dispatch thread */ #277 KeReadyThread(&Thread->Tcb); #278 #279 /* Dereference completely to kill it */ #280 ObDereferenceObjectEx(Thread,2); #281 return Status; #282 } #283
把线程放到对象管理器。 #284 /* Insert the Thread into the Object Manager */ #285 Status = ObInsertObject(Thread, #286 AccessState, #287 DesiredAccess, #288 0, #289 NULL, #290 &hThread); #291 #292 /* Delete the access state if we had one */ #293 if (AccessState) SeDeleteAccessState(AccessState); #294
通过SEH机制保存线程ID和线程句柄给用户空间的变量。 #295 /* Check for success */ #296 if (NT_SUCCESS(Status)) #297 { #298 /* Wrap in SEH to protect against bad user-mode pointers */ #299 _SEH2_TRY #300 { #301 /* Return Cid and Handle */ #302 if (ClientId) *ClientId = Thread->Cid; #303 *ThreadHandle = hThread; #304 } #305 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) #306 { #307 /* Get the exception code */ #308 Status = _SEH2_GetExceptionCode(); #309 #310 /* Thread insertion failed,thread is dead */ #311 PspSetCrossThreadFlag(Thread,CT_DEAD_THREAD_BIT); #312 #313 /* If we were suspended,wake it up */ #314 if (CreateSuspended) KeResumeThread(&Thread->Tcb); #315 #316 /* Dispatch thread */ #317 KeReadyThread(&Thread->Tcb); #318 #319 /* Dereference it,leaving only the keep-alive */ #320 ObDereferenceObject(Thread); #321 #322 /* Close its handle,killing it */ #323 ObCloseHandle(ThreadHandle,PreviousMode); #324 } #325 _SEH2_END; #326 if (!NT_SUCCESS(Status)) return Status; #327 } #328 else #329 { #330 /* Thread insertion failed,thread is dead */ #331 PspSetCrossThreadFlag(Thread,CT_DEAD_THREAD_BIT); #332 #333 /* If we were suspended,wake it up */ #334 if (CreateSuspended) KeResumeThread(&Thread->Tcb); #335 } #336
获取线程创建时间。 #337 /* Get the create time */ #338 KeQuerySystemTime(&Thread->CreateTime); #339 ASSERT(!(Thread->CreateTime.HighPart & 0xF0000000)); #340 #341 /* Make sure the thread isn't dead */ #342 if (!Thread->DeadThread) #343 { #344 /* Get the thread's SD */ #345 Status = ObGetObjectSecurity(Thread, #346 &SecurityDescriptor, #347 &SdAllocated); #348 if (!NT_SUCCESS(Status)) #349 { #350 /* Thread insertion failed,thread is dead */ #351 PspSetCrossThreadFlag(Thread,CT_DEAD_THREAD_BIT); #352 #353 /* If we were suspended,wake it up */ #354 if (CreateSuspended) KeResumeThread(&Thread->Tcb); #355 #356 /* Dispatch thread */ #357 KeReadyThread(&Thread->Tcb); #358 #359 /* Dereference it,leaving only the keep-alive */ #360 ObDereferenceObject(Thread); #361 #362 /* Close its handle,killing it */ #363 ObCloseHandle(ThreadHandle,PreviousMode); #364 return Status; #365 } #366
设置线程安全环境变量。 #367 /* Create the subject context */ #368 SubjectContext.ProcessAuditId = Process; #369 SubjectContext.PrimaryToken = PsReferencePrimaryToken(Process); #370 SubjectContext.ClientToken = NULL; #371 #372 /* Do the access check */ #373 Result = SeAccessCheck(SecurityDescriptor, #374 &SubjectContext, #375 FALSE, #376 MAXIMUM_ALLOWED, #377 0, #378 NULL, #379 &PsThreadType->TypeInfo.GenericMapping, #380 PreviousMode, #381 &Thread->GrantedAccess, #382 &AccessStatus); #383 #384 /* Dereference the token and let go the SD */ #385 ObFastDereferenceObject(&Process->Token, #386 SubjectContext.PrimaryToken); #387 ObReleaSEObjectSecurity(SecurityDescriptor,SdAllocated); #388 #389 /* Remove access if it failed */ #390 if (!Result) Process->GrantedAccess = 0; #391 #392 /* Set least some minimum access */ #393 Thread->GrantedAccess |= (THREAD_TERMINATE | #394 THREAD_SET_INFORMATION | #395 THREAD_QUERY_INFORMATION); #396 } #397 else #398 { #399 /* Set the thread access mask to maximum */ #400 Thread->GrantedAccess = THREAD_ALL_ACCESS; #401 } #402
标记线程已经可以运行,把线程放到准备就绪队列。 #403 /* Dispatch thread */ #404 KeReadyThread(&Thread->Tcb); #405 #406 /* Dereference it,leaving only the keep-alive */ #407 ObDereferenceObject(Thread); #408 #409 /* Return */ #410 return Status; #411
出错处理。 #412 /* Most annoying failure case ever,where we undo almost all manually */ #413 Quickie: #414 /* When we get here,the process is locked,unlock it */ #415 ExReleasePushLockExclusive(&Process->ProcessLock); #416 KeLeaveCriticalRegion(); #417 #418 /* Uninitailize it */ #419 KeUninitThread(&Thread->Tcb); #420 #421 /* If we had a TEB,delete it */ #422 if (TebBase) MmDeleteTeb(Process,TebBase); #423 #424 /* Release rundown protection,which we also hold */ #425 ExReleaseRundownProtection(&Process->RundownProtect); #426 #427 /* Dereference the thread and return failure */ #428 ObDereferenceObject(Thread); #429 return STATUS_PROCESS_IS_TERMINATING; #430 }
通上面函数分析,已经了解一个线程创建,不但可以创建系统线程,还可以创建用户线程。当初始化线程后,就可以把线程放到调度就绪队列,准备给下一轮调试使用。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |