/*++ Copyright (c) 1998-1999 Microsoft Corporation Module Name: rm.h Abstract: "Resource Manager" structures and APIs Author: Revision History: Who When What -------- -------- ---- josephj 11-10-98 created --*/ //================================================================================= // O S - S P E C I F I C T Y P E S //================================================================================= #define RM_OS_LOCK NDIS_SPIN_LOCK #define OS_WORK_ITEM NDIS_WORK_ITEM #define OS_TIMER NDIS_TIMER #define RM_STATUS NDIS_STATUS #define RM_OS_FILL_MEMORY(_dest, _len, _fill) NdisFillMemory(_dest, _len, _fill) #define RM_OS_ZERO_MEMORY(_dest, _len) NdisZeroMemory(_dest, _len) #define RM_OS_GET_CURRENT_THREAD_HANDLE() NULL // If set, the object tree is explicitly maintained. // #define RM_TRACK_OBJECT_TREE 1 //================================================================================= // F O R W A R D R E F E R E N C E S //================================================================================= typedef struct _RM_STACK_RECORD RM_STACK_RECORD, *PRM_STACK_RECORD; typedef struct _RM_OBJECT_HEADER RM_OBJECT_HEADER, *PRM_OBJECT_HEADER; typedef struct _RM_TASK RM_TASK, *PRM_TASK; typedef struct _RM_RESOURCE_TABLE_ENTRY RM_RESOURCE_TABLE_ENTRY, *PRM_RESOURCE_TABLE_ENTRY; //================================================================================= // T Y P E D E F S //================================================================================= // // RM_DBG_LOCK_INFO Keeps debugging information specific to an instance of a RM_LOCK. // typedef struct _RM_DBG_LOCK_INFO { // // If nonzero, LocID is a magic number which uniquely identifies the source // location where the lock was aquired. // ULONG uLocID; // // pSR points to the stack record of the currently owning thread, if there // is one. If a function F expects an object pObj to be locked on entry, // it can ASSERT(pObj->pLock->pDbgInfo->pSR == pSR); // struct _RM_STACK_RECORD *pSR; } RM_DBG_LOCK_INFO, *PRM_DBG_LOCK_INFO; // // RM_LOCK keeps information about a lock. // typedef struct _RM_LOCK { // // Native, os-provided lock structure. // RM_OS_LOCK OsLock; // // Level of this lock. Multiple locks can only be acquired in increasing order // of this value. // ULONG Level; // // Pointer to debugging info for this lock. Could be NULL. // PRM_DBG_LOCK_INFO pDbgInfo; #if RM_EXTRA_CHECKING RM_DBG_LOCK_INFO DbgInfo; #endif // RM_EXTRA_CHECKING } RM_LOCK, *PRM_LOCK; typedef ULONG (*PFNLOCKVERIFIER) ( PRM_LOCK pLock, BOOLEAN fLock, PVOID pContext, PRM_STACK_RECORD pSR ); // RM_LOCKING_INFO keeps information about a particular lock being held. // In non-checking mode, this is just the pointer to the lock. // In checking mode, this additionally contains information that can be used // to verify that the entity being protected by the lock is not changed when // the lock is not being held. // typedef struct { PRM_LOCK pLock; #if RM_EXTRA_CHECKING PFNLOCKVERIFIER pfnVerifier; PVOID pVerifierContext; #endif // RM_EXTRA_CHECKING } RM_LOCKING_INFO, PRM_LOCKING_INFO; // // RM_STACK_RECORD keeps information relevant to the current call tree. // typedef struct _RM_STACK_RECORD { // // LockInfo contains information about currently-held locks. // struct { // // Level of the currently held lock. Locks must be claimed in // order of increasing Level values. The lowest level value is 1. Level // 0 indicates no locks held. // UINT CurrentLevel; // // Pointer to the first location to store a pointers to a locks. // PRM_LOCKING_INFO *pFirst; // // Pointer to the next free location to store a pointer to a lock // that has been claimed in this call tree. // PRM_LOCKING_INFO *pNextFree; // // Pointer to the last valid location to store a lock pointer. // PRM_LOCKING_INFO *pLast; } LockInfo; // // Count of tmp refs taken with this stack record. // ULONG TmpRefs; #if DBG // // DbgInfo contains diagnostic information relevant to this call tree. // struct { // // Verbosity level // ULONG Level; // // Points to the os-provided thread handle of the current thread. // if there is one. // PVOID pvThread; } DbgInfo; #endif // DBG } RM_STACK_RECORD, *PRM_STACK_RECORD; #if DBG #define RM_INIT_DBG_STACK_RECORD(_sr, _dbglevel) \ _sr.DbgInfo.Level = _dbglevel; \ _sr.DbgInfo.pvThread = RM_OS_GET_CURRENT_THREAD_HANDLE(); #else #define RM_INIT_DBG_STACK_RECORD(_sr, _dbglevel) #endif // // RM_DECLARE_STACK_RECORD_EX is a macro to reserve some stack space for // a stack record. // #define RM_DECLARE_STACK_RECORD_EX(_sr, _max_locks, _dbglevel) \ RM_LOCKING_INFO rm_lock_array[_max_locks]; \ RM_STACK_RECORD _sr; \ RM_OS_ZERO_MEMORY(rm_lock_array, sizeof(rm_lock_array)); \ _sr.TmpRefs = 0; \ _sr.LockInfo.CurrentLevel = 0; \ _sr.LockInfo.pFirst = rm_lock_array; \ _sr.LockInfo.pNextFree = rm_lock_array; \ _sr.LockInfo.pLast = rm_lock_array+(_max_locks)-1; \ RM_INIT_DBG_STACK_RECORD(_sr, _dbglevel); // // RM_DECLARE_STACK_RECORD is a macro to reserve default stack space for // a stack record. // #define RM_DECLARE_STACK_RECORD(_sr) \ RM_DECLARE_STACK_RECORD_EX(_sr, 4, 0) // // Generic memory allocator prototype // typedef PVOID (*PFN_RM_MEMORY_ALLOCATOR)( PVOID pAllocationContext, UINT Size // in bytes ); // // Generic memory deallocator prototype // typedef PVOID (*PFN_RM_MEMORY_DEALLOCATOR)( PVOID pMem, PVOID pAllocationContext ); // RM_HASH_LINK is the field in the structures being hashed that is // used to link all items in the same bucket. It also contains the // "HashKey", which is a potentially-nonunique UINT-sized hash of the // real key. // typedef struct _RM_HASH_LINK { struct _RM_HASH_LINK *pNext; UINT uHash; } RM_HASH_LINK, *PRM_HASH_LINK; // // Hash table comparison function. // typedef BOOLEAN (*PFN_RM_COMPARISON_FUNCTION)( PVOID pKey, PRM_HASH_LINK pItem ); // // Hash computation function. // typedef ULONG (*PFN_RM_HASH_FUNCTION)( PVOID pKey ); // // RM_HASH_INFO specifies customizing information about a hash table. // typedef struct { // Allocator used to allocate the hash table if it needs to grow. // PFN_RM_MEMORY_ALLOCATOR pfnTableAllocator; // Free function for the above allocator. PFN_RM_MEMORY_DEALLOCATOR pfnTableDeallocator; // Comparison function for strict equality. // PFN_RM_COMPARISON_FUNCTION pfnCompare; // Function to generate a ULONG-sized hash. // PFN_RM_HASH_FUNCTION pfnHash; #if OBSOLETE // Offset in sizeof(UINT) to location of the place to keep // the next pointer for the bucket list. // UINT OffsetNext; // Offset in sizeof(UINT) to location of UINT-sized Temp ref // UINT OffsetTmpRef; // Offset in sizeof(UINT) to location of UINT-sized Tot ref // UINT OffsetTotRef; // Offset in sizeof(UINT) to location of ULONG-sized hash key. // UINT OffsetHashKey; #endif // OBSOLETE } RM_HASH_INFO, *PRM_HASH_INFO; #define RM_MIN_HASH_TABLE_SIZE 4 // // RM_HASH_TABLE is a hash table. // typedef struct { // Number of items currently in hash table. // UINT NumItems; // Stats is a 32-bit quantity keeps a running total of number of accesses // (add+search+remove) in the HIWORD and the total number of list nodes // traversed in the LOWORD. This field gets updated even on searches, but // it is not protected by the hash table lock -- instead it is // updated using an interlocked operation. This allows us to use // a read lock for searches while still updating this statistic value. // The Stats field is re-scaled when the counts get too high, to avoid // overflow and also to favor more recent stats in preference to older // stats. // // NumItems, Stats and TableLength are used to decide whether to // dynamically resize the hash table. // ULONG Stats; // Length of hash table in units of PVOID // ULONG TableLength; // Pointer to TableLength-sized array of PVOIDs -- this is the actual hash table // PRM_HASH_LINK *pTable; // The hash table // PRM_HASH_LINK InitialTable[RM_MIN_HASH_TABLE_SIZE]; // Static information about this hash table. // PRM_HASH_INFO pHashInfo; // Passed into the allocate/deallocate functions. // PVOID pAllocationContext; } RM_HASH_TABLE, *PRM_HASH_TABLE; // Returns approximate value of (num-nodes-traversed)/(num-accesses) // #define RM_HASH_TABLE_TRAVERSE_RATIO(_pHash_Table) \ (((_pHash_Table)->Stats & 0xffff) / (1+((_pHash_Table)->Stats >> 16))) // // NOTE: the "1+" above is simply to guard against devide-by-zero. // // RM_OBJECT_DIAGNOSTIC_INFO keeps diagnostic info specific to an instance of // an object. // // This structure is for private use of the RM APIs. // The only field of general interest is PrevState. // typedef struct { // Back pointer to owning object. // RM_OBJECT_HEADER *pOwningObject; // Each time the object-specific State field is updated, it's previous // value is saved here. // ULONG PrevState; // Used for correctly updating PrevState. // ULONG TmpState; // Diagnostic-related state. // ULONG DiagState; #define fRM_PRIVATE_DISABLE_LOCK_CHECKING (0x1<<0) // This is an object-specific checksum that is computed and // saved just before the object is unlocked. It is checked // just after the object is locked. // ULONG Checksum; // Native OS lock to be *only* to serialize access to the information // in this structure. // RM_OS_LOCK OsLock; // Keeps an associative list of all entities which have been registered // (using RmDbgAddAssociation) with this object. Ths includes objects which // have been linked to this object using the RmLinkObjects call, as well // as childen and parents of this object. // RM_HASH_TABLE AssociationTable; // Following is set to TRUE IFF there was an allocation failure when trying to // add an association. If there'e been an allocation failure, we don't complain // (i.e. ASSERT) if an attempt is made to remove an assertion that doesn't // exist. In this way we gracefully deal with allocation failures of the // association table entries. // INT AssociationTableAllocationFailure; // The per-object list of log entries. // This is serialized by the global rm lock, not the local rm-private lock! // LIST_ENTRY listObjectLog; // Count of entries in this object's log. // This is serialized by the global rm lock, not the local rm-private lock! // UINT NumObjectLogEntries; #if TODO // We haven't implemented the following yet... // Future: // RM_STATE_HISTORY -- generalization of PrevState. #endif // TODO } RM_OBJECT_DIAGNOSTIC_INFO, *PRM_OBJECT_DIAGNOSTIC_INFO; typedef PRM_OBJECT_HEADER (*PFN_CREATE_OBJECT)( PRM_OBJECT_HEADER pParentObject, PVOID pCreateParams, PRM_STACK_RECORD psr ); typedef VOID (*PFN_DELETE_OBJECT)(PRM_OBJECT_HEADER, PRM_STACK_RECORD psr); // // RM_STATIC_OBJECT_INFO keeps information that is common to all instances of // a particular type of object. // typedef struct { ULONG TypeUID; ULONG TypeFlags; char* szTypeName; UINT Timeout; // // Various Handlers // PFN_CREATE_OBJECT pfnCreate; PFN_DELETE_OBJECT pfnDelete; PFNLOCKVERIFIER pfnLockVerifier; // // Resource Information // UINT NumResourceTableEntries; struct _RM_RESOURCE_TABLE_ENTRY * pResourceTable; // // Hash-table info, if this object is part of a group. // PRM_HASH_INFO pHashInfo; } RM_STATIC_OBJECT_INFO, *PRM_STATIC_OBJECT_INFO; // // RM_OBJECT_HEADER is the common header for all objects. // typedef struct _RM_OBJECT_HEADER { // // Object-type-specific signature. // ULONG Sig; // // Description of this object (could be the same as pStaticInfo->szTypeName, // but may be something more specific). // Used only for debugging purposes. // TODO: consider moving this into the pDiagInfo struct. For now, leave it // here because it's useful when debugging. // const char *szDescription; // // Object-specific state. // ULONG State; ULONG RmState; // One or more RMOBJSTATE_* or RMTSKSTATE_* flags below... // // RM state flags.... // // Object allocation state... // #define RMOBJSTATE_ALLOCMASK 0x00f #define RMOBJSTATE_ALLOCATED 0x001 #define RMOBJSTATE_DEALLOCATED 0x000 // Task state ... // #define RMTSKSTATE_MASK 0x0f0 #define RMTSKSTATE_IDLE 0x000 #define RMTSKSTATE_STARTING 0x010 #define RMTSKSTATE_ACTIVE 0x020 #define RMTSKSTATE_PENDING 0x030 #define RMTSKSTATE_ENDING 0x040 // Task delay state // #define RMTSKDELSTATE_MASK 0x100 #define RMTSKDELSTATE_DELAYED 0x100 // Task abort state // #define RMTSKABORTSTATE_MASK 0x200 #define RMTSKABORTSTATE_ABORT_DELAY 0x200 // // Bitmap identifying resources used by this object. // ULONG ResourceMap; // Total reference count. // // ULONG TotRefs; // // Pointer to a RM_LOCK object used to serialize access to this object. // PRM_LOCK pLock; // // Pointer to information common to all instances of this object type. // PRM_STATIC_OBJECT_INFO pStaticInfo; // // Points to diagnostic information about this object. Could be NULL. // PRM_OBJECT_DIAGNOSTIC_INFO pDiagInfo; // // Points to the parent object. // struct _RM_OBJECT_HEADER *pParentObject; // // Points to the root (ancestor of all object) -- could be the same // as pParentObject; // struct _RM_OBJECT_HEADER *pRootObject; // // This is a private lock used exclusively by the RM apis. It is // never left unlocked by the RM apis. // TODO: maybe make this a native-os lock. // RM_LOCK RmPrivateLock; // Used to create groups of objects. // TODO: make this a private field, present only if the object is // meant to be in a group. // RM_HASH_LINK HashLink; #if RM_TRACK_OBJECT_TREE LIST_ENTRY listChildren; // Protected by this object's RmPrivateLock. LIST_ENTRY linkSiblings; // Protected by parent object's RmPrivateLock. #endif // RM_TRACK_OBJECT_TREE ULONG TempRefs; } RM_OBJECT_HEADER, *PRM_OBJECT_HEADER; // // Diagnostic resource tracking. // typedef struct { ULONG_PTR Instance; ULONG TypeUID; PRM_OBJECT_HEADER pParentObject; ULONG CallersUID; ULONG CallersSrUID; } RM_DBG_RESOURCE_ENTRY; typedef enum { RM_RESOURCE_OP_LOAD, RM_RESOURCE_OP_UNLOAD } RM_RESOURCE_OPERATION; typedef RM_STATUS (*PFN_RM_RESOURCE_HANDLER)( PRM_OBJECT_HEADER pObj, RM_RESOURCE_OPERATION Op, PVOID pvUserParams, PRM_STACK_RECORD psr ); typedef struct _RM_RESOURCE_TABLE_ENTRY { UINT ID; PFN_RM_RESOURCE_HANDLER pfnHandler; } RM_RESOURCE_TABLE_ENTRY, *PRM_RESOURCE_TABLE_ENTRY; typedef struct { UINT u; } RM_OBJECT_INDEX, *PRM_OBJECT_INDEX; typedef struct { PRM_OBJECT_HEADER pOwningObject; const char * szDescription; PRM_STATIC_OBJECT_INFO pStaticInfo; RM_HASH_TABLE HashTable; // Private lock used ONLY by group access functions. // RM_OS_LOCK OsLock; // When non-NULL, points to the task responsible for unloading all objects // in this group. // PRM_TASK pUnloadTask; BOOLEAN fEnabled; } RM_GROUP, *PRM_GROUP; typedef enum { RM_TASKOP_START, RM_TASKOP_PENDCOMPLETE, RM_TASKOP_END, RM_TASKOP_PRIVATE, RM_TASKOP_ABORT, RM_TASKOP_TIMEOUT } RM_TASK_OPERATION; typedef RM_STATUS (*PFN_RM_TASK_HANDLER)( IN struct _RM_TASK * pTask, IN RM_TASK_OPERATION Op, IN UINT_PTR UserParam, IN PRM_STACK_RECORD pSR ); // // For START and PENDCOMPLETE, a return value other than PENDING causes // the task to end. Of course, it is illegal to return non-pending when // the task is in a pending state. // // Task allocator prototype // typedef RM_STATUS (*PFN_RM_TASK_ALLOCATOR)( IN PRM_OBJECT_HEADER pParentObject, IN PFN_RM_TASK_HANDLER pfnHandler, IN UINT Timeout, IN const char * szDescription, OUT PRM_TASK *ppTask, IN PRM_STACK_RECORD pSR ); typedef struct _RM_TASK { RM_OBJECT_HEADER Hdr; PFN_RM_TASK_HANDLER pfnHandler; LIST_ENTRY linkFellowPendingTasks; LIST_ENTRY listTasksPendingOnMe; struct _RM_TASK * pTaskIAmPendingOn; // In the case that we need to asynchronously notify the completion of a // pending operation, we can save the completion param here. // UINT_PTR AsyncCompletionParam; UINT SuspendContext; } RM_TASK, *PRM_TASK; typedef VOID (*PFN_DBG_DUMP_LOG_ENTRY) ( char *szFormatString, UINT_PTR Param1, UINT_PTR Param2, UINT_PTR Param3, UINT_PTR Param4 ); #if RM_EXTRA_CHECKING // (For debugging only) // Keeps track of a single association (See RmDbgAddAssociation) // This is a PRIVATE data structure, and is only here because // the kd extension refers to it. // typedef struct { ULONG LocID; ULONG_PTR Entity1; ULONG_PTR Entity2; ULONG AssociationID; const char * szFormatString; RM_HASH_LINK HashLink; } RM_PRIVATE_DBG_ASSOCIATION; // (For debugging only) // Keeps track of a single per-object log entry. // This is a PRIVATE data structure, and is only here because // the kd extension refers to it. // typedef struct { // Link to other entries for this object // LIST_ENTRY linkObjectLog; // Link to other entries in the global list. // LIST_ENTRY linkGlobalLog; // Object this entry belongs to // PRM_OBJECT_HEADER pObject; // Function to be used for dumping the log. // PFN_DBG_DUMP_LOG_ENTRY pfnDumpEntry; // Prefix string to be dumped *before* the log display. // This was added so we could log associations properly, otherwise it's // extra baggage. Can be null. // char *szPrefix; // Format string for log display -- 1st arg to pfnDumpEntry // char *szFormatString; // Remaining args to pfnDumpEntry; // // UINT_PTR Param1; UINT_PTR Param2; UINT_PTR Param3; UINT_PTR Param4; // If non-NULL, piece of memory to be freed when the log entry is freed. // TODO: See notes.txt entry "03/07/1999 ... Registering root objects with RM" // on how we will find the deallocator function. For now we simply // use NdisFreeMemory. // PVOID pvBuf; } RM_DBG_LOG_ENTRY; #endif RM_EXTRA_CHECKING //================================================================================= // U T I L I T Y M A C R O S //================================================================================= #define RM_PARENT_OBJECT(_pObj) \ ((_pObj)->Hdr.pParentObject) #define RM_PEND_CODE(_pTask) \ ((_pTask)->SuspendContext) #define RM_ASSERT_SAME_LOCK_AS_PARENT(_pObj) \ ASSERTEX( \ ((_pObj)->Hdr.pLock == (_pObj)->Hdr.pParentObject->pLock), \ (_pObj)) #define RM_SET_STATE(_pObj, _Mask, _Val) \ (((_pObj)->Hdr.State) = (((_pObj)->Hdr.State) & ~(_Mask)) | (_Val)) #define RM_CHECK_STATE(_pObj, _Mask, _Val) \ ((((_pObj)->Hdr.State) & (_Mask)) == (_Val)) #define RM_GET_STATE(_pObj, _Mask) \ (((_pObj)->Hdr.State) & (_Mask)) // Asserts that the object is in the "zombie" state, i.e., it // lives on just because of references. // WARNING: It is upto the caller to synchronize access to this -- for example // if they're going to do thing's like if (!RM_IS_ZOMBIE(pObj)) {do-stuff}, they // had better make sure that only one of them goes on to "does-stuff". // #define RM_IS_ZOMBIE(_pobj) \ (((_pobj)->Hdr.RmState&RMOBJSTATE_ALLOCMASK)==RMOBJSTATE_DEALLOCATED) // Asserts that no locks are held. // #define RM_ASSERT_NOLOCKS(_psr) \ ASSERTEX((_psr)->LockInfo.CurrentLevel == 0, (_psr)) // Assert that no locks or tmprefs are held. // #define RM_ASSERT_CLEAR(_psr) \ ASSERTEX(((_psr)->LockInfo.CurrentLevel==0), (_psr)); \ ASSERTEX((_psr)->TmpRefs==0, (_psr)); #if RM_EXTRA_CHECKING // // TODO: rename the following to something better... // #define RM_DBG_ASSERT_LOCKED0(_pLk, _pSR) \ ASSERTEX((_pLk)->DbgInfo.pSR == (_pSR), (_pHdr)) // TODO -- replace calls to this by calls to RM_ASSERT_OBJLOCKED #define RM_DBG_ASSERT_LOCKED(_pHdr, _pSR) \ ASSERTEX((_pHdr)->pLock->DbgInfo.pSR == (_pSR), (_pHdr)) #define RM_ASSERT_OBJLOCKED(_pHdr, _pSR) \ ASSERTEX((_pHdr)->pLock->DbgInfo.pSR == (_pSR), (_pHdr)) // Note that we can't assume DbgInfo.pSR is NULL below (it could be locked // by some other thread), but we CAN assert that DbgInfo.pSR is not equal to the // current pSR! // #define RM_ASSERT_OBJUNLOCKED(_pHdr, _pSR) \ ASSERTEX((_pHdr)->pLock->DbgInfo.pSR != (_pSR), (_pHdr)) #else // !RM_EXTRA_CHECKING #define RM_DBG_ASSERT_LOCKED0(_pLk, _pSR) (0) #define RM_DBG_ASSERT_LOCKED(_pHdr, _pSR) (0) #define RM_ASSERT_OBJLOCKED(_pHdr, _pSR) (0) #define RM_ASSERT_OBJUNLOCKED(_pHdr, _pSR) (0) #endif // !RM_EXTRA_CHECKING #define RM_NUM_ITEMS_IN_GROUP(_pGroup) \ ((_pGroup)->HashTable.NumItems) //================================================================================= // F U N C T I O N P R O T O T Y P E S //================================================================================= VOID RmInitializeRm(VOID); VOID RmDeinitializeRm(VOID); VOID RmInitializeHeader( IN PRM_OBJECT_HEADER pParentObject, IN PRM_OBJECT_HEADER pObject, IN UINT Sig, IN PRM_LOCK pLock, IN PRM_STATIC_OBJECT_INFO pStaticInfo, IN const char * szDescription, IN PRM_STACK_RECORD pSR ); // // Object allocation and deallocation APIs // VOID RmDeallocateObject( IN PRM_OBJECT_HEADER pObject, IN PRM_STACK_RECORD pSR ); // // locking // VOID RmInitializeLock( IN PRM_LOCK pLock, IN UINT Level ); VOID RmDoWriteLock( PRM_LOCK pLock, PRM_STACK_RECORD pSR ); #if TODO VOID RmDoReadLock( IN PRM_OBJECT_HEADER pObj, IN PRM_STACK_RECORD pSR ); #else //!TODO #define RmDoReadLock RmDoWriteLock #endif //!TODO VOID RmDoUnlock( PRM_LOCK pLock, PRM_STACK_RECORD pSR ); #if TODO VOID RmReadLockObject( IN PRM_OBJECT_HEADER pObj, #if RM_EXTRA_CHECKING UINT uLocID, #endif //RM_EXTRA_CHECKING IN PRM_STACK_RECORD pSR ); #else //!TODO #define RmReadLockObject RmWriteLockObject #endif //!TODO VOID RmWriteLockObject( IN PRM_OBJECT_HEADER pObj, #if RM_EXTRA_CHECKING UINT uLocID, #endif //RM_EXTRA_CHECKING IN PRM_STACK_RECORD pSR ); VOID RmUnlockObject( IN PRM_OBJECT_HEADER pObj, IN PRM_STACK_RECORD pSR ); VOID RmUnlockAll( IN PRM_STACK_RECORD pSR ); VOID RmDbgChangeLockScope( IN PRM_OBJECT_HEADER pPreviouslyLockedObject, IN PRM_OBJECT_HEADER pObject, IN ULONG LocID, IN PRM_STACK_RECORD ); // // reference counting // VOID RmLinkObjects( IN PRM_OBJECT_HEADER pObj1, IN PRM_OBJECT_HEADER pObj2, IN PRM_STACK_RECORD pSr ); VOID RmUnlinkObjects( IN PRM_OBJECT_HEADER pObj1, IN PRM_OBJECT_HEADER pObj2, IN PRM_STACK_RECORD pSr ); VOID RmLinkObjectsEx( IN PRM_OBJECT_HEADER pObj1, IN PRM_OBJECT_HEADER pObj2, IN ULONG LocID, IN ULONG AssocID, IN const char * szAssociationFormat, IN ULONG InvAssocID, IN const char * szInvAssociationFormat, IN PRM_STACK_RECORD pSR ); VOID RmUnlinkObjectsEx( IN PRM_OBJECT_HEADER pObj1, IN PRM_OBJECT_HEADER pObj2, IN ULONG LocID, IN ULONG AssocID, IN ULONG InvAssocID, IN PRM_STACK_RECORD pSR ); VOID RmLinkToExternalEx( IN PRM_OBJECT_HEADER pObj, IN ULONG LocID, IN UINT_PTR ExternalEntity, IN ULONG AssocID, IN const char * szAssociationFormat, IN PRM_STACK_RECORD pSR ); VOID RmUnlinkFromExternalEx( IN PRM_OBJECT_HEADER pObj, IN ULONG LocID, IN UINT_PTR ExternalEntity, IN ULONG AssocID, IN PRM_STACK_RECORD pSR ); VOID RmLinkToExternalFast( // TODO make inline IN PRM_OBJECT_HEADER pObj ); VOID RmUnlinkFromExternalFast( // TODO make inline IN PRM_OBJECT_HEADER pObj ); VOID RmTmpReferenceObject( IN PRM_OBJECT_HEADER pObj, IN PRM_STACK_RECORD pSR ); VOID RmTmpDereferenceObject( IN PRM_OBJECT_HEADER pObj, IN PRM_STACK_RECORD pSR ); // // Generic resource management // RM_STATUS RmLoadGenericResource( IN PRM_OBJECT_HEADER pObj, IN UINT GenericResourceID, IN PRM_STACK_RECORD pSR ); VOID RmUnloadGenericResource( IN PRM_OBJECT_HEADER pObj, IN UINT GenericResourceID, IN PRM_STACK_RECORD pSR ); VOID RmUnloadAllGenericResources( IN PRM_OBJECT_HEADER pObj, IN PRM_STACK_RECORD pSR ); // // Diagnostic per-object tracking of arbitrary "associations" // // // NOTE: AssociationID must not have the high-bit set. Associations with the // high bit set are reserved for internal use of the Rm API implementation. // VOID RmDbgAddAssociation( IN ULONG LocID, IN PRM_OBJECT_HEADER pObject, IN ULONG_PTR Instance1, IN ULONG_PTR Instance2, IN ULONG AssociationID, IN const char * szFormatString, OPTIONAL IN PRM_STACK_RECORD pSR ); VOID RmDbgDeleteAssociation( IN ULONG LocID, IN PRM_OBJECT_HEADER pObject, IN ULONG_PTR Entity1, IN ULONG_PTR Entity2, IN ULONG AssociationID, IN PRM_STACK_RECORD pSR ); VOID RmDbgPrintAssociations( IN PRM_OBJECT_HEADER pObject, IN PRM_STACK_RECORD pSR ); // // Diagnostic per-object logging. // VOID RmDbgLogToObject( IN PRM_OBJECT_HEADER pObject, IN char * szPrefix, OPTIONAL IN char * szFormatString, IN UINT_PTR Param1, IN UINT_PTR Param2, IN UINT_PTR Param3, IN UINT_PTR Param4, IN PFN_DBG_DUMP_LOG_ENTRY pfnDumpEntry, OPTIONAL IN PVOID pvBuf OPTIONAL ); VOID RmDbgPrintObjectLog( IN PRM_OBJECT_HEADER pObject ); VOID RmDbgPrintGlobalLog(VOID); // // Groups of Objects // VOID RmInitializeGroup( IN PRM_OBJECT_HEADER pOwningObject, IN PRM_STATIC_OBJECT_INFO pStaticInfo, IN PRM_GROUP pGroup, IN const char* szDescription, IN PRM_STACK_RECORD pSR ); VOID RmDeinitializeGroup( IN PRM_GROUP pGroup, IN PRM_STACK_RECORD pSR ); RM_STATUS RmLookupObjectInGroup( IN PRM_GROUP pGroup, IN ULONG Flags, // Lookup flags defined below IN PVOID pvKey, IN PVOID pvCreateParams, OUT PRM_OBJECT_HEADER * ppObject, OUT INT * pfCreated, IN PRM_STACK_RECORD pSR ); // // Lookup flags // #define RM_CREATE 0x1 #define RM_NEW (0x1<<1) #define RM_LOCKED (0x1<<2) #define RM_CREATE_AND_LOCK_OBJECT_IN_GROUP(_pGrp, _pKey, _pParams, _ppHdr, _fC,_psr)\ RmLookupObjectInGroup( \ (_pGrp), \ RM_CREATE|RM_NEW|RM_LOCKED, \ (_pKey), \ (_pParams), \ (_ppHdr), \ (_fC), \ (_psr) \ ); // RM_STATUS // RM_LOOKUP_AND_LOCK_OBJECT_IN_GROUP( // PRM_GROUP _pGrp, // PVOID _pKey, // PRM_OBJECT_HEADER * _ppHdr, // PRM_STACK_RECORD _psr // ) // Lookup (don't create) and lock an object in the specified group. // #define RM_LOOKUP_AND_LOCK_OBJECT_IN_GROUP(_pGrp, _pKey, _ppHdr, _psr) \ RmLookupObjectInGroup( \ (_pGrp), \ RM_LOCKED, \ (_pKey), \ NULL, \ (_ppHdr), \ NULL, \ (_psr) \ ); RM_STATUS RmGetNextObjectInGroup( IN PRM_GROUP pGroup, IN PRM_OBJECT_HEADER pCurrentObject, OPTIONAL OUT PRM_OBJECT_HEADER * ppNextObject, IN PRM_STACK_RECORD pSR ); VOID RmFreeObjectInGroup( IN PRM_GROUP pGroup, IN PRM_OBJECT_HEADER pObject, IN struct _RM_TASK *pTask, OPTIONAL IN PRM_STACK_RECORD pSR ); VOID RmFreeAllObjectsInGroup( IN PRM_GROUP pGroup, IN struct _RM_TASK *pTask, OPTIONAL IN PRM_STACK_RECORD pSR ); VOID RmUnloadAllObjectsInGroup( IN PRM_GROUP pGroup, PFN_RM_TASK_ALLOCATOR pfnUnloadTaskAllocator, PFN_RM_TASK_HANDLER pfnUnloadTaskHandler, PVOID pvUserParam, IN struct _RM_TASK *pTask, OPTIONAL IN UINT uTaskPendCode, OPTIONAL IN PRM_STACK_RECORD pSR ); VOID RmEnableGroup( IN PRM_GROUP pGroup, IN PRM_STACK_RECORD pSR ); // Enumeration function prototype. This function is passed into // RmEnumerateObjectsInGroup and gets called for each object in the group // until the function returns FALSE. // typedef INT (*PFN_RM_GROUP_ENUMERATOR) ( PRM_OBJECT_HEADER pHdr, PVOID pvContext, PRM_STACK_RECORD pSR ); VOID RmEnumerateObjectsInGroup( PRM_GROUP pGroup, PFN_RM_GROUP_ENUMERATOR pfnFunction, PVOID pvContext, INT fStrong, PRM_STACK_RECORD pSR ); VOID RmWeakEnumerateObjectsInGroup( PRM_GROUP pGroup, PFN_RM_GROUP_ENUMERATOR pfnFunction, PVOID pvContext, PRM_STACK_RECORD pSR ); // // Task APIs // VOID RmInitializeTask( IN PRM_TASK pTask, IN PRM_OBJECT_HEADER pParentObject, IN PFN_RM_TASK_HANDLER pfnHandler, IN PRM_STATIC_OBJECT_INFO pStaticInfo, OPTIONAL IN const char * szDescription, OPTIONAL IN UINT Timeout, IN PRM_STACK_RECORD pSR ); RM_STATUS RmStartTask( IN PRM_TASK pTask, IN UINT_PTR UserParam, IN PRM_STACK_RECORD pSR ); VOID RmAbortTask( IN PRM_TASK pTask, IN PRM_STACK_RECORD pSR ); VOID RmDbgDumpTask( IN PRM_TASK pTask, IN PRM_STACK_RECORD pSR ); RM_STATUS RmSuspendTask( IN PRM_TASK pTask, IN UINT SuspendContext, IN PRM_STACK_RECORD pSR ); VOID RmUnsuspendTask( IN PRM_TASK pTask, IN PRM_STACK_RECORD pSR ); VOID RmResumeTask( IN PRM_TASK pTask, IN UINT_PTR SuspendCompletionParam, IN PRM_STACK_RECORD pSR ); VOID RmResumeTaskAsync( IN PRM_TASK pTask, IN UINT_PTR SuspendCompletionParam, IN OS_WORK_ITEM * pOsWorkItem, IN PRM_STACK_RECORD pSR ); VOID RmResumeTaskDelayed( IN PRM_TASK pTask, IN UINT_PTR SuspendCompletionParam, IN ULONG MsDelay, IN OS_TIMER * pOsTimerObject, IN PRM_STACK_RECORD pSR ); VOID RmResumeDelayedTaskNow( IN PRM_TASK pTask, IN OS_TIMER * pOsTimer, OUT PUINT pTaskResumed, IN PRM_STACK_RECORD pSR ); RM_STATUS RmPendTaskOnOtherTask( IN PRM_TASK pTask, IN UINT SuspendContext, IN PRM_TASK pOtherTask, IN PRM_STACK_RECORD pSR ); // See 03/26/1999 notes.txt entry "Some proposed ..." // RM_STATUS RmPendOnOtherTaskV2( IN PRM_TASK pTask, IN UINT SuspendContext, IN PRM_TASK pOtherTask, IN PRM_STACK_RECORD pSR ); VOID RmCancelPendOnOtherTask( IN PRM_TASK pTask, IN PRM_TASK pOtherTask, IN UINT_PTR UserParam, IN PRM_STACK_RECORD pSR ); // // Timer management // VOID RmResetAgeingTimer( IN PRM_OBJECT_HEADER pObj, IN UINT Timeout, IN PRM_STACK_RECORD pSR ); // // Hash table manipulation. // VOID RmInitializeHashTable( PRM_HASH_INFO pHashInfo, PVOID pAllocationContext, PRM_HASH_TABLE pHashTable ); VOID RmDeinitializeHashTable( PRM_HASH_TABLE pHashTable ); BOOLEAN RmLookupHashTable( PRM_HASH_TABLE pHashTable, PRM_HASH_LINK ** pppLink, PVOID pvRealKey ); BOOLEAN RmNextHashTableItem( PRM_HASH_TABLE pHashTable, PRM_HASH_LINK pCurrentLink, // OPTIONAL PRM_HASH_LINK * ppNextLink ); VOID RmAddHashItem( PRM_HASH_TABLE pHashTable, PRM_HASH_LINK * ppLink, PRM_HASH_LINK pLink, PVOID pvKey ); VOID RmRemoveHashItem( PRM_HASH_TABLE pHashTable, PRM_HASH_LINK pLinkToRemove ); typedef VOID (*PFN_ENUM_HASH_TABLE) ( PRM_HASH_LINK pLink, PVOID pvContext, PRM_STACK_RECORD pSR ); VOID RmEnumHashTable( PRM_HASH_TABLE pHashTable, PFN_ENUM_HASH_TABLE pfnEnumerator, PVOID pvContext, PRM_STACK_RECORD pSR ); #if OBSOLETE // // Indexes of objects. // RM_STATUS RmAllocateObjectIndex( IN PRM_OBJECT_HEADER pParentObject, // OBSOLETE IN PRM_OBJECT_ALLOCATOR pObjectAllocator, IN PRM_STATIC_OBJECT_INFO pStaticInfo, IN PULONG Flags, OUT PRM_OBJECT_INDEX * ppObjectIndex, IN PRM_STACK_RECORD pSR ); VOID RmFreeObjectIndex( IN PRM_OBJECT_INDEX pObjectIndex, IN PRM_STACK_RECORD pSR ); RM_STATUS RmLookupObjectInIndex( IN PRM_OBJECT_INDEX pObjectIndex, IN PULONG Flags, // create, remove, lock IN PVOID pvKey, OUT PRM_OBJECT_HEADER * ppObject, IN PRM_STACK_RECORD pSR ); RM_STATUS RmRemoveObjectFromIndex( IN PRM_OBJECT_INDEX pObjectIndex, IN PRM_OBJECT_HEADER pObject, IN PRM_STACK_RECORD pSR ); typedef RM_STATUS (*PFN_RM_OBJECT_INDEX_ENUMERATOR)( IN PRM_OBJECT_HEADER pObject, IN PVOID pvContext, IN PRM_STACK_RECORD pSR ); RmEnumerateObjectsInIndex( IN PRM_OBJECT_INDEX pObjectIndex, IN PFN_RM_OBJECT_INDEX_ENUMERATOR pfnEnumerator, IN PRM_STACK_RECORD pSR ); #endif // OBSOLETE