第一部分:ExpMoveFreeHandles和备用空闲表的关系
ULONG
ExpMoveFreeHandles (
IN PHANDLE_TABLE HandleTable
)
{
ULONG OldValue, NewValue;
ULONG Index, OldIndex, NewIndex, FreeSize;
PHANDLE_TABLE_ENTRY Entry, FirstEntry;
EXHANDLE Handle;
ULONG Idx;
BOOLEAN StrictFIFO;
//
// First remove all the handles from the free list so we can add them to the
// list we use for allocates.
//
OldValue = InterlockedExchange ((PLONG)&HandleTable->LastFree,
0);
Index = OldValue;
if (Index == 0) {
//
// There are no free handles. Nothing to do.
//
return OldValue;
}
//
// We are pushing old entries onto the free list.
// We have the A-B-A problem here as these items may have been moved here because
// another thread was using them in the pop code.
//
for (Idx = 1; Idx < HANDLE_TABLE_LOCKS; Idx++) {
ExAcquireReleasePushLockExclusive (&HandleTable->HandleTableLock[Idx]);
}
StrictFIFO = HandleTable->StrictFIFO;
//如果我们是严格的FIFO,那么反转列表以减少句柄重用。
// If we are strict FIFO then reverse the list to make handle reuse rare.
//
if (!StrictFIFO) {
//
// We have a complete chain here. If there is no existing chain we
// can just push this one without any hassles. If we can't then
// we can just fall into the reversing code anyway as we need
// to find the end of the chain to continue it.
//
//
// This is a push so create a new sequence number
//
if (InterlockedCompareExchange ((PLONG)&HandleTable->FirstFree,
OldValue + GetNextSeq(),
0) == 0) {
return OldValue;
}
}
//
// Loop over all the entries and reverse the chain.
//遍历所有条目并反转链。
FreeSize = OldIndex = 0;
FirstEntry = NULL;
while (1) {
FreeSize++;
Handle.Value = Index;
Entry = ExpLookupHandleTableEntry (HandleTable, Handle);
EXASSERT (Entry->Object == NULL);
NewIndex = Entry->NextFreeTableEntry;
Entry->NextFreeTableEntry = OldIndex;
if (OldIndex == 0) {
FirstEntry = Entry;
}
OldIndex = Index;
if (NewIndex == 0) {
break;
}
Index = NewIndex;
}
NewValue = ExpInterlockedExchange (&HandleTable->FirstFree,
OldIndex,
FirstEntry);
//
// If we haven't got a pool of a few handles then force
// table expansion to keep the free handle size high
//
if (FreeSize < 100 && StrictFIFO) {
OldValue = 0;
}
return OldValue;
}
FORCEINLINE
ULONG
ExpInterlockedExchange (
IN OUT PULONG Index,
IN ULONG FirstIndex,
IN PHANDLE_TABLE_ENTRY Entry
)
/*++
Routine Description:
This performs the following steps:
1. Set Entry->NextFreeTableEntry = *Index
2. Loops until *Index == (the value of *Index when we entered the function)
When they're equal, we set *Index = FirstIndex
Arguments:
Index - Points to the ULONG we want to set.
FirstIndex - New value to set Index to.
Entry - TableEntry that will get the initial value of *Index before it's
updated.
Return Value:
New value of *Index (i.e. FirstIndex).
--*/
{
ULONG OldIndex, NewIndex;
EXASSERT (Entry->Object == NULL);
//
// Load new value and generate the sequence number on pushes
//
NewIndex = FirstIndex + GetNextSeq();
while (1) {
//
// remember original value and
// archive it in NextFreeTableEntry.
//
OldIndex = *Index;
Entry->NextFreeTableEntry = OldIndex;
//
// Swap in the new value, and if the swap occurs
// successfully, we're done.
//
if (OldIndex == (ULONG) InterlockedCompareExchange ((PLONG)Index,
NewIndex,
OldIndex)) {
return OldIndex;
}
}
}
第二部分:ExpMoveFreeHandles函数的调用时机
PHANDLE_TABLE_ENTRY
ExpAllocateHandleTableEntry (
IN PHANDLE_TABLE HandleTable,
OUT PEXHANDLE pHandle
)
{
......
while (1) {
OldValue = HandleTable->FirstFree;
while (OldValue == 0) {
//
// Lock the handle table for exclusive access as we will be
// allocating a new table level.
//
ExpLockHandleTableExclusive (HandleTable, CurrentThread);
//
// If we have multiple threads trying to expand the table at
// the same time then by just acquiring the table lock we
// force those threads to complete their allocations and
// populate the free list. We must check the free list here
// so we don't expand the list twice without needing to.
//
OldValue = HandleTable->FirstFree;
if (OldValue != 0) {
ExpUnlockHandleTableExclusive (HandleTable, CurrentThread);
break;
}
//看看我们在备用空闲列表上是否有句柄
// See if we have any handles on the alternate free list
// These handles need some locking to move them over.
//
OldValue = ExpMoveFreeHandles (HandleTable);
if (OldValue != 0) {
ExpUnlockHandleTableExclusive (HandleTable, CurrentThread);
break;
}