Windows2003-3790/windows/advcore/duser/engine/services/ticketmanager.cpp
2020-09-30 16:53:55 +02:00

323 lines
8.4 KiB
C++

/***************************************************************************\
*
* File: TicketManager.cpp
*
* Description:
*
* This file contains the implementation of relevant classes, structs, and
* types for the DUser Ticket Manager.
*
* The following classes are defined for public use:
*
* DuTicketManager
* A facility which can assign a unique "ticket" to a BaseObject.
*
* History:
* 9/20/2000: DwayneN: Created
*
* Copyright (C) 2000 by Microsoft Corporation. All rights reserved.
*
\***************************************************************************/
#include "stdafx.h"
#include "Services.h"
#include "TicketManager.h"
#define INIT_OUT_PARAM(p,v) if(p != NULL) *p = v
#define VALIDATE_REQUIRED_OUT_PARAM(p) if(p == NULL) return E_POINTER;
#define VALIDATE_IN_PARAM_NOT_VALUE(p,v) if(p == v) return E_INVALIDARG;
//------------------------------------------------------------------------------
DuTicketManager::DuTicketManager()
{
Assert(sizeof(DuTicket) == sizeof(DWORD));
m_idxFreeStackTop = -1;
m_idxFreeStackBottom = -1;
}
//------------------------------------------------------------------------------
DuTicketManager::~DuTicketManager()
{
}
//------------------------------------------------------------------------------
HRESULT
DuTicketManager::Add(
IN BaseObject * pObject,
OUT DWORD * pdwTicket)
{
HRESULT hr = S_OK;
int idxFree = 0;
//
// Parameter checking.
// - Initialize all out parameters
// - Validate in parameters
//
INIT_OUT_PARAM(pdwTicket, 0);
VALIDATE_REQUIRED_OUT_PARAM(pdwTicket);
VALIDATE_IN_PARAM_NOT_VALUE(pObject, NULL);
m_crit.Enter();
//
// Scan to make sure the object isn't already in the array.
// This is too expensive to do outside of DEBUG builds.
//
Assert(FAILED(Find(pObject, idxFree)));
hr = PopFree(idxFree);
if (SUCCEEDED(hr)) {
DuTicket ticket;
m_arTicketData[idxFree].pObject = pObject;
ticket.Unused = 0;
ticket.Uniqueness = m_arTicketData[idxFree].cUniqueness;
ticket.Type = pObject->GetHandleType();
ticket.Index = idxFree;
*pdwTicket = DuTicket::CastToDWORD(ticket);
}
m_crit.Leave();
return hr;
}
//------------------------------------------------------------------------------
HRESULT
DuTicketManager::Remove(
IN DWORD dwTicket,
OUT OPTIONAL BaseObject ** ppObject)
{
HRESULT hr = S_OK;
//
// Parameter checking.
// - Initialize all out parameters
// - Validate in parameters
//
INIT_OUT_PARAM(ppObject, NULL);
VALIDATE_IN_PARAM_NOT_VALUE(dwTicket, 0);
m_crit.Enter();
hr = Lookup(dwTicket, ppObject);
if (SUCCEEDED(hr)) {
DuTicket ticket = DuTicket::CastFromDWORD(dwTicket);
//
// Clear out the object at this index just in case.
//
m_arTicketData[ticket.Index].pObject = NULL;
//
// Increment the uniqueness to invalidate any outstanding tickets.
//
m_arTicketData[ticket.Index].cUniqueness++;
if (m_arTicketData[ticket.Index].cUniqueness == 0) {
m_arTicketData[ticket.Index].cUniqueness = 1;
}
//
// Push this index back onto the free stack.
//
PushFree(ticket.Index);
}
m_crit.Leave();
return(hr);
}
//------------------------------------------------------------------------------
HRESULT
DuTicketManager::Lookup(
IN DWORD dwTicket,
OUT OPTIONAL BaseObject ** ppObject)
{
HRESULT hr = S_OK;
DuTicket ticket = DuTicket::CastFromDWORD(dwTicket);
//
// Parameter checking.
// - Initialize all out parameters
// - Validate in parameters
// - Check for manifest errors in the ticket
//
INIT_OUT_PARAM(ppObject, NULL);
VALIDATE_IN_PARAM_NOT_VALUE(dwTicket, 0);
if (ticket.Unused != 0 ||
ticket.Uniqueness == 0 ||
ticket.Index >= WORD(m_arTicketData.GetSize())) {
return E_INVALIDARG;
}
m_crit.Enter();
//
// Look up the information in the tables and see if the
// ticket still looks valid.
//
if (m_arTicketData[ticket.Index].cUniqueness == ticket.Uniqueness) {
if (ppObject != NULL && m_arTicketData[ticket.Index].pObject != NULL) {
if (ticket.Type == BYTE(m_arTicketData[ticket.Index].pObject->GetHandleType())) {
*ppObject = m_arTicketData[ticket.Index].pObject;
}
}
} else {
//
// It seems like the ticket has gone stale.
//
hr = DU_E_NOTFOUND;
}
m_crit.Leave();
return hr;
}
//------------------------------------------------------------------------------
HRESULT
DuTicketManager::Expand()
{
//
// We only need to resize our internal arrays when the free stack is empty.
//
Assert(m_idxFreeStackBottom == -1 && m_idxFreeStackTop == -1);
//
// Get the old size of the array, and calculate a new size.
// Note that we limit how big the table can grow.
//
int cOldSize = m_arTicketData.GetSize();
int cNewSize;
if (cOldSize > 0) {
if (cOldSize < USHRT_MAX) {
cNewSize = min(cOldSize * 2, USHRT_MAX);
} else {
return E_OUTOFMEMORY;
}
} else {
cNewSize = 16;
}
//
// Resize the array of objects. The contents of the new items will
// be set to NULL;
//
if (m_arTicketData.SetSize(cNewSize)) {
//
// Initialize the new data.
//
for (int i = cOldSize; i < cNewSize; i++) {
m_arTicketData[i].pObject = NULL;
m_arTicketData[i].cUniqueness = 1;
m_arTicketData[i].idxFree = WORD(i);
}
m_idxFreeStackBottom = cOldSize;
m_idxFreeStackTop = cNewSize - 1;
} else {
return E_OUTOFMEMORY;
}
return S_OK;
}
//------------------------------------------------------------------------------
HRESULT
DuTicketManager::PushFree(int idxFree)
{
if (m_idxFreeStackBottom == -1 && m_idxFreeStackTop == -1) {
Assert(m_arTicketData.GetSize() > 0);
m_idxFreeStackBottom = 0;
m_idxFreeStackTop = 0;
m_arTicketData[0].idxFree = WORD(idxFree);
} else {
int iNewTop = (m_idxFreeStackTop + 1) % m_arTicketData.GetSize();
AssertMsg(iNewTop != m_idxFreeStackBottom, "Probably more pushes than pops!");
m_arTicketData[iNewTop].idxFree = WORD(idxFree);
m_idxFreeStackTop = iNewTop;
}
return S_OK;
}
//------------------------------------------------------------------------------
HRESULT
DuTicketManager::PopFree(int & idxFree)
{
HRESULT hr = S_OK;
//
// Resize our arrays if our stack of available slots is empty.
//
if (m_idxFreeStackBottom == -1 || m_idxFreeStackTop == -1) {
hr = Expand();
Assert(SUCCEEDED(hr));
if (FAILED(hr)) {
return hr;
}
}
Assert(m_idxFreeStackBottom >=0 && m_idxFreeStackTop >=0 );
//
// Take the available slot from the bottom of the stack.
//
idxFree = m_arTicketData[m_idxFreeStackBottom].idxFree;
//
// Increment the bottom of the stack. If the stack is now empty,
// indicate so by setting the top and bottom to -1.
//
if (m_idxFreeStackBottom == m_idxFreeStackTop) {
m_idxFreeStackBottom = -1;
m_idxFreeStackTop = -1;
} else {
m_idxFreeStackBottom = (m_idxFreeStackBottom + 1) % m_arTicketData.GetSize();
}
return S_OK;
}
//------------------------------------------------------------------------------
HRESULT
DuTicketManager::Find(BaseObject * pObject, int & iFound)
{
HRESULT hr = DU_E_NOTFOUND;
iFound = -1;
//
// Note: This is a brute-force find. It does a linear search for the
// specified pointer. This is very, very slow so don't use it unless
// you absolutely have to. The BaseObject itself should remember what
// its ticket is so it doesn't have to search.
//
for (int i = 0; i < m_arTicketData.GetSize(); i++) {
if (m_arTicketData[i].pObject == pObject) {
hr = S_OK;
iFound = i;
break;
}
}
return hr;
}