You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1342 lines
32 KiB
1342 lines
32 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
objmgr.c
|
|
|
|
Abstract:
|
|
|
|
Object Manager object management routines for the NT Cluster Service
|
|
|
|
Author:
|
|
|
|
Rod Gamache (rodga) 13-Mar-1996
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#include "omp.h"
|
|
|
|
//
|
|
// Global data defined by this module
|
|
//
|
|
|
|
//
|
|
// The Object Type table and lock.
|
|
//
|
|
POM_OBJECT_TYPE OmpObjectTypeTable[ObjectTypeMax] = {0};
|
|
CRITICAL_SECTION OmpObjectTypeLock;
|
|
|
|
#if OM_TRACE_REF
|
|
LIST_ENTRY gDeadListHead;
|
|
#endif
|
|
//
|
|
// Functions local to this module
|
|
//
|
|
|
|
#if OM_TRACE_OBJREF
|
|
DWORDLONG *OmpMatchRef = NULL;
|
|
|
|
VOID
|
|
OmpReferenceHeader(
|
|
POM_HEADER pOmHeader
|
|
)
|
|
{
|
|
InterlockedIncrement(&(pOmHeader)->RefCount);
|
|
if (&(pOmHeader)->Body == OmpMatchRef) {
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[OM] Referencing %1!lx! - new ref %2!d!\n",
|
|
OmpMatchRef,
|
|
(pOmHeader)->RefCount);
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
OmpDereferenceHeader(
|
|
IN POM_HEADER Header
|
|
)
|
|
{
|
|
if (&Header->Body == OmpMatchRef) {
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[OM] Dereferencing %1!lx! - old ref %2!d!\n",
|
|
OmpMatchRef,
|
|
Header->RefCount);
|
|
}
|
|
return(InterlockedDecrement(&Header->RefCount) == 0);
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
OmCreateType(
|
|
IN OBJECT_TYPE ObjectType,
|
|
IN POM_OBJECT_TYPE_INITIALIZE ObjectTypeInitialize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates an object of the type specified. This merely
|
|
allocates an object type structure, and inserts a pointer to this
|
|
structure into the OmpObjectTypeTable.
|
|
|
|
Arguments:
|
|
ObjectType - The Object Type being created.
|
|
ObjectTypeIntialize - The initialization info.
|
|
|
|
Returns:
|
|
ERROR_SUCCESS if the request is successful.
|
|
A Win32 error code on failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
POM_OBJECT_TYPE objType;
|
|
DWORD objTypeSize;
|
|
|
|
CL_ASSERT( ObjectType < ObjectTypeMax );
|
|
CL_ASSERT( ARGUMENT_PRESENT(ObjectTypeInitialize) );
|
|
CL_ASSERT( ObjectTypeInitialize->ObjectSize );
|
|
|
|
//
|
|
// Take out a lock, just in case there can be multiple threads.
|
|
//
|
|
|
|
EnterCriticalSection( &OmpObjectTypeLock );
|
|
|
|
//
|
|
// Check if this ObjectType is already allocated.
|
|
//
|
|
|
|
if ( OmpObjectTypeTable[ObjectType] != NULL ) {
|
|
LeaveCriticalSection( &OmpObjectTypeLock );
|
|
return(ERROR_OBJECT_ALREADY_EXISTS);
|
|
}
|
|
|
|
//
|
|
// Allocate an object type block, plus its name.
|
|
//
|
|
|
|
objTypeSize = (sizeof(OM_OBJECT_TYPE) + sizeof(DWORDLONG)) &
|
|
~sizeof(DWORDLONG);
|
|
|
|
objType = LocalAlloc(LMEM_ZEROINIT, objTypeSize +
|
|
((lstrlenW(ObjectTypeInitialize->Name) + 1) *
|
|
sizeof(WCHAR)));
|
|
|
|
if ( objType == NULL ) {
|
|
LeaveCriticalSection( &OmpObjectTypeLock );
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
//
|
|
// Init the object type block.
|
|
//
|
|
|
|
InitializeListHead(&objType->ListHead);
|
|
InitializeListHead(&objType->CallbackListHead);
|
|
InitializeCriticalSection(&objType->CriticalSection);
|
|
|
|
objType->Type = ObjectType;
|
|
|
|
objType->ObjectSize = ObjectTypeInitialize->ObjectSize;
|
|
objType->Signature = ObjectTypeInitialize->Signature;
|
|
objType->DeleteObjectMethod = ObjectTypeInitialize->DeleteObjectMethod;
|
|
|
|
objType->Name = (LPWSTR)((PCHAR)objType + objTypeSize);
|
|
lstrcpyW(objType->Name, ObjectTypeInitialize->Name);
|
|
|
|
OmpObjectTypeTable[ObjectType] = objType;
|
|
|
|
LeaveCriticalSection( &OmpObjectTypeLock );
|
|
|
|
OmpLogPrint( L"OTCREATE \"%1!ws!\"\n", objType->Name );
|
|
|
|
return(ERROR_SUCCESS);
|
|
|
|
} // OmCreateType
|
|
|
|
|
|
|
|
PVOID
|
|
WINAPI
|
|
OmCreateObject(
|
|
IN OBJECT_TYPE ObjectType,
|
|
IN LPCWSTR ObjectId,
|
|
IN LPCWSTR ObjectName OPTIONAL,
|
|
OUT PBOOL Created OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates an object of the type specified or opens an
|
|
object if one of the same Id already exists. If the object is created
|
|
its reference count is 1. If it is not create, then the reference count
|
|
of the object is incremented.
|
|
|
|
Arguments:
|
|
ObjectType - The type of object being created.
|
|
ObjectId - The Id string for the object to find/create.
|
|
ObjectName - The name to set for the object if found or created.
|
|
Created - If present, returns TRUE if the object was created, returns
|
|
FALSE otherwise.
|
|
|
|
Returns:
|
|
A pointer to the created/opened object on success.
|
|
A NULL on failure - use GetLastError to get the error code.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD status;
|
|
PVOID object;
|
|
PVOID tmpObject = NULL;
|
|
LPWSTR objectName = NULL;
|
|
POM_HEADER objHeader;
|
|
POM_OBJECT_TYPE objType;
|
|
DWORD objSize;
|
|
|
|
CL_ASSERT( ObjectType < ObjectTypeMax );
|
|
CL_ASSERT( OmpObjectTypeTable[ObjectType] );
|
|
|
|
//
|
|
// Get our Object Type block.
|
|
//
|
|
objType = OmpObjectTypeTable[ObjectType];
|
|
|
|
//
|
|
// Calculate size of this object (round it to a DWORDLONG).
|
|
// Note: we don't subtract the DWORDLONG Body for rounding purposes.
|
|
//
|
|
objSize = (sizeof(OM_HEADER) + objType->ObjectSize) & ~sizeof(DWORDLONG);
|
|
|
|
EnterCriticalSection( &objType->CriticalSection );
|
|
|
|
//
|
|
// Try to open the object first
|
|
//
|
|
object = OmReferenceObjectById( ObjectType, ObjectId );
|
|
|
|
if ( object != NULL ) {
|
|
status = ERROR_SUCCESS;
|
|
if ( ARGUMENT_PRESENT(ObjectName) ) {
|
|
//
|
|
// Set the new ObjectName.
|
|
//
|
|
status = OmSetObjectName( object, ObjectName );
|
|
|
|
//
|
|
// If we failed, then return NULL.
|
|
//
|
|
if ( status != ERROR_SUCCESS ) {
|
|
OmDereferenceObject( object );
|
|
object = NULL;
|
|
}
|
|
}
|
|
LeaveCriticalSection( &objType->CriticalSection );
|
|
|
|
if ( ARGUMENT_PRESENT(Created) ) {
|
|
*Created = FALSE;
|
|
}
|
|
|
|
SetLastError( status );
|
|
return(object);
|
|
}
|
|
|
|
//
|
|
// Attempt to allocate the object, plus its Id string.
|
|
//
|
|
objHeader = LocalAlloc(LMEM_ZEROINIT, objSize +
|
|
((lstrlenW(ObjectId) + 1) * sizeof(WCHAR)));
|
|
|
|
if ( objHeader == NULL ) {
|
|
LeaveCriticalSection( &objType->CriticalSection );
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return(NULL);
|
|
}
|
|
|
|
if ( ARGUMENT_PRESENT(ObjectName) ) {
|
|
//
|
|
// Make sure ObjectName is unique.
|
|
//
|
|
tmpObject = OmReferenceObjectByName( ObjectType, ObjectName );
|
|
if ( tmpObject != NULL ) {
|
|
LeaveCriticalSection( &objType->CriticalSection );
|
|
LocalFree( objHeader );
|
|
SetLastError(ERROR_OBJECT_ALREADY_EXISTS);
|
|
return(NULL);
|
|
}
|
|
|
|
objectName = LocalAlloc(LMEM_ZEROINIT,
|
|
(lstrlenW(ObjectName) + 1) * sizeof(WCHAR));
|
|
|
|
if ( objectName == NULL ) {
|
|
LeaveCriticalSection( &objType->CriticalSection );
|
|
LocalFree( objHeader );
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return(NULL);
|
|
}
|
|
lstrcpyW( objectName, ObjectName );
|
|
}
|
|
|
|
//
|
|
// Initialize the object.
|
|
//
|
|
InitializeListHead(&objHeader->ListEntry);
|
|
objHeader->Signature = objType->Signature;
|
|
objHeader->RefCount = 1;
|
|
objHeader->ObjectType = objType;
|
|
objHeader->Name = objectName;
|
|
InitializeListHead(&objHeader->CbListHead);
|
|
|
|
//
|
|
// The Id string goes after the object header and body.
|
|
//
|
|
objHeader->Id = (LPWSTR)((PCHAR)objHeader + objSize);
|
|
lstrcpyW(objHeader->Id, ObjectId);
|
|
|
|
//
|
|
// Tell the caller that we had to create this object.
|
|
//
|
|
if ( ARGUMENT_PRESENT(Created) ) {
|
|
*Created = TRUE;
|
|
}
|
|
|
|
#if OM_TRACE_REF
|
|
//SS: all objects are added to the dead list on creation
|
|
// they are removed when the refcount goes to zero
|
|
InitializeListHead(&objHeader->DeadListEntry);
|
|
InsertTailList( &gDeadListHead, &objHeader->DeadListEntry );
|
|
#endif
|
|
|
|
LeaveCriticalSection( &objType->CriticalSection );
|
|
|
|
OmpLogPrint(L"OBCREATE \"%1!ws!\" \"%2!ws!\" \"%3!ws!\"\n",
|
|
objType->Name,
|
|
ObjectId,
|
|
ObjectName == NULL ? L"" : ObjectName);
|
|
|
|
return(&objHeader->Body);
|
|
|
|
} // OmCreateObject
|
|
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
OmInsertObject(
|
|
IN PVOID Object
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine inserts an object into the object's list.
|
|
|
|
Arguments:
|
|
|
|
Object - A pointer to the object to be inserted into its object type list.
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS - if the request was successful.
|
|
ERROR_OBJECT_ALREADY_EXISTS if this object is already in the list.
|
|
|
|
--*/
|
|
|
|
{
|
|
POM_HEADER objHeader;
|
|
POM_HEADER otherHeader;
|
|
POM_OBJECT_TYPE objType;
|
|
|
|
//
|
|
// Get our Object Header.
|
|
//
|
|
|
|
objHeader = OmpObjectToHeader( Object );
|
|
|
|
//
|
|
// Get our Object Type block.
|
|
//
|
|
|
|
objType = objHeader->ObjectType;
|
|
|
|
//
|
|
// Now perform the insertion, but first check to see if someone else
|
|
// snuck in ahead of us and inserted another object of the same name.
|
|
//
|
|
|
|
EnterCriticalSection( &objType->CriticalSection );
|
|
|
|
CL_ASSERT( !(objHeader->Flags & OM_FLAG_OBJECT_INSERTED) );
|
|
|
|
otherHeader = OmpFindIdInList( &objType->ListHead, objHeader->Id );
|
|
|
|
if ( otherHeader != NULL ) {
|
|
// We loose!
|
|
LeaveCriticalSection( &objType->CriticalSection );
|
|
return(ERROR_OBJECT_ALREADY_EXISTS);
|
|
}
|
|
|
|
//
|
|
// We generate the enumeration key for this object, and we must insert
|
|
// the object at the tail of the list, so the list is ordered by EnumKey.
|
|
// By definition, this entry must go at the end of the list.
|
|
//
|
|
|
|
objHeader->EnumKey = ++objType->EnumKey;
|
|
CL_ASSERT( objHeader->EnumKey > 0 );
|
|
|
|
InsertTailList( &objType->ListHead, &objHeader->ListEntry );
|
|
|
|
objHeader->Flags |= OM_FLAG_OBJECT_INSERTED;
|
|
|
|
LeaveCriticalSection( &objType->CriticalSection );
|
|
|
|
return(ERROR_SUCCESS);
|
|
|
|
} // OmInsertObject
|
|
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
OmRemoveObject(
|
|
IN PVOID Object
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine removes an object from its object's list.
|
|
|
|
Arguments:
|
|
|
|
Object - A pointer to the object to be removed from its object type list.
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS if the request is successful.
|
|
ERROR_RESOURCE_NOT_FOUND if the object is not in any list.
|
|
|
|
--*/
|
|
|
|
{
|
|
POM_HEADER objHeader;
|
|
POM_OBJECT_TYPE objType;
|
|
|
|
//
|
|
// Get our Object Header.
|
|
//
|
|
|
|
objHeader = OmpObjectToHeader( Object );
|
|
|
|
//
|
|
// Get our Object Type block.
|
|
//
|
|
|
|
objType = objHeader->ObjectType;
|
|
|
|
//
|
|
// Now perform the removal.
|
|
//
|
|
|
|
EnterCriticalSection( &objType->CriticalSection );
|
|
|
|
if ( !(objHeader->Flags & OM_FLAG_OBJECT_INSERTED) ) {
|
|
LeaveCriticalSection( &objType->CriticalSection );
|
|
return(ERROR_RESOURCE_NOT_FOUND);
|
|
}
|
|
|
|
RemoveEntryList( &objHeader->ListEntry );
|
|
|
|
objHeader->Flags &= ~OM_FLAG_OBJECT_INSERTED;
|
|
|
|
//
|
|
// log while the lock is held so we don't lose our pointers
|
|
//
|
|
OmpLogPrint(L"OBDELETE \"%1!ws!\" \"%2!ws!\" \"%3!ws!\"\n",
|
|
objType->Name,
|
|
objHeader->Id,
|
|
objHeader->Name == NULL ? L"" : objHeader->Name);
|
|
|
|
LeaveCriticalSection( &objType->CriticalSection );
|
|
|
|
return(ERROR_SUCCESS);
|
|
|
|
} // OmRemoveObject
|
|
|
|
|
|
|
|
PVOID
|
|
WINAPI
|
|
OmpReferenceObjectById(
|
|
IN OBJECT_TYPE ObjectType,
|
|
IN LPCWSTR Id
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine opens an object of the name and type specified. It also
|
|
increments the reference count on the object.
|
|
|
|
Arguments:
|
|
ObjectType - The Object Type to open.
|
|
Id - The Id string of the object to open.
|
|
|
|
Returns:
|
|
A pointer to the object on success.
|
|
NULL on error.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD status;
|
|
POM_OBJECT_TYPE objType;
|
|
POM_HEADER objHeader;
|
|
|
|
CL_ASSERT( ObjectType < ObjectTypeMax );
|
|
CL_ASSERT( OmpObjectTypeTable[ObjectType] );
|
|
|
|
//
|
|
// Get our Object Type block.
|
|
//
|
|
|
|
objType = OmpObjectTypeTable[ObjectType];
|
|
|
|
EnterCriticalSection( &objType->CriticalSection );
|
|
|
|
//
|
|
// Get the Object's header
|
|
//
|
|
objHeader = OmpFindIdInList( &objType->ListHead, Id );
|
|
|
|
if ( objHeader == NULL ) {
|
|
LeaveCriticalSection( &objType->CriticalSection );
|
|
return(NULL);
|
|
}
|
|
|
|
#if OM_TRACE_REF
|
|
OmReferenceObject(&objHeader->Body);
|
|
#else
|
|
OmpReferenceHeader( objHeader );
|
|
#endif
|
|
LeaveCriticalSection( &objType->CriticalSection );
|
|
|
|
return(&objHeader->Body);
|
|
|
|
} // OmpReferenceObjectById
|
|
|
|
|
|
|
|
PVOID
|
|
WINAPI
|
|
OmpReferenceObjectByName(
|
|
IN OBJECT_TYPE ObjectType,
|
|
IN LPCWSTR Name
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine opens an object of the name and type specified. It also
|
|
increments the reference count on the object.
|
|
|
|
Arguments:
|
|
ObjectType - The Object Type to open.
|
|
Name - The name of the object to open.
|
|
|
|
Returns:
|
|
A pointer to the object on success.
|
|
NULL on error.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD status;
|
|
POM_OBJECT_TYPE objType;
|
|
POM_HEADER objHeader;
|
|
|
|
CL_ASSERT( ObjectType < ObjectTypeMax );
|
|
CL_ASSERT( OmpObjectTypeTable[ObjectType] );
|
|
|
|
//
|
|
// Get our Object Type block.
|
|
//
|
|
|
|
objType = OmpObjectTypeTable[ObjectType];
|
|
|
|
EnterCriticalSection( &objType->CriticalSection );
|
|
|
|
//
|
|
// Get the Object's header
|
|
//
|
|
|
|
objHeader = OmpFindNameInList( &objType->ListHead, Name );
|
|
|
|
if ( objHeader == NULL ) {
|
|
LeaveCriticalSection( &objType->CriticalSection );
|
|
return(NULL);
|
|
}
|
|
|
|
#if OM_TRACE_REF
|
|
OmReferenceObject(&objHeader->Body);
|
|
#else
|
|
OmpReferenceHeader( objHeader );
|
|
#endif
|
|
|
|
LeaveCriticalSection( &objType->CriticalSection );
|
|
|
|
return(&objHeader->Body);
|
|
|
|
} // OmReferenceObjectByName
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
OmCountObjects(
|
|
IN OBJECT_TYPE ObjectType,
|
|
OUT LPDWORD NumberOfObjects
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the count of the number of objects of a particular type
|
|
which exist in the database at this time.
|
|
|
|
Arguments:
|
|
|
|
ObjectType - The object type to count.
|
|
|
|
NumberOfObjects - On output, contains the number of objects of the
|
|
specified type in the database.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS - if the request is successful.
|
|
A Win32 error if the request fails.
|
|
|
|
--*/
|
|
|
|
{
|
|
POM_OBJECT_TYPE objType;
|
|
PLIST_ENTRY listEntry;
|
|
DWORD objectCount = 0;
|
|
|
|
|
|
CL_ASSERT( ObjectType < ObjectTypeMax );
|
|
|
|
objType = OmpObjectTypeTable[ObjectType];
|
|
|
|
if ( !objType ) {
|
|
return(ERROR_RESOURCE_NOT_FOUND);
|
|
}
|
|
|
|
EnterCriticalSection(&objType->CriticalSection);
|
|
|
|
|
|
for ( listEntry = objType->ListHead.Flink;
|
|
listEntry != &(objType->ListHead);
|
|
listEntry = listEntry->Flink
|
|
)
|
|
{
|
|
objectCount++;
|
|
}
|
|
|
|
LeaveCriticalSection(&objType->CriticalSection);
|
|
|
|
*NumberOfObjects = objectCount;
|
|
|
|
return(ERROR_SUCCESS);
|
|
|
|
} // OmCountObjects
|
|
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
OmEnumObjects(
|
|
IN OBJECT_TYPE ObjectType,
|
|
IN OM_ENUM_OBJECT_ROUTINE EnumerationRoutine,
|
|
IN PVOID Context1,
|
|
IN PVOID Context2
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Enumerates all objects of the specified type.
|
|
|
|
Arguments:
|
|
|
|
ObjectType - The object type to enumerate.
|
|
|
|
EnumerationRoutine - Supplies the enumeration routine to be
|
|
called for each object.
|
|
|
|
Context1 - Supplies a context pointer to be passed to the
|
|
enumeration routine.
|
|
|
|
Context2 - Supplies a second context pointer to be passed to the
|
|
enumeration routine.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS - if the request is successful.
|
|
A Win32 error if the request fails.
|
|
|
|
--*/
|
|
|
|
{
|
|
POM_OBJECT_TYPE objType;
|
|
POM_HEADER objHeader;
|
|
PLIST_ENTRY listEntry;
|
|
DWORD enumKey = 0;
|
|
|
|
CL_ASSERT( ObjectType < ObjectTypeMax );
|
|
|
|
objType = OmpObjectTypeTable[ObjectType];
|
|
|
|
if ( !objType ) {
|
|
return(ERROR_RESOURCE_NOT_FOUND);
|
|
}
|
|
|
|
//
|
|
// Enumeration is a little tricky. First, we have to allow for multiple
|
|
// entries in the enumeration list to be removed as a side effect of the
|
|
// callout. Second, we have to allow the list lock to be released so the
|
|
// first issue can be handled. We'll use a sort order key to remember where
|
|
// we are in the enumeration and pick up from the next highest value.
|
|
//
|
|
|
|
while ( TRUE ) {
|
|
|
|
EnterCriticalSection(&objType->CriticalSection);
|
|
|
|
//
|
|
// Skip to next entry to process in list.
|
|
// We can treat this like an entry only after verifying it is not the
|
|
// ListHeader.
|
|
//
|
|
|
|
listEntry = objType->ListHead.Flink;
|
|
objHeader = CONTAINING_RECORD( listEntry, OM_HEADER, ListEntry );
|
|
|
|
while ( listEntry != &objType->ListHead &&
|
|
objHeader->EnumKey <= enumKey ) {
|
|
listEntry = listEntry->Flink;
|
|
objHeader = CONTAINING_RECORD( listEntry, OM_HEADER, ListEntry );
|
|
}
|
|
|
|
//
|
|
// Save the enumeration key for next iteration.
|
|
//
|
|
|
|
enumKey = objHeader->EnumKey;
|
|
|
|
//if it is a valid object, increment the reference count
|
|
// so that it is not deleted while the call out is being
|
|
// made
|
|
if ( listEntry != &objType->ListHead ) {
|
|
OmReferenceObject(&objHeader->Body);
|
|
}
|
|
//
|
|
// Drop the lock to return or call out.
|
|
//
|
|
|
|
LeaveCriticalSection(&objType->CriticalSection);
|
|
|
|
if ( listEntry == &objType->ListHead ) {
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
if (!(EnumerationRoutine)(Context1,
|
|
Context2,
|
|
&objHeader->Body,
|
|
objHeader->Id)) {
|
|
OmDereferenceObject(&objHeader->Body);
|
|
break;
|
|
}
|
|
OmDereferenceObject(&objHeader->Body);
|
|
}
|
|
|
|
return(ERROR_SUCCESS);
|
|
|
|
} // OmEnumObject
|
|
|
|
|
|
|
|
VOID
|
|
OmpDereferenceObject(
|
|
IN PVOID Object
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine dereferences an object. If the reference count goes to
|
|
zero, then the object is deallocated.
|
|
|
|
Arguments:
|
|
Object - A pointer to the object to be dereferenced.
|
|
|
|
Returns:
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD status;
|
|
POM_HEADER objHeader;
|
|
POM_OBJECT_TYPE objType;
|
|
|
|
objHeader = OmpObjectToHeader( Object );
|
|
|
|
objType = objHeader->ObjectType;
|
|
|
|
CL_ASSERT( objHeader->RefCount != 0xfeeefeee );
|
|
CL_ASSERT( objHeader->RefCount > 0 );
|
|
|
|
if ( OmpDereferenceHeader(objHeader) ) {
|
|
|
|
//
|
|
// The reference count has gone to zero. Acquire the
|
|
// lock, remove the object from the list, and perform
|
|
// cleanup.
|
|
//
|
|
|
|
EnterCriticalSection( &objType->CriticalSection );
|
|
|
|
//
|
|
// Check the ref count again, to close the race condition between
|
|
// open/create and this routine.
|
|
//
|
|
|
|
if ( objHeader->RefCount == 0 ) {
|
|
//
|
|
// If the object hasn't been previously removed from it's
|
|
// object type list, then remove it now.
|
|
//
|
|
|
|
if ( objHeader->Flags & OM_FLAG_OBJECT_INSERTED ) {
|
|
RemoveEntryList( &objHeader->ListEntry );
|
|
objHeader->Flags &= ~OM_FLAG_OBJECT_INSERTED;
|
|
}
|
|
|
|
//
|
|
// Call the object type's delete method (if present).
|
|
//
|
|
|
|
if ( ARGUMENT_PRESENT( objType->DeleteObjectMethod ) ) {
|
|
(objType->DeleteObjectMethod)( &objHeader->Body );
|
|
}
|
|
|
|
objHeader->Signature = 'rFmO';
|
|
#if OM_TRACE_REF
|
|
RemoveEntryList(&objHeader->DeadListEntry);
|
|
#endif
|
|
if ( objHeader->Name != NULL ) {
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"[OM] Deleting object %1!ws! (%2!ws!)\n",
|
|
objHeader->Name,
|
|
objHeader->Id);
|
|
LocalFree( objHeader->Name );
|
|
} else {
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"[OM] Deleting object %1!ws!\n",
|
|
objHeader->Id);
|
|
}
|
|
LocalFree( objHeader );
|
|
}
|
|
LeaveCriticalSection( &objType->CriticalSection );
|
|
}
|
|
|
|
} // OmpDereferenceObject
|
|
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
OmSetObjectName(
|
|
IN PVOID Object,
|
|
IN LPCWSTR ObjectName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the object name for an object. If the ObjectName already exists on a
|
|
different object, then this call will fail.
|
|
|
|
Arguments:
|
|
|
|
Object - A pointer to the object to set its name.
|
|
ObjectName - The name to set for the object.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful.
|
|
A Win32 error code on failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD status = ERROR_SUCCESS;
|
|
PVOID object = NULL;
|
|
LPWSTR objectName;
|
|
POM_HEADER objHeader;
|
|
POM_OBJECT_TYPE objType;
|
|
|
|
//
|
|
// Make sure object name is valid (not empty)
|
|
//
|
|
if (ObjectName[0] == '\0')
|
|
{
|
|
status = ERROR_INVALID_NAME;
|
|
goto FnExit;
|
|
}
|
|
|
|
objHeader = OmpObjectToHeader( Object );
|
|
|
|
objType = objHeader->ObjectType;
|
|
|
|
EnterCriticalSection( &objType->CriticalSection );
|
|
|
|
//
|
|
// Make sure ObjectName is unique.
|
|
//
|
|
object = OmReferenceObjectByName( objType->Type, ObjectName );
|
|
if ( object != NULL )
|
|
{
|
|
//
|
|
// If our's is the other object, then nothing to do. Otherwise,
|
|
// there is a duplicate.
|
|
//
|
|
if ( object != Object )
|
|
{
|
|
status = ERROR_OBJECT_ALREADY_EXISTS;
|
|
goto FnUnlock;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// No other object with the new name, then set the new name.
|
|
//
|
|
objectName = LocalAlloc(LMEM_ZEROINIT,
|
|
(lstrlenW(ObjectName) + 1) * sizeof(WCHAR));
|
|
if ( objectName == NULL ) {
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
} else {
|
|
if ( objHeader->Name != NULL ) {
|
|
LocalFree( objHeader->Name );
|
|
}
|
|
objHeader->Name = objectName;
|
|
lstrcpyW( objectName, ObjectName );
|
|
|
|
OmpLogPrint(L"OBRENAME \"%1!ws!\" \"%2!ws!\" \"%3!ws!\"\n",
|
|
objType->Name,
|
|
objHeader->Id,
|
|
ObjectName);
|
|
}
|
|
}
|
|
|
|
FnUnlock:
|
|
LeaveCriticalSection( &objType->CriticalSection );
|
|
FnExit:
|
|
if (object)
|
|
{
|
|
OmDereferenceObject(object);
|
|
}
|
|
return(status);
|
|
|
|
} // OmSetObjectName
|
|
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
OmRegisterTypeNotify(
|
|
IN OBJECT_TYPE ObjectType,
|
|
IN PVOID pContext,
|
|
IN DWORD dwNotifyMask,
|
|
IN OM_OBJECT_NOTIFYCB pfnObjNotifyCb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Registers a callback to be called by the FM on object state changes.
|
|
|
|
Arguments:
|
|
|
|
ObjectType - The object type that notifications should be delivered for.
|
|
|
|
pContext - A pointer to context information that is passed back into the callback.
|
|
|
|
dwNotifyMask - The type of notifications that should be delivered
|
|
|
|
pfnObjNotifyCb - a pointer to the callback.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful.
|
|
A Win32 error code on failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
POM_HEADER pObjHeader;
|
|
POM_OBJECT_TYPE pObjType;
|
|
POM_NOTIFY_RECORD pNotifyRec;
|
|
|
|
if ( !pfnObjNotifyCb ) {
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
pObjType = OmpObjectTypeTable[ObjectType];
|
|
|
|
//
|
|
// The object type lock is used to serialize callbacks. This
|
|
// is so that callees do not deadlock if they are waiting on
|
|
// another thread that needs to enumerate objects.
|
|
//
|
|
EnterCriticalSection( &OmpObjectTypeLock );
|
|
|
|
//
|
|
// First, check if the same notification is being registered twice!
|
|
// If so, then just change the notification mask and context.
|
|
//
|
|
pNotifyRec = OmpFindNotifyCbInList( &pObjType->CallbackListHead,
|
|
pfnObjNotifyCb);
|
|
if ( !pNotifyRec ) {
|
|
pNotifyRec = (POM_NOTIFY_RECORD) LocalAlloc(LMEM_FIXED,sizeof(OM_NOTIFY_RECORD));
|
|
|
|
if ( !pNotifyRec ) {
|
|
dwError = ERROR_NOT_ENOUGH_MEMORY;
|
|
CsInconsistencyHalt(dwError);
|
|
goto FnExit;
|
|
}
|
|
|
|
pNotifyRec->pfnObjNotifyCb = pfnObjNotifyCb;
|
|
|
|
//insert the notification record at the tail
|
|
InsertTailList(&pObjType->CallbackListHead, &pNotifyRec->ListEntry);
|
|
}
|
|
|
|
pNotifyRec->dwNotifyMask = dwNotifyMask;
|
|
pNotifyRec->pContext = pContext;
|
|
|
|
FnExit:
|
|
LeaveCriticalSection( &OmpObjectTypeLock );
|
|
|
|
return(dwError);
|
|
|
|
} // OmRegisterTypeNotify
|
|
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
OmRegisterNotify(
|
|
IN PVOID pObject,
|
|
IN PVOID pContext,
|
|
IN DWORD dwNotifyMask,
|
|
IN OM_OBJECT_NOTIFYCB pfnObjNotifyCb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Registers a callback to be called by the FM on object state changes.
|
|
|
|
Arguments:
|
|
|
|
pObject - A pointer to the object to set its name.
|
|
pContext - A pointer to context information that is passed back into the callback.
|
|
dwNotifyMask - The name to set for the object.
|
|
pfnObjNotifyCb - a pointer to the callback.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful.
|
|
A Win32 error code on failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
POM_HEADER pObjHeader;
|
|
POM_OBJECT_TYPE pObjType;
|
|
POM_NOTIFY_RECORD pNotifyRec;
|
|
|
|
if ( !pfnObjNotifyCb ) {
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
pObjHeader = OmpObjectToHeader( pObject );
|
|
|
|
pObjType = pObjHeader->ObjectType;
|
|
|
|
EnterCriticalSection( &OmpObjectTypeLock );
|
|
|
|
//
|
|
// First, check if the same notification is being registered twice!
|
|
// If so, then just change the notification mask and context.
|
|
//
|
|
pNotifyRec = OmpFindNotifyCbInList(&pObjHeader->CbListHead, pfnObjNotifyCb);
|
|
if ( !pNotifyRec ) {
|
|
pNotifyRec = (POM_NOTIFY_RECORD) LocalAlloc(LMEM_FIXED,sizeof(OM_NOTIFY_RECORD));
|
|
|
|
if ( !pNotifyRec ) {
|
|
dwError = ERROR_NOT_ENOUGH_MEMORY;
|
|
CsInconsistencyHalt(dwError);
|
|
goto FnExit;
|
|
}
|
|
|
|
pNotifyRec->pfnObjNotifyCb = pfnObjNotifyCb;
|
|
|
|
//insert the notification record at the tail
|
|
InsertTailList(&pObjHeader->CbListHead, &pNotifyRec->ListEntry);
|
|
}
|
|
|
|
pNotifyRec->dwNotifyMask = dwNotifyMask;
|
|
pNotifyRec->pContext = pContext;
|
|
|
|
FnExit:
|
|
LeaveCriticalSection( &OmpObjectTypeLock );
|
|
|
|
return(dwError);
|
|
|
|
} // OmRegisterNotify
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
OmDeregisterNotify(
|
|
IN PVOID pObject,
|
|
IN OM_OBJECT_NOTIFYCB pfnObjNotifyCb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes the callback registed with the object.
|
|
|
|
Arguments:
|
|
|
|
pObject - A pointer to the object to set its name.
|
|
pfnObjNotifyCb - a pointer to the callback.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful.
|
|
A Win32 error code on failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
POM_HEADER pObjHeader;
|
|
POM_OBJECT_TYPE pObjType;
|
|
POM_NOTIFY_RECORD pNotifyRec;
|
|
|
|
if ( !pfnObjNotifyCb ) {
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
|
|
pObjHeader = OmpObjectToHeader( pObject );
|
|
|
|
|
|
//SS: we use the same crit section for list manipulations
|
|
pObjType = pObjHeader->ObjectType;
|
|
|
|
//
|
|
// The object type lock is used to serialize callbacks. This
|
|
// is so that callees do not deadlock if they are waiting on
|
|
// another thread that needs to enumerate objects.
|
|
//
|
|
EnterCriticalSection( &OmpObjectTypeLock );
|
|
|
|
pNotifyRec = OmpFindNotifyCbInList(&pObjHeader->CbListHead, pfnObjNotifyCb);
|
|
if (!pNotifyRec) {
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[OM] OmRegisterNotify: OmpFindNotifyCbInList failed for 0x%1!08lx!\r\n",
|
|
pfnObjNotifyCb);
|
|
|
|
dwError = ERROR_INVALID_PARAMETER;
|
|
CL_LOGFAILURE(dwError);
|
|
goto FnExit;
|
|
}
|
|
RemoveEntryList(&pNotifyRec->ListEntry);
|
|
|
|
FnExit:
|
|
LeaveCriticalSection( &OmpObjectTypeLock );
|
|
|
|
return(dwError);
|
|
|
|
} // OmRegisterNotify
|
|
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
OmNotifyCb(
|
|
IN PVOID pObject,
|
|
IN DWORD dwNotification
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The callback registered with the quorum resource object.
|
|
|
|
Arguments:
|
|
|
|
pContext - The resource whose call back list will be traversed.
|
|
dwNotification - The notification to be passed to the callback.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful.
|
|
|
|
A Win32 error code on failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
POM_HEADER pObjHeader;
|
|
POM_OBJECT_TYPE pObjType;
|
|
PLIST_ENTRY ListEntry;
|
|
DWORD dwError=ERROR_SUCCESS;
|
|
POM_NOTIFY_RECORD pNotifyRecList = NULL;
|
|
DWORD dwCount;
|
|
DWORD i;
|
|
|
|
CL_ASSERT(pObject);
|
|
|
|
//get the callback list
|
|
pObjHeader = OmpObjectToHeader(pObject);
|
|
pObjType = pObjHeader->ObjectType;
|
|
|
|
//will walk the list of callbacks, do allow more registrations
|
|
EnterCriticalSection(&OmpObjectTypeLock);
|
|
dwError = OmpGetCbList(pObject, &pNotifyRecList, &dwCount);
|
|
LeaveCriticalSection(&OmpObjectTypeLock);
|
|
|
|
for (i=0; i < dwCount; i++)
|
|
{
|
|
if (pNotifyRecList[i].dwNotifyMask & dwNotification) {
|
|
(pNotifyRecList[i].pfnObjNotifyCb)(pNotifyRecList[i].pContext,
|
|
pObject,
|
|
dwNotification);
|
|
}
|
|
}
|
|
|
|
LocalFree(pNotifyRecList);
|
|
return(dwError);
|
|
}
|
|
|
|
DWORD OmpGetCbList(
|
|
IN PVOID pObject,
|
|
OUT POM_NOTIFY_RECORD *ppNotifyRecList,
|
|
OUT LPDWORD pdwCount
|
|
)
|
|
{
|
|
DWORD status = ERROR_SUCCESS;
|
|
POM_NOTIFY_RECORD pNotifyRecList;
|
|
POM_NOTIFY_RECORD pNotifyRec;
|
|
DWORD dwAllocated;
|
|
PLIST_ENTRY ListEntry;
|
|
DWORD dwRetrySize=1;
|
|
POM_HEADER pObjHeader;
|
|
POM_OBJECT_TYPE pObjType;
|
|
DWORD i = 0;
|
|
|
|
*ppNotifyRecList = NULL;
|
|
*pdwCount = 0;
|
|
|
|
Retry:
|
|
dwAllocated = ENUM_GROW_SIZE * dwRetrySize;
|
|
i = 0;
|
|
|
|
pObjHeader = OmpObjectToHeader(pObject);
|
|
pObjType = pObjHeader->ObjectType;
|
|
|
|
pNotifyRecList = LocalAlloc(LMEM_FIXED, sizeof(OM_NOTIFY_RECORD) * dwAllocated);
|
|
if ( pNotifyRecList == NULL ) {
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto FnExit;
|
|
}
|
|
|
|
ZeroMemory( pNotifyRecList, sizeof(OM_NOTIFY_RECORD) * dwAllocated );
|
|
|
|
//
|
|
// First notify any type-specific callbacks
|
|
//
|
|
ListEntry = pObjType->CallbackListHead.Flink;
|
|
while (ListEntry != &pObjType->CallbackListHead) {
|
|
pNotifyRec = CONTAINING_RECORD(ListEntry,
|
|
OM_NOTIFY_RECORD,
|
|
ListEntry);
|
|
if (i < dwAllocated)
|
|
{
|
|
CopyMemory(&pNotifyRecList[i++], pNotifyRec, sizeof(OM_NOTIFY_RECORD));
|
|
}
|
|
else
|
|
{
|
|
LocalFree(pNotifyRecList);
|
|
dwRetrySize++;
|
|
goto Retry;
|
|
}
|
|
ListEntry = ListEntry->Flink;
|
|
}
|
|
|
|
//
|
|
// Next notify any resource-specific callbacks
|
|
//
|
|
ListEntry = pObjHeader->CbListHead.Flink;
|
|
while (ListEntry != &(pObjHeader->CbListHead)) {
|
|
pNotifyRec = CONTAINING_RECORD(ListEntry, OM_NOTIFY_RECORD, ListEntry);
|
|
|
|
if (i < dwAllocated)
|
|
{
|
|
CopyMemory(&pNotifyRecList[i++], pNotifyRec, sizeof(OM_NOTIFY_RECORD));
|
|
}
|
|
else
|
|
{
|
|
LocalFree(pNotifyRecList);
|
|
dwRetrySize++;
|
|
goto Retry;
|
|
}
|
|
ListEntry = ListEntry->Flink;
|
|
|
|
}
|
|
|
|
FnExit:
|
|
*ppNotifyRecList = pNotifyRecList;
|
|
*pdwCount = i;
|
|
return(status);
|
|
}
|