mirror of
https://github.com/reactos/reactos.git
synced 2025-02-22 08:25:03 +00:00
implemented reuse counters for gdi objects
svn path=/trunk/; revision=13628
This commit is contained in:
parent
738f6ff916
commit
d786cecb72
3 changed files with 79 additions and 156 deletions
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue