原文发表于百度空间,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 == ) {//当前是一级表,这时再增加容量就需要升级为二级表了
//
// 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[] = NewMidLevel[]; //把刚申请到的一级表放入第二个位置
NewMidLevel[] = (PHANDLE_TABLE_ENTRY)CapturedTable; //第一个位置存放CapturedTable,即最初的一级表
//之所以按这个顺序放置,是为了保证位置靠前的句柄表确实已经满载~ //
// Encode the current level and set it to the handle table process
//
CapturedTable = ((ULONG_PTR)NewMidLevel) | ; //当前新的TableCode值,最低位置1,这是二级表的标志 OldValue = InterlockedExchangePointer( (PVOID *)&HandleTable->TableCode, (PVOID)CapturedTable );//设置新的TableCode值
} else if (TableLevel == ) {//已经是二级表,则需要看具体情况是再分配一个一级表就可以了,还是可能升级为三级表
//
// 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[] = (PHANDLE_TABLE_ENTRY*)CapturedTable;//把原来的二级表地址放入三级表的第一个位置
NewHighLevel[] = NewMidLevel; //刚申请的二级表放在第二个位置
//
// Encode the level into the table pointer
//
CapturedTable = ((ULONG_PTR)NewHighLevel) | ; //设置TableCode低两位为2,即三级表的标志
//
// Change the handle table pointer with this one
//
OldValue = InterlockedExchangePointer( (PVOID *)&HandleTable->TableCode, (PVOID)CapturedTable );//设置新的TableCode
}
} else if (TableLevel == ) {//当前已经是三级表了,情况分为三种:表全满,二级表满,一级表满
//
// 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 () {
OldFree = ReadForWriteAccess (&HandleTable->FirstFree); //OldFree是原来的FirstFree的值
NewLowLevel[LOWLEVEL_COUNT - ].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;
}

【旧文章搬运】Windows句柄表分配算法分析(二)的更多相关文章

  1. 【旧文章搬运】Windows句柄表分配算法分析(一)

    原文发表于百度空间,2009-03-30========================================================================== 阅读提示: ...

  2. 【旧文章搬运】Windows句柄表分配算法分析(实验部分)

    原文发表于百度空间,2009-03-31========================================================================== 理论结合实 ...

  3. 【旧文章搬运】Windows句柄表分配算法分析(三)

    原文发表于百度空间,2009-03-30========================================================================== 三.当需要 ...

  4. 【旧文章搬运】Windows句柄分配算法(一)

    原文发表于百度空间,2009-04-04========================================================================== 分析了Wi ...

  5. 【旧文章搬运】Windows句柄分配算法(二)

    原文发表于百度空间,2009-04-04========================================================================== 在创建句柄 ...

  6. 【旧文章搬运】Windows句柄表格式

    原文发表于百度空间,2009-02-28========================================================================== 句柄是Wi ...

  7. 【旧文章搬运】Windows内核常见数据结构(进程相关)

    原文发表于百度空间,2008-7-24========================================================================== 进程的相关结 ...

  8. 【旧文章搬运】更正一个枚举PspCidTable时的错误

    原文发表于百度空间及看雪论坛,2009-02-27 看雪论坛地址:https://bbs.pediy.com/thread-82919.htm============================= ...

  9. 【旧文章搬运】深入分析Win7的对象引用跟踪机制

    原文发表于百度空间及看雪论坛,2010-09-12 看雪论坛地址:https://bbs.pediy.com/thread-120296.htm============================ ...

随机推荐

  1. 改动Xmodem/Zmodem上传下载路径

    SecureCRT能够使用Xmodem/Zmodem方便的上传和下载文件. 在Session ptions =>Xmodem/Zmodem => Directories中设置   选项=& ...

  2. PS 如何使用液化工具给人物减肥

    进入"液化", 有个收缩按钮, 可以选择范围大小, 想瘦哪里, 瘦多少都OK   最终效果图     1.打开原图,进入通道面板,选择菜单图像计算,计算红色通道,保留人物见图.   ...

  3. vuex 与 redux 的 区别

    一:redux和flux的区别 1)redux是flux中的一个实现 2))在redux中我们只能定义一个store,在flux中我们可以定义多个 3)在redux中,store和dispatch都放 ...

  4. linked-list-cycle——链表、判断是否循环链表、快慢指针

    Given a linked list, determine if it has a cycle in it. Follow up:Can you solve it without using ext ...

  5. 关于文件与文件系统的压缩与打包命令-Linux(笔记)

    1.gzip : 压缩命令 gzip [-cdtv#] 文件名称 (后缀为.gz) -c :将压缩的数据输出到屏幕上,可通过数据流重定向处理 -d : 解压缩的參数 -v : 能够显示源文件/压缩文件 ...

  6. 说说怎样管理软件日常执行的server

    大家应该都有这种情况.就是软件开发时都是全力以赴的把软件开发出来.一旦软件上线执行起来我们就能松口气.从而放松了对server及数据的管理.往往这个时候.server的一个小故障都能让我们忙上好一阵. ...

  7. Objective-C之成魔之路【10-继承性】

    郝萌主倾心贡献.尊重作者的劳动成果.请勿转载. 假设文章对您有所帮助,欢迎给作者捐赠,支持郝萌主.捐赠数额任意.重在心意^_^ 我要捐赠: 点击捐赠 Cocos2d-X源代码下载:点我传送 继承性是面 ...

  8. Arduino 网络时钟client

    升级! 添加了12h/24h 的开关,还有标准/ 夏令时开关!见步骤7 & 步骤8. 你是否曾想要一个和办公室时间来源全然准确的表? 这就有一个网络的办公时间server,你能够根据它并同步你 ...

  9. alsa声卡切换

    环境 ubuntu12.04 因为桌面版的默认装了,而且调声音也很方便,这里说一下server版下的配置,毕竟做开发经常还是用server版的 1.安装 apt-get install alsa-ba ...

  10. 6.游戏特别离不开脚本(4)-应该避免将集合框架对象传给JS

    java map  传给 javascript 不是自动关联的,最好别传啊,遍历起来也麻烦(尽量避开集合框架吧),用数组或者自建一个对象.这里虽然有种方法: // build a Map Map< ...