alg : 单向链表排序 on drv

将单向链表排序迁移到驱动层, 验证通过(组合: (升序/降序) *(链表回环/非回环))

如果算法实现需要确认, 还是在应用层先验证完, 再迁入驱动层好些. 能节省大量时间.


迁移(应用层 => 驱动层)过程中的修改点:

结构 的new delete => lookasidelist 的 alloc free

随机数 Srand(), Rand() => KeQuerySystemTime, RtlRandomEx


工程下载:srcListSortOnDrv.rar

在驱动层中的排序效果:

>> DriverEntry on 1353 
>> TestListSort 
 
 
nTryIndex = 1 
 
 
TestListSort(LISTNODE_CNT, IS_LIST_LOOP_NOT, SORT_BY_SMALL_TO_BIG); 
uSeed = 0, sort = small to big 
ListSort Before 
======================================== 
ShowList >> 
======================================== 
Head[0x8B662E00], Head.pNext[0x903157B0], Head.data[0x26ff8a4f]
Node[0x903157B0], Node.pNext[0x9506C2A8], Node.data[0x3967c02d]
Node[0x9506C2A8], Node.pNext[0x95119988], Node.data[0x1a2b995c]
Node[0x95119988], Node.pNext[0x980B18A0], Node.data[0x4c576173]
Node[0x980B18A0], Node.pNext[0x8B66BA78], Node.data[0x17d78f8e]
Node[0x8B66BA78], Node.pNext[0x00000000], Node.data[0x39e8ed02]
ListSort After 
======================================== 
ShowList >> 
======================================== 
Head[0x980B18A0], Head.pNext[0x9506C2A8], Head.data[0x17d78f8e]
Node[0x9506C2A8], Node.pNext[0x8B662E00], Node.data[0x1a2b995c]
Node[0x8B662E00], Node.pNext[0x903157B0], Node.data[0x26ff8a4f]
Node[0x903157B0], Node.pNext[0x8B66BA78], Node.data[0x3967c02d]
Node[0x8B66BA78], Node.pNext[0x95119988], Node.data[0x39e8ed02]
Node[0x95119988], Node.pNext[0x00000000], Node.data[0x4c576173]
 
 
TestListSort(LISTNODE_CNT, IS_LIST_LOOP_NOT, SORT_BY_BIG_TO_SMALL); 
uSeed = 913725478, sort = big to small 
ListSort Before 
======================================== 
ShowList >> 
======================================== 
Head[0x903157B0], Head.pNext[0x8B662E00], Head.data[0x5735c79b]
Node[0x8B662E00], Node.pNext[0x9506C2A8], Node.data[0x056cc5e9]
Node[0x9506C2A8], Node.pNext[0x83A7DC00], Node.data[0x1510ddff]
Node[0x83A7DC00], Node.pNext[0x950A73E8], Node.data[0x5a43d391]
Node[0x950A73E8], Node.pNext[0x950B2048], Node.data[0x7034ca46]
Node[0x950B2048], Node.pNext[0x00000000], Node.data[0x6b9ff85a]
ListSort After 
======================================== 
ShowList >> 
======================================== 
Head[0x950A73E8], Head.pNext[0x950B2048], Head.data[0x7034ca46]
Node[0x950B2048], Node.pNext[0x83A7DC00], Node.data[0x6b9ff85a]
Node[0x83A7DC00], Node.pNext[0x903157B0], Node.data[0x5a43d391]
Node[0x903157B0], Node.pNext[0x9506C2A8], Node.data[0x5735c79b]
Node[0x9506C2A8], Node.pNext[0x8B662E00], Node.data[0x1510ddff]
Node[0x8B662E00], Node.pNext[0x00000000], Node.data[0x056cc5e9]
 
 
TestListSort(LISTNODE_CNT, IS_LIST_LOOP, SORT_BY_SMALL_TO_BIG); 
uSeed = 1412756275, sort = small to big 
ListSort Before 
======================================== 
ShowList >> 
======================================== 
Head[0x903157B0], Head.pNext[0x83A7DC00], Head.data[0x6ec0894e]
Node[0x83A7DC00], Node.pNext[0x950B2048], Node.data[0x0f4736c3]
Node[0x950B2048], Node.pNext[0x8B663B60], Node.data[0x7391e7d3]
Node[0x8B663B60], Node.pNext[0x9034E4C8], Node.data[0x30519197]
Node[0x9034E4C8], Node.pNext[0x8B654E30], Node.data[0x58d66ac7]
Node[0x8B654E30], Node.pNext[0x903157B0], Node.data[0x129d2a65]
ListSort After 
======================================== 
ShowList >> 
======================================== 
Head[0x83A7DC00], Head.pNext[0x8B654E30], Head.data[0x0f4736c3]
Node[0x8B654E30], Node.pNext[0x8B663B60], Node.data[0x129d2a65]
Node[0x8B663B60], Node.pNext[0x9034E4C8], Node.data[0x30519197]
Node[0x9034E4C8], Node.pNext[0x903157B0], Node.data[0x58d66ac7]
Node[0x903157B0], Node.pNext[0x950B2048], Node.data[0x6ec0894e]
Node[0x950B2048], Node.pNext[0x83A7DC00], Node.data[0x7391e7d3]
 
 
TestListSort(LISTNODE_CNT, IS_LIST_LOOP, SORT_BY_BIG_TO_SMALL); 
uSeed = 1765149990, sort = big to small 
ListSort Before 
======================================== 
ShowList >> 
======================================== 
Head[0x9034E4C8], Head.pNext[0x8B663B60], Head.data[0x4b89b0c9]
Node[0x8B663B60], Node.pNext[0x8B654E30], Node.data[0x1a43c31f]
Node[0x8B654E30], Node.pNext[0x8B630678], Node.data[0x30180ee2]
Node[0x8B630678], Node.pNext[0x903157B0], Node.data[0x65a6e602]
Node[0x903157B0], Node.pNext[0x8B65C3C0], Node.data[0x76ad2254]
Node[0x8B65C3C0], Node.pNext[0x9034E4C8], Node.data[0x5fbdb2dd]
ListSort After 
======================================== 
ShowList >> 
======================================== 
Head[0x903157B0], Head.pNext[0x8B630678], Head.data[0x76ad2254]
Node[0x8B630678], Node.pNext[0x8B65C3C0], Node.data[0x65a6e602]
Node[0x8B65C3C0], Node.pNext[0x9034E4C8], Node.data[0x5fbdb2dd]
Node[0x9034E4C8], Node.pNext[0x8B654E30], Node.data[0x4b89b0c9]
Node[0x8B654E30], Node.pNext[0x8B663B60], Node.data[0x30180ee2]
Node[0x8B663B60], Node.pNext[0x903157B0], Node.data[0x1a43c31f]
 

