_DISPATCHER_HEADER 结构
c
//0x10 bytes (sizeof)
struct _DISPATCHER_HEADER
{
union
{
struct
{
UCHAR Type; //0x0
union
{
UCHAR TimerControlFlags; //0x1
struct
{
UCHAR Absolute:1; //0x1
UCHAR Coalescable:1; //0x1
UCHAR KeepShifting:1; //0x1
UCHAR EncodedTolerableDelay:5; //0x1
};
UCHAR Abandoned; //0x1
UCHAR Signalling; //0x1
};
union
{
UCHAR ThreadControlFlags; //0x2
struct
{
UCHAR CpuThrottled:1; //0x2
UCHAR CycleProfiling:1; //0x2
UCHAR CounterProfiling:1; //0x2
UCHAR Reserved:5; //0x2
};
UCHAR Hand; //0x2
UCHAR Size; //0x2
};
union
{
UCHAR TimerMiscFlags; //0x3
struct
{
UCHAR Index:1; //0x3
UCHAR Processor:5; //0x3
UCHAR Inserted:1; //0x3
volatile UCHAR Expired:1; //0x3
};
UCHAR DebugActive; //0x3
struct
{
UCHAR ActiveDR7:1; //0x3
UCHAR Instrumented:1; //0x3
UCHAR Reserved2:4; //0x3
UCHAR UmsScheduled:1; //0x3
UCHAR UmsPrimary:1; //0x3
};
UCHAR DpcActive; //0x3
};
};
volatile LONG Lock; //0x0
};
LONG SignalState; //0x4
struct _LIST_ENTRY WaitListHead; //0x8
};
在windows内核中,凡是头部以_DISPATCHER_HEADER 开始的对象都是被等待对象
如:
- KTHREAD
- KEVENT
- KMUTANT(内核互斥体)
- KSEMAPHORE
- KTIMER
- KQUEUE 等
_DISPATCHER_HEADER = 内核等待对象的公共头
Windows 等待机制里,线程是唯一的等待者;而带 _DISPATCHER_HEADER 的对象是可被等待的 dispatcher object,其中线程对象本身也属于可被等待对象。
等待者永远是线程;被等待者是 dispatcher object;线程对象本身既能等待别人,也能被别人等待。
KTHREAD._KWAIT_BLOCK
c
//0x18 bytes (sizeof)
struct _KWAIT_BLOCK
{
struct _LIST_ENTRY WaitListEntry; //0x0
struct _KTHREAD* Thread; //0x8
VOID* Object; //0xc
struct _KWAIT_BLOCK* NextWaitBlock; //0x10
USHORT WaitKey; //0x14
UCHAR WaitType; //0x16
volatile UCHAR BlockState; //0x17
};
线程一旦进入等待,内核就需要有个结构把这几个信息串起来:
- 是谁在等(哪个线程)
- 在等谁(哪个对象)
- 这次等待属于哪种等待
- 把它挂到哪个等待链表里
KWAIT_BLOCK 就是干这个的。它本质上是 线程 和 等待对象 之间的一条"挂接记录"。
字段解释
WaitListEntry
这是双向链表节点。
它的作用是把当前这个 KWAIT_BLOCK 挂到等待对象的 DISPATCHER_HEADER.WaitListHead 里。
也就是:"这个对象当前有哪些线程在等它",靠的就是这一串 KWAIT_BLOCK 链表。
Thread
指向正在等待的线程。
对象被置为 signaled 时,内核会通过这个字段知道:
应该唤醒哪一个线程。
Object
指向当前正在等待的对象。
这个对象通常就是某个 dispatcher object,比如:
- event
- semaphore
- mutant / mutex
- timer
- thread
因为这些对象都带有 DISPATCHER_HEADER,所以都能维护等待链表。
NextWaitBlock
这是单向链表 把多个 KWAIT_BLOCK 串起来的指针。
它更偏向从线程这一侧去组织多个等待块。
当一个线程同时等待多个对象时,这些 KWAIT_BLOCK 可以通过 NextWaitBlock 组成链。
WaitKey
在 WaitAny / 多对象等待里,标识是第几个对象满足了等待。对应的值本质上就是该 KWAIT_BLOCK 在等待块数组里的 0 基索引。
WaitType
是枚举类型:
c
typedef enum _WAIT_TYPE
{
WaitAll,
WaitAny
}WAIT_TYPE;
- WaitAll:线程要等待所有对象都变成有信号状态
- WaitAny:只要任意一个对象编程有信号状态即可。
BlockState
这是 等待块自身的状态。
它不是对象状态,也不是线程状态,而是这个 KWAIT_BLOCK 当前处于什么阶段。