鏈表的使用
鏈表是驅動開發(fā)中經(jīng)常遇到的一個數(shù)據(jù)結構,主要是雙向循環(huán)鏈表;要使用鏈表,需要用到一個LIST_ENTRY的結構,其定義如下:
typedef struct _LIST_ENTRY {
struct _LIST_ENTRY *Flink; // 指向下一個節(jié)點
struct _LIST_ENTRY *Blink; // 指向前一個節(jié)點
} LIST_ENTRY, *PLIST_ENTRY;
在實際的編程中,我們需要自己定義鏈表的節(jié)點,并把節(jié)點的第一個成員設置為LIST_ENTRY類型的變量(不一定放在第一位,但通常是這樣);此外,我們還需要一個LIST_ENTRY類型的鏈表頭;其他的就靠下面的函數(shù)或者宏來操作了:
InitializeListHead,初始化鏈表頭
IsListEmpty,判斷鏈表是否為空
InsertHeadList,從鏈表頭部插入節(jié)點
InsertTailList,從鏈表尾部插入節(jié)點
RemoveHeadList,從鏈表頭部刪除節(jié)點
RemoveTailList,從鏈表尾部刪除節(jié)點
CONTAINING_RECORD,從RemoveHeadList或者RemoveTailList返回的數(shù)據(jù)獲取一個指向刪除節(jié)點的指針
示例代碼:
typedef struct _LIST_NODE
{
LIST_ENTRY ListEntry;
ULONG ulData;
} LIST_NODE, *PLIST_NODE;
VOID LinkListTest()
{
LIST_ENTRY listHead;
PLIST_NODE pListNode = NULL;
ULONG i = 0;
InitializeListHead(&listHead);
DebugPrint(("Begin insert to link list\r\n"));
for (i = 0; i < 10; ++i)
{
pListNode = (PLIST_NODE)
ExAllocatePool(PagedPool, sizeof(LIST_NODE));
pListNode->ulData = i;
InsertHeadList(&listHead, &pListNode->ListEntry);
}
DebugPrint(("Begin remove from link list\r\n"));
while (!IsListEmpty(&listHead))
{
PLIST_ENTRY pEntry = RemoveTailList(&listHead);
pListNode = CONTAINING_RECORD(pEntry,
LIST_NODE,
ListEntry);
DebugPrint(("Delete Node's Value: %d\r\n", pListNode->ulData));
ExFreePool(pListNode);
}
}
DPC定時器的使用
DPC定時器可以對任意間隔時間進行定時,DPC定時器內(nèi)部使用定時器對象KTIMER,當對定時器設定一個時間間隔后,每隔這段時間操作系統(tǒng)就會將一個DPC例程插入DPC隊列,當操作系統(tǒng)讀取DPC隊列時,對應的DPC例程被執(zhí)行。在DPC定時器需要用到的一些函數(shù):
KeInitializeTimer,初始化定時器對象
KeInitializeDpc,初始化DPC對象
KeSetTimer,開啟定時器
KeCancelTimer,取消定時器
在調(diào)用KeSetTimer之后,只會觸發(fā)一次DPC例程。如果想周期觸發(fā)DPC例程,需要在DPC例程觸發(fā)后,再次調(diào)用KeSetTimer。示例代碼可以參考《Windows驅動開發(fā)技術詳解》一書。