主程序:

/// @file           sys.c
/// @brief          驱动主程序

#include "Function.h"

#define MODULE_NAME         L"DrvDemo"
#define DRIVER_NAME         MODULE_NAME L".sys"
#define DEVICE_NAME_GLOBAL  L"\\\\.\\" MODULE_NAME
#define DEVICE_NAME         L"\\device\\" MODULE_NAME
#define LINK_NAME           L"\\dosDevices\\" MODULE_NAME

/// 测试单向链表排序
#define LISTNODE_CNT            6       ///< 单向链表节点数量
#define IS_LIST_LOOP            TRUE    ///< 单向链表是否回环, 是
#define IS_LIST_LOOP_NOT        FALSE   ///< 单向链表是否回环, 否
#define SORT_BY_SMALL_TO_BIG    TRUE    ///< 排序方式, 升序
#define SORT_BY_BIG_TO_SMALL    FALSE   ///< 排序方式, 降序
#define TEST_LIST_SORT_CNT      10      ///< 测试ListSort的次数

extern LARGE_INTEGER g_liSeed;

NTSTATUS DispatchCommon(PDEVICE_OBJECT pDeviceObject, PIRP pIrp);
VOID DriverUnload(PDRIVER_OBJECT pDriverObject);

/// 测试单向链表排序
void TestCaseListSort();
void TestListSort(size_t nListNodeCnt, BOOL bIsListLoop, BOOL bSortBySmallToBig);

NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, 
                     IN PUNICODE_STRING pRegPath)
{
    size_t          nIndex          =   0;
    NTSTATUS        ntStatus        =   STATUS_SUCCESS;

    PDEVICE_OBJECT  pDeviceObject = NULL;

    UNICODE_STRING  ustrDeviceName = {0};
    UNICODE_STRING  ustrLinkName = {0};

    DbgPrint(">> DriverEntry on 1353\r\n");

    g_liSeed.QuadPart = 0;    ///< 初始化随机种子

    RtlInitUnicodeString(&ustrDeviceName, DEVICE_NAME);
    RtlInitUnicodeString(&ustrLinkName, LINK_NAME);

    ntStatus = IoCreateDevice(
        pDriverObject, 
        0, 
        &ustrDeviceName, 
        FILE_DEVICE_UNKNOWN, 
        0, 
        FALSE, 
        &pDeviceObject);
    if (!NT_SUCCESS(ntStatus))
    {
        DbgPrint("<< DriverEntry : error IoCreateDevice\r\n");
        return ntStatus;
    }

    pDeviceObject->Flags |= DO_BUFFERED_IO;
    ntStatus = IoCreateSymbolicLink(
        &ustrLinkName, 
        &ustrDeviceName);
    if (!NT_SUCCESS(ntStatus))
    {
        DbgPrint("<< DriverEntry : error IoDeleteDevice\r\n");
        IoDeleteDevice(pDeviceObject);
        return ntStatus;
    }

    for(nIndex = 0; nIndex < IRP_MJ_MAXIMUM_FUNCTION; nIndex++)
    {
        pDriverObject->MajorFunction[nIndex] = DispatchCommon;
    }

    pDriverObject->DriverUnload = DriverUnload;

    ListNodeDataInit();
    TestCaseListSort(); ///< 测试链表排序(回环, 非回环, 降序, 升序)
    ListNodeDataUnInit();

    DbgPrint("<< DriverEntry\r\n");

    return STATUS_SUCCESS;
}

