zoukankan      html  css  js  c++  java
  • 【旧文章搬运】Windows句柄表分配算法分析(二)

    原文发表于百度空间,2009-03-30
    ==========================================================================

    四.句柄表的扩容:已分配的句柄表被用完时,ExpAllocateHandleTableEntrySlow被调用以分配一个新的句柄表,实现对句柄表的扩容.每次增加粒度都是一个一级表的大小(大小为PAGE_SIZE,句柄容量为PAGE_SIZE/sizeof(HANDLE_TABLE_ENTRY)*HANDLE_VALUE_INC=0x800),但是根据具体情况不同,表的结构可能会发生改变,可能只是增加了一个一级表,也有可能由一级升级为二级表等等,情况比较多.搞清这个函数的调用时机对于分析该函数的流程非常重要.

    BOOLEAN
    ExpAllocateHandleTableEntrySlow (
         IN PHANDLE_TABLE HandleTable,
         IN BOOLEAN DoInit
         )
    /*++
    Routine Description:
         This worker routine allocates a new handle table entry for the specified
         handle table.
         Note: The caller must have already locked the handle table
    Arguments:
         HandleTable - Supplies the handle table being used
         DoInit - If FALSE then the caller (duplicate) doesn't need the free list built
    Return Value:
         BOOLEAN - TRUE, Retry the fast allocation path, FALSE, We failed to allocate memory
    --*/
    {
        ULONG i,j;
         PHANDLE_TABLE_ENTRY NewLowLevel;
         PHANDLE_TABLE_ENTRY *NewMidLevel;
         PHANDLE_TABLE_ENTRY **NewHighLevel;
        ULONG NewFree, OldFree;
        ULONG OldIndex;
        PVOID OldValue;
        
        ULONG_PTR CapturedTable = HandleTable->TableCode;
        ULONG TableLevel = (ULONG)(CapturedTable & LEVEL_CODE_MASK); //当前句柄表的级数
        
         PAGED_CODE();
        //
        // Initializing NewLowLevel is not needed for
        // correctness but without it the compiler cannot compile this code
        // W4 to check for use of uninitialized variables.
        //
         NewLowLevel = NULL;
         CapturedTable = CapturedTable & ~LEVEL_CODE_MASK; //当前句柄表的基址
        if ( TableLevel == 0 ) {//当前是一级表,这时再增加容量就需要升级为二级表了
            //
            //   We have a single level. We need to ad a mid-layer
            //   to the process handle table
            //
      //分配一个二级表,ExpAllocateMidLevelTable的流程前面已经分析过了,它同时还分配了一个新的一级表,放在NewMidLevel[0]中
             NewMidLevel = ExpAllocateMidLevelTable( HandleTable, DoInit, &NewLowLevel );
            if (NewMidLevel == NULL) {
                return FALSE;
             }
            //
            //   Since ExpAllocateMidLevelTable initialize the
            //   first position with a new table, we need to move it in
            //   the second position, and store in the first position the current one
            //
             NewMidLevel[1] = NewMidLevel[0]; //把刚申请到的一级表放入第二个位置
             NewMidLevel[0] = (PHANDLE_TABLE_ENTRY)CapturedTable; //第一个位置存放CapturedTable,即最初的一级表
            //之所以按这个顺序放置,是为了保证位置靠前的句柄表确实已经满载~
                
            //
            //   Encode the current level and set it to the handle table process
            //
             CapturedTable = ((ULONG_PTR)NewMidLevel) | 1; //当前新的TableCode值,最低位置1,这是二级表的标志
                
             OldValue = InterlockedExchangePointer( (PVOID *)&HandleTable->TableCode, (PVOID)CapturedTable );//设置新的TableCode值
         } else if (TableLevel == 1) {//已经是二级表,则需要看具体情况是再分配一个一级表就可以了,还是可能升级为三级表
            //
            //   We have a 2 levels handle table
            //
             PHANDLE_TABLE_ENTRY *TableLevel2 = (PHANDLE_TABLE_ENTRY *)CapturedTable;
            //
            //   Test whether the index we need to create is still in the
            //   range for a 2 layers table
            //
             i = HandleTable->NextHandleNeedingPool / (LOWLEVEL_COUNT * HANDLE_VALUE_INC); //i是当前一级表的个数
            if (i < MIDLEVEL_COUNT) { //若比二级表的最大容量小,则只需要再分配一个一级表(LowLevelTable)就可以了
                //
                //   We just need to allocate a new low-level
                //   table
                //
                    
                 NewLowLevel = ExpAllocateLowLevelTable( HandleTable, DoInit ); //再申请一个一级表
                if (NewLowLevel == NULL) {
                    return FALSE;
                 }
                //
                //   Set the new one to the table, at appropriate position
                //
                 OldValue = InterlockedExchangePointer( (PVOID *) (&TableLevel2[i]), NewLowLevel ); //放入二级表中
                 EXASSERT (OldValue == NULL);
             } else {//已达到二级表最大数目,需要升级至三级表
                //
                //   We exhausted the 2 level domain. We need to insert a new one
                //
                 NewHighLevel = ExpAllocateTablePagedPool( HandleTable->QuotaProcess,
                                                           HIGHLEVEL_SIZE
                                                         );//申请一个表作为三级表
                if (NewHighLevel == NULL) {
                    return FALSE;
                 }
                    
                 NewMidLevel = ExpAllocateMidLevelTable( HandleTable, DoInit, &NewLowLevel );//给这个三级表申请一个二级表,至于为什么,原因前面分析ExpAllocateMidLevelTable时就分析过了,只不那是给二级表申请了一个一级表,道理是一样的~~
                if (NewMidLevel == NULL) {
                        
                     ExpFreeTablePagedPool( HandleTable->QuotaProcess,
                                            NewHighLevel,
                                            HIGHLEVEL_SIZE
                                          );
                    return FALSE;
                 }
                //
                //   Initialize the first index with the previous mid-level layer
                //
                 NewHighLevel[0] = (PHANDLE_TABLE_ENTRY*)CapturedTable;//把原来的二级表地址放入三级表的第一个位置
                 NewHighLevel[1] = NewMidLevel; //刚申请的二级表放在第二个位置
                //
                //   Encode the level into the table pointer
                //
                 CapturedTable = ((ULONG_PTR)NewHighLevel) | 2; //设置TableCode低两位为2,即三级表的标志
                //
                //   Change the handle table pointer with this one
                //
                 OldValue = InterlockedExchangePointer( (PVOID *)&HandleTable->TableCode, (PVOID)CapturedTable );//设置新的TableCode
             }
         } else if (TableLevel == 2) {//当前已经是三级表了,情况分为三种:表全满,二级表满,一级表满
            //
            //   we have already a table with 3 levels
            //
            ULONG RemainingIndex;
             PHANDLE_TABLE_ENTRY **TableLevel3 = (PHANDLE_TABLE_ENTRY **)CapturedTable;
             i = HandleTable->NextHandleNeedingPool / (MIDLEVEL_THRESHOLD * HANDLE_VALUE_INC); //三级表中二级表的个数
            //
            //   Check whether we exhausted all possible indexes.
            //
            if (i >= HIGHLEVEL_COUNT) { //二级表个数超出三级表的容易则失败!(实际上达不到这个数)
                return FALSE;
             }
            if (TableLevel3[i] == NULL) { //确定这个位置可用,还没有放置二级表指针, 这也表明需要申请一个新的二级表了
                //
                //   The new available handle points to a free mid-level entry
                //   We need then to allocate a new one and save it in that position
                //
                 NewMidLevel = ExpAllocateMidLevelTable( HandleTable, DoInit, &NewLowLevel );//申请一个二级表
                    
                if (NewMidLevel == NULL) {
                        
                    return FALSE;
                 }             
                 OldValue = InterlockedExchangePointer( (PVOID *) &(TableLevel3[i]), NewMidLevel );//放入刚才的位置
                 EXASSERT (OldValue == NULL);
             } else { //若TableLevel3[i]不为NULL,则表明TableLevel3[i]这个二级表已存在,但还没有放满,只需要给这个二级表再申请一个一级表就可以了
                //
                //   We have already a mid-level table. We just need to add a new low-level one
                //   at the end
                //
                    
                 RemainingIndex = (HandleTable->NextHandleNeedingPool / HANDLE_VALUE_INC) -
                                   i * MIDLEVEL_THRESHOLD;
                 j = RemainingIndex / LOWLEVEL_COUNT;//计算出新的一级表在TableLevel3[i]这个二级表中的偏移
                 NewLowLevel = ExpAllocateLowLevelTable( HandleTable, DoInit ); //只需要申请一个一级表
                if (NewLowLevel == NULL) {
                    return FALSE;
                 }
                 OldValue = InterlockedExchangePointer( (PVOID *)(&TableLevel3[i][j]) , NewLowLevel );//把刚申请的一级表放入TableLevel3[i]这个二级表中
                 EXASSERT (OldValue == NULL);
             }
         }
        //
        // This must be done after the table pointers so that new created handles
        // are valid before being freed.
        //
         OldIndex = InterlockedExchangeAdd ((PLONG) &HandleTable->NextHandleNeedingPool,
                                            LOWLEVEL_COUNT * HANDLE_VALUE_INC);//设置新的NextHandleNeedingPool,增量为一个一级句柄表的句柄容量(即一级表中HANDLE_TABEL_ENTRY的个数再乘4)
    //并把原来的NextHandleNeedingPool值放入OldIndex,也就是说,OldIndex是曾经的句柄值上限
    if (DoInit) {//这里对刚申请的一级表进行一些初始化工作 // // Generate a new sequence number since this is a push // OldIndex += HANDLE_VALUE_INC + GetNextSeq();//GetNextSeq()的结果为0,所以相当于只加了一个HANDLE_VALUE_INC,即4,此时的OldIndex是新分配的句柄表中的最小句柄 // // Now free the handles. These are all ready to be accepted by the lookup logic now. // while (1) { OldFree = ReadForWriteAccess (&HandleTable->FirstFree); //OldFree是原来的FirstFree的值 NewLowLevel[LOWLEVEL_COUNT - 1].NextFreeTableEntry = OldFree; //把一级表的最后一项的NextFreeHandle指向以前的HandleTable->FirstFree,
    //这就相当于把原来的FreeHandleList连在了新申请的句柄表的FreeHandleList链后面,成为一条新的FreeHandleList
    // // These are new entries that have never existed before. We can't have an A-B-A problem // with these so we don't need to take any locks // NewFree = InterlockedCompareExchange ((PLONG)&HandleTable->FirstFree, OldIndex,//用为新的FirstFree的值放入,新申请的句柄将从这个值开始 OldFree); if (NewFree == OldFree) {//成功,就跳出这个循环了 break; } } } return TRUE; }
  • 相关阅读:
    【转载】SAP_ECC6.0_EHP4或SAP_ECC6.0_EHP5_基于Windows_Server_2008R2_和SQL_server_2008下的安装
    使用delphi 开发多层应用(二十四)KbmMW 的消息方式和创建WIB节点
    使用delphi 开发多层应用(二十三)KbmMW 的WIB
    实现KbmMw web server 支持https
    KbmMW 服务器架构简介
    Devexpress VCL Build v2014 vol 14.1.1 beta发布
    使用delphi 开发多层应用(二十二)使用kbmMW 的认证管理器
    KbmMW 4.50.00 测试版发布
    Basic4android v3.80 beta 发布
    KbmMW 认证管理器说明(转载)
  • 原文地址:https://www.cnblogs.com/achillis/p/10181290.html
Copyright © 2011-2022 走看看