zl程序教程

您现在的位置是:首页 >  系统

当前栏目

reactos操作系统实现(39)

操作系统 实现 39 reactos
2023-09-14 09:10:38 时间

到底一个线程是怎么样创建的呢?又是怎么样放到就绪队列呢?

#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, 0, 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  }

 

通上面函数分析,已经了解一个线程创建,不但可以创建系统线程,还可以创建用户线程。当初始化线程后,就可以把线程放到调度就绪队列,准备给下一轮调试使用。