void TestCaseListSort()
{
    size_t  nTryIndex   =   0;
    size_t  nTryCnt     =   TEST_LIST_SORT_CNT;
    DbgPrint(">> TestListSort\r\n");

    g_liSeed.QuadPart = 0;  ///< 随机种子清零
    do 
    {
        DbgPrint("\r\n\r\nnTryIndex = %d\r\n", ++nTryIndex);

        DbgPrint("\r\n\r\nTestListSort(LISTNODE_CNT, IS_LIST_LOOP_NOT, "
            "SORT_BY_SMALL_TO_BIG);\r\n");
        TestListSort(LISTNODE_CNT, IS_LIST_LOOP_NOT, SORT_BY_SMALL_TO_BIG);


        DbgPrint("\r\n\r\nTestListSort(LISTNODE_CNT, IS_LIST_LOOP_NOT, "
            "SORT_BY_BIG_TO_SMALL);\r\n");
        TestListSort(LISTNODE_CNT, IS_LIST_LOOP_NOT, SORT_BY_BIG_TO_SMALL);

        DbgPrint("\r\n\r\nTestListSort(LISTNODE_CNT, IS_LIST_LOOP, "
            "SORT_BY_SMALL_TO_BIG);\r\n");
        TestListSort(LISTNODE_CNT, IS_LIST_LOOP, SORT_BY_SMALL_TO_BIG);

        DbgPrint("\r\n\r\nTestListSort(LISTNODE_CNT, IS_LIST_LOOP, "
            "SORT_BY_BIG_TO_SMALL);\r\n");
        TestListSort(LISTNODE_CNT, IS_LIST_LOOP, SORT_BY_BIG_TO_SMALL);
    } while (nTryCnt-- > 0);

    DbgPrint("<< TestListSort\r\n");
}

void TestListSort(size_t nListNodeCnt, BOOL bIsListLoop, BOOL bSortBySmallToBig)
{
    PNODE           pNode       =   NULL;

    DbgPrint("uSeed = %d, sort = %s\r\n", 
        g_liSeed.LowPart, 
        bSortBySmallToBig ? "small to big" : "big to small");

    /// 初始化链表数据

    /// 建立链表(节点数量, 是否回环)
    ListCreate(&pNode, nListNodeCnt, bIsListLoop);
    DbgPrint("ListSort Before\r\n");
    ListShow(&pNode);

    /// 单向链表排序
    ListSort(&pNode, bSortBySmallToBig);
    DbgPrint("ListSort After\r\n");
    ListShow(&pNode);

    /// 释放链表
    ListRemove(&pNode);

    /// 反初始化链表数据
}

VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
    UNICODE_STRING ustrLinkName = {0};

    DbgPrint(">> DriverUnload\r\n");

    RtlInitUnicodeString(&ustrLinkName, LINK_NAME);
    IoDeleteDevice(pDriverObject->DeviceObject);
    IoDeleteSymbolicLink(&ustrLinkName);

    DbgPrint("<< DriverUnload\r\n");
}

NTSTATUS DispatchCommon(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
    pIrp->IoStatus.Information = 0;
    pIrp->IoStatus.Status = STATUS_SUCCESS;

    IoCompleteRequest(pIrp, IO_NO_INCREMENT);

    return STATUS_SUCCESS;
}

辅助函数实现

/// @file           Function.h
/// @brief          功能的实现

#ifndef __FUNCTION_H__
#define __FUNCTION_H__

/// ntddk.h 和 Ntifs.h 不能同时包含如果不行, 需要拷贝没有的定义过来
// #include <ntddk.h>

#include <Ntifs.h>  ///< for RtlRandomEx
#include <WINDEF.H>

// for warning C4996: 'ExAllocatePool': was declared deprecated
#pragma warning(disable:4996)

// #define DEBUG_SHOW_LIST ///< 打印中间调试过程的单向链表
#define MEM_TYPE_NODE   'NODE'  ///< 节点类型的内存

typedef struct _node
{
    int data;
    struct _node * pNext;
} NODE,*PNODE;

/// 链表数据初始化与反初始化
/// 原因: 分配节点时, 要从lookasideList中分配空间
void ListNodeDataInit();
void ListNodeDataUnInit();


/// 外部接口
/// @fn         ListSort
/// @brief      链表排序
/// @param      PNODE * ppNodeHead, 单向链表头指针, 支持回环单向链表
/// @param      BOOL bSortBySmallToBig, TRUE, 从小到大排序; FALSE, 从大到小排序
BOOL ListSort(PNODE * ppNodeHead, BOOL bSortBySmallToBig);

