From 8d1df272ce0c48fb746ca84d2a03fdda611d33aa Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Tue, 17 Mar 2009 00:30:15 +0000 Subject: [PATCH] Rewrite DRIVEROBJ api, giving the object a handle, belonging to the current process. Let the gdi obj cleanup take care for calling the callback function. Allow deleting of objects that are exclusively locked by the current thread. svn path=/trunk/; revision=40068 --- reactos/include/reactos/win32k/ntgdihdl.h | 1 + .../subsystems/win32/win32k/eng/driverobj.c | 222 ++++++++---------- reactos/subsystems/win32/win32k/eng/objects.h | 6 - .../win32/win32k/include/driverobj.h | 23 ++ .../subsystems/win32/win32k/include/inteng.h | 10 - .../subsystems/win32/win32k/include/win32k.h | 1 + .../subsystems/win32/win32k/main/dllmain.c | 1 - .../subsystems/win32/win32k/objects/gdiobj.c | 11 +- 8 files changed, 131 insertions(+), 144 deletions(-) create mode 100644 reactos/subsystems/win32/win32k/include/driverobj.h diff --git a/reactos/include/reactos/win32k/ntgdihdl.h b/reactos/include/reactos/win32k/ntgdihdl.h index c69a266427d..244d8242a6f 100644 --- a/reactos/include/reactos/win32k/ntgdihdl.h +++ b/reactos/include/reactos/win32k/ntgdihdl.h @@ -66,6 +66,7 @@ #define GDI_OBJECT_TYPE_DD_VIDEOPORT 0x00120000 /* Should be moved away from gdi objects */ #define GDI_OBJECT_TYPE_DD_MOTIONCOMP 0x00140000 /* Should be moved away from gdi objects */ #define GDI_OBJECT_TYPE_ENUMFONT 0x00160000 +#define GDI_OBJECT_TYPE_DRIVEROBJ 0x001C0000 /* Confrim on XP value is taken from NtGdiCreateDirectDrawObject */ #define GDI_OBJECT_TYPE_DIRECTDRAW 0x00200000 diff --git a/reactos/subsystems/win32/win32k/eng/driverobj.c b/reactos/subsystems/win32/win32k/eng/driverobj.c index 3c12fd5bd27..6706c0036f9 100644 --- a/reactos/subsystems/win32/win32k/eng/driverobj.c +++ b/reactos/subsystems/win32/win32k/eng/driverobj.c @@ -1,180 +1,156 @@ /* - * ReactOS W32 Subsystem - * Copyright (C) 2005 ReactOS Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel + * COPYRIGHT: GPL, see COPYING in the top level directory + * PROJECT: ReactOS win32 kernel mode sunsystem * PURPOSE: GDI DRIVEROBJ Functions - * FILE: subsys/win32k/eng/driverobj.c - * PROGRAMER: Gregor Anich - * REVISION HISTORY: - * 04/01/2005: Created + * FILE: subsystems/win32k/eng/driverobj.c + * PROGRAMER: Timo Kreuzer */ +/** Includes ******************************************************************/ + #include #define NDEBUG #include -/*!\brief Called when the process is terminated. - * - * Calls the free-proc for each existing DRIVEROBJ. - * - * \param Process Pointer to the EPROCESS struct for the process beeing terminated. - * \param Win32Process Pointer to the W32PROCESS - */ -VOID FASTCALL -IntEngCleanupDriverObjs(struct _EPROCESS *Process, - PW32PROCESS Win32Process) -{ - PDRIVERGDI DrvObjInt; - PW32PROCESS CurrentWin32Process; - CurrentWin32Process = PsGetCurrentProcessWin32Process(); - IntEngLockProcessDriverObjs(CurrentWin32Process); - while (!IsListEmpty(&Win32Process->DriverObjListHead)) +/** Internal interface ********************************************************/ + +/*! + * \brief DRIVEROBJ cleanup function + */ +BOOL INTERNAL_CALL +DRIVEROBJ_Cleanup(PVOID pObject) +{ + PEDRIVEROBJ pedo = pObject; + FREEOBJPROC pFreeProc; + + pFreeProc = pedo->drvobj.pFreeProc; + if (pFreeProc) { - DrvObjInt = CONTAINING_RECORD(Win32Process->DriverObjListHead.Flink, - DRIVERGDI, ListEntry); - IntEngUnLockProcessDriverObjs(CurrentWin32Process); - EngDeleteDriverObj((HDRVOBJ)(&DrvObjInt->DriverObj), TRUE, FALSE); - IntEngLockProcessDriverObjs(CurrentWin32Process); + return pFreeProc(pedo->drvobj.pvObj); } - IntEngUnLockProcessDriverObjs(CurrentWin32Process); + + return TRUE; } +/** Public interface **********************************************************/ -/* - * @implemented - */ HDRVOBJ APIENTRY EngCreateDriverObj( - IN PVOID pvObj, - IN FREEOBJPROC pFreeObjProc, - IN HDEV hdev - ) + IN PVOID pvObj, + IN FREEOBJPROC pFreeObjProc, + IN HDEV hdev) { - PDRIVERGDI DrvObjInt; - PDRIVEROBJ DrvObjUser; - PW32PROCESS CurrentWin32Process; + PEDRIVEROBJ pedo; + HDRVOBJ hdo; + GDIDEVICE *ppdev = (GDIDEVICE*)hdev; - /* Create DRIVEROBJ */ - DrvObjInt = EngAllocMem(0, sizeof (DRIVERGDI), TAG_DRIVEROBJ); - if (DrvObjInt == NULL) + /* Allocate a new DRIVEROBJ */ + pedo = DRIVEROBJ_AllocObjectWithHandle(); + if (!pedo) { - DPRINT1("Failed to allocate memory for a DRIVERGDI structure!\n"); - return NULL; + return NULL; } + hdo = pedo->baseobj.hHmgr; - /* fill user object */ - DrvObjUser = GDIToObj(DrvObjInt, DRIVER); - DrvObjUser->pvObj = pvObj; - DrvObjUser->pFreeProc = pFreeObjProc; - DrvObjUser->hdev = hdev; - DrvObjUser->dhpdev = ((GDIDEVICE*)hdev)->hPDev; + /* Fill in fields */ + pedo->drvobj.pvObj = pvObj; + pedo->drvobj.pFreeProc = pFreeObjProc; + pedo->drvobj.hdev = hdev; + pedo->drvobj.dhpdev = ppdev->hPDev; - /* fill internal object */ - ExInitializeFastMutex(&DrvObjInt->Lock); - CurrentWin32Process = PsGetCurrentProcessWin32Process(); - IntEngLockProcessDriverObjs(CurrentWin32Process); - InsertTailList(&CurrentWin32Process->DriverObjListHead, &DrvObjInt->ListEntry); - IntEngUnLockProcessDriverObjs(CurrentWin32Process); + /* Unlock the object */ + DRIVEROBJ_UnlockObject(pedo); - return (HDRVOBJ)DrvObjUser; + /* Return the handle */ + return hdo; } -/* - * @implemented - */ BOOL APIENTRY EngDeleteDriverObj( - IN HDRVOBJ hdo, - IN BOOL bCallBack, - IN BOOL bLocked - ) + IN HDRVOBJ hdo, + IN BOOL bCallBack, + IN BOOL bLocked) { - PDRIVEROBJ DrvObjUser = (PDRIVEROBJ)hdo; - PDRIVERGDI DrvObjInt = ObjToGDI(DrvObjUser, DRIVER); - PW32PROCESS CurrentWin32Process; + PEDRIVEROBJ pedo; - /* Make sure the obj is locked */ - if (!bLocked) + /* Lock the object */ + pedo = DRIVEROBJ_LockObject(hdo); + if (!pedo) { - if (!ExTryToAcquireFastMutex(&DrvObjInt->Lock)) + return FALSE; + } + + /* Manually call cleanup callback */ + if (bCallBack) + { + if (!pedo->drvobj.pFreeProc(pedo->drvobj.pvObj)) { - return FALSE; + /* Callback failed */ + DRIVEROBJ_UnlockObject(pedo); + return FALSE; } } - /* Call the free-proc */ - if (bCallBack) - { - if (!DrvObjUser->pFreeProc(DrvObjUser)) - { - return FALSE; - } - } + /* Prevent cleanup callback from being called again */ + pedo->drvobj.pFreeProc = NULL; - /* Free the DRIVEROBJ */ - CurrentWin32Process = PsGetCurrentProcessWin32Process(); - IntEngLockProcessDriverObjs(CurrentWin32Process); - RemoveEntryList(&DrvObjInt->ListEntry); - IntEngUnLockProcessDriverObjs(CurrentWin32Process); - EngFreeMem(DrvObjInt); + /* NOTE: We don't care about the bLocked param, as our handle manager + allows freeing the object, while we hold any number of locks. */ - return TRUE; + /* Free the object */ + return DRIVEROBJ_FreeObjectByHandle(hdo); } -/* - * @implemented - */ PDRIVEROBJ APIENTRY -EngLockDriverObj( IN HDRVOBJ hdo ) +EngLockDriverObj( + IN HDRVOBJ hdo) { - PDRIVEROBJ DrvObjUser = (PDRIVEROBJ)hdo; - PDRIVERGDI DrvObjInt = ObjToGDI(DrvObjUser, DRIVER); + PEDRIVEROBJ pedo; - if (!ExTryToAcquireFastMutex(&DrvObjInt->Lock)) - { - return NULL; - } + /* Lock the object */ + pedo = DRIVEROBJ_LockObject(hdo); - return DrvObjUser; + /* Return pointer to the DRIVEROBJ structure */ + return &pedo->drvobj; } -/* - * @implemented - */ BOOL APIENTRY -EngUnlockDriverObj ( IN HDRVOBJ hdo ) +EngUnlockDriverObj( + IN HDRVOBJ hdo) { - PDRIVERGDI DrvObjInt = ObjToGDI((PDRIVEROBJ)hdo, DRIVER); + PEDRIVEROBJ pedo; - ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&DrvObjInt->Lock); - return TRUE; + /* First lock to get a pointer to the object */ + pedo = DRIVEROBJ_LockObject(hdo); + if(!pedo) + { + /* Object could not be locked, fail. */ + return FALSE; + } + + /* Unlock object */ + DRIVEROBJ_UnlockObject(pedo); + + /* Check if we still hold a lock */ + if (pedo->baseobj.cExclusiveLock < 1) + { + /* Object wasn't locked before, fail. */ + return FALSE; + } + + /* Unlock again */ + DRIVEROBJ_UnlockObject(pedo); + + /* Success */ + return TRUE; } -/* EOF */ - diff --git a/reactos/subsystems/win32/win32k/eng/objects.h b/reactos/subsystems/win32/win32k/eng/objects.h index 35515ae3c8d..f8500de90fb 100644 --- a/reactos/subsystems/win32/win32k/eng/objects.h +++ b/reactos/subsystems/win32/win32k/eng/objects.h @@ -51,12 +51,6 @@ typedef struct _CLIPGDI { ENUMRECTS EnumRects; } CLIPGDI, *PCLIPGDI; -typedef struct _DRIVERGDI { - DRIVEROBJ DriverObj; - LIST_ENTRY ListEntry; - FAST_MUTEX Lock; -} DRIVERGDI, *PDRIVERGDI; - /*ei What is this for? */ typedef struct _DRVFUNCTIONSGDI { HDEV hdev; diff --git a/reactos/subsystems/win32/win32k/include/driverobj.h b/reactos/subsystems/win32/win32k/include/driverobj.h new file mode 100644 index 00000000000..0799465484a --- /dev/null +++ b/reactos/subsystems/win32/win32k/include/driverobj.h @@ -0,0 +1,23 @@ +#ifndef _WIN32K_DRIVEROBJ_H +#define _WIN32K_DRIVEROBJ_H + +#include "gdiobj.h" + +/* Object structure */ +typedef struct _EDRIVEROBJ +{ + BASEOBJECT baseobj; + DRIVEROBJ drvobj; + PVOID reserved; +} EDRIVEROBJ, *PEDRIVEROBJ; + +/* Cleanup function */ +BOOL INTERNAL_CALL DRIVEROBJ_Cleanup(PVOID pObject); + + +#define DRIVEROBJ_AllocObjectWithHandle() ((PEDRIVEROBJ)GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_DRIVEROBJ)) +#define DRIVEROBJ_FreeObjectByHandle(hdo) GDIOBJ_FreeObjByHandle((HGDIOBJ)hdo, GDI_OBJECT_TYPE_DRIVEROBJ) +#define DRIVEROBJ_LockObject(hdo) ((PEDRIVEROBJ)GDIOBJ_LockObj((HGDIOBJ)hdo, GDI_OBJECT_TYPE_DRIVEROBJ)) +#define DRIVEROBJ_UnlockObject(pdo) GDIOBJ_UnlockObjByPtr((POBJ)pdo) + +#endif /* !_WIN32K_DRIVEROBJ_H */ diff --git a/reactos/subsystems/win32/win32k/include/inteng.h b/reactos/subsystems/win32/win32k/include/inteng.h index 53b1fd00750..88e9a3f41c4 100644 --- a/reactos/subsystems/win32/win32k/include/inteng.h +++ b/reactos/subsystems/win32/win32k/include/inteng.h @@ -34,16 +34,6 @@ typedef struct tagSPAN /* Definitions of IntEngXxx functions */ -#define IntEngLockProcessDriverObjs(W32Process) \ - ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&(W32Process)->DriverObjListLock) - -#define IntEngUnLockProcessDriverObjs(W32Process) \ - ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&(W32Process)->DriverObjListLock) - -VOID FASTCALL -IntEngCleanupDriverObjs(struct _EPROCESS *Process, - PW32PROCESS Win32Process); - BOOL APIENTRY IntEngLineTo(SURFOBJ *Surface, CLIPOBJ *Clip, diff --git a/reactos/subsystems/win32/win32k/include/win32k.h b/reactos/subsystems/win32/win32k/include/win32k.h index f8c8a5f3504..7ffcac53bf1 100644 --- a/reactos/subsystems/win32/win32k/include/win32k.h +++ b/reactos/subsystems/win32/win32k/include/win32k.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include diff --git a/reactos/subsystems/win32/win32k/main/dllmain.c b/reactos/subsystems/win32/win32k/main/dllmain.c index 69df156c199..fdb5df2cb70 100644 --- a/reactos/subsystems/win32/win32k/main/dllmain.c +++ b/reactos/subsystems/win32/win32k/main/dllmain.c @@ -136,7 +136,6 @@ Win32kProcessCallback(struct _EPROCESS *Process, DPRINT("Destroying W32 process PID:%d at IRQ level: %lu\n", Process->UniqueProcessId, KeGetCurrentIrql()); IntCleanupMenus(Process, Win32Process); IntCleanupCurIcons(Process, Win32Process); - IntEngCleanupDriverObjs(Process, Win32Process); CleanupMonitorImpl(); /* no process windows should exist at this point, or the function will assert! */ diff --git a/reactos/subsystems/win32/win32k/objects/gdiobj.c b/reactos/subsystems/win32/win32k/objects/gdiobj.c index ac81d7cb2b0..4b6e29ba3a5 100644 --- a/reactos/subsystems/win32/win32k/objects/gdiobj.c +++ b/reactos/subsystems/win32/win32k/objects/gdiobj.c @@ -70,7 +70,7 @@ OBJ_TYPE_INFO ObjTypeInfo[BASE_OBJTYPE_COUNT] = {0, 0, TAG_TTFD, NULL}, /* 19 TTFD, unused */ {0, 0, TAG_RC, NULL}, /* 1a RC, unused */ {0, 0, TAG_TEMP, NULL}, /* 1b TEMP, unused */ - {0, 0, TAG_DRVOBJ, NULL}, /* 1c DRVOBJ, unused */ + {0, sizeof(EDRIVEROBJ), TAG_DRVOBJ, DRIVEROBJ_Cleanup},/* 1c DRVOBJ */ {0, 0, TAG_DCIOBJ, NULL}, /* 1d DCIOBJ, unused */ {0, 0, TAG_SPOOL, NULL}, /* 1e SPOOL, unused */ {0, 0, 0, NULL}, /* 1f reserved entry */ @@ -537,7 +537,8 @@ LockHandle: Object = Entry->KernelData; - if (Object->cExclusiveLock == 0) + if (Object->cExclusiveLock == 0 || + Object->Tid == (PW32THREAD)PsGetCurrentThreadWin32Thread()) { BOOL Ret; PW32PROCESS W32Process = PsGetCurrentProcessWin32Process(); @@ -571,14 +572,16 @@ LockHandle: else { /* - * The object is currently locked, so freeing is forbidden! + * The object is currently locked by another thread, so freeing is forbidden! */ DPRINT1("Object->cExclusiveLock = %d\n", Object->cExclusiveLock); GDIDBG_TRACECALLER(); GDIDBG_TRACELOCKER(GDI_HANDLE_GET_INDEX(hObj)); (void)InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId); /* do not assert here for it will call again from dxg.sys it being call twice */ - //ASSERT(FALSE); + + DelayExecution(); + goto LockHandle; } } else