|
|
/******************************Module*Header*******************************\
* Module Name: DdHmgr.cxx * * DirectDraw handle manager API entry points * * Created: 30-Apr-1999 23:03:03 * Author: Lindsay Steventon [linstev] * * Copyright (c) 1989-1999 Microsoft Corporation \**************************************************************************/
#include "precomp.hxx"
ULONG gcSizeDdHmgr = DD_TABLESIZE_DELTA; // Start table size
DD_ENTRY *gpentDdHmgrLast = NULL; // Previous handle table
DD_ENTRY *gpentDdHmgr = NULL; // Points to handle table
HDD_OBJ ghFreeDdHmgr; // Free handle
ULONG gcMaxDdHmgr; // Max handle alloc-ed so far
HSEMAPHORE ghsemHmgr = NULL; // Synchronization of the handle manager
PLARGE_INTEGER gpLockShortDelay;
// Prototype for a handy debugging routine.
#if DBG
extern "C" VOID DdHmgPrintBadHandle( HDD_OBJ hobj, DD_OBJTYPE objt ); #else
#define DdHmgPrintBadHandle(hobj, objt)
#endif
HDD_OBJ hDdGetFreeHandle(DD_OBJTYPE objt); VOID DdFreeObject(PVOID pvFree, ULONG ulType); HDD_OBJ FASTCALL DdHmgNextOwned(HDD_OBJ hobj, W32PID pid);
/*****************************Exported*Routine*****************************\
* DdHmgCreate() * * Initializes a new handle manager with an initial allocation. * * History: * * 30-Apr-1999 -by- Lindsay Steventon [linstev] * Wrote it. \**************************************************************************/
BOOL DdHmgCreate() { //
// Initialize the handle manager allocation database.
//
ghFreeDdHmgr = 0; // No free handles
gcMaxDdHmgr = DD_HMGR_HANDLE_BASE; // Initialize with handle index base
//
// Create memory block for handle table
//
gpentDdHmgr = (DD_ENTRY *)PALLOCMEM(sizeof(DD_ENTRY) * gcSizeDdHmgr, 'ddht'); if (gpentDdHmgr == NULL) { WARNING("Could not allocated DDraw handle table."); return(FALSE); }
//
// Initialize exclusion stuff.
//
if ((ghsemHmgr = EngCreateSemaphore()) == NULL) { WARNING("Could not allocated DDraw handle semaphore."); VFREEMEM(gpentDdHmgr); gpentDdHmgr = NULL; return(FALSE); }
//
// allocate and initialize the timeout lock for the handle manager.
//
gpLockShortDelay = (PLARGE_INTEGER) PALLOCNONPAGED(sizeof(LARGE_INTEGER), 'iniG');
if (gpLockShortDelay == NULL) { WARNING("Could not allocated DDraw shortdelay."); EngDeleteSemaphore(ghsemHmgr); ghsemHmgr = NULL; VFREEMEM(gpentDdHmgr); gpentDdHmgr = NULL; return(FALSE); }
gpLockShortDelay->LowPart = (ULONG) -100000; gpLockShortDelay->HighPart = -1;
return(TRUE); }
/*****************************Exported*Routine*****************************\
* DdHmgDestroy() * * Free memory allocated by the handle manager. This happens on system * shutdown. Always succeeds. * * History: * * 30-Apr-1999 -by- Lindsay Steventon [linstev] * Wrote it. \**************************************************************************/
BOOL DdHmgDestroy() { ghFreeDdHmgr = 0; // Zero free handles
gcMaxDdHmgr = 0; // Zero current last handle
gcSizeDdHmgr = 0; // Handle table size
gpentDdHmgrLast = NULL; // Zero previos handle table pointer
if (gpentDdHmgr) // Free handle table
{ VFREEMEM(gpentDdHmgr); gpentDdHmgr = NULL; }
if (ghsemHmgr) { EngDeleteSemaphore(ghsemHmgr); ghsemHmgr = NULL; } return(TRUE); }
/*****************************Exported*Routine*****************************\
* DdHmgCloseProcess() * * Free handles in handle table from process. Occurs on process cleanup. * * History: * * 30-Apr-1999 -by- Lindsay Steventon [linstev] * Wrote it. \**************************************************************************/
BOOL DdHmgCloseProcess(W32PID W32Pid) { BOOL bRes = TRUE;
HDD_OBJ hobj;
DdHmgAcquireHmgrSemaphore();
hobj = DdHmgNextOwned((HDD_OBJ) 0, W32Pid);
DdHmgReleaseHmgrSemaphore();
while (hobj != (HDD_OBJ) NULL) { switch (DdHmgObjtype(hobj)) { case DD_DIRECTDRAW_TYPE: bRes = bDdDeleteDirectDrawObject((HANDLE)hobj, TRUE); break;
case DD_SURFACE_TYPE: bRes = bDdDeleteSurfaceObject((HANDLE)hobj, NULL); break;
case DD_MOTIONCOMP_TYPE: bRes = bDdDeleteMotionCompObject((HANDLE)hobj, NULL); break;
case DD_VIDEOPORT_TYPE: bRes = bDdDeleteVideoPortObject((HANDLE)hobj, NULL); break;
case D3D_HANDLE_TYPE: HRESULT hr; bRes = D3dDeleteHandle((HANDLE)hobj, 0, NULL, &hr) == DDHAL_DRIVER_HANDLED; break;
default: bRes = FALSE; break; }
#if DBG
if (bRes == FALSE) { DbgPrint("DDRAW ERROR: DdHmgCloseProcess couldn't delete " "obj = %p, type j=%lx\n", hobj, DdHmgObjtype(hobj)); } #endif
// Move on to next object.
DdHmgAcquireHmgrSemaphore();
hobj = DdHmgNextOwned(hobj, W32Pid);
DdHmgReleaseHmgrSemaphore(); }
return (bRes); }
/******************************Public*Routine******************************\
* DdHmgValidHandle * * Returns TRUE if the handle is valid, FALSE if not. * * Note we don't need to lock the semaphore, we aren't changing anything, * we are just looking. * * History: * * 30-Apr-1999 -by- Lindsay Steventon [linstev] * Wrote it. \**************************************************************************/
BOOL DdHmgValidHandle( HDD_OBJ hobj, DD_OBJTYPE objt) { BOOL bRes = FALSE; PDD_ENTRY pentTmp; UINT uiIndex = (UINT) (UINT) DdHmgIfromH(hobj);
//
// Acquire the handle manager lock before touching gpentDdHmgr
//
DdHmgAcquireHmgrSemaphore();
if ((uiIndex < gcMaxDdHmgr) && ((pentTmp = &gpentDdHmgr[uiIndex])->Objt == objt) && (pentTmp->FullUnique == DdHmgUfromH(hobj))) { ASSERTGDI(pentTmp->einfo.pobj != (PDD_OBJ) NULL, "ERROR how can it be NULL"); bRes = TRUE; }
DdHmgReleaseHmgrSemaphore();
return (bRes); }
/******************************Public*Routine******************************\
* DdHmgRemoveObject * * Removes an object from the handle table if certain conditions are met. * * History: * * 30-Apr-1999 -by- Lindsay Steventon [linstev] * Wrote it. \**************************************************************************/
PVOID DdHmgRemoveObject( HDD_OBJ hobj, LONG cExclusiveLock, LONG cShareLock, BOOL bIgnoreUndeletable, DD_OBJTYPE objt) { PDD_OBJ pobj; UINT uiIndex = (UINT) DdHmgIfromH(hobj);
if (uiIndex < gcMaxDdHmgr) { //
// Acquire the handle manager lock before touching gpentDdHmgr
//
DdHmgAcquireHmgrSemaphore();
//
// lock handle
//
PDD_ENTRY pentTmp = &gpentDdHmgr[uiIndex];
if (VerifyObjectOwner(pentTmp)) { //
// verify objt and unique
//
if ((pentTmp->Objt == objt) && (pentTmp->FullUnique == DdHmgUfromH(hobj))) { pobj = pentTmp->einfo.pobj;
if ((pobj->cExclusiveLock == (USHORT)cExclusiveLock) && (pobj->ulShareCount == (ULONG)cShareLock)) { if (bIgnoreUndeletable || (!(pentTmp->Flags & DD_HMGR_ENTRY_UNDELETABLE))) { //
// set the handle in the object to NULL
// to prevent/catch accidental decrement of the
// shared reference count
//
pobj->hHmgr = NULL;
//
// free the handle
//
((DD_ENTRYOBJ *) pentTmp)->vFree(uiIndex); } else { WARNING1("DdHmgRemove failed object is undeletable\n"); pobj = NULL; } } else { //
// object is busy
//
WARNING1("DdHmgRemove failed - object busy elsewhere\n"); pobj = NULL; } } else { WARNING1("DdHmgRemove: bad objt or unique\n"); pobj = NULL; } } else { WARNING1("DdHmgRemove: failed to lock handle\n"); pobj = NULL; }
DdHmgReleaseHmgrSemaphore(); } else { WARNING1("DdHmgRemove failed invalid index\n"); pobj = NULL; }
return((PVOID)pobj); }
/******************************Public*Routine******************************\
* DdAllocateObject * * Allocates an object out of the heap. * * History: * * 30-Apr-1999 -by- Lindsay Steventon [linstev] * Wrote it. \**************************************************************************/
//
// This struct and the following union can be thrown away
// when someone fixes the BASEOBJECT cExclusiveLock and BaseFlags sharing
// the same DWORD.
//
struct SplitLockAndFlags { USHORT c_cExclusiveLock; USHORT c_BaseFlags; };
union SplitOrCombinedLockAndFlags { SplitLockAndFlags S; ULONG W; };
PVOID DdAllocateObject( ULONG cBytes, ULONG ulType, BOOL bZero) {
PVOID pvReturn = NULL;
ASSERTGDI(ulType != DD_DEF_TYPE, "DdAllocateObject ulType is bad"); ASSERTGDI(cBytes >= sizeof(DD_BASEOBJECT), "DdAllocateObject cBytes is bad");
//
// Debug check to avoid assert in ExAllocatePool
//
#if DBG
if (cBytes >= (PAGE_SIZE * 10000)) { WARNING("DdAllocateObject: cBytes >= 10000 pages"); return(NULL); } #endif
ULONG ulTag = '0 hD'; ulTag += ulType << 24;
//
// BASEOBJECT is always zero-initialized.
//
if (bZero) { pvReturn = PALLOCMEM(cBytes, ulTag); } else { pvReturn = PALLOCNOZ(cBytes, ulTag);
//
// At least the BASEOBJECT should be initialized.
//
if (pvReturn) { RtlZeroMemory(pvReturn, (UINT) sizeof(DD_BASEOBJECT)); } }
//
// If the allocation failed again, then set the extended
// error status and return an invalid handle.
//
if (!pvReturn) { KdPrint(("DXG: DdAllocateObject failed alloc of %lu bytes\n", (cBytes))); SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY); return NULL; }
return(pvReturn); }
/******************************Public*Routine******************************\
* DdHmgAlloc * * Allocate an object from Handle Manager. * * WARNING: * -------- * * If the object is share-lockable via an API, you MUST use DdHmgInsertObject * instead. If the object is only exclusive-lockable via an API, you MUST * either use DdHmgInsertObject or specify HMGR_ALLOC_LOCK. * * (This is because if you use DdHmgAlloc, a malicious multi-threaded * application could guess the handle and cause it to be dereferenced * before you've finished initializing it, possibly causing an access * violation.) * * History: * * 30-Apr-1999 -by- Lindsay Steventon [linstev] * Wrote it. \**************************************************************************/
HDD_OBJ DdHmgAlloc( ULONGSIZE_T cb, DD_OBJTYPE objt, FSHORT fs) // fs can be a combination of the following:
// HMGR_NO_ZERO_INIT - Don't zero initialize
// HMGR_MAKE_PUBLIC - Allow object to be lockable by
// any process
// HMGR_ALLOC_LOCK - Do an DdHmgLock on the object and
// return a pointer instead of handle
{ HDD_OBJ Handle; PVOID pv;
ASSERTGDI(objt != (DD_OBJTYPE) DD_DEF_TYPE, "DdHmgAlloc objt is bad"); ASSERTGDI(cb >= 8, "ERROR DdHmgr writes in first 8 bytes");
//
// Allocate a pointer.
//
pv = DdAllocateObject(cb, (ULONG) objt, ((fs & HMGR_NO_ZERO_INIT) == 0));
if (pv != (PVOID) NULL) { //
// We need the semaphore to access the free list
//
DdHmgAcquireHmgrSemaphore();
//
// Allocate a handle: can only fail if we run out of memory or bits to
// store the handle index.
//
Handle = hDdGetFreeHandle(objt);
if (Handle != (HDD_OBJ) 0) { //
// Store a pointer to the object in the entry corresponding to the
// allocated handle and initialize the handle data.
//
((DD_ENTRYOBJ *) &(gpentDdHmgr[DdHmgIfromH(Handle)]))->vSetup((PDD_OBJ) pv, objt, fs);
//
// Store the object handle at the beginning of the object memory.
//
((DD_OBJECT *)pv)->hHmgr = (HANDLE)Handle;
DdHmgReleaseHmgrSemaphore();
return ((fs & HMGR_ALLOC_LOCK) ? (HDD_OBJ)pv : Handle); } else { //
// We just failed a handle allocation. Release the memory.
//
WARNING("Failed DdHmgAlloc to allocate a handle\n");
DdHmgReleaseHmgrSemaphore(); DdFreeObject(pv,(ULONG) objt); } }
return((HDD_OBJ) 0); }
/******************************Public*Routine******************************\
* DdFreeObject * * Frees the object from where it was allocated. We have this as a separate * function in case we implement lookaside lists (as in GDI) later. * * History: * * 30-Apr-1999 -by- Lindsay Steventon [linstev] * Wrote it. \**************************************************************************/
VOID DdFreeObject(PVOID pvFree, ULONG ulType) { VFREEMEM(pvFree); }
/******************************Public*Routine******************************\
* DdHmgFree * * Free an object from the handle manager. * * History: * * 30-Apr-1999 -by- Lindsay Steventon [linstev] * Wrote it. \**************************************************************************/
VOID DdHmgFree(HDD_OBJ hobj) { UINT uiIndex = (UINT) DdHmgIfromH(hobj); PDD_OBJ pobjTmp; DD_OBJTYPE objtTmp;
ASSERTGDI(uiIndex != 0, "ERROR DdHmgFree invalid 0 handle");
if (uiIndex < gcMaxDdHmgr) { //
// Acquire the handle manager lock before touching gpentDdHmgr
//
DdHmgAcquireHmgrSemaphore();
PDD_ENTRY pentTmp = &gpentDdHmgr[uiIndex];
pobjTmp = pentTmp->einfo.pobj; objtTmp = pentTmp->Objt;
//
// Free the object handle
//
((DD_ENTRYOBJ *) pentTmp)->vFree(uiIndex);
DdHmgReleaseHmgrSemaphore();
if (pobjTmp) { DdFreeObject((PVOID)pobjTmp, (ULONG) objtTmp); } } else { WARNING1("DdHmgFree: bad handle index"); } }
/*****************************Exported*Routine*****************************\
* HDD_OBJ DdHmgNextOwned(hobj, pid) * * Report the next object owned by specified process * * Must be called with the Hmgr semaphore acquired. * * History: * * 30-Apr-1999 -by- Lindsay Steventon [linstev] * Wrote it. \**************************************************************************/
HDD_OBJ FASTCALL DdHmgNextOwned( HDD_OBJ hobj, W32PID pid) { PDD_ENTRYOBJ pentTmp; UINT uiIndex = (UINT) DdHmgIfromH(hobj);
//
// If we are passed 0 we inc to 1 because 0 can never be valid.
// If we are passed != 0 we inc 1 to find the next one valid.
//
uiIndex++;
while (uiIndex < gcMaxDdHmgr) { pentTmp = (PDD_ENTRYOBJ) &gpentDdHmgr[uiIndex];
if (pentTmp->bOwnedBy(pid)) { LONG_PTR uiIndex1 = (LONG_PTR)DD_MAKE_HMGR_HANDLE(uiIndex,pentTmp->FullUnique);
return((HDD_OBJ)(uiIndex1 & 0xFFFFFFFF)); }
// Advance to next object
uiIndex++; }
// No objects found
return((HDD_OBJ) 0); }
/*****************************Exported*Routine*****************************\
* HDD_OBJ DdHmgNextObjt * * Report the next object of a certain type. * * Must be called with the Hmgr semaphore acquired. * * History: * * 30-Apr-1999 -by- Lindsay Steventon [linstev] * Wrote it. \**************************************************************************/
PDD_OBJ FASTCALL DdHmgNextObjt( HDD_OBJ hobj, DD_OBJTYPE objt) { PDD_ENTRYOBJ pentTmp; UINT uiIndex = (UINT) DdHmgIfromH(hobj);
//
// If we are passed 0 we inc to 1 because 0 can never be valid.
// If we are passed != 0 we inc 1 to find the next one valid.
//
uiIndex++;
while (uiIndex < gcMaxDdHmgr) { pentTmp = (PDD_ENTRYOBJ) &gpentDdHmgr[uiIndex];
if (pentTmp->Objt == objt) { return(pentTmp->einfo.pobj); }
//
// Advance to next object
//
uiIndex++; }
//
// no objects found
//
return((PDD_OBJ) 0); }
/*******************************Routine************************************\
* DdHmgLock * * Description: * * Acquire an exclusive lock on an object, PID owner must match current PID * or be a public. * * Arguments: * * hobj - Handle to lock * objt - Check to make sure handle is of expected type * * Return Value: * * Pointer to object or NULL * * History: * * 30-Apr-1999 -by- Lindsay Steventon [linstev] * Wrote it. \**************************************************************************/
PDD_OBJ FASTCALL DdHmgLock( HDD_OBJ hobj, DD_OBJTYPE objt, BOOL underSemaphore ) { PDD_OBJ pobj = (PDD_OBJ)NULL; UINT uiIndex = (UINT)DdHmgIfromH(hobj);
//
// Acquire the handle manager lock before touching gpentDdHmgr
// Only do this if we are not already under the semaphore
//
if (!underSemaphore) { DdHmgAcquireHmgrSemaphore(); } if (uiIndex < gcMaxDdHmgr) { PDD_ENTRY pentry = &gpentDdHmgr[uiIndex];
if (VerifyObjectOwner(pentry)) { if ((pentry->Objt == objt) && (pentry->FullUnique == DdHmgUfromH(hobj))) { ULONG_PTR thread = (ULONG_PTR)PsGetCurrentThread();
pobj = pentry->einfo.pobj;
if ((pobj->cExclusiveLock == 0) || (pobj->Tid == thread)) { INC_EXCLUSIVE_REF_CNT(pobj); pobj->Tid = thread; } else { WARNING1("DdHmgLock: object already locked by another thread"); pobj = (PDD_OBJ)NULL; } } else { DdHmgPrintBadHandle(hobj, objt); } } else { DdHmgPrintBadHandle(hobj, objt); } } else { DdHmgPrintBadHandle(hobj, objt); }
if (!underSemaphore) { DdHmgReleaseHmgrSemaphore(); }
return(pobj); }
/******************************Public*Routine******************************\
* DdHmgQueryLock * * This returns the number of times an object has been Locked. * * Expects: A valid handle. The handle should be validated and locked * before calling this. Note we don't need to grab the semaphore * because this call assumes the handle has already been locked * down and we are just reading memory. * * Returns: The number of times the object has been locked. * * History: * * 30-Apr-1999 -by- Lindsay Steventon [linstev] * Wrote it. \**************************************************************************/
ULONG FASTCALL DdHmgQueryLock(HDD_OBJ hobj) { //
// Acquire the handle manager lock before touching gpentDdHmgr
//
DdHmgAcquireHmgrSemaphore();
UINT uiIndex = (UINT)DdHmgIfromH(hobj); ASSERTGDI(uiIndex < gcMaxDdHmgr, "DdHmgQueryLock invalid handle");
ULONG ulRes = gpentDdHmgr[uiIndex].einfo.pobj->cExclusiveLock;
DdHmgReleaseHmgrSemaphore();
return ulRes; }
/******************************Public*Routine******************************\
* HDD_OBJ hDdGetFreeHandle() * * Get the next available handle. If the handle table is full, we grow it. * This function can fail under any of these circumstances: * 1. Handle manager didn't initialize * 2. Insufficient memory to grow the handle table * 3. Insufficient bits to store the handle index * * Note: * We must already have the HmgrSemaphore * * History: * * 30-Apr-1999 -by- Lindsay Steventon [linstev] * Wrote it. \**************************************************************************/
HDD_OBJ hDdGetFreeHandle( DD_OBJTYPE objt ) { LONG_PTR uiIndex;
//
// Handle manager initialized and bounds check
//
if ((gpentDdHmgr == NULL) || (gcMaxDdHmgr == DD_MAX_HANDLE_COUNT)) { return ((HDD_OBJ)0); } //
// Check if there is a free handle we can use
//
if (ghFreeDdHmgr != (HDD_OBJ) 0) { PDD_ENTRYOBJ pentTmp;
uiIndex = (LONG_PTR)ghFreeDdHmgr; pentTmp = (PDD_ENTRYOBJ) &gpentDdHmgr[uiIndex]; ghFreeDdHmgr = pentTmp->einfo.hFree;
pentTmp->FullUnique = DD_USUNIQUE(pentTmp->FullUnique,objt);
uiIndex = (LONG_PTR)DD_MAKE_HMGR_HANDLE(uiIndex,pentTmp->FullUnique);
return((HDD_OBJ)(uiIndex & 0xFFFFFFFF)); }
//
// Check if we've run out of handles
//
if (gcMaxDdHmgr == gcSizeDdHmgr) { // Increase the table size
ULONG dwNewSize = gcSizeDdHmgr + DD_TABLESIZE_DELTA;
// Allocate a new block
DD_ENTRY *ptHmgr = (DD_ENTRY *)PALLOCMEM(sizeof(DD_ENTRY) * dwNewSize, 'ddht');
if (ptHmgr == NULL) { WARNING("DdHmgr failed to grow handle table\n"); return ((HDD_OBJ) 0); }
//
// Copy the old handles into the new table
//
RtlMoveMemory(ptHmgr, gpentDdHmgr, sizeof(DD_ENTRY) * gcSizeDdHmgr);
gcSizeDdHmgr = dwNewSize; gpentDdHmgrLast = gpentDdHmgr; VFREEMEM(gpentDdHmgr); gpentDdHmgr = ptHmgr; } //
// Allocate a new handle table entry and set the uniqueness value.
//
uiIndex = DD_USUNIQUE(DD_UNIQUE_INCREMENT,objt); gpentDdHmgr[gcMaxDdHmgr].FullUnique = (USHORT) uiIndex; uiIndex = (LONG_PTR)DD_MAKE_HMGR_HANDLE(gcMaxDdHmgr,uiIndex); gcMaxDdHmgr++;
return((HDD_OBJ)(uiIndex & 0xFFFFFFFF)); }
/******************************Public*Routines*****************************\
* DdHmgAcquireHmgrSemaphore * * DdHmgReleaseHmgrSemaphore * * * * Convenience functions for the handle manager semaphore. * * * \**************************************************************************/
VOID DdHmgAcquireHmgrSemaphore() { EngAcquireSemaphore(ghsemHmgr); }
VOID DdHmgReleaseHmgrSemaphore() { EngReleaseSemaphore(ghsemHmgr); }
/******************************Public*Routine******************************\
* DdHmgPrintBadHandle * * Simple routine that prints out a warning when a handle manager * lock fails due to a bad handle. * \**************************************************************************/
#if DBG
CONST CHAR* aszDdType[] = { "hdef", // DD_DEF_TYPE
"hddraw", // DD_DIRECTDRAW_TYPE
"hddrawsurf", // DD_SURFACE_TYPE
"hd3d", // D3D_HANDLE_TYPE
"hddrawvport", // DD_VIDEOPORT_TYPE
"hmotioncomp", // DD_MOTIONCOMP_TYPE
"hunused", //
};
VOID DdHmgPrintBadHandle( HDD_OBJ hobj, DD_OBJTYPE objt ) { static CHAR *szSystem = "System"; static CHAR *szUnknown = "???"; CHAR *pszImage;
{ PETHREAD pet; PEPROCESS pep;
if (pep = PsGetCurrentProcess()) { pszImage = (CHAR *)PsGetProcessImageFileName(pep); if (*pszImage == '\0') { pszImage = szSystem; } } else { pszImage = szUnknown; } }
KdPrint(("DXG: %s or DLL gave bad handle 0x%p as an %s.\n", pszImage, hobj, aszDdType[objt])); }
#endif
|