|
|
/******************************Module*Header*******************************\
* Module Name: hmgrp.hxx * * Private definitions for handle manager * * Created: 08-Dec-1989 23:03:03 * Author: Donald Sidoroff [donalds] * * Copyright (c) 1989-1999 Microsoft Corporation \**************************************************************************/
HOBJ hGetFreeHandle(OBJTYPE objt); extern LONG lRandom(); extern LONG glAllocChance;
/**************************************************************************\
* * Lookaside structures * \**************************************************************************/
//
// Define number of lookaside entries to allocate for selected objects.
//
// Note, the following numbers are based in winbench object usage.
//
#define HMG_DC_OBJECTS 40
#define HMG_RGN_OBJECTS 96
#define HMG_SURF_OBJECTS 40
#define HMG_PAL_OBJECTS 12
#define HMG_BRUSH_OBJECTS 96
#define HMG_LFONT_OBJECTS 64
#define HMG_RFONT_OBJECTS 55
//
// Define objects sizes
//
#define HMG_DC_SIZE sizeof(DC)
#define HMG_RGN_SIZE (QUANTUM_REGION_SIZE)
#define HMG_SURF_SIZE (SURFACE::tSizeOf() + 32)
#define HMG_PAL_SIZE (sizeof(PALETTE)+sizeof(DWORD)*16)
#define HMG_BRUSH_SIZE sizeof(BRUSH)
#define HMG_LFONT_SIZE (offsetof(LFONT,elfw) + \
offsetof(ENUMLOGFONTEXDVW,elfDesignVector) + \ SIZEOFDV(0)) #define HMG_RFONT_SIZE sizeof(RFONT)
//
// Define Maximum allowed size when there is enough memory in the system
//
// These numbers are based on WinBench 97, WinStone97, and system boot usage
//
#define HMG_DC_MAX HMG_DC_SIZE
#define HMG_RGN_MAX (QUANTUM_REGION_SIZE)
#define HMG_SURF_MAX (SURFACE::tSizeOf() + 256)
#define HMG_PAL_MAX HMG_PAL_SIZE
#define HMG_BRUSH_MAX (sizeof(BRUSH) + 32)
#define HMG_LFONT_MAX HMG_LFONT_SIZE
#define HMG_RFONT_MAX HMG_RFONT_SIZE
BOOL HmgInitializeLookAsideList( ULONG ulType, ULONG size, ULONG dwTag, USHORT Number );
/*********************************Class************************************\
* class OBJLOCK * * This class is used to lock a handle entry against anybody fooling with * it. This is currently being used for regions to keep another thread * from using the handle entry since the object pointed to by the handle * may be invalid for a time. * * History: * 28-Nov-1994 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/
#define OBJLOCK_TYPE DEF_TYPE
class OBJLOCK { private: OBJTYPE objt; PENTRY pent; public: OBJLOCK(HOBJ hobj) { pent = &gpentHmgr[HmgIfromH(hobj)]; objt = pent->Objt; pent->Objt = OBJLOCK_TYPE; }
~OBJLOCK() { pent->Objt = objt; } };
/*********************************Class************************************\
* SIMPLELOCK * * Locks a LONG at the given address, will wait for lock to be acquired. * * History: * * 09-Oct-2001 -by- Pravin Santiago [pravins] * \**************************************************************************/
class SIMPLELOCK { LONG *pLong; public:
SIMPLELOCK (LONG *pl) { LONG nl = 1; LONG cl; BOOL bLockStatus = FALSE; pLong = 0;
KeEnterCriticalRegion();
do { cl = *pl; if (cl) { KeDelayExecutionThread(KernelMode,FALSE,gpLockShortDelay); WARNING1("DELAY EXECUTION for SIMPLELOCK"); } else { if (InterlockedCompareExchange(pl,nl,cl) == cl) { bLockStatus = TRUE; } }
} while (!bLockStatus);
pLong = pl; }
void vUnlock() { if (pLong) { LONG nl = 0; LONG cl = *pLong; LONG exRes = InterlockedCompareExchange(pLong,nl,cl);
ASSERTGDI(exRes == cl, "SIMPLELOCK::~SIMPLELOCK InterlockedCompareExchange failed");
pLong = 0; KeLeaveCriticalRegion(); } }
~SIMPLELOCK() { vUnlock(); } };
/*********************************Class************************************\
* HANDLELOCK * * Locks given handle, will wait for handle lock to be set. * * Will be in CriticalRegion for the duration of the handle lock. * * History: * * 21-Feb-1996 -by- Mark Enstrom [marke] * \**************************************************************************/
class HANDLELOCK { private: PENTRY pent; BOOL bLockStatus; OBJECTOWNER ObjOld; OBJECTOWNER ObjNew;
//
// Lock handle
//
public:
//
// no contstructor
//
HANDLELOCK() { bLockStatus = FALSE; pent = NULL; }
VOID vLockHandle(PENTRY pentry,BOOL bCheck) { PW32THREAD pw32thread = W32GetCurrentThread(); #if defined(_WIN64)
KERNEL_PVOID pclientID = (pw32thread != NULL) ? pw32thread->pClientID : NULL; #endif
bLockStatus = FALSE; pent = pentry;
//
// must be in critical region while handle lock held
//
KeEnterCriticalRegion();
do { ObjOld = pent->ObjectOwner;
//
// if pclientID is not null, we are doing WOW64 printing via LPC
// allow the proxy server to access the handle
//
if (bCheck && (OBJECTOWNER_PID(ObjOld) != W32GetCurrentPID()) && (OBJECTOWNER_PID(ObjOld) != OBJECT_OWNER_PUBLIC) #if defined(_WIN64)
&& (pclientID == NULL || (OBJECTOWNER_PID(ObjOld) != ((PRINTCLIENTID*)pclientID)->clientPid)) #endif
) { WARNING1("CHECK_LOCK_HANDLE failed, incorrect PID owner");
break; }
if (ObjOld.Share.Lock) { KeDelayExecutionThread(KernelMode,FALSE,gpLockShortDelay); WARNING1("DELAY EXECUTION for handle check lock"); } else { ObjNew = ObjOld; ObjNew.Share.Lock = 1;
if (InterlockedCompareExchange( (PLONG)&pent->ObjectOwner.ulObj, ObjNew.ulObj, ObjOld.ulObj) == (LONG)ObjOld.ulObj) { bLockStatus = TRUE; } }
} while (!bLockStatus);
//
// exit critical region if lock failed
//
if (!bLockStatus) { pent = NULL; KeLeaveCriticalRegion(); } }
HANDLELOCK(PENTRY pentry,BOOL bCheck) { vLockHandle(pentry,bCheck); }
//
// destructor: make sure handle is not locked
//
~HANDLELOCK() { if (bLockStatus) { RIP("GDI Handle still locked at destructor!");
if ((pent != (PENTRY)NULL)) { ObjOld = pent->ObjectOwner; ObjNew = ObjOld; ObjNew.Share.Lock = 0; LONG ExchRes = InterlockedCompareExchange( (PLONG)&pent->ObjectOwner.ulObj, ObjNew.ulObj, ObjOld.ulObj); //
// Note that the InterlockedCompareExchange should never fail.
// This handle's locked so nobody should be changing it.
//
ASSERTGDI(ExchRes == (LONG)ObjOld.ulObj, "HANDLELOCK ~HANDLELOCK InterlockedCompareExchange failed"); }
bLockStatus = FALSE; pent = (PENTRY)NULL; KeLeaveCriticalRegion(); } }
//
// Full check lock
//
BOOL bLockHobj(HOBJ hobj,OBJTYPE objt) { UINT uiIndex = (UINT) HmgIfromH(hobj);
BOOL bStatus = FALSE; PENTRY pentTemp = (PENTRY)NULL;
if (uiIndex < gcMaxHmgr) { pentTemp = &gpentHmgr[uiIndex];
vLockHandle(pentTemp,TRUE);
if (bLockStatus) { if ( (pent->Objt != objt) || (pent->FullUnique != HmgUfromH(hobj)) ) { ObjOld = pent->ObjectOwner; ObjNew = ObjOld; ObjNew.Share.Lock = 0; LONG ExchRes = InterlockedCompareExchange( (PLONG)&pent->ObjectOwner.ulObj, ObjNew.ulObj, ObjOld.ulObj); //
// Note that the InterlockedCompareExchange should never fail.
// This handle's locked so nobody should be changing it.
//
ASSERTGDI(ExchRes == (LONG)ObjOld.ulObj, "HANDLELOCK bLockHobj InterlockedCompareExchange failed"); bLockStatus = FALSE; pent = (PENTRY)NULL; KeLeaveCriticalRegion(); } } } return(bLockStatus); }
//
// Always call unlock explicitly: destructor will RIP
// if it must unlock handle
//
VOID vUnlock() { ASSERTGDI(bLockStatus,"HANDLELOCK vUnlock called when handle not bLockStatus"); ASSERTGDI((pent != NULL),"HANDLELOCK vUnlock called when pent == NULL"); ASSERTGDI((pent->ObjectOwner.Share.Lock == 1), "HANDLELOCK vUnlock called when handle not locked"); ObjOld = pent->ObjectOwner; ObjNew = ObjOld; ObjNew.Share.Lock = 0;
LONG ExchRes = InterlockedCompareExchange( (PLONG)&pent->ObjectOwner.ulObj, ObjNew.ulObj, ObjOld.ulObj); //
// Note that the InterlockedCompareExchange should never fail.
// This handle's locked so nobody should be changing it.
//
ASSERTGDI(ExchRes == (LONG)ObjOld.ulObj, "HANDLELOCK vUnlock InterlockedCompareExchange failed");
bLockStatus = FALSE; pent = (PENTRY)NULL; KeLeaveCriticalRegion(); }
//
// entry routines
//
BOOL bValid() { return(bLockStatus && (pent != (PENTRY)NULL)); }
//
// return entry share count
//
ULONG ShareCount() { ASSERTGDI((bLockStatus && (pent != NULL)),"HANDLELOCK::ShareCount: handle not locked"); ASSERTGDI(pent->einfo.pobj != NULL, "HANDLELOCK::ShareCount: pent->einfo.pobj is NULL"); return(pent->einfo.pobj->ulShareCount); }
//
// return entry pEntry
//
PENTRY pentry() { ASSERTGDI((bLockStatus && (pent != NULL)),"pUser: handle not locked"); return(pent); }
//
// return entry pUser
//
PVOID pUser() { ASSERTGDI((bLockStatus && (pent != NULL)),"pUser: handle not locked"); return(pent->pUser); }
//
// return pobj
//
POBJ pObj() { ASSERTGDI((bLockStatus && (pent != NULL)),"pObj: handle not locked"); return(pent->einfo.pobj); }
//
// set PID
//
VOID Pid(W32PID pid) { ASSERTGDI((bLockStatus && (pent != NULL)),"Pid: handle not locked"); SET_OBJECTOWNER_PID(pent->ObjectOwner,pid); }
W32PID Pid() { ASSERTGDI((bLockStatus && (pent != NULL)),"Pid: handle not locked"); return(OBJECTOWNER_PID(pent->ObjectOwner)); }
};
// Notes on entry structure
//
// The internal entry in the handle manager appears as follows
//
// +-------------------+
// | einfo.pobj, hfree | 4 bytes
// +-------------------+
// | ObjectOwner | 4 bytes
// +-------------------+
// | FullUnique | 2 bytes
// +-------------------+
// | Objt | 1 byte
// +-------------------+
// | Flags | 1 byte
// +-------------------+
// | pUser | 4 bytes
// +-------------------+
// 16 bytes total space
class ENTRYOBJ : public _ENTRY { public: ENTRYOBJ() { } ~ENTRYOBJ() { }
VOID vSetup(POBJ pObj,OBJTYPE objt_,FSHORT fs) { OBJECTOWNER ObjNew; PW32THREAD pw32thread = W32GetCurrentThread(); #if defined(_WIN64)
KERNEL_PVOID pclientID = (pw32thread != NULL) ? pw32thread->pClientID : NULL; #endif
HANDLELOCK HandleLock(this, FALSE); if (HandleLock.bValid()) { ObjNew = ObjectOwner; einfo.pobj = (POBJ) pObj; Objt = objt_; Flags = 0; pUser = NULL;
//
// if pclientID is not NULL we are doing WOW64 printing
// set handle's Tid and owner Pid to print client's.
//
if (fs & HMGR_MAKE_PUBLIC) { SET_OBJECTOWNER_PID(ObjNew,OBJECT_OWNER_PUBLIC); } else { #if defined(_WIN64)
if (pclientID) { SET_OBJECTOWNER_PID(ObjNew, ((PRINTCLIENTID*)pclientID)->clientPid); } else #endif
{ SET_OBJECTOWNER_PID(ObjNew,W32GetCurrentPID()); } } if (fs & HMGR_ALLOC_LOCK) { #if defined(_WIN64)
if (pclientID) { pObj->Tid = ((PRINTCLIENTID*)pclientID)->clientTid; } else #endif
{ pObj->Tid = (PW32THREAD)PsGetCurrentThread(); } } pObj->cExclusiveLock = (USHORT)(fs & HMGR_ALLOC_LOCK); pObj->ulShareCount = (USHORT)((fs & HMGR_ALLOC_ALT_LOCK) >> 1); //
// clear user date pointer
//
pUser = NULL; //
// Update the ObjectOwner.
//
ObjectOwner = ObjNew; HandleLock.vUnlock(); } }
VOID vFree(UINT uiIndex) { //
// handle must already be locked
//
ENTRY *pentry = &gpentHmgr[uiIndex]; OBJECTOWNER ObjNew = pentry->ObjectOwner;
ASSERTGDI((ObjNew.Share.Lock == 1), "ENTRYOBJ::vFree must be called with locked handle");
HmgDecProcessHandleCount(OBJECTOWNER_PID(ObjNew));
//
// Insert the specified handle in the free list.
//
pentry->einfo.hFree = ghFreeHmgr;
//Sundown: ghFreeHmgr only has the index, we call MAKE_HMGR_HANDLE in hGetFreeHandle
ghFreeHmgr = (HOBJ) (ULONG_PTR)uiIndex;
//
// Set the object type to the default type so all handle translations
// will fail and increment the uniqueness value.
//
Objt = (OBJTYPE) DEF_TYPE; FullUnique += UNIQUE_INCREMENT;
//
// clear user date pointer
//
pUser = NULL;
//
// Clear shared count, set initial pid. Caller
// must unlock handle.
//
SET_OBJECTOWNER_PID(ObjNew,0); pentry->ObjectOwner = ObjNew; }
BOOL bOwnedBy(W32PID pid_) { return((Objt != DEF_TYPE) && (OBJECTOWNER_PID(ObjectOwner) == (pid_ & PID_BITS))); } };
typedef ENTRYOBJ *PENTRYOBJ;
|