diff --git a/reactos/subsystems/win32/win32k/objects/gdiobj.c b/reactos/subsystems/win32/win32k/objects/gdiobj.c index 64f824e8475..bde3402a2a7 100644 --- a/reactos/subsystems/win32/win32k/objects/gdiobj.c +++ b/reactos/subsystems/win32/win32k/objects/gdiobj.c @@ -48,13 +48,6 @@ KeRosDumpStackFrames( /* apparently the first 10 entries are never used in windows as they are empty */ #define RESERVE_ENTRIES_COUNT 10 -typedef struct -{ - ULONG Type; - ULONG Size; - GDICLEANUPPROC CleanupProc; -} GDI_OBJ_INFO, *PGDI_OBJ_INFO; - /* * Dummy GDI Cleanup Callback */ @@ -64,31 +57,6 @@ GDI_CleanupDummy(PVOID ObjectBody) return TRUE; } -/* Testing shows that regions are the most used GDIObj type, - so put that one first for performance */ -static const -GDI_OBJ_INFO ObjInfo[] = -{ - /* Type */ /* Size */ /* CleanupProc */ - {GDI_OBJECT_TYPE_REGION, sizeof(ROSRGNDATA), RGNDATA_Cleanup}, - {GDI_OBJECT_TYPE_BITMAP, sizeof(BITMAPOBJ), BITMAP_Cleanup}, - {GDI_OBJECT_TYPE_DC, sizeof(DC), DC_Cleanup}, - {GDI_OBJECT_TYPE_PALETTE, sizeof(PALGDI), PALETTE_Cleanup}, - {GDI_OBJECT_TYPE_BRUSH, sizeof(GDIBRUSHOBJ), BRUSH_Cleanup}, - {GDI_OBJECT_TYPE_PEN, sizeof(GDIBRUSHOBJ), BRUSH_Cleanup}, - {GDI_OBJECT_TYPE_FONT, sizeof(TEXTOBJ), GDI_CleanupDummy}, - {GDI_OBJECT_TYPE_DIRECTDRAW, sizeof(DD_DIRECTDRAW), DD_Cleanup}, - {GDI_OBJECT_TYPE_DD_SURFACE, sizeof(DD_SURFACE), DDSURF_Cleanup}, - {GDI_OBJECT_TYPE_EXTPEN, sizeof(GDIBRUSHOBJ), BRUSH_Cleanup}, - /* FIXME do not use normal DC struct for this */ - {GDI_OBJECT_TYPE_METADC, sizeof(DC), GDI_CleanupDummy}, - {GDI_OBJECT_TYPE_METAFILE, sizeof(DC), GDI_CleanupDummy}, - {GDI_OBJECT_TYPE_ENHMETAFILE, 0, GDI_CleanupDummy}, - {GDI_OBJECT_TYPE_EMF, 0, GDI_CleanupDummy} -}; - -#define OBJTYPE_COUNT (sizeof(ObjInfo) / sizeof(ObjInfo[0])) - typedef struct { BOOL bUseLookaside; @@ -200,7 +168,7 @@ GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT *SectionObject) } HandleTable->LookasideLists = ExAllocatePoolWithTag(NonPagedPool, - OBJTYPE_COUNT * sizeof(PAGED_LOOKASIDE_LIST), + BASE_OBJTYPE_COUNT * sizeof(PAGED_LOOKASIDE_LIST), TAG_GDIHNDTBLE); if(HandleTable->LookasideLists == NULL) { @@ -210,10 +178,13 @@ GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT *SectionObject) return NULL; } - for(ObjType = 0; ObjType < OBJTYPE_COUNT; ObjType++) + for(ObjType = 0; ObjType < BASE_OBJTYPE_COUNT; ObjType++) { - ExInitializePagedLookasideList(HandleTable->LookasideLists + ObjType, NULL, NULL, 0, - ObjInfo[ObjType].Size + sizeof(GDIOBJHDR), TAG_GDIOBJ, 0); + if (ObjTypeInfo[ObjType].bUseLookaside) + { + ExInitializePagedLookasideList(HandleTable->LookasideLists + ObjType, NULL, NULL, 0, + ObjTypeInfo[ObjType].ulBodySize + sizeof(GDIOBJHDR), ObjTypeInfo[ObjType].Tag, 0); + } } ShortDelay.QuadPart = -5000LL; /* FIXME - 0.5 ms? */ @@ -223,55 +194,21 @@ GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT *SectionObject) static __inline PPAGED_LOOKASIDE_LIST FindLookasideList(PGDI_HANDLE_TABLE HandleTable, - DWORD ObjectType) + ULONG TypeIndex) { - int Index; - - for (Index = 0; Index < OBJTYPE_COUNT; Index++) - { - if (ObjInfo[Index].Type == ObjectType) - { - return HandleTable->LookasideLists + Index; - } - } - - DPRINT1("Can't find lookaside list for object type 0x%08x\n", ObjectType); - - return NULL; + return HandleTable->LookasideLists + TypeIndex; } static __inline BOOL -RunCleanupCallback(PGDIOBJ pObj, DWORD ObjectType) +RunCleanupCallback(PGDIOBJ pObj, ULONG TypeIndex) { - int Index; - - for (Index = 0; Index < OBJTYPE_COUNT; Index++) - { - if (ObjInfo[Index].Type == ObjectType) - { - return ((GDICLEANUPPROC)ObjInfo[Index].CleanupProc)(pObj); - } - } - - DPRINT1("Can't find cleanup callback for object type 0x%08x\n", ObjectType); - return TRUE; + return ((GDICLEANUPPROC)ObjTypeInfo[TypeIndex].CleanupProc)(pObj); } static __inline ULONG -GetObjectSize(DWORD ObjectType) +GetObjectSize(ULONG TypeIndex) { - int Index; - - for (Index = 0; Index < OBJTYPE_COUNT; Index++) - { - if (ObjInfo[Index].Type == ObjectType) - { - return ObjInfo[Index].Size; - } - } - - DPRINT1("Can't find size for object type 0x%08x\n", ObjectType); - return 0; + return ObjTypeInfo[TypeIndex].ulBodySize; } #ifdef GDI_DEBUG @@ -411,9 +348,10 @@ GDIOBJ_AllocObj(PGDI_HANDLE_TABLE HandleTable, ULONG ObjectType) #endif /* GDI_DEBUG */ { PW32PROCESS W32Process; - PGDIOBJHDR newObject; - PPAGED_LOOKASIDE_LIST LookasideList; + PGDIOBJHDR newObject = NULL; + PPAGED_LOOKASIDE_LIST LookasideList = NULL; HANDLE CurrentProcessId, LockedProcessId; + ULONG TypeIndex; #ifdef GDI_DEBUG ULONG Attempts = 0; #endif @@ -426,115 +364,128 @@ GDIOBJ_AllocObj(PGDI_HANDLE_TABLE HandleTable, ULONG ObjectType) ASSERT(ObjectType != GDI_OBJECT_TYPE_DONTCARE); - LookasideList = FindLookasideList(HandleTable, ObjectType); - if(LookasideList != NULL) + TypeIndex = GDI_OBJECT_GET_TYPE_INDEX(ObjectType); + if (ObjTypeInfo[TypeIndex].bUseLookaside) { - newObject = ExAllocateFromPagedLookasideList(LookasideList); - if(newObject != NULL) + LookasideList = FindLookasideList(HandleTable, TypeIndex); + if(LookasideList != NULL) { - PSLIST_ENTRY FreeEntry; - PGDI_TABLE_ENTRY Entry; - PGDIOBJ ObjectBody; - LONG TypeInfo; - - CurrentProcessId = PsGetCurrentProcessId(); - LockedProcessId = (HANDLE)((ULONG_PTR)CurrentProcessId | 0x1); - - newObject->LockingThread = NULL; - newObject->Locks = 0; - -#ifdef GDI_DEBUG - newObject->createdfile = file; - newObject->createdline = line; - newObject->lockfile = NULL; - newObject->lockline = 0; -#endif - - ObjectBody = GDIHdrToBdy(newObject); - - RtlZeroMemory(ObjectBody, GetObjectSize(ObjectType)); - - /* FIXME: On Windows the higher 16 bit of the type field don't always match - the type from the handle, it is probably a storage type - (type = pen, storage = brush) */ - TypeInfo = (ObjectType & GDI_HANDLE_TYPE_MASK) | (ObjectType >> GDI_ENTRY_UPPER_SHIFT); - - FreeEntry = InterlockedPopEntrySList(&HandleTable->FreeEntriesHead); - if(FreeEntry != NULL) - { - 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]; - -LockHandle: - PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId, LockedProcessId, 0); - if(PrevProcId == NULL) - { - HGDIOBJ Handle; - - ASSERT(Entry->KernelData == NULL); - - Entry->KernelData = ObjectBody; - - /* copy the reuse-counter */ - TypeInfo |= Entry->Type & GDI_ENTRY_REUSE_MASK; - - /* we found a free entry, no need to exchange this field atomically - since we're holding the lock */ - Entry->Type = TypeInfo; - - /* unlock the entry */ - (void)InterlockedExchangePointer(&Entry->ProcessId, CurrentProcessId); - -#ifdef GDI_DEBUG - memset ( GDIHandleAllocator[Index], 0xcd, GDI_STACK_LEVELS * sizeof(ULONG) ); - KeRosGetStackFrames ( GDIHandleAllocator[Index], GDI_STACK_LEVELS ); -#endif /* GDI_DEBUG */ - - if(W32Process != NULL) - { - InterlockedIncrement(&W32Process->GDIObjects); - } - Handle = (HGDIOBJ)((Index & 0xFFFF) | (TypeInfo << GDI_ENTRY_UPPER_SHIFT)); - - DPRINT("GDIOBJ_AllocObj: 0x%x ob: 0x%x\n", Handle, ObjectBody); - return Handle; - } - else - { -#ifdef GDI_DEBUG - if(++Attempts > 20) - { - DPRINT1("[%d]Waiting on handle in index 0x%x\n", Attempts, Index); - } -#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; - } - } - - ExFreeToPagedLookasideList(LookasideList, newObject); - DPRINT1("Failed to insert gdi object into the handle table, no handles left!\n"); -#ifdef GDI_DEBUG - IntDumpHandleTable(HandleTable); -#endif /* GDI_DEBUG */ - } - else - { - DPRINT1("Not enough memory to allocate gdi object!\n"); + newObject = ExAllocateFromPagedLookasideList(LookasideList); } } else { - DPRINT1("Failed to find lookaside list for object type 0x%x\n", ObjectType); + newObject = ExAllocatePoolWithTag(PagedPool, + ObjTypeInfo[TypeIndex].ulBodySize + sizeof(GDIOBJHDR), + ObjTypeInfo[TypeIndex].Tag); + } + if(newObject != NULL) + { + PSLIST_ENTRY FreeEntry; + PGDI_TABLE_ENTRY Entry; + PGDIOBJ ObjectBody; + LONG TypeInfo; + + CurrentProcessId = PsGetCurrentProcessId(); + LockedProcessId = (HANDLE)((ULONG_PTR)CurrentProcessId | 0x1); + + newObject->LockingThread = NULL; + newObject->Locks = 0; + +#ifdef GDI_DEBUG + newObject->createdfile = file; + newObject->createdline = line; + newObject->lockfile = NULL; + newObject->lockline = 0; +#endif + + ObjectBody = GDIHdrToBdy(newObject); + + RtlZeroMemory(ObjectBody, GetObjectSize(TypeIndex)); + + /* FIXME: On Windows the higher 16 bit of the type field don't always match + the type from the handle, it is probably a storage type + (type = pen, storage = brush) */ + TypeInfo = (ObjectType & GDI_HANDLE_TYPE_MASK) | (ObjectType >> GDI_ENTRY_UPPER_SHIFT); + + FreeEntry = InterlockedPopEntrySList(&HandleTable->FreeEntriesHead); + if(FreeEntry != NULL) + { + 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]; + +LockHandle: + PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId, LockedProcessId, 0); + if(PrevProcId == NULL) + { + HGDIOBJ Handle; + + ASSERT(Entry->KernelData == NULL); + + Entry->KernelData = ObjectBody; + + /* copy the reuse-counter */ + TypeInfo |= Entry->Type & GDI_ENTRY_REUSE_MASK; + + /* we found a free entry, no need to exchange this field atomically + since we're holding the lock */ + Entry->Type = TypeInfo; + + /* unlock the entry */ + (void)InterlockedExchangePointer(&Entry->ProcessId, CurrentProcessId); + +#ifdef GDI_DEBUG + memset ( GDIHandleAllocator[Index], 0xcd, GDI_STACK_LEVELS * sizeof(ULONG) ); + KeRosGetStackFrames ( GDIHandleAllocator[Index], GDI_STACK_LEVELS ); +#endif /* GDI_DEBUG */ + + if(W32Process != NULL) + { + InterlockedIncrement(&W32Process->GDIObjects); + } + Handle = (HGDIOBJ)((Index & 0xFFFF) | (TypeInfo << GDI_ENTRY_UPPER_SHIFT)); + + DPRINT("GDIOBJ_AllocObj: 0x%x ob: 0x%x\n", Handle, ObjectBody); + return Handle; + } + else + { +#ifdef GDI_DEBUG + if(++Attempts > 20) + { + DPRINT1("[%d]Waiting on handle in index 0x%x\n", Attempts, Index); + } +#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; + } + } + + if (ObjTypeInfo[TypeIndex].bUseLookaside) + { + ExFreeToPagedLookasideList(LookasideList, newObject); + } + else + { + ExFreePool(newObject); + } + DPRINT1("Failed to insert gdi object into the handle table, no handles left!\n"); +#ifdef GDI_DEBUG + IntDumpHandleTable(HandleTable); +#endif /* GDI_DEBUG */ + } + else + { + DPRINT1("Not enough memory to allocate gdi object!\n"); } return NULL; } @@ -559,7 +510,7 @@ GDIOBJ_FreeObj(PGDI_HANDLE_TABLE HandleTable, HGDIOBJ hObj, DWORD ExpectedType) PGDI_TABLE_ENTRY Entry; PPAGED_LOOKASIDE_LIST LookasideList; HANDLE ProcessId, LockedProcessId, PrevProcId; - ULONG HandleType, HandleUpper; + ULONG HandleType, HandleUpper, TypeIndex; BOOL Silent; #ifdef GDI_DEBUG ULONG Attempts = 0; @@ -632,13 +583,21 @@ LockHandle: } /* call the cleanup routine. */ - Ret = RunCleanupCallback(GDIHdrToBdy(GdiHdr), HandleType); + TypeIndex = GDI_OBJECT_GET_TYPE_INDEX(HandleType); + Ret = RunCleanupCallback(GDIHdrToBdy(GdiHdr), TypeIndex); /* Now it's time to free the memory */ - LookasideList = FindLookasideList(HandleTable, HandleType); - if(LookasideList != NULL) + if (ObjTypeInfo[TypeIndex].bUseLookaside) { - ExFreeToPagedLookasideList(LookasideList, GdiHdr); + LookasideList = FindLookasideList(HandleTable, TypeIndex); + if(LookasideList != NULL) + { + ExFreeToPagedLookasideList(LookasideList, GdiHdr); + } + } + else + { + ExFreePool(GdiHdr); } return Ret;