From f49768c160d0ee8008bf846c100dea65a0faef25 Mon Sep 17 00:00:00 2001 From: Thomas Bluemel Date: Mon, 13 Dec 2004 21:59:28 +0000 Subject: [PATCH] cache free gdi handles svn path=/trunk/; revision=12100 --- reactos/include/win32k/gdiobj.h | 6 +- reactos/subsys/win32k/objects/gdiobj.c | 131 ++++++++++++++++--------- 2 files changed, 91 insertions(+), 46 deletions(-) diff --git a/reactos/include/win32k/gdiobj.h b/reactos/include/win32k/gdiobj.h index be4e9eb5e66..71c699a6e8d 100644 --- a/reactos/include/win32k/gdiobj.h +++ b/reactos/include/win32k/gdiobj.h @@ -65,6 +65,8 @@ typedef struct _GDIOBJHDR PETHREAD LockingThread; /* only assigned if a thread is holding the lock! */ ULONG Locks; #ifdef GDI_DEBUG + const char* createdfile; + int createdline; const char* lockfile; int lockline; #endif @@ -77,7 +79,6 @@ typedef struct _GDIMULTILOCK DWORD ObjectType; } GDIMULTILOCK, *PGDIMULTILOCK; -HGDIOBJ INTERNAL_CALL GDIOBJ_AllocObj(ULONG ObjectType); BOOL INTERNAL_CALL GDIOBJ_LockMultipleObj(PGDIMULTILOCK pList, INT nObj); BOOL INTERNAL_CALL GDIOBJ_UnlockMultipleObj(PGDIMULTILOCK pList, INT nObj); BOOL INTERNAL_CALL GDIOBJ_OwnedByCurrentProcess(HGDIOBJ ObjectHandle); @@ -92,16 +93,19 @@ BOOL INTERNAL_CALL GDIOBJ_LockMultipleObj(PGDIMULTILOCK pList, INT nObj); #ifdef GDI_DEBUG /* a couple macros for debugging GDIOBJ locking */ +#define GDIOBJ_AllocObj(ty) GDIOBJ_AllocObjDbg(__FILE__,__LINE__,ty) #define GDIOBJ_FreeObj(obj,ty) GDIOBJ_FreeObjDbg(__FILE__,__LINE__,obj,ty) #define GDIOBJ_LockObj(obj,ty) GDIOBJ_LockObjDbg(__FILE__,__LINE__,obj,ty) #define GDIOBJ_UnlockObj(obj) GDIOBJ_UnlockObjDbg(__FILE__,__LINE__,obj) +HGDIOBJ INTERNAL_CALL GDIOBJ_AllocObjDbg(const char* file, int line, ULONG ObjectType); BOOL INTERNAL_CALL GDIOBJ_FreeObjDbg (const char* file, int line, HGDIOBJ hObj, DWORD ObjectType); PGDIOBJ INTERNAL_CALL GDIOBJ_LockObjDbg (const char* file, int line, HGDIOBJ hObj, DWORD ObjectType); BOOL INTERNAL_CALL GDIOBJ_UnlockObjDbg (const char* file, int line, HGDIOBJ hObj); #else /* !GDI_DEBUG */ +HGDIOBJ INTERNAL_CALL GDIOBJ_AllocObj(ULONG ObjectType); BOOL INTERNAL_CALL GDIOBJ_FreeObj (HGDIOBJ hObj, DWORD ObjectType); PGDIOBJ INTERNAL_CALL GDIOBJ_LockObj (HGDIOBJ hObj, DWORD ObjectType); BOOL INTERNAL_CALL GDIOBJ_UnlockObj (HGDIOBJ hObj); diff --git a/reactos/subsys/win32k/objects/gdiobj.c b/reactos/subsys/win32k/objects/gdiobj.c index cf9f288fbdc..cf4b9f96897 100644 --- a/reactos/subsys/win32k/objects/gdiobj.c +++ b/reactos/subsys/win32k/objects/gdiobj.c @@ -19,7 +19,7 @@ /* * GDIOBJ.C - GDI object manipulation routines * - * $Id: gdiobj.c,v 1.76 2004/12/13 12:51:51 weiden Exp $ + * $Id: gdiobj.c,v 1.77 2004/12/13 21:59:28 weiden Exp $ */ #include @@ -52,13 +52,13 @@ STDCALL PsGetProcessId( typedef struct _GDI_HANDLE_TABLE { - LONG HandlesCount; - LONG nEntries; PPAGED_LOOKASIDE_LIST LookasideLists; + + SLIST_HEADER FreeEntriesHead; + SLIST_ENTRY FreeEntries[((GDI_HANDLE_COUNT * sizeof(GDI_TABLE_ENTRY)) << 3) / + (sizeof(SLIST_ENTRY) << 3)]; - PGDI_TABLE_ENTRY EntriesEnd; - - GDI_TABLE_ENTRY Entries[1]; + GDI_TABLE_ENTRY Entries[GDI_HANDLE_COUNT]; } GDI_HANDLE_TABLE, *PGDI_HANDLE_TABLE; typedef struct @@ -116,20 +116,26 @@ static LARGE_INTEGER ShortDelay; * \param Size - number of entries in the object table. */ static PGDI_HANDLE_TABLE INTERNAL_CALL -GDIOBJ_iAllocHandleTable(ULONG Entries) +GDIOBJ_iAllocHandleTable(VOID) { PGDI_HANDLE_TABLE handleTable; UINT ObjType; - ULONG MemSize = sizeof(GDI_HANDLE_TABLE) + (sizeof(GDI_TABLE_ENTRY) * (Entries - 1)); + UINT i; + PGDI_TABLE_ENTRY Entry; - handleTable = ExAllocatePoolWithTag(NonPagedPool, MemSize, TAG_GDIHNDTBLE); + handleTable = ExAllocatePoolWithTag(NonPagedPool, sizeof(GDI_HANDLE_TABLE), TAG_GDIHNDTBLE); ASSERT( handleTable ); - RtlZeroMemory(handleTable, MemSize); - - handleTable->HandlesCount = 0; - handleTable->nEntries = Entries; - - handleTable->EntriesEnd = &handleTable->Entries[Entries]; + 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, OBJTYPE_COUNT * sizeof(PAGED_LOOKASIDE_LIST), @@ -214,12 +220,19 @@ GetObjectSize(DWORD ObjectType) * \todo return the object pointer and lock it by default. */ HGDIOBJ INTERNAL_CALL +#ifdef GDI_DEBUG +GDIOBJ_AllocObjDbg(const char* file, int line, ULONG ObjectType) +#else /* !GDI_DEBUG */ GDIOBJ_AllocObj(ULONG ObjectType) +#endif /* GDI_DEBUG */ { PW32PROCESS W32Process; PGDIOBJHDR newObject; PPAGED_LOOKASIDE_LIST LookasideList; LONG CurrentProcessId, LockedProcessId; +#ifdef GDI_DEBUG + ULONG Attempts = 0; +#endif ASSERT(ObjectType != GDI_OBJECT_TYPE_DONTCARE); @@ -229,6 +242,7 @@ GDIOBJ_AllocObj(ULONG ObjectType) newObject = ExAllocateFromPagedLookasideList(LookasideList); if(newObject != NULL) { + PSLIST_ENTRY FreeEntry; PGDI_TABLE_ENTRY Entry; PGDIOBJ ObjectBody; LONG TypeInfo; @@ -244,6 +258,8 @@ GDIOBJ_AllocObj(ULONG ObjectType) newObject->Locks = 0; #ifdef GDI_DEBUG + newObject->createdfile = file; + newObject->createdline = line; newObject->lockfile = NULL; newObject->lockline = 0; #endif @@ -253,40 +269,57 @@ GDIOBJ_AllocObj(ULONG ObjectType) RtlZeroMemory(ObjectBody, GetObjectSize(ObjectType)); TypeInfo = (ObjectType & 0xFFFF0000) | (ObjectType >> 16); - - /* Search for a free handle entry */ - for(Entry = &HandleTable->Entries[RESERVE_ENTRIES_COUNT]; - Entry < HandleTable->EntriesEnd; - Entry++) + + FreeEntry = InterlockedPopEntrySList(&HandleTable->FreeEntriesHead); + if(FreeEntry != NULL) { - LONG PrevProcId = InterlockedCompareExchange(&Entry->ProcessId, LockedProcessId, 0); + LONG PrevProcId; + UINT Index; + HGDIOBJ Handle; + + /* 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]; + Handle = (HGDIOBJ)((Index & 0xFFFF) | (ObjectType & 0xFFFF0000)); + +LockHandle: + PrevProcId = InterlockedCompareExchange(&Entry->ProcessId, LockedProcessId, 0); if(PrevProcId == 0) { - if(InterlockedCompareExchangePointer(&Entry->KernelData, ObjectBody, NULL) == NULL) + ASSERT(Entry->KernelData == NULL); + + Entry->KernelData = ObjectBody; + + /* we found a free entry, no need to exchange this field atomically + since we're holding the lock */ + Entry->Type = TypeInfo; + + /* unlock the entry */ + InterlockedExchange(&Entry->ProcessId, CurrentProcessId); + + if(W32Process != NULL) { - HGDIOBJ Handle; - UINT Index = GDI_ENTRY_TO_INDEX(HandleTable, Entry); - - Handle = (HGDIOBJ)((Index & 0xFFFF) | (ObjectType & 0xFFFF0000)); - - /* we found a free entry, no need to exchange this field atomically - since we're holding the lock */ - Entry->Type = TypeInfo; - - InterlockedExchange(&Entry->ProcessId, CurrentProcessId); - - if(W32Process != NULL) - { - InterlockedIncrement(&W32Process->GDIObjects); - } - - DPRINT("GDIOBJ_AllocObj: 0x%x ob: 0x%x\n", Handle, ObjectBody); - return Handle; + InterlockedIncrement(&W32Process->GDIObjects); } - else + + DPRINT("GDIOBJ_AllocObj: 0x%x ob: 0x%x\n", Handle, ObjectBody); + return Handle; + } + else + { +#ifdef GDI_DEBUG + if(++Attempts > 20) { - InterlockedExchange(&Entry->ProcessId, PrevProcId); + DPRINT1("[%d]Waiting on 0x%x\n", Attempts, Handle); } +#endif + /* damn, someone is trying to lock the object even though it doesn't + eve nexist anymore, wait a little and try again! + FIXME - we shouldn't loop forever! Give up after some time! */ + DelayExecution(); + /* try again */ + goto LockHandle; } } @@ -374,6 +407,10 @@ LockHandle: /* unlock the handle slot */ InterlockedExchange(&Entry->ProcessId, 0); + /* push this entry to the free list */ + InterlockedPushEntrySList(&HandleTable->FreeEntriesHead, + &HandleTable->FreeEntries[GDI_ENTRY_TO_INDEX(HandleTable, Entry)]); + if(W32Process != NULL) { InterlockedDecrement(&W32Process->GDIObjects); @@ -536,7 +573,7 @@ InitGdiObjectHandleTable (VOID) { DPRINT("InitGdiObjectHandleTable\n"); - HandleTable = GDIOBJ_iAllocHandleTable (GDI_HANDLE_COUNT); + HandleTable = GDIOBJ_iAllocHandleTable(); DPRINT("HandleTable: %x\n", HandleTable); } @@ -561,7 +598,7 @@ NtGdiDeleteObject(HGDIOBJ hObject) BOOL INTERNAL_CALL GDI_CleanupForProcess (struct _EPROCESS *Process) { - PGDI_TABLE_ENTRY Entry; + PGDI_TABLE_ENTRY Entry, End; PEPROCESS CurrentProcess; PW32PROCESS W32Process; LONG ProcId; @@ -582,8 +619,9 @@ GDI_CleanupForProcess (struct _EPROCESS *Process) we should delete it directly here! */ ProcId = ((LONG)Process->UniqueProcessId << 1); + End = &HandleTable->Entries[GDI_HANDLE_COUNT]; for(Entry = &HandleTable->Entries[RESERVE_ENTRIES_COUNT]; - Entry < HandleTable->EntriesEnd; + Entry < End; Entry++, Index++) { /* ignore the lock bit */ @@ -832,6 +870,9 @@ LockHandle: Entry->KernelData = NULL; InterlockedExchange(&Entry->ProcessId, 0); + InterlockedPushEntrySList(&HandleTable->FreeEntriesHead, + &HandleTable->FreeEntries[GDI_ENTRY_TO_INDEX(HandleTable, Entry)]); + if(W32Process != NULL) { InterlockedDecrement(&W32Process->GDIObjects);