Author: ion Date: Mon May 29 04:05:07 2006 New Revision: 22098
URL: http://svn.reactos.ru/svn/reactos?rev=22098&view=rev Log: - Object Manager Improvement Patch 1/3: - Re-implement delayed object deletion by using an optimized Object Reaper based on OBJECT_HEADER->NextToFree. Thanks to Thomas for the algorithm. - Refactor object deletion into two operations: Removal and de-allocation (this is needed for failure during allocation, which we don't do yet). - BugFixes: * After freeing an object header structure, also clear the pointer so we don't attempt it again. * Clear the handle database if there is one * Make sure the create info flag is set before deleting captured attributes. * Use the allocation pool tag when de-allocating. * Use OBJECT_TYPE accounting for tracking the numbef of objects. * Remove the object from it's typelist if it has creator information. * Call the security procedure to delete the security descriptor.
Modified: trunk/reactos/include/ndk/obtypes.h trunk/reactos/ntoskrnl/include/internal/ob.h trunk/reactos/ntoskrnl/ob/oblife.c trunk/reactos/ntoskrnl/ob/obref.c
Modified: trunk/reactos/include/ndk/obtypes.h URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/include/ndk/obtypes.h?rev=22... ============================================================================== --- trunk/reactos/include/ndk/obtypes.h (original) +++ trunk/reactos/include/ndk/obtypes.h Mon May 29 04:05:07 2006 @@ -416,7 +416,7 @@ union { LONG HandleCount; - PVOID NextToFree; + volatile PVOID NextToFree; }; POBJECT_TYPE Type; UCHAR NameInfoOffset;
Modified: trunk/reactos/ntoskrnl/include/internal/ob.h URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/ntoskrnl/include/internal/ob... ============================================================================== --- trunk/reactos/ntoskrnl/include/internal/ob.h (original) +++ trunk/reactos/ntoskrnl/include/internal/ob.h Mon May 29 04:05:07 2006 @@ -30,6 +30,8 @@ extern POBJECT_DIRECTORY NameSpaceRoot; extern POBJECT_DIRECTORY ObpTypeDirectoryObject; extern PHANDLE_TABLE ObpKernelHandleTable; +extern WORK_QUEUE_ITEM ObpReaperWorkItem; +extern volatile PVOID ObpReaperList;
BOOLEAN NTAPI @@ -157,10 +159,16 @@ STDCALL ObKillProcess(PEPROCESS Process);
-NTSTATUS -ObpDeleteObjectDpcLevel( - IN POBJECT_HEADER ObjectHeader, - IN LONG OldPointerCount +VOID +FASTCALL +ObpDeleteObject( + IN PVOID Object +); + +VOID +NTAPI +ObpReapObject( + IN PVOID Unused );
/* Security descriptor cache functions */
Modified: trunk/reactos/ntoskrnl/ob/oblife.c URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/ntoskrnl/ob/oblife.c?rev=220... ============================================================================== --- trunk/reactos/ntoskrnl/ob/oblife.c (original) +++ trunk/reactos/ntoskrnl/ob/oblife.c Mon May 29 04:05:07 2006 @@ -21,59 +21,33 @@
POBJECT_TYPE ObTypeObjectType = NULL; KEVENT ObpDefaultObject; - -typedef struct _RETENTION_CHECK_PARAMS -{ - WORK_QUEUE_ITEM WorkItem; - POBJECT_HEADER ObjectHeader; -} RETENTION_CHECK_PARAMS, *PRETENTION_CHECK_PARAMS; +WORK_QUEUE_ITEM ObpReaperWorkItem; +volatile PVOID ObpReaperList;
/* PRIVATE FUNCTIONS *********************************************************/
-static NTSTATUS -ObpDeleteObject(POBJECT_HEADER Header) -{ - PVOID HeaderLocation = Header; +VOID +FASTCALL +ObpDeallocateObject(IN PVOID Object) +{ + PVOID HeaderLocation; + POBJECT_HEADER Header; + POBJECT_TYPE ObjectType; POBJECT_HEADER_HANDLE_INFO HandleInfo; POBJECT_HEADER_NAME_INFO NameInfo; POBJECT_HEADER_CREATOR_INFO CreatorInfo; - - DPRINT("ObpDeleteObject(Header %p)\n", Header); - if (KeGetCurrentIrql() != PASSIVE_LEVEL) - { - DPRINT("ObpDeleteObject called at an unsupported IRQL. Use ObpDeleteObjectDpcLevel instead.\n"); - KEBUGCHECK(0); - } - - if (Header->Type != NULL && - Header->Type->TypeInfo.DeleteProcedure != NULL) - { - Header->Type->TypeInfo.DeleteProcedure(&Header->Body); - } - - if (Header->SecurityDescriptor != NULL) - { - ObpRemoveSecurityDescriptor(Header->SecurityDescriptor); - } - - if (OBJECT_HEADER_TO_NAME_INFO(Header)) - { - if(OBJECT_HEADER_TO_NAME_INFO(Header)->Name.Buffer) - { - ExFreePool(OBJECT_HEADER_TO_NAME_INFO(Header)->Name.Buffer); - } - } - if (Header->ObjectCreateInfo) - { - ObpReleaseCapturedAttributes(Header->ObjectCreateInfo); - ExFreePool(Header->ObjectCreateInfo); - } + PAGED_CODE(); + + /* Get the header and assume this is what we'll free */ + Header = OBJECT_TO_OBJECT_HEADER(Object); + ObjectType = Header->Type; + HeaderLocation = Header;
/* To find the header, walk backwards from how we allocated */ if ((CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(Header))) { HeaderLocation = CreatorInfo; - } + } if ((NameInfo = OBJECT_HEADER_TO_NAME_INFO(Header))) { HeaderLocation = NameInfo; @@ -83,88 +57,124 @@ HeaderLocation = HandleInfo; }
- DPRINT("ObPerformRetentionChecks() = Freeing object\n"); - ExFreePool(HeaderLocation); - - return(STATUS_SUCCESS); -} - - -VOID STDCALL -ObpDeleteObjectWorkRoutine (IN PVOID Parameter) -{ - PRETENTION_CHECK_PARAMS Params = (PRETENTION_CHECK_PARAMS)Parameter; - /* ULONG Tag; */ /* See below */ - - ASSERT(Params); - ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); /* We need PAGED_CODE somewhere... */ - - /* Turn this on when we have ExFreePoolWithTag - Tag = Params->ObjectHeader->Type->Tag; */ - ObpDeleteObject(Params->ObjectHeader); - ExFreePool(Params); - /* ExFreePoolWithTag(Params, Tag); */ -} - - -NTSTATUS -ObpDeleteObjectDpcLevel(IN POBJECT_HEADER ObjectHeader, - IN LONG OldPointerCount) -{ -#if 0 - if (ObjectHeader->PointerCount < 0) - { - CPRINT("Object %p/%p has invalid reference count (%d)\n", - ObjectHeader, HEADER_TO_BODY(ObjectHeader), - ObjectHeader->PointerCount); - KEBUGCHECK(0); - } - - if (ObjectHeader->HandleCount < 0) - { - CPRINT("Object %p/%p has invalid handle count (%d)\n", - ObjectHeader, HEADER_TO_BODY(ObjectHeader), - ObjectHeader->HandleCount); - KEBUGCHECK(0); - } -#endif - - - switch (KeGetCurrentIrql ()) - { - case PASSIVE_LEVEL: - return ObpDeleteObject (ObjectHeader); - - case APC_LEVEL: - case DISPATCH_LEVEL: - { - PRETENTION_CHECK_PARAMS Params; - - /* - We use must succeed pool here because if the allocation fails - then we leak memory. - */ - Params = (PRETENTION_CHECK_PARAMS) - ExAllocatePoolWithTag(NonPagedPoolMustSucceed, - sizeof(RETENTION_CHECK_PARAMS), - ObjectHeader->Type->Key); - Params->ObjectHeader = ObjectHeader; - ExInitializeWorkItem(&Params->WorkItem, - ObpDeleteObjectWorkRoutine, - (PVOID)Params); - ExQueueWorkItem(&Params->WorkItem, - CriticalWorkQueue); - } - return STATUS_PENDING; - - default: - DPRINT("ObpDeleteObjectDpcLevel called at unsupported " - "IRQL %u!\n", KeGetCurrentIrql()); - KEBUGCHECK(0); - return STATUS_UNSUCCESSFUL; - } - - return STATUS_SUCCESS; + /* Check if we have create info */ + if (Header->Flags & OB_FLAG_CREATE_INFO) + { + /* Double-check that it exists */ + if (Header->ObjectCreateInfo) + { + /* Free it */ + ObpReleaseCapturedAttributes(Header->ObjectCreateInfo); + Header->ObjectCreateInfo = NULL; + } + } + + /* Check if a handle database was active */ + if ((HandleInfo) && (Header->Flags & OB_FLAG_SINGLE_PROCESS)) + { + /* Free it */ + ExFreePool(HandleInfo->HandleCountDatabase); + HandleInfo->HandleCountDatabase = NULL; + } + + /* Check if we have a name */ + if ((NameInfo) && (NameInfo->Name.Buffer)) + { + /* Free it */ + ExFreePool(NameInfo->Name.Buffer); + NameInfo->Name.Buffer = NULL; + } + + /* Free the object using the same allocation tag */ + ExFreePoolWithTag(HeaderLocation, + ObjectType ? TAG('T', 'j', 'b', 'O') : ObjectType->Key); + + /* Decrease the total */ + ObjectType->TotalNumberOfObjects--; +} + +VOID +FASTCALL +ObpDeleteObject(IN PVOID Object) +{ + POBJECT_HEADER Header; + POBJECT_TYPE ObjectType; + POBJECT_HEADER_NAME_INFO NameInfo; + POBJECT_HEADER_CREATOR_INFO CreatorInfo; + PAGED_CODE(); + + /* Get the header and type */ + Header = OBJECT_TO_OBJECT_HEADER(Object); + ObjectType = Header->Type; + + /* Get creator and name information */ + NameInfo = OBJECT_HEADER_TO_NAME_INFO(Header); + CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(Header); + + /* Check if the object is on a type list */ + if ((CreatorInfo) && !(IsListEmpty(&CreatorInfo->TypeList))) + { + /* Remove the object from the type list */ + RemoveEntryList(&CreatorInfo->TypeList); + } + + /* Check if we have a name */ + if ((NameInfo) && (NameInfo->Name.Buffer)) + { + /* Free it */ + ExFreePool(NameInfo->Name.Buffer); + + /* Clean up the string so we don't try this again */ + RtlInitUnicodeString(&NameInfo->Name, NULL); + } + + /* Check if we have a security descriptor */ + if (Header->SecurityDescriptor) + { + ObjectType->TypeInfo.SecurityProcedure(Object, + DeleteSecurityDescriptor, + 0, + NULL, + NULL, + &Header->SecurityDescriptor, + 0, + NULL); + } + + /* Check if we have a delete procedure */ + if (ObjectType->TypeInfo.DeleteProcedure) + { + /* Call it */ + ObjectType->TypeInfo.DeleteProcedure(Object); + } + + /* Now de-allocate all object members */ + ObpDeallocateObject(Object); +} + +VOID +NTAPI +ObpReapObject(IN PVOID Parameter) +{ + POBJECT_HEADER ReapObject; + PVOID NextObject; + + /* Start reaping */ + while((ReapObject = InterlockedExchangePointer(&ObpReaperList, NULL))) + { + /* Start deletion loop */ + do + { + /* Get the next object */ + NextObject = ReapObject->NextToFree; + + /* Delete the object */ + ObpDeleteObject(&ReapObject->Body); + + /* Move to the next one */ + ReapObject = NextObject; + } while(NextObject != NULL); + } }
NTSTATUS
Modified: trunk/reactos/ntoskrnl/ob/obref.c URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/ntoskrnl/ob/obref.c?rev=2209... ============================================================================== --- trunk/reactos/ntoskrnl/ob/obref.c (original) +++ trunk/reactos/ntoskrnl/ob/obref.c Mon May 29 04:05:07 2006 @@ -104,28 +104,37 @@ ObfDereferenceObject(IN PVOID Object) { POBJECT_HEADER Header; - LONG NewPointerCount; - BOOL Permanent; - - ASSERT(Object); - - /* Extract the object header. */ + + /* Extract the object header */ Header = OBJECT_TO_OBJECT_HEADER(Object); - Permanent = Header->Flags & OB_FLAG_PERMANENT; - - /* - Drop our reference and get the new count so we can tell if this was the - last reference. - */ - NewPointerCount = InterlockedDecrement(&Header->PointerCount); - DPRINT("ObfDereferenceObject(0x%x)==%d\n", Object, NewPointerCount); - ASSERT(NewPointerCount >= 0);
/* Check whether the object can now be deleted. */ - if (NewPointerCount == 0 && - !Permanent) - { - ObpDeleteObjectDpcLevel(Header, NewPointerCount); + if (!(InterlockedDecrement(&Header->PointerCount)) && + !(Header->Flags & OB_FLAG_PERMANENT)) + { + /* Sanity check */ + ASSERT(!Header->HandleCount); + + /* Check if we're at PASSIVE */ + if (KeGetCurrentIrql() == PASSIVE_LEVEL) + { + /* Remove the object */ + ObpDeleteObject(Object); + } + else + { + /* Add us to the list */ + do + { + Header->NextToFree = ObpReaperList; + } while (InterlockedCompareExchangePointer(&ObpReaperList, + Header, + Header->NextToFree) != + Header->NextToFree); + + /* Queue the work item */ + ExQueueWorkItem(&ObpReaperWorkItem, DelayedWorkQueue); + } } }