windows-nt/Source/XPSP1/NT/multimedia/opengl/client/local.c
2020-09-26 16:20:57 +08:00

275 lines
8.7 KiB
C

/*****************************Module*Header*******************************\
* Module Name: local.c *
* *
* Support routines for client side objects. *
* *
* Created: 30-May-1991 21:55:57 *
* Author: Charles Whitmer [chuckwh] *
* *
* Copyright (c) 1991,1993 Microsoft Corporation *
\**************************************************************************/
#include "precomp.h"
#pragma hdrstop
#include <ntcsrdll.h>
LHE *pLocalTable; // Points to handle table.
ULONG iFreeLhe = INVALID_INDEX; // Identifies a free handle index.
ULONG cLheCommitted = 0; // Count of LHEs with committed RAM.
CRITICAL_SECTION semLocal; // Semaphore for handle allocation.
//XXX Useless but needed by csrgdi.h
#if DBG
ULONG gcHits = 0;
ULONG gcBatch = 0;
ULONG gcCache = 0;
ULONG gcUser = 0;
#endif
/******************************Private*Routine*****************************\
* bMakeMoreHandles () *
* *
* Commits more RAM to the local handle table and links the new free *
* handles together. Returns TRUE on success, FALSE on error. *
* *
* History: *
* Sat 01-Jun-1991 17:06:45 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
BOOL bMakeMoreHandles()
{
UINT ii;
// Commit more RAM for the handle table.
if (
(cLheCommitted >= MAX_HANDLES) ||
(VirtualAlloc(
(LPVOID) &pLocalTable[cLheCommitted],
COMMIT_COUNT * sizeof(LHE),
MEM_COMMIT,
PAGE_READWRITE
) == (LPVOID) NULL)
)
{
WARNING("bMakeMoreHandles(): failed to commit more memory\n");
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return(FALSE);
}
// Initialize the new handles.
ii = iFreeLhe = cLheCommitted;
cLheCommitted += COMMIT_COUNT;
for (; ii<cLheCommitted; ii++)
{
pLocalTable[ii].metalink = ii+1;
pLocalTable[ii].iUniq = 1;
pLocalTable[ii].iType = LO_NULL;
}
pLocalTable[ii-1].metalink = INVALID_INDEX;
return(TRUE);
}
/******************************Public*Routine******************************\
* iAllocHandle (iType,hgre,pv) *
* *
* Allocates a handle from the local handle table, initializes fields in *
* the handle entry. Returns the handle index or INVALID_INDEX on error. *
* *
* History: *
* Sat 01-Jun-1991 17:08:54 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
ULONG iAllocHandle(ULONG iType,ULONG hgre,PVOID pv)
{
ULONG ii = INVALID_INDEX;
PLHE plhe;
// Get critical for handle allocation.
ENTERCRITICALSECTION(&semLocal);
// Make sure a handle is available.
if (iFreeLhe != INVALID_INDEX || bMakeMoreHandles())
{
ii = iFreeLhe;
plhe = pLocalTable + ii;
iFreeLhe = plhe->metalink;
plhe->hgre = hgre;
plhe->cRef = 0;
plhe->iType = (BYTE) iType;
plhe->pv = pv;
plhe->metalink = 0;
plhe->tidOwner = 0;
plhe->cLock = 0;
}
// Leave the critical section.
LEAVECRITICALSECTION(&semLocal);
return(ii);
}
/******************************Public*Routine******************************\
* vFreeHandle (h) *
* *
* Frees up a local handle. The handle is added to the free list. This *
* may be called with either an index or handle. The iUniq count is *
* updated so the next user of this handle slot will have a different *
* handle. *
* *
* Note for client side implementation: *
* Caller should have handle locked before calling this. *
* *
* History: *
* Sat 01-Jun-1991 17:11:23 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
VOID vFreeHandle(ULONG_PTR h)
{
// Extract the index from the handle.
UINT ii = MASKINDEX(h);
// Get critical for handle deallocation.
ENTERCRITICALSECTION(&semLocal);
// Caller should lock handle before freeing.
ASSERTOPENGL(pLocalTable[ii].cLock == 1,
"vFreeHandle(): cLock != 1\n");
ASSERTOPENGL(pLocalTable[ii].tidOwner == GetCurrentThreadId(),
"vFreeHandle(): thread not owner\n");
// Add the handle to the free list.
pLocalTable[ii].metalink = iFreeLhe;
iFreeLhe = ii;
// Increment the iUniq count.
pLocalTable[ii].iUniq++;
if (pLocalTable[ii].iUniq == 0)
pLocalTable[ii].iUniq = 1;
pLocalTable[ii].iType = LO_NULL;
// Leave the critical section.
LEAVECRITICALSECTION(&semLocal);
}
/******************************Public*Routine******************************\
* cLockHandle (h)
*
* Lock handle for access by a thread. If another thread possesses the lock,
* this will fail.
*
* Returns:
* Lock count. Returns -1 if failure.
*
* History:
* 31-Jan-1995 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
LONG cLockHandle(ULONG_PTR h)
{
LONG lRet = -1;
// Extract the index from the handle.
UINT ii = MASKINDEX(h);
PLHE plhe = pLocalTable + ii;
// Get critical for handle locking.
ENTERCRITICALSECTION(&semLocal);
if ((ii >= cLheCommitted) ||
(!MATCHUNIQ(plhe,h)) ||
((plhe->iType != LO_RC))
)
{
DBGLEVEL1(LEVEL_ERROR, "cLockHandle: invalid handle 0x%lx\n", h);
SetLastError(ERROR_INVALID_HANDLE);
goto cLockHandle_exit;
}
// If not currently locked or if current owning thread is the same,
// do the lock.
if ( (pLocalTable[ii].cLock == 0) ||
(pLocalTable[ii].tidOwner == GetCurrentThreadId()) )
{
pLocalTable[ii].cLock++;
pLocalTable[ii].tidOwner = GetCurrentThreadId();
lRet = (LONG) pLocalTable[ii].cLock;
}
else
{
WARNING("cLockHandle(): current thread not owner\n");
SetLastError(ERROR_BUSY);
}
// Leave the critical section.
cLockHandle_exit:
LEAVECRITICALSECTION(&semLocal);
return lRet;
}
/******************************Public*Routine******************************\
* vUnlockHandle (h)
*
* Removes a lock from the handle. Must be owned by current thread.
*
* Note:
* Caller should possess the lock before this is called. This implies
* that cLockHandle must be called and its return code must be heeded.
*
* History:
* 31-Jan-1995 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
VOID vUnlockHandle(ULONG_PTR h)
{
// Extract the index from the handle.
UINT ii = MASKINDEX(h);
// Get critical for handle deallocation.
ENTERCRITICALSECTION(&semLocal);
// If not currently locked or if current owning thread is the same,
// do the lock.
ASSERTOPENGL(pLocalTable[ii].cLock > 0,
"vUnlockHandle(): not locked\n");
ASSERTOPENGL(pLocalTable[ii].tidOwner == GetCurrentThreadId(),
"vUnlockHandle(): thread not owner\n");
if ( (pLocalTable[ii].cLock > 0) &&
(pLocalTable[ii].tidOwner == GetCurrentThreadId()) )
{
pLocalTable[ii].cLock--;
}
// Leave the critical section.
LEAVECRITICALSECTION(&semLocal);
}