|
|
/*++
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
|