change gdi object deleting mechanism to a windows compatible one.

svn path=/trunk/; revision=31661
This commit is contained in:
Timo Kreuzer 2008-01-08 05:04:52 +00:00
parent 238f8e2ac9
commit eb5c44b4a9
2 changed files with 78 additions and 31 deletions

View file

@ -24,9 +24,9 @@ typedef struct _GDI_HANDLE_TABLE
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
PPAGED_LOOKASIDE_LIST LookasideLists; PPAGED_LOOKASIDE_LIST LookasideLists;
SLIST_HEADER FreeEntriesHead; ULONG FirstFree;
SLIST_ENTRY FreeEntries[((GDI_HANDLE_COUNT * sizeof(GDI_TABLE_ENTRY)) << 3) / ULONG FirstUnused;
(sizeof(SLIST_ENTRY) << 3)];
} GDI_HANDLE_TABLE, *PGDI_HANDLE_TABLE; } GDI_HANDLE_TABLE, *PGDI_HANDLE_TABLE;
extern PGDI_HANDLE_TABLE GdiHandleTable; extern PGDI_HANDLE_TABLE GdiHandleTable;

View file

@ -124,9 +124,7 @@ GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT *SectionObject)
PGDI_HANDLE_TABLE HandleTable = NULL; PGDI_HANDLE_TABLE HandleTable = NULL;
LARGE_INTEGER htSize; LARGE_INTEGER htSize;
UINT ObjType; UINT ObjType;
UINT i;
ULONG ViewSize = 0; ULONG ViewSize = 0;
PGDI_TABLE_ENTRY Entry;
NTSTATUS Status; NTSTATUS Status;
ASSERT(SectionObject != NULL); ASSERT(SectionObject != NULL);
@ -157,16 +155,6 @@ GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT *SectionObject)
RtlZeroMemory(HandleTable, sizeof(GDI_HANDLE_TABLE)); RtlZeroMemory(HandleTable, sizeof(GDI_HANDLE_TABLE));
/*
* initialize the free entry cache
*/
InitializeSListHead(&HandleTable->FreeEntriesHead);
Entry = &HandleTable->Entries[RESERVE_ENTRIES_COUNT];
for(i = GDI_HANDLE_COUNT - 1; i >= RESERVE_ENTRIES_COUNT; i--)
{
InterlockedPushEntrySList(&HandleTable->FreeEntriesHead, &HandleTable->FreeEntries[i]);
}
HandleTable->LookasideLists = ExAllocatePoolWithTag(NonPagedPool, HandleTable->LookasideLists = ExAllocatePoolWithTag(NonPagedPool,
BASE_OBJTYPE_COUNT * sizeof(PAGED_LOOKASIDE_LIST), BASE_OBJTYPE_COUNT * sizeof(PAGED_LOOKASIDE_LIST),
TAG_GDIHNDTBLE); TAG_GDIHNDTBLE);
@ -188,6 +176,9 @@ GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT *SectionObject)
} }
ShortDelay.QuadPart = -5000LL; /* FIXME - 0.5 ms? */ ShortDelay.QuadPart = -5000LL; /* FIXME - 0.5 ms? */
HandleTable->FirstFree = 0;
HandleTable->FirstUnused = RESERVE_ENTRIES_COUNT;
return HandleTable; return HandleTable;
} }
@ -329,6 +320,69 @@ LockErrorDebugOutput(HGDIOBJ hObj, PGDI_TABLE_ENTRY Entry, LPSTR Function)
KeRosDumpStackFrames(NULL, 20); KeRosDumpStackFrames(NULL, 20);
} }
ULONG
FASTCALL
InterlockedPopFreeEntry(PGDI_HANDLE_TABLE HandleTable)
{
ULONG idxFirstFree, idxNextFree, idxPrev;
PGDI_TABLE_ENTRY pFreeEntry;
DPRINT("Enter InterLockedPopFreeEntry\n");
do
{
idxFirstFree = HandleTable->FirstFree;
if (idxFirstFree)
{
pFreeEntry = HandleTable->Entries + idxFirstFree;
ASSERT(((ULONG)pFreeEntry->KernelData & ~GDI_HANDLE_INDEX_MASK) == 0);
idxNextFree = (ULONG)pFreeEntry->KernelData;
idxPrev = (ULONG)_InterlockedCompareExchange((LONG*)&HandleTable->FirstFree, idxNextFree, idxFirstFree);
}
else
{
idxFirstFree = HandleTable->FirstUnused;
idxNextFree = idxFirstFree + 1;
if (idxNextFree >= GDI_HANDLE_COUNT)
{
DPRINT1("No more gdi handles left!\n");
return 0;
}
idxPrev = (ULONG)_InterlockedCompareExchange((LONG*)&HandleTable->FirstUnused, idxNextFree, idxFirstFree);
}
}
while (idxPrev != idxFirstFree);
return idxFirstFree;
}
/* Pushes an entry of the handle table to the free list,
The entry must be unlocked and the base type field must be 0 */
VOID
FASTCALL
InterlockedPushFreeEntry(PGDI_HANDLE_TABLE HandleTable, ULONG idxToFree)
{
ULONG idxFirstFree, idxPrev;
PGDI_TABLE_ENTRY pFreeEntry;
DPRINT("Enter InterlockedPushFreeEntry\n");
pFreeEntry = HandleTable->Entries + idxToFree;
ASSERT((pFreeEntry->Type & GDI_ENTRY_BASETYPE_MASK) == 0);
ASSERT(pFreeEntry->ProcessId == 0);
pFreeEntry->UserData = NULL;
do
{
idxFirstFree = HandleTable->FirstFree;
pFreeEntry->KernelData = (PVOID)idxFirstFree;
idxPrev = (ULONG)_InterlockedCompareExchange((LONG*)&HandleTable->FirstFree, idxToFree, idxFirstFree);
}
while (idxPrev != idxFirstFree);
}
/*! /*!
* Allocate memory for GDI object and return handle to it. * Allocate memory for GDI object and return handle to it.
* *
@ -380,7 +434,7 @@ GDIOBJ_AllocObj(PGDI_HANDLE_TABLE HandleTable, ULONG ObjectType)
} }
if(newObject != NULL) if(newObject != NULL)
{ {
PSLIST_ENTRY FreeEntry; UINT Index;
PGDI_TABLE_ENTRY Entry; PGDI_TABLE_ENTRY Entry;
PGDIOBJ ObjectBody; PGDIOBJ ObjectBody;
LONG TypeInfo; LONG TypeInfo;
@ -407,15 +461,11 @@ GDIOBJ_AllocObj(PGDI_HANDLE_TABLE HandleTable, ULONG ObjectType)
(type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */ (type = BRSUH, PEN, EXTPEN, basetype = BRUSH) */
TypeInfo = (ObjectType & GDI_HANDLE_BASETYPE_MASK) | (ObjectType >> GDI_ENTRY_UPPER_SHIFT); TypeInfo = (ObjectType & GDI_HANDLE_BASETYPE_MASK) | (ObjectType >> GDI_ENTRY_UPPER_SHIFT);
FreeEntry = InterlockedPopEntrySList(&HandleTable->FreeEntriesHead); Index = InterlockedPopFreeEntry(HandleTable);
if(FreeEntry != NULL) if (Index != 0)
{ {
HANDLE PrevProcId; HANDLE PrevProcId;
UINT Index;
/* calculate the entry from the address of the entry in the free slot array */
Index = ((ULONG_PTR)FreeEntry - (ULONG_PTR)&HandleTable->FreeEntries[0]) /
sizeof(HandleTable->FreeEntries[0]);
Entry = &HandleTable->Entries[Index]; Entry = &HandleTable->Entries[Index];
LockHandle: LockHandle:
@ -424,8 +474,6 @@ LockHandle:
{ {
HGDIOBJ Handle; HGDIOBJ Handle;
ASSERT(Entry->KernelData == NULL);
Entry->KernelData = ObjectBody; Entry->KernelData = ObjectBody;
/* copy the reuse-counter */ /* copy the reuse-counter */
@ -554,7 +602,8 @@ LockHandle:
if(PrevProcId == ProcessId) if(PrevProcId == ProcessId)
{ {
if( (Entry->KernelData != NULL) && if( (Entry->KernelData != NULL) &&
((Entry->Type << GDI_ENTRY_UPPER_SHIFT) == HandleUpper) ) ((Entry->Type << GDI_ENTRY_UPPER_SHIFT) == HandleUpper) &&
((Entry->Type & GDI_ENTRY_BASETYPE_MASK) == (HandleUpper & GDI_ENTRY_BASETYPE_MASK)) )
{ {
PGDIOBJHDR GdiHdr; PGDIOBJHDR GdiHdr;
@ -565,16 +614,14 @@ LockHandle:
BOOL Ret; BOOL Ret;
PW32PROCESS W32Process = PsGetCurrentProcessWin32Process(); PW32PROCESS W32Process = PsGetCurrentProcessWin32Process();
/* Clear the type field so when unlocking the handle it gets finally deleted and increment reuse counter */ /* Clear the basetype field so when unlocking the handle it gets finally deleted and increment reuse counter */
Entry->Type = (Entry->Type + GDI_ENTRY_REUSE_INC) & GDI_ENTRY_REUSE_MASK; Entry->Type = (Entry->Type + GDI_ENTRY_REUSE_INC) & ~GDI_ENTRY_BASETYPE_MASK;
Entry->KernelData = NULL;
/* unlock the handle slot */ /* unlock the handle slot */
(void)InterlockedExchangePointer(&Entry->ProcessId, NULL); (void)InterlockedExchangePointer(&Entry->ProcessId, NULL);
/* push this entry to the free list */ /* push this entry to the free list */
InterlockedPushEntrySList(&HandleTable->FreeEntriesHead, InterlockedPushFreeEntry(HandleTable, GDI_ENTRY_TO_INDEX(HandleTable, Entry));
&HandleTable->FreeEntries[GDI_ENTRY_TO_INDEX(HandleTable, Entry)]);
if(W32Process != NULL) if(W32Process != NULL)
{ {
@ -646,7 +693,7 @@ LockHandle:
else else
{ {
DPRINT1("Attempted to free foreign handle: 0x%x Owner: 0x%x from Caller: 0x%x\n", hObj, (ULONG_PTR)PrevProcId & ~0x1, (ULONG_PTR)ProcessId & ~0x1); DPRINT1("Attempted to free foreign handle: 0x%x Owner: 0x%x from Caller: 0x%x\n", hObj, (ULONG_PTR)PrevProcId & ~0x1, (ULONG_PTR)ProcessId & ~0x1);
KeRosDumpStackFrames(NULL, 20); KeRosDumpStackFrames(NULL, 20);
} }
#ifdef GDI_DEBUG #ifdef GDI_DEBUG
DPRINT1("-> called from %s:%i\n", file, line); DPRINT1("-> called from %s:%i\n", file, line);