From d786cecb72bf561f3a1f1a89b053fc6af989e384 Mon Sep 17 00:00:00 2001 From: Thomas Bluemel Date: Fri, 18 Feb 2005 12:54:17 +0000 Subject: [PATCH] implemented reuse counters for gdi objects svn path=/trunk/; revision=13628 --- reactos/include/win32k/gdiobj.h | 23 ++--- reactos/subsys/win32k/objects/gdiobj.c | 127 ++++++------------------- reactos/subsys/win32k/objects/region.c | 85 ++++++++--------- 3 files changed, 79 insertions(+), 156 deletions(-) diff --git a/reactos/include/win32k/gdiobj.h b/reactos/include/win32k/gdiobj.h index 692d28d3d3b..1640e2d37f1 100644 --- a/reactos/include/win32k/gdiobj.h +++ b/reactos/include/win32k/gdiobj.h @@ -19,13 +19,16 @@ #define GDI_HANDLE_INDEX_MASK (GDI_HANDLE_COUNT - 1) #define GDI_HANDLE_TYPE_MASK 0x007f0000 #define GDI_HANDLE_STOCK_MASK 0x00800000 +#define GDI_HANDLE_REUSE_MASK 0xff000000 + +#define GDI_HANDLE_REUSECNT_SHIFT 24 #define GDI_HANDLE_CREATE(i, t) ((HANDLE)(((i) & GDI_HANDLE_INDEX_MASK) | ((t) & GDI_HANDLE_TYPE_MASK))) -#define GDI_HANDLE_GET_INDEX(h) (((DWORD)(h)) & GDI_HANDLE_INDEX_MASK) -#define GDI_HANDLE_GET_TYPE(h) (((DWORD)(h)) & GDI_HANDLE_TYPE_MASK) -#define GDI_HANDLE_IS_TYPE(h, t) ((t) == (((DWORD)(h)) & GDI_HANDLE_TYPE_MASK)) -#define GDI_HANDLE_IS_STOCKOBJ(h) (0 != (((DWORD)(h)) & GDI_HANDLE_STOCK_MASK)) -#define GDI_HANDLE_SET_STOCKOBJ(h) ((h) = (HANDLE)(((DWORD)(h)) | GDI_HANDLE_STOCK_MASK)) +#define GDI_HANDLE_GET_INDEX(h) (((ULONG_PTR)(h)) & GDI_HANDLE_INDEX_MASK) +#define GDI_HANDLE_GET_TYPE(h) (((ULONG_PTR)(h)) & GDI_HANDLE_TYPE_MASK) +#define GDI_HANDLE_IS_TYPE(h, t) ((t) == (((ULONG_PTR)(h)) & GDI_HANDLE_TYPE_MASK)) +#define GDI_HANDLE_IS_STOCKOBJ(h) (0 != (((ULONG_PTR)(h)) & GDI_HANDLE_STOCK_MASK)) +#define GDI_HANDLE_SET_STOCKOBJ(h) ((h) = (HANDLE)(((ULONG_PTR)(h)) | GDI_HANDLE_STOCK_MASK)) /*! \defgroup GDI object types @@ -74,20 +77,10 @@ typedef struct _GDIOBJHDR #endif } GDIOBJHDR, *PGDIOBJHDR; -typedef struct _GDIMULTILOCK -{ - HGDIOBJ hObj; - PGDIOBJ pObj; - DWORD ObjectType; -} GDIMULTILOCK, *PGDIMULTILOCK; - -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); void INTERNAL_CALL GDIOBJ_SetOwnership(HGDIOBJ ObjectHandle, PEPROCESS Owner); void INTERNAL_CALL GDIOBJ_CopyOwnership(HGDIOBJ CopyFrom, HGDIOBJ CopyTo); BOOL INTERNAL_CALL GDIOBJ_ConvertToStockObj(HGDIOBJ *hObj); -BOOL INTERNAL_CALL GDIOBJ_LockMultipleObj(PGDIMULTILOCK pList, INT nObj); #define GDIOBJ_GetObjectType(Handle) \ GDI_HANDLE_GET_TYPE(Handle) diff --git a/reactos/subsys/win32k/objects/gdiobj.c b/reactos/subsys/win32k/objects/gdiobj.c index 927bfc65d6c..f883af8d4a3 100644 --- a/reactos/subsys/win32k/objects/gdiobj.c +++ b/reactos/subsys/win32k/objects/gdiobj.c @@ -377,28 +377,31 @@ GDIOBJ_AllocObj(ULONG ObjectType) RtlZeroMemory(ObjectBody, GetObjectSize(ObjectType)); - TypeInfo = (ObjectType & 0xFFFF0000) | (ObjectType >> 16); + TypeInfo = (ObjectType & GDI_HANDLE_TYPE_MASK) | (ObjectType >> 16); FreeEntry = InterlockedPopEntrySList(&HandleTable->FreeEntriesHead); if(FreeEntry != NULL) { HANDLE 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 = 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_HANDLE_REUSE_MASK; /* we found a free entry, no need to exchange this field atomically since we're holding the lock */ @@ -416,6 +419,7 @@ LockHandle: { InterlockedIncrement(&W32Process->GDIObjects); } + Handle = (HGDIOBJ)((Index & 0xFFFF) | (TypeInfo & (GDI_HANDLE_TYPE_MASK | GDI_HANDLE_REUSE_MASK))); DPRINT("GDIOBJ_AllocObj: 0x%x ob: 0x%x\n", Handle, ObjectBody); return Handle; @@ -425,7 +429,7 @@ LockHandle: #ifdef GDI_DEBUG if(++Attempts > 20) { - DPRINT1("[%d]Waiting on 0x%x\n", Attempts, Handle); + 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 @@ -508,7 +512,8 @@ LockHandle: PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId, LockedProcessId, ProcessId); if(PrevProcId == ProcessId) { - if(Entry->Type != 0 && Entry->KernelData != NULL && (ExpectedType == 0 || ((Entry->Type << 16) == ExpectedType))) + if(Entry->Type != 0 && Entry->KernelData != NULL && + (ExpectedType == 0 || ((Entry->Type << 16) == ExpectedType))) { PGDIOBJHDR GdiHdr; @@ -520,8 +525,8 @@ LockHandle: PW32PROCESS W32Process = PsGetWin32Process(); ULONG Type = Entry->Type << 16; - /* Clear the type field so when unlocking the handle it gets finally deleted */ - Entry->Type = 0; + /* Clear the type field so when unlocking the handle it gets finally deleted and increment reuse counter */ + Entry->Type = ((Entry->Type >> GDI_HANDLE_REUSECNT_SHIFT) + 1) << GDI_HANDLE_REUSECNT_SHIFT; Entry->KernelData = NULL; /* unlock the handle slot */ @@ -551,8 +556,9 @@ LockHandle: else { /* the object is currently locked. just clear the type field so when the - object gets unlocked it will be finally deleted from the table. */ - Entry->Type = 0; + object gets unlocked it will be finally deleted from the table. Also + incrment the reuse counter! */ + Entry->Type = ((Entry->Type >> GDI_HANDLE_REUSECNT_SHIFT) + 1) << GDI_HANDLE_REUSECNT_SHIFT; /* unlock the handle slot */ InterlockedExchangePointer(&Entry->ProcessId, NULL); @@ -563,7 +569,7 @@ LockHandle: } else { - if(Entry->Type != 0) + if((Entry->Type & ~GDI_HANDLE_REUSE_MASK) != 0) { DPRINT1("Attempted to delete object 0x%x, type mismatch (0x%x : 0x%x)\n", hObj, ObjectType, ExpectedType); } @@ -609,85 +615,6 @@ LockHandle: return FALSE; } -/*! - * Lock multiple objects. Use this function when you need to lock multiple objects and some of them may be - * duplicates. You should use this function to avoid trying to lock the same object twice! - * - * \param pList pointer to the list that contains handles to the objects. You should set hObj and ObjectType fields. - * \param nObj number of objects to lock - * \return for each entry in pList this function sets pObj field to point to the object. - * - * \note this function uses an O(n^2) algoritm because we shouldn't need to call it with more than 3 or 4 objects. -*/ -BOOL INTERNAL_CALL -GDIOBJ_LockMultipleObj(PGDIMULTILOCK pList, INT nObj) -{ - INT i, j; - ASSERT( pList ); - /* FIXME - check for "invalid" handles */ - /* go through the list checking for duplicate objects */ - for (i = 0; i < nObj; i++) - { - pList[i].pObj = NULL; - for (j = 0; j < i; j++) - { - if (pList[i].hObj == pList[j].hObj) - { - /* already locked, so just copy the pointer to the object */ - pList[i].pObj = pList[j].pObj; - break; - } - } - - if (NULL == pList[i].pObj) - { - /* object hasn't been locked, so lock it. */ - if (NULL != pList[i].hObj) - { - pList[i].pObj = GDIOBJ_LockObj(pList[i].hObj, pList[i].ObjectType); - } - } - } - - return TRUE; -} - -/*! - * Unlock multiple objects. Use this function when you need to unlock multiple objects and some of them may be - * duplicates. - * - * \param pList pointer to the list that contains handles to the objects. You should set hObj and ObjectType fields. - * \param nObj number of objects to lock - * - * \note this function uses O(n^2) algoritm because we shouldn't need to call it with more than 3 or 4 objects. -*/ -BOOL INTERNAL_CALL -GDIOBJ_UnlockMultipleObj(PGDIMULTILOCK pList, INT nObj) -{ - INT i, j; - ASSERT(pList); - - /* go through the list checking for duplicate objects */ - for (i = 0; i < nObj; i++) - { - if (NULL != pList[i].pObj) - { - for (j = i + 1; j < nObj; j++) - { - if ((pList[i].pObj == pList[j].pObj)) - { - /* set the pointer to zero for all duplicates */ - pList[j].pObj = NULL; - } - } - GDIOBJ_UnlockObj(pList[i].hObj); - pList[i].pObj = NULL; - } - } - - return TRUE; -} - /*! * Initialization of the GDI object engine. */ @@ -744,11 +671,11 @@ GDI_CleanupForProcess (struct _EPROCESS *Process) End = &HandleTable->Entries[GDI_HANDLE_COUNT]; for(Entry = &HandleTable->Entries[RESERVE_ENTRIES_COUNT]; - Entry < End; + Entry != End; Entry++, Index++) { /* ignore the lock bit */ - if((HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) == ProcId && Entry->Type != 0) + if((HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) == ProcId && (Entry->Type & ~GDI_HANDLE_REUSE_MASK) != 0) { HGDIOBJ ObjectHandle; @@ -824,7 +751,8 @@ LockHandle: /* we're locking an object that belongs to our process or it's a global object if ProcessId == 0 here. ProcessId can only be 0 here if it previously failed to lock the object and it turned out to be a global object. */ - if(EntryType != 0 && Entry->KernelData != NULL && (ExpectedType == 0 || (EntryType == ExpectedType))) + if(EntryType != 0 && Entry->KernelData != NULL && + (ExpectedType == 0 || (EntryType == ExpectedType))) { PETHREAD PrevThread; PGDIOBJHDR GdiHdr; @@ -870,14 +798,15 @@ LockHandle: { InterlockedExchangePointer(&Entry->ProcessId, PrevProcId); - if(EntryType == 0) + if((EntryType & ~GDI_HANDLE_REUSE_MASK) == 0) { DPRINT1("Attempted to lock object 0x%x that is deleted!\n", hObj); KeRosDumpStackFrames ( NULL, 20 ); } else { - DPRINT1("Attempted to lock object 0x%x, type mismatch (0x%x : 0x%x)\n", hObj, EntryType, ExpectedType); + DPRINT1("Attempted to lock object 0x%x, type mismatch (0x%x : 0x%x)\n", + hObj, EntryType & ~GDI_HANDLE_REUSE_MASK, ExpectedType & ~GDI_HANDLE_REUSE_MASK); KeRosDumpStackFrames ( NULL, 20 ); } #ifdef GDI_DEBUG @@ -981,7 +910,7 @@ LockHandle: #endif } - if(Entry->Type == 0 && GdiHdr->Locks == 0) + if((Entry->Type & ~GDI_HANDLE_REUSE_MASK) == 0 && GdiHdr->Locks == 0) { PPAGED_LOOKASIDE_LIST LookasideList; PW32PROCESS W32Process = PsGetWin32Process(); @@ -1095,7 +1024,7 @@ GDIOBJ_OwnedByCurrentProcess(HGDIOBJ ObjectHandle) Entry = GDI_HANDLE_GET_ENTRY(HandleTable, ObjectHandle); Ret = Entry->KernelData != NULL && - Entry->Type != 0 && + (Entry->Type & ~GDI_HANDLE_REUSE_MASK) != 0 && (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) == ProcessId; return Ret; @@ -1143,6 +1072,8 @@ LockHandle: exchange it.*/ NewType = GDI_HANDLE_GET_TYPE(*hObj); NewType |= NewType >> 16; + NewType |= (ULONG_PTR)(*hObj) & GDI_HANDLE_REUSE_MASK; + /* This is the type that the object should have right now, save it */ OldType = NewType; /* As the object should be a stock object, set it's flag, but only in the upper 16 bits */ @@ -1268,7 +1199,7 @@ LockHandle: { PETHREAD PrevThread; - if(Entry->Type != 0 && Entry->KernelData != NULL) + if((Entry->Type & ~GDI_HANDLE_REUSE_MASK) != 0 && Entry->KernelData != NULL) { PGDIOBJHDR GdiHdr = GDIBdyToHdr(Entry->KernelData); @@ -1401,7 +1332,7 @@ LockHandleFrom: PETHREAD PrevThread; PGDIOBJHDR GdiHdr; - if(FromEntry->Type != 0 && FromEntry->KernelData != NULL) + if((FromEntry->Type & ~GDI_HANDLE_REUSE_MASK) != 0 && FromEntry->KernelData != NULL) { GdiHdr = GDIBdyToHdr(FromEntry->KernelData); diff --git a/reactos/subsys/win32k/objects/region.c b/reactos/subsys/win32k/objects/region.c index 2feb5a31a7b..48f9152b4c7 100644 --- a/reactos/subsys/win32k/objects/region.c +++ b/reactos/subsys/win32k/objects/region.c @@ -707,45 +707,43 @@ empty: HRGN FASTCALL REGION_CropRgn(HRGN hDst, HRGN hSrc, const PRECT lpRect, PPOINT lpPt) { PROSRGNDATA objSrc, rgnDst; - HRGN hNewDst, hRet = NULL; - GDIMULTILOCK Lock[2] = {{hDst, 0, GDI_OBJECT_TYPE_REGION}, {hSrc, 0, GDI_OBJECT_TYPE_REGION}}; + HRGN hRet = NULL; + POINT pt = { 0, 0 }; if( !hDst ) { - if( !( hNewDst = RGNDATA_AllocRgn(1) ) ) + if( !( hDst = RGNDATA_AllocRgn(1) ) ) { return 0; } - Lock[0].hObj = hNewDst; } - if ( !GDIOBJ_LockMultipleObj(Lock, sizeof(Lock)/sizeof(Lock[0])) ) - { - DPRINT1("GDIOBJ_LockMultipleObj() failed\n" ); - return 0; - } - rgnDst = Lock[0].pObj; - objSrc = Lock[1].pObj; - - if( objSrc && rgnDst ) + rgnDst = RGNDATA_LockRgn(hDst); + if(rgnDst == NULL) { - if(rgnDst) - { - POINT pt = { 0, 0 }; - - if(!lpPt) - lpPt = &pt; - - if(REGION_CropAndOffsetRegion(lpPt, lpRect, objSrc, rgnDst) == FALSE) - { // ve failed cleanup and return - hRet = NULL; - } - else{ // ve are fine. unlock the correct pointer and return correct handle - hRet = Lock[0].hObj; - } - } + return NULL; } - GDIOBJ_UnlockMultipleObj(Lock, sizeof(Lock)/sizeof(Lock[0])); + + objSrc = RGNDATA_LockRgn(hSrc); + if(objSrc == NULL) + { + RGNDATA_UnlockRgn(hDst); + return NULL; + } + if(!lpPt) + lpPt = &pt; + + if(REGION_CropAndOffsetRegion(lpPt, lpRect, objSrc, rgnDst) == FALSE) + { // ve failed cleanup and return + hRet = NULL; + } + else{ // ve are fine. unlock the correct pointer and return correct handle + hRet = hDst; + } + + RGNDATA_UnlockRgn(hSrc); + RGNDATA_UnlockRgn(hDst); + return hRet; } @@ -1957,21 +1955,12 @@ NtGdiCombineRgn(HRGN hDest, INT CombineMode) { INT result = ERROR; - GDIMULTILOCK Lock[3] = {{hDest, 0, GDI_OBJECT_TYPE_REGION}, {hSrc1, 0, GDI_OBJECT_TYPE_REGION}, {hSrc2, 0, GDI_OBJECT_TYPE_REGION}}; PROSRGNDATA destRgn, src1Rgn, src2Rgn; - - if ( !GDIOBJ_LockMultipleObj(Lock, sizeof(Lock)/sizeof(Lock[0])) ) - { - DPRINT1("GDIOBJ_LockMultipleObj() failed\n" ); - return ERROR; - } - - destRgn = (PROSRGNDATA) Lock[0].pObj; - src1Rgn = (PROSRGNDATA) Lock[1].pObj; - src2Rgn = (PROSRGNDATA) Lock[2].pObj; - + + destRgn = RGNDATA_LockRgn(hDest); if( destRgn ) { + src1Rgn = RGNDATA_LockRgn(hSrc1); if( src1Rgn ) { if (CombineMode == RGN_COPY) @@ -1982,7 +1971,8 @@ NtGdiCombineRgn(HRGN hDest, } else { - if( src2Rgn ) + src2Rgn = RGNDATA_LockRgn(hSrc2); + if( src2Rgn ) { switch (CombineMode) { @@ -1999,17 +1989,26 @@ NtGdiCombineRgn(HRGN hDest, REGION_SubtractRegion(destRgn, src1Rgn, src2Rgn); break; } + RGNDATA_UnlockRgn(hSrc2); result = destRgn->rdh.iType; } + else + { + DPRINT1("NtGdiCombineRgn requires hSrc2 != NULL for combine mode %d!\n", CombineMode); + } } + + RGNDATA_UnlockRgn(hSrc1); } + + RGNDATA_UnlockRgn(hDest); } else { DPRINT("NtGdiCombineRgn: hDest unavailable\n"); result = ERROR; } - GDIOBJ_UnlockMultipleObj(Lock, sizeof(Lock)/sizeof(Lock[0])); + return result; }