/// 内部接口

/// @fn         ListNodeSwap
/// @brief      交换2个节点(节点本身, 父节点, 子节点)
/// @param      PNODE * ppNodeCur, 当前节点
/// @param      PNODE * ppNodeCurParent, 当前节点的父节点
/// @param      PNODE * ppNodeReplace, 要交换的节点
/// @param      PNODE * ppNodeReplaceParent, 要交换的节点的父节点
BOOL ListNodeSwap(PNODE * ppNodeCur,
                  PNODE * ppNodeCurParent,
                  PNODE * ppNodeReplace,
                  PNODE * ppNodeReplaceParent);

/// @fn         CreateList
/// @brief       建立一个单向链表
/// @param      PNODE * ppNode, 链表首节点指针, *ppNode 必须为空
/// @param      size_t nListSize, 链表的元素个数
/// @param      BOOL bIsListLoop, 是否创建单回环链表, 如果是, 该链表首尾相接
void ListCreate(PNODE * ppNode, size_t nListSize, BOOL bIsListLoop);

void ListNodeCreate(PNODE * ppNode);
void ListNodeFree(PNODE * ppNode);

void ListRemove(PNODE * ppNode);
void ListShow(PNODE * ppNode);

/// @fn         IsListLoop
/// @brief      链表是否回环
/// @param      IN PNODE * ppNodeHead, 单向链表头指针
/// @param      OUT size_t * pnElementsCnt, 单向链表的元素计数
/// @param      OUT PNODE * ppNodeTail, 单向链表尾指针
/// @return     BOOL
/// @retval     TRUE, 链表回环
/// @retval     FALSE, 不是回环链表
/// @note OUT size_t & nElementsCnt 编译不过 ?
BOOL IsListLoop(IN PNODE * ppNodeHead, 
                OUT size_t * pnElementsCnt, 
                OUT PNODE * ppNodeTail);

/// @fn         GenerateRand
/// @param      产生一个在uMin~ulMax之间的随机数
ULONG GenerateRand(ULONG ulMin, ULONG ulMax);

#endif

/// @file           Function.c
/// @brief          功能的实现

#include "Function.h"
#include "LookasideListOpt.h"

LARGE_INTEGER g_liSeed;

ULONG GenerateRand(ULONG ulMin, ULONG ulMax)
{
    /// 浮点运算在内核编程中不被支持, 可以定义DWORD值来解决

    ULONG       ulRand  =   0;
    ULONG       ulRange =   0;
    ULONG       ulMinReal   =   min(ulMax, ulMin);
    ULONG       ulMaxReal   =   max(ulMax, ulMin);
    ULONGLONG   ullTmp  =   0;

    if (0 == g_liSeed.QuadPart)
        KeQuerySystemTime(&g_liSeed);

    g_liSeed.QuadPart++;   ///<  每次的种子都不同
    ulRand = RtlRandomEx(&(g_liSeed.LowPart));

    ullTmp = ulRand;
    ullTmp = ullTmp * (ulMaxReal - ulMinReal);
    return (ULONG)((ullTmp / MAXLONG) + ulMinReal);
}

/// 为Node节点分配空间的LookasideList
PAGED_LOOKASIDE_LIST   g_PageLookasideList_Node;
PAGED_LOOKASIDE_LIST * g_pPageLookasideList_Node = &g_PageLookasideList_Node;

void ListNodeDataInit()
{
    LookasideListInit(TRUE, &g_pPageLookasideList_Node, sizeof(NODE));
}

void ListNodeDataUnInit()
{
    LookasideListDelete(TRUE, &g_pPageLookasideList_Node);
}

void ListNodeCreate(PNODE * ppNode)
{
    PNODE   pNode   =   NULL;

    NT_ASSERT(NULL != ppNode);

    if (!NT_SUCCESS(LookasideListAllocate(TRUE, 
        g_pPageLookasideList_Node, 
        &pNode)))
    {
        DbgPrint("LookasideListAllocate(TRUE) error\r\n");
        *ppNode = NULL;
    }
    else
    {
        *ppNode = pNode;
    }

    NT_ASSERT(NULL != *ppNode);

    (*ppNode)->data = GenerateRand(1, MAXLONG); ///< 结点的数据是随机的
    (*ppNode)->pNext = NULL;
}

void ListNodeFree(PNODE * ppNode)
{
    if ((NULL != ppNode) && (NULL != *ppNode))
    {
        if (!NT_SUCCESS(LookasideListFree(TRUE, 
            g_pPageLookasideList_Node, 
            ppNode)))
        {
            DbgPrint("LookasideListFree(TRUE) error\r\n");
        }

        *ppNode = NULL;
    }
}

