From e2be2729b0c0e41a5c23a424cb65ec187d813401 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Gardou?= Date: Wed, 29 Jan 2014 18:32:14 +0000 Subject: [PATCH] [WIN32K] - Implement GDIOBJ_TryLockObject and used it for DRIVEROBJs - Fix EngUnlockDriverObj svn path=/trunk/; revision=61883 --- reactos/win32ss/gdi/eng/driverobj.c | 13 +++--- reactos/win32ss/gdi/eng/driverobj.h | 4 +- reactos/win32ss/gdi/ntgdi/gdiobj.c | 69 +++++++++++++++++++++++++++++ reactos/win32ss/gdi/ntgdi/gdiobj.h | 6 +++ reactos/win32ss/gdi/ntgdi/misc.h | 8 ++++ 5 files changed, 92 insertions(+), 8 deletions(-) diff --git a/reactos/win32ss/gdi/eng/driverobj.c b/reactos/win32ss/gdi/eng/driverobj.c index d3488a668e6..db2e8e3e39a 100644 --- a/reactos/win32ss/gdi/eng/driverobj.c +++ b/reactos/win32ss/gdi/eng/driverobj.c @@ -80,7 +80,7 @@ EngDeleteDriverObj( PEDRIVEROBJ pedo; /* Lock the object */ - pedo = DRIVEROBJ_LockObject(hdo); + pedo = DRIVEROBJ_TryLockObject(hdo); if (!pedo) { return FALSE; @@ -100,10 +100,11 @@ EngDeleteDriverObj( /* Prevent cleanup callback from being called again */ pedo->drvobj.pFreeProc = NULL; - /* NOTE: We don't care about the bLocked param, as our handle manager - allows freeing the object, while we hold any number of locks. */ + /* Unlock if the caller indicates it is locked */ + if (bLocked) + DRIVEROBJ_UnlockObject(pedo); - /* Delete the object */ + /* Now delete the object */ GDIOBJ_vDeleteObject(&pedo->baseobj); return TRUE; } @@ -117,7 +118,7 @@ EngLockDriverObj( PEDRIVEROBJ pedo; /* Lock the object */ - pedo = DRIVEROBJ_LockObject(hdo); + pedo = DRIVEROBJ_TryLockObject(hdo); /* Return pointer to the DRIVEROBJ structure */ return &pedo->drvobj; @@ -133,7 +134,7 @@ EngUnlockDriverObj( ULONG cLocks; /* First lock to get a pointer to the object */ - pedo = DRIVEROBJ_LockObject(hdo); + pedo = DRIVEROBJ_TryLockObject(hdo); if(!pedo) { /* Object could not be locked, fail. */ diff --git a/reactos/win32ss/gdi/eng/driverobj.h b/reactos/win32ss/gdi/eng/driverobj.h index 92a0bab7ad9..25961e461ad 100644 --- a/reactos/win32ss/gdi/eng/driverobj.h +++ b/reactos/win32ss/gdi/eng/driverobj.h @@ -20,7 +20,7 @@ BOOL NTAPI DRIVEROBJ_Cleanup(PVOID pObject); FORCEINLINE PEDRIVEROBJ -DRIVEROBJ_LockObject(HDRVOBJ hdo) +DRIVEROBJ_TryLockObject(HDRVOBJ hdo) { - return GDIOBJ_LockObject(hdo, GDIObjType_DRVOBJ_TYPE); + return GDIOBJ_TryLockObject(hdo, GDIObjType_DRVOBJ_TYPE); } diff --git a/reactos/win32ss/gdi/ntgdi/gdiobj.c b/reactos/win32ss/gdi/ntgdi/gdiobj.c index 34f33668592..2958a186dd5 100644 --- a/reactos/win32ss/gdi/ntgdi/gdiobj.c +++ b/reactos/win32ss/gdi/ntgdi/gdiobj.c @@ -52,11 +52,14 @@ #define ASSERT_EXCLUSIVE_OBJECT_TYPE(objt) \ ASSERT((objt) == GDIObjType_DC_TYPE || \ (objt) == GDIObjType_RGN_TYPE) +#define ASSERT_TRYLOCK_OBJECT_TYPE(objt) \ + ASSERT((objt) == GDIObjType_DRVOBJ_TYPE) #else #define DBG_INCREASE_LOCK_COUNT(ppi, hobj) #define DBG_DECREASE_LOCK_COUNT(x, y) #define ASSERT_SHARED_OBJECT_TYPE(objt) #define ASSERT_EXCLUSIVE_OBJECT_TYPE(objt) +#define ASSERT_TRYLOCK_OBJECT_TYPE(objt) #endif #if defined(_M_IX86) || defined(_M_AMD64) @@ -621,6 +624,72 @@ GDIOBJ_vReferenceObjectByPointer(POBJ pobj) DBG_LOGEVENT(&pobj->slhLog, EVENT_REFERENCE, cRefs); } +PGDIOBJ +NTAPI +GDIOBJ_TryLockObject( + HGDIOBJ hobj, + UCHAR objt) +{ + PENTRY pentry; + POBJ pobj; + DWORD dwThreadId; + + /* Check if the handle type matches */ + ASSERT_TRYLOCK_OBJECT_TYPE(objt); + if ((((ULONG_PTR)hobj >> 16) & 0x1f) != objt) + { + DPRINT("Wrong object type: hobj=0x%p, objt=0x%x\n", hobj, objt); + return NULL; + } + + /* Reference the handle entry */ + pentry = ENTRY_ReferenceEntryByHandle(hobj, 0); + if (!pentry) + { + DPRINT("GDIOBJ: Requested handle 0x%p is not valid.\n", hobj); + return NULL; + } + + /* Get the pointer to the BASEOBJECT */ + pobj = pentry->einfo.pobj; + + /* Check if we already own the lock */ + dwThreadId = PtrToUlong(PsGetCurrentThreadId()); + if (pobj->dwThreadId != dwThreadId) + { + /* Disable APCs and try acquiring the push lock */ + KeEnterCriticalRegion(); + if(!ExTryAcquirePushLockExclusive(&pobj->pushlock)) + { + ULONG cRefs, ulIndex; + /* Already owned. Clean up and leave. */ + KeLeaveCriticalRegion(); + + /* Calculate the index */ + ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr); + + /* Decrement reference count */ + ASSERT((gpaulRefCount[ulIndex] & REF_MASK_COUNT) > 0); + cRefs = InterlockedDecrement((LONG*)&gpaulRefCount[ulIndex]); + ASSERT(cRefs & REF_MASK_VALID); + + return NULL; + } + + /* Set us as lock owner */ + ASSERT(pobj->dwThreadId == 0); + pobj->dwThreadId = dwThreadId; + } + + /* Increase lock count */ + pobj->cExclusiveLock++; + DBG_INCREASE_LOCK_COUNT(PsGetCurrentProcessWin32Process(), hobj); + DBG_LOGEVENT(&pobj->slhLog, EVENT_LOCK, 0); + + /* Return the object */ + return pobj; +} + PGDIOBJ NTAPI GDIOBJ_LockObject( diff --git a/reactos/win32ss/gdi/ntgdi/gdiobj.h b/reactos/win32ss/gdi/ntgdi/gdiobj.h index 5eb30a3ea7d..b049ff5d801 100644 --- a/reactos/win32ss/gdi/ntgdi/gdiobj.h +++ b/reactos/win32ss/gdi/ntgdi/gdiobj.h @@ -141,6 +141,12 @@ GDIOBJ_LockObject( HGDIOBJ hobj, UCHAR objt); +PGDIOBJ +NTAPI +GDIOBJ_TryLockObject( + HGDIOBJ hobj, + UCHAR objt); + VOID NTAPI GDIOBJ_vUnlockObject( diff --git a/reactos/win32ss/gdi/ntgdi/misc.h b/reactos/win32ss/gdi/ntgdi/misc.h index 22297f05bf7..3684f402b0d 100644 --- a/reactos/win32ss/gdi/ntgdi/misc.h +++ b/reactos/win32ss/gdi/ntgdi/misc.h @@ -112,6 +112,14 @@ ExAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock) } } +FORCEINLINE +BOOLEAN +ExTryAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock) +{ + /* Try acquiring the lock */ + return !InterlockedBitTestAndSet((PLONG)PushLock, EX_PUSH_LOCK_LOCK_V); +} + FORCEINLINE VOID ExReleasePushLockExclusive(PEX_PUSH_LOCK PushLock) -- 2.17.1