Author: fireball
Date: Tue Dec 4 21:44:51 2007
New Revision: 31004
URL:
http://svn.reactos.org/svn/reactos?rev=31004&view=rev
Log:
Do a full clean rebuild after this commit!
- Begin fixing CM_KEY_NODE.
- More proper use of registry lock in create operations.
- Use ObOpenObjectByName (as a test only, ignore the results) in CmpLinkHiveToMaster.
- Implement routines to acquire/release two KCB locks atomically.
- Implement KCB dereference without lock.
- Fix locking in CmpCreateKeyControlBlock so that it now properly locks KCBs when
requested.
- Implement rudimentary new-style parse routine that only walks the registry path until
it's time to create the link node (since this is the only scenario where it's
called from). Prints out the status of the operation but doesn't actually do
anything.
Modified:
trunk/reactos/lib/cmlib/cmdata.h
trunk/reactos/ntoskrnl/cm/ntfunc.c
trunk/reactos/ntoskrnl/cm/regobj.c
trunk/reactos/ntoskrnl/config/cm.h
trunk/reactos/ntoskrnl/config/cmkcbncb.c
trunk/reactos/ntoskrnl/config/cmparse.c
trunk/reactos/ntoskrnl/config/cmsysini.c
Modified: trunk/reactos/lib/cmlib/cmdata.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/cmlib/cmdata.h?rev=310…
==============================================================================
--- trunk/reactos/lib/cmlib/cmdata.h (original)
+++ trunk/reactos/lib/cmlib/cmdata.h Tue Dec 4 21:44:51 2007
@@ -77,6 +77,15 @@
} CHILD_LIST, *PCHILD_LIST;
//
+// Node Key Reference to Parents
+//
+typedef struct _CM_KEY_REFERENCE
+{
+ HCELL_INDEX KeyCell;
+ PHHIVE KeyHive;
+} CM_KEY_REFERENCE, *PCM_KEY_REFERENCE;
+
+//
// Node Key
//
typedef struct _CM_KEY_NODE
@@ -87,6 +96,15 @@
ULONG Spare;
HCELL_INDEX Parent;
ULONG SubKeyCounts[HTYPE_COUNT];
+ union
+ {
+ struct
+ {
+ HCELL_INDEX SubKeyLists[HTYPE_COUNT];
+ CHILD_LIST ValueList;
+ };
+ //CM_KEY_REFERENCE ChildHiveReference;
+ };
HCELL_INDEX SubKeyLists[HTYPE_COUNT];
CHILD_LIST ValueList;
HCELL_INDEX Security;
Modified: trunk/reactos/ntoskrnl/cm/ntfunc.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/cm/ntfunc.c?rev=3…
==============================================================================
--- trunk/reactos/ntoskrnl/cm/ntfunc.c (original)
+++ trunk/reactos/ntoskrnl/cm/ntfunc.c Tue Dec 4 21:44:51 2007
@@ -136,6 +136,9 @@
Status = STATUS_OBJECT_NAME_NOT_FOUND;
goto Cleanup;
}
+
+ /* Lock the registry */
+ CmpLockRegistry();
/* Create the key */
Status = CmpDoCreate(Parent->KeyControlBlock->KeyHive,
@@ -187,6 +190,9 @@
/* Add the keep-alive reference */
ObReferenceObject(KeyObject);
+
+ /* Unlock registry */
+ CmpUnlockRegistry();
/* Force a lazy flush */
CmpLazyFlush();
Modified: trunk/reactos/ntoskrnl/cm/regobj.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/cm/regobj.c?rev=3…
==============================================================================
--- trunk/reactos/ntoskrnl/cm/regobj.c (original)
+++ trunk/reactos/ntoskrnl/cm/regobj.c Tue Dec 4 21:44:51 2007
@@ -493,20 +493,31 @@
return STATUS_SUCCESS;
}
-
+NTSTATUS
+NTAPI
+CmpParseKey2(IN PVOID ParseObject,
+ IN PVOID ObjectType,
+ IN OUT PACCESS_STATE AccessState,
+ IN KPROCESSOR_MODE AccessMode,
+ IN ULONG Attributes,
+ IN OUT PUNICODE_STRING CompleteName,
+ IN OUT PUNICODE_STRING RemainingName,
+ IN OUT PVOID Context OPTIONAL,
+ IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
+ OUT PVOID *Object);
NTSTATUS
NTAPI
CmpParseKey(IN PVOID ParsedObject,
- IN PVOID ObjectType,
- IN OUT PACCESS_STATE AccessState,
- IN KPROCESSOR_MODE AccessMode,
- IN ULONG Attributes,
- IN OUT PUNICODE_STRING FullPath,
- IN OUT PUNICODE_STRING RemainingName,
- IN OUT PVOID Context OPTIONAL,
- IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
- OUT PVOID *NextObject)
+ IN PVOID ObjectType,
+ IN OUT PACCESS_STATE AccessState,
+ IN KPROCESSOR_MODE AccessMode,
+ IN ULONG Attributes,
+ IN OUT PUNICODE_STRING FullPath,
+ IN OUT PUNICODE_STRING RemainingName,
+ IN OUT PVOID Context OPTIONAL,
+ IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
+ OUT PVOID *NextObject)
{
HCELL_INDEX BlockOffset;
PKEY_OBJECT FoundObject;
@@ -523,6 +534,22 @@
PCM_KEY_CONTROL_BLOCK ParentKcb = NULL, Kcb;
PCM_KEY_NODE Node;
+ /* Detect new-style parse */
+ if (Context)
+ {
+ /* Call proper parse routine */
+ return CmpParseKey2(ParsedObject,
+ ObjectType,
+ AccessState,
+ AccessMode,
+ Attributes,
+ FullPath,
+ RemainingName,
+ Context,
+ SecurityQos,
+ NextObject);
+ }
+
ParsedKey = ParsedObject;
VERIFY_KEY_OBJECT(ParsedKey);
Modified: trunk/reactos/ntoskrnl/config/cm.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/config/cm.h?rev=3…
==============================================================================
--- trunk/reactos/ntoskrnl/config/cm.h (original)
+++ trunk/reactos/ntoskrnl/config/cm.h Tue Dec 4 21:44:51 2007
@@ -192,15 +192,6 @@
ULONG Count;
ULONG HashKey[ANYSIZE_ARRAY];
} CM_INDEX_HINT_BLOCK, *PCM_INDEX_HINT_BLOCK;
-
-//
-// Key Reference
-//
-typedef struct _CM_KEY_REFERENCE
-{
- HCELL_INDEX KeyCell;
- PHHIVE KeyHive;
-} CM_KEY_REFERENCE, *PCM_KEY_REFERENCE;
//
// Key Body
@@ -782,6 +773,12 @@
VOID
);
+BOOLEAN
+NTAPI
+CmpTestRegistryLock(
+ VOID
+);
+
VOID
NTAPI
CmpLockRegistryExclusive(
@@ -886,6 +883,12 @@
VOID
NTAPI
+CmpDereferenceKeyControlBlock(
+ IN PCM_KEY_CONTROL_BLOCK Kcb
+);
+
+VOID
+NTAPI
EnlistKeyBodyWithKCB(
IN PCM_KEY_BODY KeyObject,
IN ULONG Flags
@@ -904,6 +907,20 @@
IN PHHIVE Hive,
IN HCELL_INDEX Cell,
IN BOOLEAN Unlink
+);
+
+VOID
+NTAPI
+CmpAcquireTwoKcbLocksExcusiveByKey(
+ IN ULONG ConvKey1,
+ IN ULONG ConvKey2
+);
+
+VOID
+NTAPI
+CmpReleaseTwoKcbLockByKey(
+ IN ULONG ConvKey1,
+ IN ULONG ConvKey2
);
//
Modified: trunk/reactos/ntoskrnl/config/cmkcbncb.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/config/cmkcbncb.c…
==============================================================================
--- trunk/reactos/ntoskrnl/config/cmkcbncb.c (original)
+++ trunk/reactos/ntoskrnl/config/cmkcbncb.c Tue Dec 4 21:44:51 2007
@@ -503,6 +503,39 @@
VOID
NTAPI
+CmpDereferenceKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb)
+{
+ LONG OldRefCount, NewRefCount;
+ ULONG ConvKey;
+
+ /* Get the ref count and update it */
+ OldRefCount = *(PLONG)&Kcb->RefCount;
+ NewRefCount = OldRefCount - 1;
+
+ /* Check if we still have refenreces */
+ if( (NewRefCount & 0xffff) > 0)
+ {
+ /* Do the dereference */
+ if (InterlockedCompareExchange((PLONG)&Kcb->RefCount,
+ NewRefCount,
+ OldRefCount) == OldRefCount)
+ {
+ /* We'de done */
+ return;
+ }
+ }
+
+ /* Save the key */
+ ConvKey = Kcb->ConvKey;
+
+ /* Do the dereference inside the lock */
+ CmpAcquireKcbLockExclusive(Kcb);
+ CmpDereferenceKeyControlBlockWithLock(Kcb, FALSE);
+ CmpReleaseKcbLockByKey(ConvKey);
+}
+
+VOID
+NTAPI
CmpDereferenceKeyControlBlockWithLock(IN PCM_KEY_CONTROL_BLOCK Kcb,
IN BOOLEAN LockHeldExclusively)
{
@@ -621,10 +654,19 @@
/* Check if we have two hash entires */
HashLock = Flags & CMP_LOCK_HASHES_FOR_KCB ? TRUE : FALSE;
- if (HashLock)
- {
- /* Not yet implemented */
- KeBugCheck(0);
+ if (!HashLock)
+ {
+ /* It's not locked, do we have a parent? */
+ if (Parent)
+ {
+ /* Lock the parent KCB and ourselves */
+ CmpAcquireTwoKcbLocksExcusiveByKey(ConvKey, Parent->ConvKey);
+ }
+ else
+ {
+ /* Lock only ourselves */
+ CmpAcquireKcbLockExclusive(Kcb);
+ }
}
/* Check if we already have a KCB */
@@ -746,10 +788,19 @@
ASSERT((!Kcb) || (Kcb->Delete == FALSE));
/* Check if we had locked the hashes */
- if (HashLock)
- {
- /* Not yet implemented: Unlock hashes */
- KeBugCheck(0);
+ if (!HashLock)
+ {
+ /* We locked them manually, do we have a parent? */
+ if (Parent)
+ {
+ /* Unlock the parent KCB and ourselves */
+ CmpReleaseTwoKcbLockByKey(ConvKey, Parent->ConvKey);
+ }
+ else
+ {
+ /* Unlock only ourselves */
+ CmpReleaseKcbLockByKey(ConvKey);
+ }
}
/* Return the KCB */
@@ -764,3 +815,4 @@
ASSERT(FALSE);
}
+
Modified: trunk/reactos/ntoskrnl/config/cmparse.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/config/cmparse.c?…
==============================================================================
--- trunk/reactos/ntoskrnl/config/cmparse.c (original)
+++ trunk/reactos/ntoskrnl/config/cmparse.c Tue Dec 4 21:44:51 2007
@@ -215,7 +215,7 @@
*KeyCell,
KeyNode,
ParentKcb,
- 0,
+ CMP_LOCK_HASHES_FOR_KCB,
Name);
if (!Kcb)
{
@@ -281,6 +281,12 @@
UNICODE_STRING LocalClass = {0};
if (!Class) Class = &LocalClass;
+ /* Sanity check */
+#if 0
+ ASSERT((CmpIsKcbLockedExclusive(ParentKcb) == TRUE) ||
+ (CmpTestRegistryLockExclusive() == TRUE));
+#endif
+
/* Acquire the flusher lock */
ExAcquirePushLockShared((PVOID)&((PCMHIVE)Hive)->FlusherLock);
@@ -447,7 +453,12 @@
//ASSERT(CmpIsKcbLockedExclusive(*CachedKcb));
/* Create the KCB. FIXME: Use lock flag */
- Kcb = CmpCreateKeyControlBlock(Hive, Cell, Node, *CachedKcb, 0, KeyName);
+ Kcb = CmpCreateKeyControlBlock(Hive,
+ Cell,
+ Node,
+ *CachedKcb,
+ CMP_LOCK_HASHES_FOR_KCB,
+ KeyName);
if (!Kcb) return STATUS_INSUFFICIENT_RESOURCES;
/* Make sure it's also locked, and set the pointer */
@@ -503,7 +514,10 @@
LARGE_INTEGER TimeStamp;
PCM_KEY_NODE KeyNode;
PCM_KEY_CONTROL_BLOCK Kcb = ParentKcb;
-
+#if 0
+ CMP_ASSERT_REGISTRY_LOCK();
+#endif
+
/* Link nodes only allowed on the master */
if (Hive != &CmiVolatileHive->Hive)
{
@@ -712,3 +726,238 @@
ExReleasePushLock((PVOID)&((PCMHIVE)Hive)->FlusherLock);
return Status;
}
+
+NTSTATUS
+NTAPI
+CmpBuildHashStackAndLookupCache(IN PCM_KEY_BODY ParseObject,
+ IN OUT PCM_KEY_CONTROL_BLOCK *Kcb,
+ IN PUNICODE_STRING Current,
+ OUT PHHIVE *Hive,
+ OUT HCELL_INDEX *Cell,
+ OUT PULONG TotalRemainingSubkeys,
+ OUT PULONG MatchRemainSubkeyLevel,
+ OUT PULONG TotalSubkeys,
+ OUT PULONG OuterStackArray,
+ OUT PULONG *LockedKcbs)
+{
+ ULONG HashKeyCopy;
+
+ /* We don't lock anything for now */
+ *LockedKcbs = NULL;
+
+ /* Make a copy of the hash key */
+ HashKeyCopy = (*Kcb)->ConvKey;
+
+ /* Calculate hash values */
+ *TotalRemainingSubkeys = 0xBAADF00D;
+
+ /* Lock the registry */
+ CmpLockRegistry();
+
+ /* Return hive and cell data */
+ *Hive = (*Kcb)->KeyHive;
+ *Cell = (*Kcb)->KeyCell;
+
+ /* Return success for now */
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+CmpParseKey2(IN PVOID ParseObject,
+ IN PVOID ObjectType,
+ IN OUT PACCESS_STATE AccessState,
+ IN KPROCESSOR_MODE AccessMode,
+ IN ULONG Attributes,
+ IN OUT PUNICODE_STRING CompleteName,
+ IN OUT PUNICODE_STRING RemainingName,
+ IN OUT PVOID Context OPTIONAL,
+ IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
+ OUT PVOID *Object)
+{
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+ PCM_KEY_CONTROL_BLOCK Kcb, ParentKcb;
+ PHHIVE Hive = NULL;
+ PCM_KEY_NODE Node = NULL;
+ HCELL_INDEX Cell = HCELL_NIL, NextCell;
+ UNICODE_STRING Current, NextName;
+ PCM_PARSE_CONTEXT ParseContext = Context;
+ ULONG TotalRemainingSubkeys = 0, MatchRemainSubkeyLevel = 0, TotalSubkeys = 0;
+ PULONG LockedKcbs = NULL;
+ BOOLEAN Result, Last;
+ PAGED_CODE();
+ DPRINT1("New style parse routine called: %wZ %wZ!\n", CompleteName,
RemainingName);
+
+ /* Loop path separators at the end */
+ while ((RemainingName->Length) &&
+ (RemainingName->Buffer[(RemainingName->Length / sizeof(WCHAR)) - 1] ==
+ OBJ_NAME_PATH_SEPARATOR))
+ {
+ /* Remove path separator */
+ RemainingName->Length -= sizeof(WCHAR);
+ }
+
+ /* Fail if this isn't a key object */
+ if (ObjectType != CmpKeyObjectType) return STATUS_OBJECT_TYPE_MISMATCH;
+
+ /* Copy the remaining name */
+ Current = *RemainingName;
+
+ /* Check if this is a create */
+ if (!(ParseContext) || !(ParseContext->CreateOperation))
+ {
+ /* It isn't, so no context */
+ ParseContext = NULL;
+ }
+
+ /* Grab the KCB */
+ Kcb = ((PKEY_OBJECT)ParseObject)->KeyControlBlock;
+ DPRINT1("KCB Parse: %p\n", Kcb);
+
+ /* Lookup in the cache */
+ Status = CmpBuildHashStackAndLookupCache(ParseObject,
+ &Kcb,
+ &Current,
+ &Hive,
+ &Cell,
+ &TotalRemainingSubkeys,
+ &MatchRemainSubkeyLevel,
+ &TotalSubkeys,
+ NULL,
+ &LockedKcbs);
+
+ /* This is now the parent */
+ ParentKcb = Kcb;
+ DPRINT1("ParentKcb Parse: %p\n", ParentKcb);
+ DPRINT1("Hive Parse: %p\n", Hive);
+ DPRINT1("Cell Parse: %p\n", Cell);
+
+ /* Check if everything was found cached */
+ if (!TotalRemainingSubkeys) ASSERTMSG("Caching not implemented", FALSE);
+
+ /* Don't do anything if we're being deleted */
+ if (Kcb->Delete) return STATUS_OBJECT_NAME_NOT_FOUND;
+
+ /* Check if this is a symlink */
+ if (Kcb->Flags & KEY_SYM_LINK)
+ {
+ /* Not implemented */
+ DPRINT1("Parsing sym link\n");
+ while (TRUE);
+ }
+
+ /* Get the key node */
+ Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
+ if (!Node) return STATUS_INSUFFICIENT_RESOURCES;
+ DPRINT1("Node Parse: %p\n", Node);
+
+ /* Start parsing */
+ Status = STATUS_SUCCESS;
+ while (TRUE)
+ {
+ /* Get the next component */
+ Result = CmpGetNextName(&Current, &NextName, &Last);
+ DPRINT1("Result Parse: %p\n", Result);
+ if ((Result) && (NextName.Length))
+ {
+ /* See if this is a sym link */
+ if (!(Kcb->Flags & KEY_SYM_LINK))
+ {
+ /* Find the subkey */
+ NextCell = CmpFindSubKeyByName(Hive, Node, &NextName);
+ DPRINT1("NextCell Parse: %lx\n", NextCell);
+ if (NextCell != HCELL_NIL)
+ {
+ /* Get the new node */
+ Cell = NextCell;
+ Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
+ DPRINT1("Node Parse: %p\n", Node);
+ if (!Node) ASSERT(FALSE);
+
+ /* Check if this was the last key */
+ if (Last)
+ {
+ /* Shouldn't happen yet */
+ DPRINT1("Unhandled: Open of last key\n");
+ break;
+ }
+
+ /* Get hive and cell from reference */
+ //Hive = Node->ChildHiveReference.KeyHive;
+ //Cell = Node->ChildHiveReference.KeyCell;
+ Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
+ DPRINT1("Node Parse: %p\n", Node);
+ if (!Node) ASSERT(FALSE);
+
+ /* Create a KCB for this key */
+ Kcb = CmpCreateKeyControlBlock(Hive,
+ Cell,
+ Node,
+ ParentKcb,
+ 0,
+ &NextName);
+ if (!Kcb) ASSERT(FALSE);
+ DPRINT1("Kcb Parse: %p\n", Kcb);
+
+ /* Dereference the parent and set the new one */
+ CmpDereferenceKeyControlBlock(ParentKcb);
+ ParentKcb = Kcb;
+ }
+ else
+ {
+ /* Check if this was the last key for a create */
+ if ((Last) && (ParseContext))
+ {
+ /* Check if we're doing a link node */
+ if (ParseContext->CreateLink)
+ {
+ /* The only thing we should see */
+ DPRINT1("Expected: Creating new link\n");
+ }
+ else
+ {
+ /* Create: should not see this (yet) */
+ DPRINT1("Unexpected: Creating new child\n");
+ while (TRUE);
+ }
+
+ /* Update disposition */
+ ParseContext->Disposition = REG_CREATED_NEW_KEY;
+ break;
+ }
+ else
+ {
+ /* Key not found */
+ Status = STATUS_OBJECT_NAME_NOT_FOUND;
+ break;
+ }
+ }
+ }
+ else
+ {
+ /* Not implemented */
+ DPRINT1("Parsing sym link\n");
+ while (TRUE);
+ }
+ }
+ else if ((Result) && (Last))
+ {
+ /* Opening root: unexpected */
+ DPRINT1("Unexpected: Opening root\n");
+ while (TRUE);
+ }
+ else
+ {
+ /* Bogus */
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+ }
+
+ /* Dereference the parent if it exists */
+ if (ParentKcb) CmpDereferenceKeyControlBlock(ParentKcb);
+
+ /* Unlock the registry */
+ CmpUnlockRegistry();
+ return STATUS_NOT_IMPLEMENTED;
+}
Modified: trunk/reactos/ntoskrnl/config/cmsysini.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/config/cmsysini.c…
==============================================================================
--- trunk/reactos/ntoskrnl/config/cmsysini.c (original)
+++ trunk/reactos/ntoskrnl/config/cmsysini.c Tue Dec 4 21:44:51 2007
@@ -504,6 +504,7 @@
UNICODE_STRING ObjectName;
OBJECT_CREATE_INFORMATION ObjectCreateInfo;
CM_PARSE_CONTEXT ParseContext = {0};
+ HANDLE KeyHandle;
PAGED_CODE();
/* Setup the object attributes */
@@ -529,6 +530,17 @@
/* We have one */
ParseContext.ChildHive.KeyCell = RegistryHive->Hive.BaseBlock->RootCell;
}
+
+ DPRINT1("Ready to parse\n");
+ Status = ObOpenObjectByName(&ObjectAttributes,
+ CmpKeyObjectType,
+ KernelMode,
+ NULL,
+ KEY_READ | KEY_WRITE,
+ (PVOID)&ParseContext,
+ &KeyHandle);
+ DPRINT1("Parse done: %lx\n", Status);
+ //while (TRUE);
/* Capture all the info */
Status = ObpCaptureObjectAttributes(&ObjectAttributes,
@@ -1604,6 +1616,73 @@
VOID
NTAPI
+CmpAcquireTwoKcbLocksExcusiveByKey(IN ULONG ConvKey1,
+ IN ULONG ConvKey2)
+{
+ ULONG Index1, Index2;
+
+ /* Sanity check */
+ CMP_ASSERT_REGISTRY_LOCK();
+
+ /* Get hash indexes */
+ Index1 = GET_HASH_INDEX(ConvKey1);
+ Index2 = GET_HASH_INDEX(ConvKey2);
+
+ /* See which one is highest */
+ if (Index1 < Index2)
+ {
+ /* Grab them in the proper order */
+ CmpAcquireKcbLockExclusiveByKey(ConvKey1);
+ CmpAcquireKcbLockExclusiveByKey(ConvKey2);
+ }
+ else
+ {
+ /* Grab the second one first, then the first */
+ CmpAcquireKcbLockExclusiveByKey(ConvKey2);
+ if (Index1 != Index2) CmpAcquireKcbLockExclusiveByKey(ConvKey1);
+ }
+}
+
+VOID
+NTAPI
+CmpReleaseTwoKcbLockByKey(IN ULONG ConvKey1,
+ IN ULONG ConvKey2)
+{
+ ULONG Index1, Index2;
+
+ /* Sanity check */
+ CMP_ASSERT_REGISTRY_LOCK();
+
+ /* Get hash indexes */
+ Index1 = GET_HASH_INDEX(ConvKey1);
+ Index2 = GET_HASH_INDEX(ConvKey2);
+ ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey2).Owner == KeGetCurrentThread()) ||
+ (CmpTestRegistryLockExclusive()));
+
+ /* See which one is highest */
+ if (Index1 < Index2)
+ {
+ /* Grab them in the proper order */
+ ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1).Owner == KeGetCurrentThread())
||
+ (CmpTestRegistryLockExclusive()));
+ CmpReleaseKcbLockByKey(ConvKey2);
+ CmpReleaseKcbLockByKey(ConvKey1);
+ }
+ else
+ {
+ /* Release the first one first, then the second */
+ if (Index1 != Index2)
+ {
+ ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1).Owner ==
KeGetCurrentThread()) ||
+ (CmpTestRegistryLockExclusive()));
+ CmpReleaseKcbLockByKey(ConvKey1);
+ }
+ CmpReleaseKcbLockByKey(ConvKey2);
+ }
+}
+
+VOID
+NTAPI
CmShutdownSystem(VOID)
{
/* Kill the workers and fush all hives */