void ListCreate(PNODE * ppNode, size_t nListSize, BOOL bIsListLoop)
{
    PNODE   pNodeHead   =   NULL;
    PNODE   pNodeCur    =   NULL;
    size_t  nIndex      =   0;

    if ((NULL == ppNode) || (NULL != *ppNode) || (nListSize < 1))
        return;

    ListNodeCreate(&pNodeHead);
    *ppNode = pNodeHead;

    pNodeCur = pNodeHead;
    for (nIndex = 1; nIndex < nListSize; nIndex++)
    {
        ListNodeCreate(&pNodeCur->pNext);
        pNodeCur = pNodeCur->pNext;
    }

    if (bIsListLoop)
        pNodeCur->pNext = pNodeHead; ///< 形成单链表回环
}

void ListShow(PNODE * ppNode)
{
    PNODE   pNodeCur    =   NULL;
    PNODE   pNodeHead   =   NULL;

    DbgPrint("========================================\r\n");
    DbgPrint("ShowList >>\r\n");
    DbgPrint("========================================\r\n");

    if ((NULL == ppNode) || (NULL == *ppNode))
    {
        DbgPrint("ppNode is invalid\n");
        return;
    }

    pNodeHead = *ppNode;

    DbgPrint("Head[0x%p], Head.pNext[0x%p], Head.data[0x%8.8x]\n", 
        pNodeHead, pNodeHead->pNext, pNodeHead->data);

    pNodeCur = pNodeHead->pNext;
    while ((NULL != pNodeCur) && (pNodeCur != pNodeHead))
    {
        DbgPrint("Node[0x%p], Node.pNext[0x%p], Node.data[0x%8.8x]\n",
            pNodeCur, pNodeCur->pNext, pNodeCur->data);
        pNodeCur = pNodeCur->pNext;
    }
}

void ListRemove(PNODE * ppNode)
{
    PNODE   pNodeHead   =   NULL;
    PNODE   pNodeCur    =   NULL;
    PNODE   pNodeNext   =   NULL;

    if ((NULL == ppNode) || (NULL == *ppNode))
    {
        return;
    }

    pNodeHead = *ppNode;

    /// 释放头节点之外的数据
    pNodeCur = pNodeHead->pNext;
    while ((NULL != pNodeCur) && (pNodeCur != pNodeHead))
    {
        pNodeNext = pNodeCur->pNext;
        ListNodeFree(&pNodeCur);
        pNodeCur = pNodeNext;
    }

    /// 释放头节点
    ListNodeFree(&pNodeHead);
    *ppNode = NULL;
}

BOOL IsListLoop(IN PNODE * ppNodeHead, 
                OUT size_t * pnElementsCnt, 
                OUT PNODE * ppNodeTail)
{
    BOOL bFind       =   FALSE;
    PNODE   pNodeCur    =   NULL;
    PNODE   pNodeHead   =   NULL;

    NT_ASSERT(NULL != ppNodeHead);
    NT_ASSERT(NULL != *ppNodeHead);
    NT_ASSERT(NULL != pnElementsCnt);
    NT_ASSERT(NULL != ppNodeTail);

    pNodeHead = *ppNodeHead;
    pNodeCur = pNodeHead->pNext;

    *ppNodeTail = pNodeCur;
    (*pnElementsCnt)++;

    while (NULL != pNodeCur)
    {
        if (pNodeCur == pNodeHead)
        {
            bFind = TRUE;
            break;
        }

        *ppNodeTail = pNodeCur;
        pNodeCur = pNodeCur->pNext;
        (*pnElementsCnt)++;
    }

    return bFind;
}

