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; }
  • 相关阅读:
    国外C#开源系统一览表
    国外的开源的CMS系统(ASP.Net_c#)
    CSS简写方法说明
    比较著名的.net技术论坛网址(含国外的)
    :domino用户的新邮件不出现在$Inbox(收件箱),但可以在'所有文档'视图中看到
    Domino邮件记录
    Lotus notes685升级安装设置
    Lotus 与 Exchange 对比评测
    Domino维护与监控
    用户在notes和shmail禁用离开办公室后,为何离开办公室代理依然运行
  • 原文地址:https://www.cnblogs.com/achillis/p/10181290.html
Copyright © 2011-2022 走看看