[WIN32K]
authorJérôme Gardou <jerome.gardou@reactos.org>
Wed, 29 Jan 2014 18:32:14 +0000 (18:32 +0000)
committerJérôme Gardou <jerome.gardou@reactos.org>
Wed, 29 Jan 2014 18:32:14 +0000 (18:32 +0000)
 - Implement GDIOBJ_TryLockObject and used it for DRIVEROBJs
 - Fix EngUnlockDriverObj

svn path=/trunk/; revision=61883

reactos/win32ss/gdi/eng/driverobj.c
reactos/win32ss/gdi/eng/driverobj.h
reactos/win32ss/gdi/ntgdi/gdiobj.c
reactos/win32ss/gdi/ntgdi/gdiobj.h
reactos/win32ss/gdi/ntgdi/misc.h

index d3488a6..db2e8e3 100644 (file)
@@ -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. */
index 92a0bab..25961e4 100644 (file)
@@ -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);
 }
index 34f3366..2958a18 100644 (file)
 #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(
index 5eb30a3..b049ff5 100644 (file)
@@ -141,6 +141,12 @@ GDIOBJ_LockObject(
     HGDIOBJ hobj,
     UCHAR objt);
 
+PGDIOBJ
+NTAPI
+GDIOBJ_TryLockObject(
+    HGDIOBJ hobj,
+    UCHAR objt);
+
 VOID
 NTAPI
 GDIOBJ_vUnlockObject(
index 22297f0..3684f40 100644 (file)
@@ -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)