NewEntry = ExpA11ocateHand1eTab1eEntry(Hand1eTab1e, &Handle); if (NewEntry) { /*禁用内核模式异步调用八?&,进入关键段*/ KeEnterCriticalRegion(); /*Write the entry*/ *NewEntry = *Hand1eTab1eEntry; /*解锁并离开关键段*/ ExUnlockHandleTab1eEntry(Hand1eTab1e, NewEntry); KeLeaveCriticalRegion(); } /*Return the handle value*/ return Handle. GenericHandleOverlay; 下面我们将重点分析句柄分配算法的实现。事实上,整个分配算法包括3个重要步骤,若3 个步骤都无法寻找到一个新的合法句柄,则函数跑出异常错误。 (1) 访问此1^161&1^6-汗^^81[^6值,若非零,则分配此节点并更新?1^1[^6域,返 回成功。 (2 ) 调用nt! ExpMoveFreeHand 1 es,以利用空闲交换列表中的空闲句柄,若寻找到空闲 句柄,则更新?^〖[〜6域,并返回成功。 (3) 调用1^!£1口人1100&丨6服1^3!161&1^6£1^17810界,以扩展句柄表当前大小,若扩展成功, 至少可产生一个新句柄值。 (4) 若上述方法都失败,函数则认定此请求无法满足,并返回错误。 内核管理着两个重要的空闲句柄队列即?1^1[^6和1381[^6队列。句柄分配函数首先 检查HandleTab 16->[^^8〖[166是否为空。 若为空则表示[^611&1^161181队列中存在?1^1[^6可分配,此时函数获取与此句柄相 关的句柄表项£的”,然后修改11&1^161&1^6-汗化81[166使其指向下一个 NextFreeTab 1 eEntry,相当于从?化81[^6队列中卸载已经计划分配出去的节点,然后将它 的下一结点指针赋给上一节点。这部分工作的代码实现如下: Handle. Value = (HandleTable->FirstFree & FREE_HANDLE_MASK); //给新句柄赋 值 Entry = ExpLookupHandleTab 1 eEntry (HandleTable, Handle); //寻找此句柄对 应的表项 /*获取新申请到fKlHANDLE_TABLE_ENTRY* fi<INextFreeTableEntry */ NewValue = *(volatile ULONG *) &Entry->NextFreeTableEntry; /*将%¥¥&1收赋值给11&1^16了&1^6->卩^^81卩166 */ NewYaluel = InterlockedCompareExchange ((PLONG)&HandleTab1e->FirstFree, NewValue, 01dValue); (注释:函数11^11001^此(聊^^101^(^^用即将参数1与参数3的值进行比较,若相同则 将参数2的值赋给参数1.)此时步骤i^^) (4)都略去。 若非空,则转入步骤(2)执0 #^设我们的测试程序打开了3个文件对象,故需请 求分配3个句柄,然而[118丨[^^^^^1^^经为空,此时£1口1^^^^66他1^168()函数会将 [&81[作6队列中的空闲句0^^^^^到¥^181[166队列。 函数首先会先检查版^^^_>1&81?『66是否为0,不为0则开始进行队列表项调整, 若没有设置3化1&?€#,1^^设置?化#?^6指向队形头,反之,则将队形逆序后再设置 卩化8〖作66指向$^^^78《^(^[1?0=0(普通进程)的句柄表申请释放均不涉及[&8丨作66,所 有操作都在?^^^^头部进行,申请句柄时从队列头取走一个,释放时仍放回队列头, [&&{[^©始终是一^^圣队列。而若81^1(^[1[0=1,则句柄申请时首先遍历?1^丨[166队列, 若为空则将1&8〖[166队列反向,插入到?化8〖[166队列末尾,开始使用1&8丨[166队列表项。 系统每释放一个句柄时则在1&8〖[^6队列头插入一个。具体分配过程如图4、5所示。 undefined | HandteTable->Hfstrree | HandleTablfr->Lastrree ![]() /*遍历整个队列,并逆向队列,然后将1^1^161&516-汗^^81[^6指向逆向后的队列首个 节点*/ FreeSize = 01dIndex = 0; FirstEntry = NULL; while (1) { FreeSize++; Handle. Value = Index; /*寻找句柄对应的句柄表项*/ Entry = ExpLookupHandleTab1eEntry (HandleTable, Handle); EXASSERT (Entry->Object == NULL); NewIndex = Entry->NextFreeTableEntry; Entry->NextFreeTableEntry = 01dIndex; if (01dIndex 二二 0) { FirstEntry = Entry; 01dIndex = Index; if (NewIndex 二二 0) Index = NewIndex; / *将01 ^!^㊀叉赋值给!^!^ 1 eT ab 1 e->F irstFree*/ NewValue = (&HandleTable->FirstFree, 01dIndex, FirstEntry); 若步骤(1) (2)都无法满>^^^的1^_统会调用£1口人1100&丨61^1^16了&1^6£1^^810界 分配一个新的句柄表,实现对,^^&。每次增加粒度都是一个一级表的大小(大小为 PAGE_SIZE,句柄容量为?4砷一312私 /sizeof (HMDLE_TABLE^^J^HMDLE_VALUE_INC=0x800) • |