BOOL ListSort(PNODE * ppNodeHead, BOOL bSortBySmallToBig)
{
    BOOL    bListIsLoop         =   FALSE;  ///< 链表是否回环

    /// 是否需要修复链表尾部Next指针(当链表头被移动后)
    BOOL    bNeedFixListTail    =   FALSE;

    /// 节点交换是否成功, 如果是相同节点, 不需要交换
    BOOL    bListNodeSwapOK     =   FALSE;

    size_t  nElementsCnt    =   0;      ///< 链表元素个数
    PNODE   pNodeTail       =   NULL;   ///< 链表尾节点

    PNODE   pNodeCur        =   NULL;   ///< 当前节点
    PNODE   pNodeCurParent  =   NULL;   ///< pNodeCur节点的父节点

    /// 需要交换的节点, 根据bSortBySmallToBig标志可能为最小值节点或最大值节点
    PNODE   pNodeReplace        =   NULL;
    PNODE   pNodeReplaceParent  =   NULL;   ///< pNodeReplace节点的父节点

    PNODE   pNodeNext       =   NULL;   ///< 下一个节点
    PNODE   pNodeNextParent =   NULL;   ///< pNodeNext节点的父节点

    /// 临时链表头, 使原始链表有父节点, 为了防止节点size过大, 需要new出来
    PNODE   pNodeHeadTmp    =   NULL;

    NT_ASSERT(NULL != ppNodeHead);
    NT_ASSERT(NULL != *ppNodeHead);

    /// 不关心链表是否回环, 只需要链表元素个数
    bListIsLoop = IsListLoop(ppNodeHead, &nElementsCnt, &pNodeTail);
    if (nElementsCnt <= 1)
        return TRUE;    ///< 链表节点2个以上, 才需要排序

    /// 加入临时链表头, 使链表头指针有父节点
    ListNodeCreate(&pNodeHeadTmp);

    pNodeHeadTmp->pNext = *ppNodeHead;  ///< 链表头指针

    /// 每个节点都记录父节点和子节点, 用于节点插入法排序
    /// 排序, 小的节点在前
    pNodeCurParent = pNodeHeadTmp;
    for (pNodeCur = pNodeHeadTmp->pNext; ; pNodeCur = pNodeCur->pNext)
    {
        if ((NULL == pNodeCur) || (pNodeCur == pNodeTail))
            break;  ///< 放在for循环条件中不行?

        pNodeReplace = pNodeCur;
        pNodeNextParent = pNodeCur;
        for (pNodeNext = pNodeCur->pNext; ; pNodeNext = pNodeNext->pNext)
        {
            if ((NULL == pNodeNext) || (pNodeNext == pNodeHeadTmp->pNext))
                break; ///< 放在for循环条件中不行?

            if (bSortBySmallToBig ? (pNodeNext->data < pNodeReplace->data)
                : (pNodeNext->data > pNodeReplace->data))
            {
                pNodeReplace = pNodeNext;           ///< 找到了需要交换的节点

                /// 为了交换节点, 需要记录该节点的父节点
                pNodeReplaceParent = pNodeNextParent;
            }

            pNodeNextParent = pNodeNext;
        }

        bNeedFixListTail = bListIsLoop && (pNodeCur == pNodeHeadTmp->pNext);
        bListNodeSwapOK = ListNodeSwap(&pNodeCur, 
            &pNodeCurParent, 
            &pNodeReplace, 
            &pNodeReplaceParent);
        if (bListNodeSwapOK && bNeedFixListTail)
        {
            /// 对于回环情况的链表尾部节点, 当被交换的节点涉及到首节点时,
            /// 链表尾部节点->pNext应重新设置成首节点

            /// 求链表尾部节点
            bListIsLoop = IsListLoop(ppNodeHead, &nElementsCnt, &pNodeTail);
            pNodeTail->pNext = pNodeHeadTmp->pNext;
        }

#ifdef DEBUG_SHOW_LIST
        if (bListNodeSwapOK)
        {
            /// 测试用, 每交换一次节点, 就打印一次
            ListShow(&pNodeHeadTmp->pNext);
        }
#endif

        pNodeCurParent = pNodeCur;  ///< 记录当前节点的父节点
    }

    /// 在替换链表节点过程中, 链表首节点已经变了
    /// pNodeHeadTmp->pNext 一直指向的是真正的链表头
    *ppNodeHead = pNodeHeadTmp->pNext;  ///< 设置真正的链表头

    /// 释放临时链表头
    ListNodeFree(&pNodeHeadTmp);

    return TRUE;
}

BOOL ListNodeSwap(PNODE * ppNodeCur, 
                  PNODE * ppNodeCurParent,
                  PNODE * ppNodeReplace, 
                  PNODE * ppNodeReplaceParent)
{
    PNODE   pNodeCur            =   NULL;
    PNODE   pNodeCurParent      =   NULL;   ///< 当前节点的父节点

    PNODE   pNodeReplace        =   NULL;
    PNODE   pNodeReplaceParent  =   NULL;   ///< pNodeReplace节点的父节点

    PNODE   pNodeTmp            =   NULL;   ///< 临时节点指针, 用于交换节点指针

    NT_ASSERT(NULL != ppNodeCur);
    NT_ASSERT(NULL != ppNodeCurParent);

    NT_ASSERT(NULL != ppNodeReplace);
    NT_ASSERT(NULL != ppNodeReplaceParent);

    pNodeCur = *ppNodeCur;
    pNodeCurParent = *ppNodeCurParent;

    pNodeReplace = *ppNodeReplace;
    pNodeReplaceParent = *ppNodeReplaceParent;

    if (pNodeReplace != pNodeCur)
    {
        /// 用插入法交换pNodeCur和pNodeReplace(节点本身指针, 父节点,子节点)

        /// 将pNodeReplace放到pNodeCur原来的位置
        pNodeCurParent->pNext = pNodeReplace;

        pNodeTmp = pNodeReplace->pNext;

        if (pNodeCur->pNext != pNodeReplace)
        {
            /// 如果两个节点不相邻, 
            /// 交换后, 最小值节点的下一个节点是是pNodeCur的下一个节点
            pNodeReplace->pNext = pNodeCur->pNext;
        }
        else
        {
            /// 这种情况下, pNodeCur的下一个节点是pNodeReplace
            /// 交换后, pNodeReplace->pNext 应该直接指向 pNodeCur
            pNodeReplace->pNext = pNodeCur;
        }

        /// 将pNodeCur放到pNodeReplace原来的位置
        pNodeReplaceParent->pNext = pNodeCur;
        pNodeCur->pNext = pNodeTmp;

        /// 使交换后的pNodeCur为pNodeReplace, 保证可以继续查找值
        /// 否则: 数据在链表尾部, 导致交换节点后, 不能再继续查找值
        /// ! pNodeReplaceParent->pNext 指的的原来的 pNodeReplace 节点
        *ppNodeCur = pNodeReplace;

        return TRUE;
    }
    else
        return FALSE;
}

