/***************************************************************************\ * * 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; }