summaryrefslogtreecommitdiff
path: root/src/gc/handletablepriv.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/gc/handletablepriv.h')
-rw-r--r--src/gc/handletablepriv.h1069
1 files changed, 1069 insertions, 0 deletions
diff --git a/src/gc/handletablepriv.h b/src/gc/handletablepriv.h
new file mode 100644
index 0000000000..59c08ca744
--- /dev/null
+++ b/src/gc/handletablepriv.h
@@ -0,0 +1,1069 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*
+ * Generational GC handle manager. Internal Implementation Header.
+ *
+ * Shared defines and declarations for handle table implementation.
+ *
+
+ *
+ */
+
+#include "common.h"
+
+#include "handletable.h"
+
+/*--------------------------------------------------------------------------*/
+
+//<TODO>@TODO: find a home for this in a project-level header file</TODO>
+#define BITS_PER_BYTE (8)
+/*--------------------------------------------------------------------------*/
+
+
+
+/****************************************************************************
+ *
+ * MAJOR TABLE DEFINITIONS THAT CHANGE DEPENDING ON THE WEATHER
+ *
+ ****************************************************************************/
+
+// 64k reserved per segment with 4k as header.
+#define HANDLE_SEGMENT_SIZE (0x10000) // MUST be a power of 2 (and currently must be 64K due to VirtualAlloc semantics)
+#define HANDLE_HEADER_SIZE (0x1000) // SHOULD be <= OS page size
+
+#define HANDLE_SEGMENT_ALIGNMENT HANDLE_SEGMENT_SIZE
+
+
+#if !BIGENDIAN
+
+ // little-endian write barrier mask manipulation
+ #define GEN_CLUMP_0_MASK (0x000000FF)
+ #define NEXT_CLUMP_IN_MASK(dw) (dw >> BITS_PER_BYTE)
+
+#else
+
+ // big-endian write barrier mask manipulation
+ #define GEN_CLUMP_0_MASK (0xFF000000)
+ #define NEXT_CLUMP_IN_MASK(dw) (dw << BITS_PER_BYTE)
+
+#endif
+
+
+// if the above numbers change than these will likely change as well
+#define HANDLE_HANDLES_PER_CLUMP (16) // segment write-barrier granularity
+#define HANDLE_HANDLES_PER_BLOCK (64) // segment suballocation granularity
+#define HANDLE_OPTIMIZE_FOR_64_HANDLE_BLOCKS // flag for certain optimizations
+
+// maximum number of internally supported handle types
+#define HANDLE_MAX_INTERNAL_TYPES (12) // should be a multiple of 4
+
+// number of types allowed for public callers
+#define HANDLE_MAX_PUBLIC_TYPES (HANDLE_MAX_INTERNAL_TYPES - 1) // reserve one internal type
+
+// internal block types
+#define HNDTYPE_INTERNAL_DATABLOCK (HANDLE_MAX_INTERNAL_TYPES - 1) // reserve last type for data blocks
+
+// max number of generations to support statistics on
+#define MAXSTATGEN (5)
+
+/*--------------------------------------------------------------------------*/
+
+
+
+/****************************************************************************
+ *
+ * MORE DEFINITIONS
+ *
+ ****************************************************************************/
+
+// fast handle-to-segment mapping
+#define HANDLE_SEGMENT_CONTENT_MASK (HANDLE_SEGMENT_SIZE - 1)
+#define HANDLE_SEGMENT_ALIGN_MASK (~HANDLE_SEGMENT_CONTENT_MASK)
+
+// table layout metrics
+#define HANDLE_SIZE sizeof(_UNCHECKED_OBJECTREF)
+#define HANDLE_HANDLES_PER_SEGMENT ((HANDLE_SEGMENT_SIZE - HANDLE_HEADER_SIZE) / HANDLE_SIZE)
+#define HANDLE_BLOCKS_PER_SEGMENT (HANDLE_HANDLES_PER_SEGMENT / HANDLE_HANDLES_PER_BLOCK)
+#define HANDLE_CLUMPS_PER_SEGMENT (HANDLE_HANDLES_PER_SEGMENT / HANDLE_HANDLES_PER_CLUMP)
+#define HANDLE_CLUMPS_PER_BLOCK (HANDLE_HANDLES_PER_BLOCK / HANDLE_HANDLES_PER_CLUMP)
+#define HANDLE_BYTES_PER_BLOCK (HANDLE_HANDLES_PER_BLOCK * HANDLE_SIZE)
+#define HANDLE_HANDLES_PER_MASK (sizeof(uint32_t) * BITS_PER_BYTE)
+#define HANDLE_MASKS_PER_SEGMENT (HANDLE_HANDLES_PER_SEGMENT / HANDLE_HANDLES_PER_MASK)
+#define HANDLE_MASKS_PER_BLOCK (HANDLE_HANDLES_PER_BLOCK / HANDLE_HANDLES_PER_MASK)
+#define HANDLE_CLUMPS_PER_MASK (HANDLE_HANDLES_PER_MASK / HANDLE_HANDLES_PER_CLUMP)
+
+// We use this relation to check for free mask per block.
+C_ASSERT (HANDLE_HANDLES_PER_MASK * 2 == HANDLE_HANDLES_PER_BLOCK);
+
+
+// cache layout metrics
+#define HANDLE_CACHE_TYPE_SIZE 128 // 128 == 63 handles per bank
+#define HANDLES_PER_CACHE_BANK ((HANDLE_CACHE_TYPE_SIZE / 2) - 1)
+
+// cache policy defines
+#define REBALANCE_TOLERANCE (HANDLES_PER_CACHE_BANK / 3)
+#define REBALANCE_LOWATER_MARK (HANDLES_PER_CACHE_BANK - REBALANCE_TOLERANCE)
+#define REBALANCE_HIWATER_MARK (HANDLES_PER_CACHE_BANK + REBALANCE_TOLERANCE)
+
+// bulk alloc policy defines
+#define SMALL_ALLOC_COUNT (HANDLES_PER_CACHE_BANK / 10)
+
+// misc constants
+#define MASK_FULL (0)
+#define MASK_EMPTY (0xFFFFFFFF)
+#define MASK_LOBYTE (0x000000FF)
+#define TYPE_INVALID ((uint8_t)0xFF)
+#define BLOCK_INVALID ((uint8_t)0xFF)
+
+/*--------------------------------------------------------------------------*/
+
+
+
+/****************************************************************************
+ *
+ * CORE TABLE LAYOUT STRUCTURES
+ *
+ ****************************************************************************/
+
+/*
+ * we need byte packing for the handle table layout to work
+ */
+#pragma pack(push,1)
+
+
+/*
+ * Table Segment Header
+ *
+ * Defines the layout for a segment's header data.
+ */
+struct _TableSegmentHeader
+{
+ /*
+ * Write Barrier Generation Numbers
+ *
+ * Each slot holds four bytes. Each byte corresponds to a clump of handles.
+ * The value of the byte corresponds to the lowest possible generation that a
+ * handle in that clump could point into.
+ *
+ * WARNING: Although this array is logically organized as a uint8_t[], it is sometimes
+ * accessed as uint32_t[] when processing bytes in parallel. Code which treats the
+ * array as an array of ULONG32s must handle big/little endian issues itself.
+ */
+ uint8_t rgGeneration[HANDLE_BLOCKS_PER_SEGMENT * sizeof(uint32_t) / sizeof(uint8_t)];
+
+ /*
+ * Block Allocation Chains
+ *
+ * Each slot indexes the next block in an allocation chain.
+ */
+ uint8_t rgAllocation[HANDLE_BLOCKS_PER_SEGMENT];
+
+ /*
+ * Block Free Masks
+ *
+ * Masks - 1 bit for every handle in the segment.
+ */
+ uint32_t rgFreeMask[HANDLE_MASKS_PER_SEGMENT];
+
+ /*
+ * Block Handle Types
+ *
+ * Each slot holds the handle type of the associated block.
+ */
+ uint8_t rgBlockType[HANDLE_BLOCKS_PER_SEGMENT];
+
+ /*
+ * Block User Data Map
+ *
+ * Each slot holds the index of a user data block (if any) for the associated block.
+ */
+ uint8_t rgUserData[HANDLE_BLOCKS_PER_SEGMENT];
+
+ /*
+ * Block Lock Count
+ *
+ * Each slot holds a lock count for its associated block.
+ * Locked blocks are not freed, even when empty.
+ */
+ uint8_t rgLocks[HANDLE_BLOCKS_PER_SEGMENT];
+
+ /*
+ * Allocation Chain Tails
+ *
+ * Each slot holds the tail block index for an allocation chain.
+ */
+ uint8_t rgTail[HANDLE_MAX_INTERNAL_TYPES];
+
+ /*
+ * Allocation Chain Hints
+ *
+ * Each slot holds a hint block index for an allocation chain.
+ */
+ uint8_t rgHint[HANDLE_MAX_INTERNAL_TYPES];
+
+ /*
+ * Free Count
+ *
+ * Each slot holds the number of free handles in an allocation chain.
+ */
+ uint32_t rgFreeCount[HANDLE_MAX_INTERNAL_TYPES];
+
+ /*
+ * Next Segment
+ *
+ * Points to the next segment in the chain (if we ran out of space in this one).
+ */
+#ifdef DACCESS_COMPILE
+ TADDR pNextSegment;
+#else
+ struct TableSegment *pNextSegment;
+#endif // DACCESS_COMPILE
+
+ /*
+ * Handle Table
+ *
+ * Points to owning handle table for this table segment.
+ */
+ PTR_HandleTable pHandleTable;
+
+ /*
+ * Flags
+ */
+ uint8_t fResortChains : 1; // allocation chains need sorting
+ uint8_t fNeedsScavenging : 1; // free blocks need scavenging
+ uint8_t _fUnused : 6; // unused
+
+ /*
+ * Free List Head
+ *
+ * Index of the first free block in the segment.
+ */
+ uint8_t bFreeList;
+
+ /*
+ * Empty Line
+ *
+ * Index of the first KNOWN block of the last group of unused blocks in the segment.
+ */
+ uint8_t bEmptyLine;
+
+ /*
+ * Commit Line
+ *
+ * Index of the first uncommited block in the segment.
+ */
+ uint8_t bCommitLine;
+
+ /*
+ * Decommit Line
+ *
+ * Index of the first block in the highest committed page of the segment.
+ */
+ uint8_t bDecommitLine;
+
+ /*
+ * Sequence
+ *
+ * Indicates the segment sequence number.
+ */
+ uint8_t bSequence;
+};
+
+typedef DPTR(struct _TableSegmentHeader) PTR__TableSegmentHeader;
+typedef DPTR(uintptr_t) PTR_uintptr_t;
+
+// The handle table is large and may not be entirely mapped. That's one reason for splitting out the table
+// segment and the header as two separate classes. In DAC builds, we generally need only a single element from
+// the table segment, so we can use the DAC to retrieve just the information we require.
+/*
+ * Table Segment
+ *
+ * Defines the layout for a handle table segment.
+ */
+struct TableSegment : public _TableSegmentHeader
+{
+ /*
+ * Filler
+ */
+ uint8_t rgUnused[HANDLE_HEADER_SIZE - sizeof(_TableSegmentHeader)];
+
+ /*
+ * Handles
+ */
+ _UNCHECKED_OBJECTREF rgValue[HANDLE_HANDLES_PER_SEGMENT];
+
+#ifdef DACCESS_COMPILE
+ static uint32_t DacSize(TADDR addr);
+#endif
+};
+
+typedef SPTR(struct TableSegment) PTR_TableSegment;
+
+/*
+ * restore default packing
+ */
+#pragma pack(pop)
+
+
+/*
+ * Handle Type Cache
+ *
+ * Defines the layout of a per-type handle cache.
+ */
+struct HandleTypeCache
+{
+ /*
+ * reserve bank
+ */
+ OBJECTHANDLE rgReserveBank[HANDLES_PER_CACHE_BANK];
+
+ /*
+ * index of next available handle slot in the reserve bank
+ */
+ int32_t lReserveIndex;
+
+
+ /*---------------------------------------------------------------------------------
+ * N.B. this structure is split up this way so that when HANDLES_PER_CACHE_BANK is
+ * large enough, lReserveIndex and lFreeIndex will reside in different cache lines
+ *--------------------------------------------------------------------------------*/
+
+ /*
+ * free bank
+ */
+ OBJECTHANDLE rgFreeBank[HANDLES_PER_CACHE_BANK];
+
+ /*
+ * index of next empty slot in the free bank
+ */
+ int32_t lFreeIndex;
+};
+
+
+/*---------------------------------------------------------------------------*/
+
+
+
+/****************************************************************************
+ *
+ * SCANNING PROTOTYPES
+ *
+ ****************************************************************************/
+
+/*
+ * ScanCallbackInfo
+ *
+ * Carries parameters for per-segment and per-block scanning callbacks.
+ *
+ */
+struct ScanCallbackInfo
+{
+ PTR_TableSegment pCurrentSegment; // segment we are presently scanning, if any
+ uint32_t uFlags; // HNDGCF_* flags
+ BOOL fEnumUserData; // whether user data is being enumerated as well
+ HANDLESCANPROC pfnScan; // per-handle scan callback
+ uintptr_t param1; // callback param 1
+ uintptr_t param2; // callback param 2
+ uint32_t dwAgeMask; // generation mask for ephemeral GCs
+
+#ifdef _DEBUG
+ uint32_t DEBUG_BlocksScanned;
+ uint32_t DEBUG_BlocksScannedNonTrivially;
+ uint32_t DEBUG_HandleSlotsScanned;
+ uint32_t DEBUG_HandlesActuallyScanned;
+#endif
+};
+
+
+/*
+ * BLOCKSCANPROC
+ *
+ * Prototype for callbacks that implement per-block scanning logic.
+ *
+ */
+typedef void (CALLBACK *BLOCKSCANPROC)(PTR_TableSegment pSegment, uint32_t uBlock, uint32_t uCount, ScanCallbackInfo *pInfo);
+
+
+/*
+ * SEGMENTITERATOR
+ *
+ * Prototype for callbacks that implement per-segment scanning logic.
+ *
+ */
+typedef PTR_TableSegment (CALLBACK *SEGMENTITERATOR)(PTR_HandleTable pTable, PTR_TableSegment pPrevSegment, CrstHolderWithState *pCrstHolder);
+
+
+/*
+ * TABLESCANPROC
+ *
+ * Prototype for TableScanHandles and xxxTableScanHandlesAsync.
+ *
+ */
+typedef void (CALLBACK *TABLESCANPROC)(PTR_HandleTable pTable,
+ const uint32_t *puType, uint32_t uTypeCount,
+ SEGMENTITERATOR pfnSegmentIterator,
+ BLOCKSCANPROC pfnBlockHandler,
+ ScanCallbackInfo *pInfo,
+ CrstHolderWithState *pCrstHolder);
+
+/*--------------------------------------------------------------------------*/
+
+
+
+/****************************************************************************
+ *
+ * ADDITIONAL TABLE STRUCTURES
+ *
+ ****************************************************************************/
+
+/*
+ * AsyncScanInfo
+ *
+ * Tracks the state of an async scan for a handle table.
+ *
+ */
+struct AsyncScanInfo
+{
+ /*
+ * Underlying Callback Info
+ *
+ * Specifies callback info for the underlying block handler.
+ */
+ struct ScanCallbackInfo *pCallbackInfo;
+
+ /*
+ * Underlying Segment Iterator
+ *
+ * Specifies the segment iterator to be used during async scanning.
+ */
+ SEGMENTITERATOR pfnSegmentIterator;
+
+ /*
+ * Underlying Block Handler
+ *
+ * Specifies the block handler to be used during async scanning.
+ */
+ BLOCKSCANPROC pfnBlockHandler;
+
+ /*
+ * Scan Queue
+ *
+ * Specifies the nodes to be processed asynchronously.
+ */
+ struct ScanQNode *pScanQueue;
+
+ /*
+ * Queue Tail
+ *
+ * Specifies the tail node in the queue, or NULL if the queue is empty.
+ */
+ struct ScanQNode *pQueueTail;
+};
+
+
+/*
+ * Handle Table
+ *
+ * Defines the layout of a handle table object.
+ */
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4200 ) // zero-sized array
+#endif
+struct HandleTable
+{
+ /*
+ * flags describing handle attributes
+ *
+ * N.B. this is at offset 0 due to frequent access by cache free codepath
+ */
+ uint32_t rgTypeFlags[HANDLE_MAX_INTERNAL_TYPES];
+
+ /*
+ * lock for this table
+ */
+ CrstStatic Lock;
+
+ /*
+ * number of types this table supports
+ */
+ uint32_t uTypeCount;
+
+ /*
+ * number of handles owned by this table that are marked as "used"
+ * (this includes the handles residing in rgMainCache and rgQuickCache)
+ */
+ uint32_t dwCount;
+
+ /*
+ * head of segment list for this table
+ */
+ PTR_TableSegment pSegmentList;
+
+ /*
+ * information on current async scan (if any)
+ */
+ AsyncScanInfo *pAsyncScanInfo;
+
+ /*
+ * per-table user info
+ */
+ uint32_t uTableIndex;
+
+ /*
+ * per-table AppDomain info
+ */
+ ADIndex uADIndex;
+
+ /*
+ * one-level per-type 'quick' handle cache
+ */
+ OBJECTHANDLE rgQuickCache[HANDLE_MAX_INTERNAL_TYPES]; // interlocked ops used here
+
+ /*
+ * debug-only statistics
+ */
+#ifdef _DEBUG
+ int _DEBUG_iMaxGen;
+ int64_t _DEBUG_TotalBlocksScanned [MAXSTATGEN];
+ int64_t _DEBUG_TotalBlocksScannedNonTrivially[MAXSTATGEN];
+ int64_t _DEBUG_TotalHandleSlotsScanned [MAXSTATGEN];
+ int64_t _DEBUG_TotalHandlesActuallyScanned [MAXSTATGEN];
+#endif
+
+ /*
+ * primary per-type handle cache
+ */
+ HandleTypeCache rgMainCache[0]; // interlocked ops used here
+};
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+/*--------------------------------------------------------------------------*/
+
+
+
+/****************************************************************************
+ *
+ * HELPERS
+ *
+ ****************************************************************************/
+
+/*
+ * A 32/64 comparison callback
+ *<TODO>
+ * @TODO: move/merge into common util file
+ *</TODO>
+ */
+typedef int (*PFNCOMPARE)(uintptr_t p, uintptr_t q);
+
+
+/*
+ * A 32/64 neutral quicksort
+ *<TODO>
+ * @TODO: move/merge into common util file
+ *</TODO>
+ */
+void QuickSort(uintptr_t *pData, int left, int right, PFNCOMPARE pfnCompare);
+
+
+/*
+ * CompareHandlesByFreeOrder
+ *
+ * Returns:
+ * <0 - handle P should be freed before handle Q
+ * =0 - handles are eqivalent for free order purposes
+ * >0 - handle Q should be freed before handle P
+ *
+ */
+int CompareHandlesByFreeOrder(uintptr_t p, uintptr_t q);
+
+/*--------------------------------------------------------------------------*/
+
+
+
+/****************************************************************************
+ *
+ * CORE TABLE MANAGEMENT
+ *
+ ****************************************************************************/
+
+/*
+ * TypeHasUserData
+ *
+ * Determines whether a given handle type has user data.
+ *
+ */
+__inline BOOL TypeHasUserData(HandleTable *pTable, uint32_t uType)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ // sanity
+ _ASSERTE(uType < HANDLE_MAX_INTERNAL_TYPES);
+
+ // consult the type flags
+ return (pTable->rgTypeFlags[uType] & HNDF_EXTRAINFO);
+}
+
+
+/*
+ * TableCanFreeSegmentNow
+ *
+ * Determines if it is OK to free the specified segment at this time.
+ *
+ */
+BOOL TableCanFreeSegmentNow(HandleTable *pTable, TableSegment *pSegment);
+
+
+/*
+ * BlockIsLocked
+ *
+ * Determines if the lock count for the specified block is currently non-zero.
+ *
+ */
+__inline BOOL BlockIsLocked(TableSegment *pSegment, uint32_t uBlock)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ // sanity
+ _ASSERTE(uBlock < HANDLE_BLOCKS_PER_SEGMENT);
+
+ // fetch the lock count and compare it to zero
+ return (pSegment->rgLocks[uBlock] != 0);
+}
+
+
+/*
+ * BlockLock
+ *
+ * Increases the lock count for a block.
+ *
+ */
+__inline void BlockLock(TableSegment *pSegment, uint32_t uBlock)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ // fetch the old lock count
+ uint8_t bLocks = pSegment->rgLocks[uBlock];
+
+ // assert if we are about to trash the count
+ _ASSERTE(bLocks < 0xFF);
+
+ // store the incremented lock count
+ pSegment->rgLocks[uBlock] = bLocks + 1;
+}
+
+
+/*
+ * BlockUnlock
+ *
+ * Decreases the lock count for a block.
+ *
+ */
+__inline void BlockUnlock(TableSegment *pSegment, uint32_t uBlock)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ // fetch the old lock count
+ uint8_t bLocks = pSegment->rgLocks[uBlock];
+
+ // assert if we are about to trash the count
+ _ASSERTE(bLocks > 0);
+
+ // store the decremented lock count
+ pSegment->rgLocks[uBlock] = bLocks - 1;
+}
+
+
+/*
+ * BlockFetchUserDataPointer
+ *
+ * Gets the user data pointer for the first handle in a block.
+ *
+ */
+PTR_uintptr_t BlockFetchUserDataPointer(PTR__TableSegmentHeader pSegment, uint32_t uBlock, BOOL fAssertOnError);
+
+
+/*
+ * HandleValidateAndFetchUserDataPointer
+ *
+ * Gets the user data pointer for a handle.
+ * ASSERTs and returns NULL if handle is not of the expected type.
+ *
+ */
+uintptr_t *HandleValidateAndFetchUserDataPointer(OBJECTHANDLE handle, uint32_t uTypeExpected);
+
+
+/*
+ * HandleQuickFetchUserDataPointer
+ *
+ * Gets the user data pointer for a handle.
+ * Less validation is performed.
+ *
+ */
+PTR_uintptr_t HandleQuickFetchUserDataPointer(OBJECTHANDLE handle);
+
+
+/*
+ * HandleQuickSetUserData
+ *
+ * Stores user data with a handle.
+ * Less validation is performed.
+ *
+ */
+void HandleQuickSetUserData(OBJECTHANDLE handle, uintptr_t lUserData);
+
+
+/*
+ * HandleFetchType
+ *
+ * Computes the type index for a given handle.
+ *
+ */
+uint32_t HandleFetchType(OBJECTHANDLE handle);
+
+
+/*
+ * HandleFetchHandleTable
+ *
+ * Returns the containing handle table of a given handle.
+ *
+ */
+PTR_HandleTable HandleFetchHandleTable(OBJECTHANDLE handle);
+
+
+/*
+ * SegmentAlloc
+ *
+ * Allocates a new segment.
+ *
+ */
+TableSegment *SegmentAlloc(HandleTable *pTable);
+
+
+/*
+ * SegmentFree
+ *
+ * Frees the specified segment.
+ *
+ */
+void SegmentFree(TableSegment *pSegment);
+
+/*
+ * TableHandleAsyncPinHandles
+ *
+ * Mark ready for all non-pending OverlappedData that get moved to default domain.
+ *
+ */
+BOOL TableHandleAsyncPinHandles(HandleTable *pTable);
+
+/*
+ * TableRelocateAsyncPinHandles
+ *
+ * Replaces async pin handles with ones in default domain.
+ *
+ */
+void TableRelocateAsyncPinHandles(HandleTable *pTable, HandleTable *pTargetTable);
+
+/*
+ * Check if a handle is part of a HandleTable
+ */
+BOOL TableContainHandle(HandleTable *pTable, OBJECTHANDLE handle);
+
+/*
+ * SegmentRemoveFreeBlocks
+ *
+ * Removes a block from a block list in a segment. The block is returned to
+ * the segment's free list.
+ *
+ */
+void SegmentRemoveFreeBlocks(TableSegment *pSegment, uint32_t uType);
+
+
+/*
+ * SegmentResortChains
+ *
+ * Sorts the block chains for optimal scanning order.
+ * Sorts the free list to combat fragmentation.
+ *
+ */
+void SegmentResortChains(TableSegment *pSegment);
+
+
+/*
+ * DoesSegmentNeedsToTrimExcessPages
+ *
+ * Checks to see if any pages can be decommitted from the segment.
+ *
+ */
+BOOL DoesSegmentNeedsToTrimExcessPages(TableSegment *pSegment);
+
+/*
+ * SegmentTrimExcessPages
+ *
+ * Checks to see if any pages can be decommitted from the segment.
+ * In case there any unused pages it goes and decommits them.
+ *
+ */
+void SegmentTrimExcessPages(TableSegment *pSegment);
+
+
+/*
+ * TableAllocBulkHandles
+ *
+ * Attempts to allocate the requested number of handes of the specified type.
+ *
+ * Returns the number of handles that were actually allocated. This is always
+ * the same as the number of handles requested except in out-of-memory conditions,
+ * in which case it is the number of handles that were successfully allocated.
+ *
+ */
+uint32_t TableAllocBulkHandles(HandleTable *pTable, uint32_t uType, OBJECTHANDLE *pHandleBase, uint32_t uCount);
+
+
+/*
+ * TableFreeBulkPreparedHandles
+ *
+ * Frees an array of handles of the specified type.
+ *
+ * This routine is optimized for a sorted array of handles but will accept any order.
+ *
+ */
+void TableFreeBulkPreparedHandles(HandleTable *pTable, uint32_t uType, OBJECTHANDLE *pHandleBase, uint32_t uCount);
+
+
+/*
+ * TableFreeBulkUnpreparedHandles
+ *
+ * Frees an array of handles of the specified type by preparing them and calling TableFreeBulkPreparedHandles.
+ *
+ */
+void TableFreeBulkUnpreparedHandles(HandleTable *pTable, uint32_t uType, const OBJECTHANDLE *pHandles, uint32_t uCount);
+
+/*--------------------------------------------------------------------------*/
+
+
+
+/****************************************************************************
+ *
+ * HANDLE CACHE
+ *
+ ****************************************************************************/
+
+/*
+ * TableAllocSingleHandleFromCache
+ *
+ * Gets a single handle of the specified type from the handle table by
+ * trying to fetch it from the reserve cache for that handle type. If the
+ * reserve cache is empty, this routine calls TableCacheMissOnAlloc.
+ *
+ */
+OBJECTHANDLE TableAllocSingleHandleFromCache(HandleTable *pTable, uint32_t uType);
+
+
+/*
+ * TableFreeSingleHandleToCache
+ *
+ * Returns a single handle of the specified type to the handle table
+ * by trying to store it in the free cache for that handle type. If the
+ * free cache is full, this routine calls TableCacheMissOnFree.
+ *
+ */
+void TableFreeSingleHandleToCache(HandleTable *pTable, uint32_t uType, OBJECTHANDLE handle);
+
+
+/*
+ * TableAllocHandlesFromCache
+ *
+ * Allocates multiple handles of the specified type by repeatedly
+ * calling TableAllocSingleHandleFromCache.
+ *
+ */
+uint32_t TableAllocHandlesFromCache(HandleTable *pTable, uint32_t uType, OBJECTHANDLE *pHandleBase, uint32_t uCount);
+
+
+/*
+ * TableFreeHandlesToCache
+ *
+ * Frees multiple handles of the specified type by repeatedly
+ * calling TableFreeSingleHandleToCache.
+ *
+ */
+void TableFreeHandlesToCache(HandleTable *pTable, uint32_t uType, const OBJECTHANDLE *pHandleBase, uint32_t uCount);
+
+/*--------------------------------------------------------------------------*/
+
+
+
+/****************************************************************************
+ *
+ * TABLE SCANNING
+ *
+ ****************************************************************************/
+
+/*
+ * TableScanHandles
+ *
+ * Implements the core handle scanning loop for a table.
+ *
+ */
+void CALLBACK TableScanHandles(PTR_HandleTable pTable,
+ const uint32_t *puType,
+ uint32_t uTypeCount,
+ SEGMENTITERATOR pfnSegmentIterator,
+ BLOCKSCANPROC pfnBlockHandler,
+ ScanCallbackInfo *pInfo,
+ CrstHolderWithState *pCrstHolder);
+
+
+/*
+ * xxxTableScanHandlesAsync
+ *
+ * Implements asynchronous handle scanning for a table.
+ *
+ */
+void CALLBACK xxxTableScanHandlesAsync(PTR_HandleTable pTable,
+ const uint32_t *puType,
+ uint32_t uTypeCount,
+ SEGMENTITERATOR pfnSegmentIterator,
+ BLOCKSCANPROC pfnBlockHandler,
+ ScanCallbackInfo *pInfo,
+ CrstHolderWithState *pCrstHolder);
+
+
+/*
+ * TypesRequireUserDataScanning
+ *
+ * Determines whether the set of types listed should get user data during scans
+ *
+ * if ALL types passed have user data then this function will enable user data support
+ * otherwise it will disable user data support
+ *
+ * IN OTHER WORDS, SCANNING WITH A MIX OF USER-DATA AND NON-USER-DATA TYPES IS NOT SUPPORTED
+ *
+ */
+BOOL TypesRequireUserDataScanning(HandleTable *pTable, const uint32_t *types, uint32_t typeCount);
+
+
+/*
+ * BuildAgeMask
+ *
+ * Builds an age mask to be used when examining/updating the write barrier.
+ *
+ */
+uint32_t BuildAgeMask(uint32_t uGen, uint32_t uMaxGen);
+
+
+/*
+ * QuickSegmentIterator
+ *
+ * Returns the next segment to be scanned in a scanning loop.
+ *
+ */
+PTR_TableSegment CALLBACK QuickSegmentIterator(PTR_HandleTable pTable, PTR_TableSegment pPrevSegment, CrstHolderWithState *pCrstHolder = 0);
+
+
+/*
+ * StandardSegmentIterator
+ *
+ * Returns the next segment to be scanned in a scanning loop.
+ *
+ * This iterator performs some maintenance on the segments,
+ * primarily making sure the block chains are sorted so that
+ * g0 scans are more likely to operate on contiguous blocks.
+ *
+ */
+PTR_TableSegment CALLBACK StandardSegmentIterator(PTR_HandleTable pTable, PTR_TableSegment pPrevSegment, CrstHolderWithState *pCrstHolder = 0);
+
+
+/*
+ * FullSegmentIterator
+ *
+ * Returns the next segment to be scanned in a scanning loop.
+ *
+ * This iterator performs full maintenance on the segments,
+ * including freeing those it notices are empty along the way.
+ *
+ */
+PTR_TableSegment CALLBACK FullSegmentIterator(PTR_HandleTable pTable, PTR_TableSegment pPrevSegment, CrstHolderWithState *pCrstHolder = 0);
+
+
+/*
+ * BlockScanBlocksWithoutUserData
+ *
+ * Calls the specified callback for each handle, optionally aging the corresponding generation clumps.
+ * NEVER propagates per-handle user data to the callback.
+ *
+ */
+void CALLBACK BlockScanBlocksWithoutUserData(PTR_TableSegment pSegment, uint32_t uBlock, uint32_t uCount, ScanCallbackInfo *pInfo);
+
+
+/*
+ * BlockScanBlocksWithUserData
+ *
+ * Calls the specified callback for each handle, optionally aging the corresponding generation clumps.
+ * ALWAYS propagates per-handle user data to the callback.
+ *
+ */
+void CALLBACK BlockScanBlocksWithUserData(PTR_TableSegment pSegment, uint32_t uBlock, uint32_t uCount, ScanCallbackInfo *pInfo);
+
+
+/*
+ * BlockScanBlocksEphemeral
+ *
+ * Calls the specified callback for each handle from the specified generation.
+ * Propagates per-handle user data to the callback if present.
+ *
+ */
+void CALLBACK BlockScanBlocksEphemeral(PTR_TableSegment pSegment, uint32_t uBlock, uint32_t uCount, ScanCallbackInfo *pInfo);
+
+
+/*
+ * BlockAgeBlocks
+ *
+ * Ages all clumps in a range of consecutive blocks.
+ *
+ */
+void CALLBACK BlockAgeBlocks(PTR_TableSegment pSegment, uint32_t uBlock, uint32_t uCount, ScanCallbackInfo *pInfo);
+
+
+/*
+ * BlockAgeBlocksEphemeral
+ *
+ * Ages all clumps within the specified generation.
+ *
+ */
+void CALLBACK BlockAgeBlocksEphemeral(PTR_TableSegment pSegment, uint32_t uBlock, uint32_t uCount, ScanCallbackInfo *pInfo);
+
+
+/*
+ * BlockResetAgeMapForBlocks
+ *
+ * Clears the age maps for a range of blocks.
+ *
+ */
+void CALLBACK BlockResetAgeMapForBlocks(PTR_TableSegment pSegment, uint32_t uBlock, uint32_t uCount, ScanCallbackInfo *pInfo);
+
+
+/*
+ * BlockVerifyAgeMapForBlocks
+ *
+ * Verifies the age maps for a range of blocks, and also validates the objects pointed to.
+ *
+ */
+void CALLBACK BlockVerifyAgeMapForBlocks(PTR_TableSegment pSegment, uint32_t uBlock, uint32_t uCount, ScanCallbackInfo *pInfo);
+
+
+/*
+ * xxxAsyncSegmentIterator
+ *
+ * Implements the core handle scanning loop for a table.
+ *
+ */
+PTR_TableSegment CALLBACK xxxAsyncSegmentIterator(PTR_HandleTable pTable, TableSegment *pPrevSegment, CrstHolderWithState *pCrstHolder);
+
+/*--------------------------------------------------------------------------*/