/// @file           LookasideListOpt.h
/// @brief          LookasideList 封装

#ifndef __LOOK_A_SIDE_LIST_OPT_H__
#define __LOOK_A_SIDE_LIST_OPT_H__

#include <ntddk.h>
#include <WINDEF.H>

/// operate LookasideList

#define LOOK_A_SIDE_LIST_POOL_TAG_NAME 'lasl'   ///< 内存分配标记

/// @fn         LookasideListInit
/// @brief      初始化LookAsideList
/// @param      BOOLEAN bpage, TRUE = 分页内存, FALSE = 非分页内存
/// @param      void ** ppLookAsideList, ppLookAsideList2级指针, 函数内部用到的
///             时候强转类型
/// @param      size_t nBufSize,  每次从LookAsideList中可以分配的内存大小
/// @return     NTSTATUS, 调用方使用 NT_SUCCESS 宏来判断是否成功
NTSTATUS LookasideListInit(BOOLEAN bpage, 
                           void ** ppLookAsideList, 
                           size_t nBufSize);

/// @fn         LookasideListAllocate
/// @param      从LookAsideList中分配一块内存
/// @param      BOOLEAN bpage, TRUE = 分页内存, FALSE = 非分页内存
/// @param      void ** ppLookAsideList, ppLookAsideList2级指针, 函数内部用到的
///             时候强转类型
/// @param      void ** ppNodeOut, 传出分配后的内存2级指针
/// @return     NTSTATUS, 调用方使用 NT_SUCCESS 宏来判断是否成功
NTSTATUS LookasideListAllocate(BOOLEAN bpage, 
                               void * pLookAsideList, 
                               void ** ppNodeOut);

/// @fn         LookasideListFree
/// @param      从LookAsideList中释放一块内存
/// @param      BOOLEAN bpage, TRUE = 分页内存, FALSE = 非分页内存
/// @param      void ** ppLookAsideList, ppLookAsideList2级指针, 函数内部用到的
///             时候强转类型
/// @param      void ** ppNodeOut, 曾经分配好的的内存2级指针
/// @return     NTSTATUS, 调用方使用 NT_SUCCESS 宏来判断是否成功
NTSTATUS LookasideListFree(BOOLEAN bpage, 
                           void * pLookAsideList, 
                           void ** ppNodeOut);

/// @fn         LookasideListDelete
/// @brief      释放LookasideList
/// @param      BOOLEAN bpage, TRUE = 分页内存, FALSE = 非分页内存
/// @return     NTSTATUS, 调用方使用 NT_SUCCESS 宏来判断是否成功
NTSTATUS LookasideListDelete(BOOLEAN bpage, void ** ppLookAsideList);

/// 内部函数
NTSTATUS LookasideListInit_Page(void ** ppLookAsideList, size_t nBufSize);
NTSTATUS LookasideListInit_NPage(void ** ppLookAsideList, size_t nBufSize);

NTSTATUS LookasideListAllocate_Page(void * pLookAsideList, void ** ppNodeOut);
NTSTATUS LookasideListAllocate_NPage(void * pLookAsideList, void ** ppNodeOut);

NTSTATUS LookasideListFree_Page(void * pLookAsideList, void ** ppNodeOut);
NTSTATUS LookasideListFree_NPage(void * pLookAsideList, void ** ppNodeOut);

NTSTATUS LookasideListDelete_Page(void ** ppLookAsideList);
NTSTATUS LookasideListDelete_NPage(void ** ppLookAsideList);

#endif  // #ifndef __LOOK_A_SIDE_LIST_OPT_H__

/// @file           LookasideListOpt.c
/// @brief          ...

#include "LookasideListOpt.h"

NTSTATUS LookasideListInit(BOOLEAN bpage, 
                           void ** ppLookAsideList, 
                           size_t nBufSize)
{
    if (NULL == ppLookAsideList)
        return STATUS_INVALID_PARAMETER;

    if (bpage)
        return LookasideListInit_Page(ppLookAsideList, nBufSize);
    else
        return LookasideListInit_NPage(ppLookAsideList, nBufSize);
}

