★.线程等待对象
一些对象时刻等待的 进程 线程 定时器 各种同步对象等等
可被等待的对象,开头都是一个分发器头,这是WRK中的定义,WDK中的定义要更复杂点
typedef struct _DISPATCHER_HEADER {
union {
struct {
UCHAR Type; 对象类型
union {
UCHAR Absolute;
UCHAR NpxIrql;
};
union {
UCHAR Size;
UCHAR Hand;
};
union {
UCHAR Inserted;
BOOLEAN DebugActive;
};
};
volatile LONG Lock;
};
LONG SignalState; 受信状态
LIST_ENTRY WaitListHead; 这是链表头 连接了所有等待此对象的线程的KWAIT_BLOCK
} DISPATCHER_HEADER;
KiUnwaitThread用于唤醒一个线程,使其变成延迟就绪状态
KTHREAD.WaitBlockList记录线程等待的对象,指向第一个等待的对象
typedef struct _KWAIT_BLOCK {
LIST_ENTRY WaitListEntry; //挂入WaitListHead,一个对象所有的等待块 struct _KTHREAD *Thread;
PVOID Object; //指要等待的对象
struct _KWAIT_BLOCK *NextWaitBlock; //挂入线程链表,这个链表组成的线程等待的所有对象,单循环链表,头是KTHREAD.WaitBlockList
USHORT WaitKey;
UCHAR WaitType; //WaitAny 任意对象满足后唤醒 WaitAll要等到所有都满足
UCHAR SpareByte;
} KWAIT_BLOCK, *PKWAIT_BLOCK, *PRKWAIT_BLOCK;
1.线程进入等待
先看一下线程进入等待的状况,以KeWaitForSingleObject为例
//插入代码
等待一定时间的KeDelayxxx还有KeWaitForMultie 原理类似
NTSTATUS
KeWaitForSingleObject (
__in PVOID Object,
__in KWAIT_REASON WaitReason,
__in KPROCESSOR_MODE WaitMode,
__in BOOLEAN Alertable,
__in_opt PLARGE_INTEGER Timeout
)
--*/
{
Hand = 0;
Thread = KeGetCurrentThread();
Objectx = (PKMUTANT)Object;
OriginalTime = Timeout;
Timer = &Thread->Timer;
WaitBlock = &Thread->WaitBlock[0];
WaitTimer = &Thread->WaitBlock[TIMER_WAIT_BLOCK]; //最后一个用于超时
if (ReadForWriteAccess(&Thread->WaitNext) == FALSE) {
goto WaitStart;
}
Thread->WaitNext = FALSE;
/*InitializeWaitSingle();
#define InitializeWaitSingle() 宏展开*/
Thread->WaitBlockList = WaitBlock; //初始化等待块
WaitBlock->Object = Object;
WaitBlock->WaitKey = (CSHORT)(STATUS_SUCCESS);
WaitBlock->WaitType = WaitAny;
Thread->WaitStatus = 0;
if (ARGUMENT_PRESENT(Timeout)) { //如果有到期时间 ,初始化一个定时器
KiSetDueTime(Timer, *Timeout, &Hand);
DueTime.QuadPart = Timer->DueTime.QuadPart;
WaitBlock->NextWaitBlock = WaitTimer; //定时器等待块和要等待的等待块构成循环链表
WaitTimer->NextWaitBlock = WaitBlock;
Timer->Header.WaitListHead.Flink = &WaitTimer->WaitListEntry;
Timer->Header.WaitListHead.Blink = &WaitTimer->WaitListEntry;
} else {
WaitBlock->NextWaitBlock = WaitBlock;
}
Thread->Alertable = Alertable;
Thread->WaitMode = WaitMode;
Thread->WaitReason = (UCHAR)WaitReason;
Thread->WaitListEntry.Flink = NULL;
StackSwappable = KiIsKernelStackSwappable(WaitMode, Thread);
Thread->WaitTime = KiQueryLowTickCount()
do {
//这个循环是为了能够在等待过程中处理APC
Thread->Preempted = FALSE;
if (Thread->ApcState.KernelApcPending &&
(Thread->SpecialApcDisable == 0) &&
(Thread->WaitIrql < APC_LEVEL)) {
//irql提升到DISPATCH_LEVEL,其他cpu投递了一个apc,dispatcher数据库仍在锁定的情况
//这样会请求一个中断派发掉apc
KiUnlockDispatcherDatabase(Thread->WaitIrql);
} else {
//MutantObject要特别对待 Mutant对应的是R3的mutex概念
if (Objectx->Header.Type == MutantObject) {
if ((Objectx->Header.SignalState > 0) ||
(Thread == Objectx->OwnerThread)) {
if (Objectx->Header.SignalState != MINLONG) {
KiWaitSatisfyMutant(Objectx, Thread);
WaitStatus = (NTSTATUS)(Thread->WaitStatus);
goto NoWait;
} else {
KiUnlockDispatcherDatabase(Thread->WaitIrql);
ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
}
}
} else if (Objectx->Header.SignalState > 0) {//条件已经满足
KiWaitSatisfyOther(Objectx);
WaitStatus = (NTSTATUS)(0);
goto NoWait;
}
TestForAlertPending(Alertable); //检测是否可以被叫醒(用户态APC神马的) 更改等待状态 WaitStatus
/* 以下是宏定义 如果被叫醒,则提前结束循环
#define TestForAlertPending(Alertable) \
if (Alertable) { \
if (Thread->Alerted[WaitMode] != FALSE) { \
Thread->Alerted[WaitMode] = FALSE; \
WaitStatus = STATUS_ALERTED; \
break; \
} else if ((WaitMode != KernelMode) && \
(IsListEmpty(&Thread->ApcState.ApcListHead[UserMode])) == FALSE) { \
Thread->ApcState.UserApcPending = TRUE; \
WaitStatus = STATUS_USER_APC; \
break; \
} else if (Thread->Alerted[KernelMode] != FALSE) { \
Thread->Alerted[KernelMode] = FALSE; \
WaitStatus = STATUS_ALERTED; \
break; \
} \
} else if (Thread->ApcState.UserApcPending & WaitMode) { \
WaitStatus = STATUS_USER_APC; \
break; \
}
*/
if (ARGUMENT_PRESENT(Timeout)) {// 检查定时是否到期
if (KiCheckDueTime(Timer) == FALSE) {
WaitStatus = (NTSTATUS)STATUS_TIMEOUT;
goto NoWait;
}
}
InsertTailList(&Objectx->Header.WaitListHead, &WaitBlock->WaitListEntry);// 等待块插入对象的派发头
Queue = Thread->Queue;
if (Queue != NULL) {
KiActivateWaiterQueue(Queue);
}
Thread->State = Waiting; //设置线程进入等待状态
CurrentPrcb = KeGetCurrentPrcb();
if (StackSwappable != FALSE) {
InsertTailList(&CurrentPrcb->WaitListHead, &Thread->WaitListEntry);
}
ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
KiSetContextSwapBusy(Thread);
if (ARGUMENT_PRESENT(Timeout)) {
KiInsertOrSignalTimer(Timer, Hand);
} else {
KiUnlockDispatcherDatabaseFromSynchLevel();
}
WaitStatus = (NTSTATUS)KiSwapThread(Thread, CurrentPrcb); //放弃执行,切换线程,当从这里返回之后意味着
//条件已经被满足,或者超时,或者有内核APC插入
if (WaitStatus != STATUS_KERNEL_APC) {//只要不是内核apc插入,就可以返回了
return WaitStatus;
}
if (ARGUMENT_PRESENT(Timeout)) {//否则这不是一次真的等到了,而是被内核apc搞醒的 重新计算时间 重新构造一个等待 循环
Timeout = KiComputeWaitInterval(OriginalTime, //减少时间
&DueTime,
&NewTime);
}
}
WaitStart:
Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
InitializeWaitSingle();
KiLockDispatcherDatabaseAtSynchLevel();
} while (TRUE);
KiUnlockDispatcherDatabase(Thread->WaitIrql);
return WaitStatus;
NoWait:
KiUnlockDispatcherDatabaseFromSynchLevel();
KiAdjustQuantumThread(Thread);
return WaitStatus;
}
KeWaitForMultie需要在每次被唤醒后需要重新构造等待块,判断条件是否满足,如果不满足,那就继续等待下去
2.测试已满足等待条件
KeSetEvent 等等使对象受信的函数会调用测试线程是否在等待这个对象,并且尝试释放
Event->Header.SignalState = 1;
if ((OldState == 0) &&
(IsListEmpty(&Event->Header.WaitListHead) == FALSE)) {
if (Event->Header.Type == EventNotificationObject) {
KiWaitTestWithoutSideEffects(Event, Increment); //事件通知 一次唤醒所有线程
} else {
KiWaitTestSynchronizationObject(Event, Increment); //事件同步 一次唤醒一个线程并且重置事件
}
}
看一下这个KiWaitTestWithoutSideEffects
VOID
KiWaitTestWithoutSideEffects (
IN PVOID Object,
IN KPRIORITY Increment
)
{
PKEVENT Event = Object;
PLIST_ENTRY ListHead;
PRKTHREAD Thread;
PRKWAIT_BLOCK WaitBlock;
PLIST_ENTRY WaitEntry;
ListHead = &Event->Header.WaitListHead;
ASSERT(IsListEmpty(&Event->Header.WaitListHead) == FALSE);
WaitEntry = ListHead->Flink;
do {
//遍历等待这个对象的等待块,如果是waitany 可以直接唤醒,否则以APC形式唤醒,交由waitformutie处理
WaitBlock = CONTAINING_RECORD(WaitEntry, KWAIT_BLOCK, WaitListEntry);
Thread = WaitBlock->Thread;
if (WaitBlock->WaitType == WaitAny) {
KiUnwaitThread(Thread, (NTSTATUS)WaitBlock->WaitKey, Increment);
} else {
KiUnwaitThread(Thread, STATUS_KERNEL_APC, Increment);
}
WaitEntry = ListHead->Flink;
} while (WaitEntry != ListHead);
return;
}
其他测试函数也大同小异
3.线程取消等待
线程取消等待的函数是KiUnwaitThread,它先调用了了KiUnlinkThread
KiUnlinkThread这个函数做了三件事,移除Thread->WaitBlockList,移除Timer,递增线程队列的活动系数(Thread->Queue)
之后KiUnwaitThread调用了KiReadyThread使线程进入了延迟等待状态