接着下来,就需要分析函数KiReadyThread的作用了。根据线程状态来判断是否可以放入延迟队列,还是设置它为转换状态,代码如下:
#001 VOID
#002 NTAPI
#003 KiReadyThread(IN PKTHREAD Thread)
#004 {
获取当前线程的进程对象。
#005 IN PKPROCESS Process = Thread->ApcState.Process;
#006
检查进程是否已经换出内存。
#007 /* Check if the process is paged out */
#008 if (Process->State != ProcessInMemory)
#009 {
如果进程已经换出内存,就不做任何的操作。
#010 /* We don't page out processes in ROS */
#011 ASSERT(FALSE);
#012 }
#013 else if (!Thread->KernelStackResident)
#014 {
检查线程的内核栈是否为空,如果为空就需要增加栈的大小。
#015 /* Increase the stack count */
#016 ASSERT(Process->StackCount != MAXULONG_PTR);
#017 Process->StackCount++;
#018
设置线程为转换状态,由于需要内核栈。
#019 /* Set the thread to transition */
#020 ASSERT(Thread->State != Transition);
#021 Thread->State = Transition;
#022
#023 /* The stack is always resident in ROS */
#024 ASSERT(FALSE);
#025 }
#026 else
#027 {
把线程放到延迟调用队列。
#028 /* Insert the thread on the deferred ready list */
#029 KiInsertDeferredReadyList(Thread);
#030 }
#031 }
KiInsertDeferredReadyList函数是把线程设置为延迟状态,然后插入到当前处理器的延迟队列,代码如下:
#001 //
#002 // This routine inserts a thread into the deferred ready list of the given CPU
#003 //
#004 FORCEINLINE
#005 VOID
#006 KiInsertDeferredReadyList(IN PKTHREAD Thread)
#007 {
获取当前处理器的控制块。
#008 PKPRCB Prcb = KeGetCurrentPrcb();
#009
设置线程为延迟状态。
#010 /* Set the thread to deferred state and CPU */
#011 Thread->State = DeferredReady;
设置线程运行的CPU。
#012 Thread->DeferredProcessor = Prcb->Number;
#013
把线程放到当前处理器控制块的延迟队列。
#014 /* Add it on the list */
#015 PushEntryList(&Prcb->DeferredReadyListHead, &Thread->SwapListEntry);
#016 }
在上面这个函数里,调用PushEntryList函数来把当前准备好的线程放到延迟队列。你也许看不明白为什么使用Thread->SwapListEntry就可以把线程的指针放到延迟队列呢?其实需要仔细看线程的结构才可以明白的,如下:
#068 union
#069 {
#070 LIST_ENTRY WaitListEntry;
#071 SINGLE_LIST_ENTRY SwapListEntry;
#072 };
在线程结构里是使用上面的联合来表达的,因此设置WaitListEntry变量,就相当设置SwapListEntry变量的值了。这是在函数KeInitThread里设置它的值,如下:
#027 /* Initialize the wait blocks */
#028 for (i = 0; i< (THREAD_WAIT_OBJECTS + 1); i++)
#029 {
#030 /* Put our pointer */
#031 Thread->WaitBlock[i].Thread = Thread;
#032 }
#033
......
#072 KeInitializeTimer(Timer);
#073 TimerWaitBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
因此Thread->SwapListEntry变量的值,就可通过结构里的Thread来访问线程数据。
SwapListEntry的结构排列如下:
#001 typedef struct _KWAIT_BLOCK {
#002 LIST_ENTRY WaitListEntry;
#003 struct _KTHREAD * RESTRICTED_POINTER Thread;
#004 PVOID Object;
#005 struct _KWAIT_BLOCK * RESTRICTED_POINTER NextWaitBlock;
#006 USHORT WaitKey;
#007 UCHAR WaitType;
#008 UCHAR SpareByte;
#009 } KWAIT_BLOCK, *PKWAIT_BLOCK, *RESTRICTED_POINTER PRKWAIT_BLOCK;