NTSTATUS LookasideListAllocate(BOOLEAN bpage, 
                               void * pLookAsideList, 
                               void ** ppNodeOut)
{
    if ((NULL == pLookAsideList) || (NULL == ppNodeOut))
        return STATUS_INVALID_PARAMETER;

    if (bpage)
        return LookasideListAllocate_Page(pLookAsideList, ppNodeOut);
    else
        return LookasideListAllocate_NPage(pLookAsideList, ppNodeOut);
}

NTSTATUS LookasideListFree(BOOLEAN bpage, 
                           void * pLookAsideList, 
                           void ** ppNodeOut)
{
    if ((NULL == pLookAsideList) || (NULL == ppNodeOut) || (NULL == *ppNodeOut))
        return STATUS_INVALID_PARAMETER;

    if (bpage)
        return LookasideListFree_Page(pLookAsideList, ppNodeOut);
    else
        return LookasideListFree_NPage(pLookAsideList, ppNodeOut);
}

NTSTATUS LookasideListDelete(BOOLEAN bpage, void ** ppLookAsideList)
{
    if ((NULL == ppLookAsideList) || (NULL == *ppLookAsideList))
        return STATUS_INVALID_PARAMETER;

    if (bpage)
        return LookasideListDelete_Page(ppLookAsideList);
    else
        return LookasideListDelete_NPage(ppLookAsideList);
}

//////////////////////////////////////////////////////////////////////////
/// 内部函数
//////////////////////////////////////////////////////////////////////////
NTSTATUS LookasideListInit_Page(void ** ppLookAsideList, size_t nBufSize)
{
    PPAGED_LOOKASIDE_LIST pLookaside    =   NULL;;

    NT_ASSERT(NULL != ppLookAsideList);
    NT_ASSERT(NULL != *ppLookAsideList);

    PAGED_CODE();
    pLookaside = *((PAGED_LOOKASIDE_LIST **)ppLookAsideList);
    ExInitializePagedLookasideList(pLookaside,
        NULL,
        NULL,
        0,
        nBufSize,
        LOOK_A_SIDE_LIST_POOL_TAG_NAME,
        0 );

    *ppLookAsideList = pLookaside;
    return (NULL != pLookaside) ? 
            STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES;
}

NTSTATUS LookasideListInit_NPage(void ** ppLookAsideList, size_t nBufSize)
{
    PNPAGED_LOOKASIDE_LIST pLookaside = NULL;

    NT_ASSERT(NULL != ppLookAsideList);
    NT_ASSERT(NULL != *ppLookAsideList);

    pLookaside = *((NPAGED_LOOKASIDE_LIST **)ppLookAsideList);
    ExInitializeNPagedLookasideList(pLookaside,
        NULL,
        NULL,
        0,
        nBufSize,
        LOOK_A_SIDE_LIST_POOL_TAG_NAME,
        0 );

    *ppLookAsideList = pLookaside;
    return (NULL != pLookaside) ? 
            STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES;
}

NTSTATUS LookasideListAllocate_Page(void * pLookAsideList, void ** ppNodeOut)
{
    PAGED_CODE();

    *ppNodeOut = ExAllocateFromPagedLookasideList(
                    (PPAGED_LOOKASIDE_LIST)pLookAsideList);
    return (NULL != *ppNodeOut) ? 
            STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES;
}

NTSTATUS LookasideListAllocate_NPage(void * pLookAsideList, void ** ppNodeOut)
{
    *ppNodeOut = ExAllocateFromNPagedLookasideList(
                    (PNPAGED_LOOKASIDE_LIST)pLookAsideList);
    return (NULL != *ppNodeOut) ? 
            STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES;
}

NTSTATUS LookasideListFree_Page(void * pLookAsideList, void ** ppNodeOut)
{
    PAGED_CODE();

    ExFreeToPagedLookasideList((PPAGED_LOOKASIDE_LIST)pLookAsideList, 
                                *ppNodeOut);
    *ppNodeOut = NULL;
    return STATUS_SUCCESS;
}

NTSTATUS LookasideListFree_NPage(void * pLookAsideList, void ** ppNodeOut)
{
    ExFreeToNPagedLookasideList((PNPAGED_LOOKASIDE_LIST)pLookAsideList, 
                                *ppNodeOut);
    *ppNodeOut = NULL;
    return STATUS_SUCCESS;
}

NTSTATUS LookasideListDelete_Page(void ** ppLookAsideList)
{
    PPAGED_LOOKASIDE_LIST pLookAsideList = *ppLookAsideList;

    PAGED_CODE();

    ExDeletePagedLookasideList(pLookAsideList);
    *ppLookAsideList = NULL;

    return STATUS_SUCCESS;
}

NTSTATUS LookasideListDelete_NPage(void ** ppLookAsideList)
{
    PNPAGED_LOOKASIDE_LIST pLookAsideList = *ppLookAsideList;

    ExDeleteNPagedLookasideList(pLookAsideList);
    *ppLookAsideList = NULL;

    return STATUS_SUCCESS;
}

你可能感兴趣的:(alg : 单向链表排序 on drv)