2012年12月7日星期五

ExInterlockedInsertTailList.C

/*
链表一个重要的概念,
数据结构里面有,内核里面有双链表。

本文主要操作的是同步安全的双链表。
不用单链表的原因是,内核里面的结构大多是双链表。

应用层的有stl等。
那几个应用层的链表API不适用,还不如自己实现链表的结构和操作。

内核中的主要操作安全性的双链表的函数有:
KeInitializeSpinLock
InitializeListHead
ExInterlockedInsertTailList //插入尾,这是正常的思维。
ExInterlockedInsertHeadList //这个不常用,特殊的情况下使用。
ExInterlockedRemoveHeadList //带锁的双链表没有尾删除的。所以使用的用途第队列不是堆栈。
IsListEmpty //这个可以不用。

本文是简单的示例,要使用,还要进一步的加强。
链表怎能不会,光看别人的代码是不行的,必须自己体验:编码调试。
微软没有完整的例子,所以自己写。
made by correy
made at 2012.12.07
QQ:112426112
Email:kouleguan at hotmail dot com
Homepage:http://correy.webs.com
*/

#include <ntddk.h>

KSPIN_LOCK g_sl;
LIST_ENTRY g_le;

#define TAG 'tset' //test

typedef struct _dl{ //加不加下划线都可以。
    LIST_ENTRY le;
    int x;
}dl;//定义指针会出错。不知啥原因。*dl

VOID OnUnload(IN PDRIVER_OBJECT DriverObject) { }

void InsertTail()
{
    int i = 0;

    for (i = 0; i < 9; i++)
    {
        dl * dl1 = (dl *)ExAllocatePoolWithTag(NonPagedPool, sizeof(dl), TAG);//不能用栈内空间,否则移除会蓝屏。
        if (dl1 == NULL)
        {
            return;
        }

        dl1->x = i;
        ExInterlockedInsertTailList(&g_le, &dl1->le, &g_sl);//前两个个参数的顺序翻了会蓝屏的,并且注意第二个参数的用法。
        DbgPrint("%08x\n",dl1->x);
    }
}

void Ergodic_chain_table()
{
    LIST_ENTRY * p = g_le.Flink;//&g_le;//

    do
    {
        dl * temp = CONTAINING_RECORD(p, dl, le);      
        p = p->Flink;
        if (p == g_le.Flink)//不加这一句的后果是:这样会再最后一次多现实第一个一次。
        {
            break;
        }
        DbgPrint("%08x\n",temp->x);
    } while (p != g_le.Flink);
}

void RemoveHead()
{
    PLIST_ENTRY temp;

    do
    {
        temp = ExInterlockedRemoveHeadList(&g_le, &g_sl);
        if (temp)
        {
            dl * dl2 = CONTAINING_RECORD(temp, dl, le);//是一个宏,用于取自己定义的结构的指针。
            DbgPrint("%08x\n",dl2->x);
            ExFreePoolWithTag(dl2, TAG);
        }
    } while (temp != 0);//为啥是不等呢?还有分号。
}

NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath)
{
    KdBreakPoint();//#define KdBreakPoint() DbgBreakPoint()
    DriverObject->DriverUnload = OnUnload;

    KeInitializeSpinLock(&g_sl);
    InitializeListHead(&g_le);

    InsertTail();//插入,形成一个双链表示例
    Ergodic_chain_table();//遍历示例。查询就是添加个比较的条件而已。
    RemoveHead();//从全部头删除示例

    return STATUS_SUCCESS;
}


//添加一些函数.
int InsertTail(HANDLE pid) //插入一个到尾部 HANDLE DWORD
{
    dl * dl1;

    dl1 = (dl *)ExAllocatePoolWithTag(NonPagedPool, sizeof(dl), TAG);//不能用栈内空间,否则移除会蓝屏。
    if (dl1 == NULL)
    {
        return 0 /*false*/;
    }

    dl1->x = pid;

    if (ExInterlockedInsertTailList(&g_le, &dl1->le, &g_sl) == 0)//前两个个参数的顺序翻了会蓝屏的,并且注意第二个参数的用法。
    { //第一次操作,链表为空,ExInterlockedInsertTailList返回值为0。
        return 1 /*false*/;
    }

    KdPrint(("成功插入:%d\n",pid));

    return 1 /*true*/;
}

int delete_node(HANDLE pid) //DWORD
{
    LIST_ENTRY * p = g_le.Flink;//&g_le;//
    dl * head = CONTAINING_RECORD(p, dl, le);

    do
    {
        dl * temp = CONTAINING_RECORD(p, dl, le);      
        p = p->Flink;
        if (p == g_le.Flink)//不加这一句的后果是:这样会再最后一次多现实第一个一次。
        {
            break;
        }

        if (temp->x == pid)
        {
            //没有删除特定节点的函数,所以自己实现:
            /*
            1.替换链表的节点的指针,把本节点释放掉。
            * p = temp->le;
            ExFreePoolWithTag(temp, TAG);
            2.把第一个节点的值赋值给指定的节点,然后ExInterlockedRemoveHeadList删除第一个。
            3.把指定的节点的值赋值给0,这个值是没有用的。但这样做浪费内存。
            4.删除链表的特定的节点:
              遍历,从头删除,不是就添加到尾部,
                              是就直接删除,不再添加.
              不过要先判断一下存在不,以防使循环.
              还可以先添加在删除(看看允许重复添加不).
            */

            temp->x = head->x;//注意这个结构的一些操作最好加锁同步。
            ExInterlockedRemoveHeadList(&g_le, &g_sl);//IsListEmpty

            KdPrint(("成功删除:%d\n",pid));

            return 1;
        }      

    } while (p != g_le.Flink);

    KdPrint(("删除失败:%d\n",pid));
    return 0;
}

BOOLEAN find (HANDLE pid) //查询  DWORD
{
    LIST_ENTRY * p = g_le.Flink;//&g_le;//

    do
    {
        dl * temp = CONTAINING_RECORD(p, dl, le);      
        p = p->Flink;
        if (p == g_le.Flink)//不加这一句的后果是:这样会再最后一次多现实第一个一次。
        {
            //KdPrint(("没有找到:%d\n",temp->x));//这个显示的频率太多.
            break;
        }

        if (temp->x == pid)
        {
            //KdPrint(("成功找到:%d\n",temp->x));//这个显示的频率太多.
            return 1;
        }
    } while (p != g_le.Flink);

    return 0;
}

int ListAll() //遍历示例。
{
    LIST_ENTRY * p = g_le.Flink;//&g_le;//

    KdPrint(("开始显示\n"));

    do
    {
        dl * temp = CONTAINING_RECORD(p, dl, le);      
        p = p->Flink;
        if (p == g_le.Flink)//不加这一句的后果是:这样会再最后一次多现实第一个一次。
        {
            break;
        }

        KdPrint(("pid:%d\n",temp->x));

    } while (p != g_le.Flink);

    KdPrint(("显示结束\n\n"));

    return 0;
}

void RemoveAll() //从全部头删除示例
{
    PLIST_ENTRY temp;
    NTSTATUS status = STATUS_UNSUCCESSFUL;

    do
    {
        temp = ExInterlockedRemoveHeadList(&g_le, &g_sl);
        if (temp)
        {
            dl * dl2 = CONTAINING_RECORD(temp, dl, le);//是一个宏,用于取自己定义的结构的指针。
            ExFreePoolWithTag(dl2, TAG);
        }
    } while (temp != 0);//为啥是不等呢?还有分号。
}

//以后添加单链表的操作,因为但链表的操作更多,只不过要加个同步的处理而已.

没有评论:

发表评论