Leaked source code of windows server 2003
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
|
|
//-----------------------------------------------------------------------------
//
//
// File: msgguid.cpp
//
// Description: Implementation of AQMsgGuidList and CAQMsgGuidListEntry
// classes which provide the functionality to supersede outdated
// msg ID's.
//
// Author: Mike Swafford (MikeSwa)
//
// History:
// 10/10/98 - MikeSwa Created
//
// Copyright (C) 1998 Microsoft Corporation
//
//-----------------------------------------------------------------------------
#include "aqprecmp.h"
#include "msgguid.h"
CPool CAQMsgGuidListEntry::s_MsgGuidListEntryPool(MSGGUIDLIST_ENTRY_SIG); //
// A brief note about locks for thess classes.
//
// The CAMsgGuidList* classes are protected by a single per-virtual server
// ShareLock (m_slPrivateData of course). These locks are non-reentrant, so
// it is critical that we do not hold these locks while doing something that
// may cause a locking call back into us (like releasing a CMsgReference).
//
//---[ CAQMsgGuidListEntry::CAQMsgGuidListEntry ]------------------------------
//
//
// Description:
// Constructor for CAQMsgGuidListEntry
// Parameters:
// pmsgref Ptr to CMsgRef for this ID
// pguid GUID ID of this message
// pliHead Head of list to add to
// pmgl List this entry belongs to
// Returns:
// -
// History:
// 10/10/98 - MikeSwa Created
//
//-----------------------------------------------------------------------------
CAQMsgGuidListEntry::CAQMsgGuidListEntry(CMsgRef *pmsgref, GUID *pguid, PLIST_ENTRY pliHead, CAQMsgGuidList *pmgl) { _ASSERT(pmsgref); _ASSERT(pguid); _ASSERT(pmgl); _ASSERT(pliHead);
m_dwSignature = MSGGUIDLIST_ENTRY_SIG; m_pmsgref = pmsgref; m_pmsgref->AddRef(); m_pmgl = pmgl;
memcpy(&m_guidMsgID, pguid, sizeof(GUID));
InsertHeadList(pliHead, &m_liMsgGuidList); }
//---[ CAQMsgGuidListEntry::~CAQMsgGuidListEntry ]-----------------------------
//
//
// Description:
// Destructor for CAQMsgGuidListEntry
// Parameters:
// -
// Returns:
// -
// History:
// 10/10/98 - MikeSwa Created
//
//-----------------------------------------------------------------------------
CAQMsgGuidListEntry::~CAQMsgGuidListEntry() { //we should not still be in a list
_ASSERT(!m_liMsgGuidList.Flink); _ASSERT(!m_liMsgGuidList.Blink);
m_dwSignature = MSGGUIDLIST_ENTRY_SIG_INVALID;
//It is safe to release the message ref here, since there is no way it
//can call back into use (unless there is a ref-counting bug).
if (m_pmsgref) m_pmsgref->Release();
m_pmgl = NULL; }
//---[ CAQMsgGuidListEntry::pmgleGetEntry ]------------------------------------
//
//
// Description:
// Static function to get entry from LIST_ENTRY
//
// NOTE: inline function for use by CAQMsgGuidList only
// Parameters:
// pli LIST ENTRY
// Returns:
// pointer to associated CAQMsgGuidListEntry
// History:
// 10/10/98 - MikeSwa Created
//
//-----------------------------------------------------------------------------
CAQMsgGuidListEntry *CAQMsgGuidListEntry::pmgleGetEntry(PLIST_ENTRY pli) { _ASSERT(pli); CAQMsgGuidListEntry *pmgle = CONTAINING_RECORD(pli, CAQMsgGuidListEntry, m_liMsgGuidList); ASSERT(pmgle->m_dwSignature == MSGGUIDLIST_ENTRY_SIG); return pmgle; } //---[ CAQMsgGuidListEntry::fCompareGuid ]-------------------------------------
//
//
// Description:
// Function used by CAQMsgGuidList to determine if this has a the GUID
// matching the superseded ID.
//
// NOTE: inline function for use by CAQMsgGuidList only
// Parameters:
// pguid GUID to check against
// Returns:
// TRUE if they match
// FALSE otherwise
// History:
// 10/10/98 - MikeSwa Created
//
//-----------------------------------------------------------------------------
BOOL CAQMsgGuidListEntry::fCompareGuid(GUID *pguid) { _ASSERT(pguid); return (0 == memcmp(pguid, &m_guidMsgID, sizeof(GUID))); }
//---[ CAQMsgGuidListEntry::RemoveFromList ]-----------------------------------
//
//
// Description:
// Used by CMsgRef to remove an entry from the list once delivery is
// complete.
// Parameters:
// -
// Returns:
// -
// History:
// 10/10/98 - MikeSwa Created
//
//-----------------------------------------------------------------------------
void CAQMsgGuidListEntry::RemoveFromList() { _ASSERT(m_pmgl); m_pmgl->RemoveFromList(&m_liMsgGuidList); }
//---[ CAQMsgGuidListEntry::pmsgrefGetAndClearMsgRef ]-------------------------
//
//
// Description:
// First phase shutdown/deletion of object. Will set to NULL and return
// orginal msgref pointer. When caller releases lock, they should release
// the returned msgref.
//
// NOTE: Releasing the msgref while holding onto m_slPrivateData can
// lead to a deadlock. m_slPrivateData should be held while this
// Parameters:
// -
// Returns:
// -
// History:
// 10/10/98 - MikeSwa Created
//
//-----------------------------------------------------------------------------
CMsgRef *CAQMsgGuidListEntry::pmsgrefGetAndClearMsgRef() { CMsgRef *pmsgref = m_pmsgref; m_pmsgref = NULL; return pmsgref; }
//---[ CAQMsgGuidListEntry::SupersedeMsg ]-------------------------------------
//
//
// Description:
// Function to supersede msg associated with this object. Will flag the
// associated CMsgRef as "non-deliverable"
//
// NOTE: Should have MsgGuidList Write lock when calling
// Parameters:
// -
// Returns:
// -
// History:
// 10/10/98 - MikeSwa Created
//
//-----------------------------------------------------------------------------
void CAQMsgGuidListEntry::SupersedeMsg() { m_pmsgref->SupersedeMsg(); m_pmsgref->Release(); m_pmsgref = NULL; }
//---[ CAQMsgGuidList::CAQMsgGuidList ]-----------------------------------------
//
//
// Description:
// Constructor for CAQMsgGuidList.
// Parameters:
// pcSupersededMsgs Ptr to DWORD to InterlockedIncrement for
// a count of superseded messages.
// (can be NULL if no counters are wanted)
// Returns:
// -
// History:
// 10/11/98 - MikeSwa Created
//
//-----------------------------------------------------------------------------
CAQMsgGuidList::CAQMsgGuidList(DWORD *pcSupersededMsgs) { m_dwSignature = MSGGUIDLIST_SIG; m_pcSupersededMsgs = pcSupersededMsgs; InitializeListHead(&m_liMsgGuidListHead); }
//---[ CAQMsgGuidList::~CAQMsgGuidList ]---------------------------------------
//
//
// Description:
// Desctructor for CAQMsgGuidList
// Parameters:
// -
// Returns:
// -
// History:
// 10/11/98 - MikeSwa Created
//
//-----------------------------------------------------------------------------
CAQMsgGuidList::~CAQMsgGuidList() { Deinitialize(NULL); _ASSERT(IsListEmpty(&m_liMsgGuidListHead)); }
//---[ CAQMsgGuidList::pmgleAddMsgGuid ]---------------------------------------
//
//
// Description:
// Adds a message ID/Msg to the list of msg GUIDs. Will also search for
// the superseded msg GUID ID from the tail of the list.
//
// This is meant as a server-side optimization. There is *no* attempt
// to recover from out of memory situations.
// Parameters:
// pmsgref MsgRef associated with this ID
// pguidID GUID ID of this message
// pguidSuperseded GUID ID of message superseded by this message
//
// Returns:
// Pointer to list entry for this msg (caller *must* Release)
// NULL if no entry allocated
// History:
// 10/11/98 - MikeSwa Created
// 05/08/99 - MikeSwa Fixed AV
//
//-----------------------------------------------------------------------------
CAQMsgGuidListEntry *CAQMsgGuidList::pmgleAddMsgGuid(CMsgRef *pmsgref, GUID *pguidID, GUID *pguidSuperseded) { _ASSERT(pmsgref); _ASSERT(pguidID); CAQMsgGuidListEntry *pmgle = NULL; PLIST_ENTRY pliCurrent = NULL; CMsgRef *pmsgrefSuperseded = NULL;
//First search list for matching GUID
m_slPrivateData.ShareLock(); pliCurrent = m_liMsgGuidListHead.Blink; while (pliCurrent && (pliCurrent != &m_liMsgGuidListHead)) { pmgle = CAQMsgGuidListEntry::pmgleGetEntry(pliCurrent); if (pguidSuperseded && pmgle->fCompareGuid(pguidSuperseded)) { //we found a match... addref it and stop looking
pmgle->AddRef(); break; }
//NOTE: We may want to consider adding functionality that
//would allow us to supersede messages that are added to the
//system later... if some layer of abstaction (like the pickup dir)
//causes out of order submission, this would allow us to handle
//that case. It could require:
// - Additional check of current ID against all superseded ID's (2x cost)
// - Additional storage of original superseded ID's.
pmgle = NULL; pliCurrent = pliCurrent->Blink; } m_slPrivateData.ShareUnlock();
m_slPrivateData.ExclusiveLock(); if (pmgle) { //make sure someone else hasn't removed it from the list
if (pliCurrent->Blink && pliCurrent->Flink) { //If we found a match supersede
if (m_pcSupersededMsgs) InterlockedIncrement((PLONG) m_pcSupersededMsgs); pmgle->SupersedeMsg(); RemoveEntryList(pliCurrent); pliCurrent->Flink = NULL; pliCurrent->Blink = NULL;
pmsgrefSuperseded = pmgle->pmsgrefGetAndClearMsgRef(); //Release once for entry in list, and once for AddRef above
_VERIFY(pmgle->Release()); pmgle->Release(); } }
pmgle = new CAQMsgGuidListEntry(pmsgref, pguidID, &m_liMsgGuidListHead, this); if (pmgle) pmgle->AddRef();
m_slPrivateData.ExclusiveUnlock();
if (pmsgrefSuperseded) pmsgrefSuperseded->Release();
return pmgle; }
//---[ CAQMsgGuidList::Deinitialize ]------------------------------------------
//
//
// Description:
// Walks list and released all msg id objects. Calls server stop hint
// function if provided.
// Parameters:
// painst Ptr to virtual server object to call stop hint function
// Returns:
// -
// History:
// 10/11/98 - MikeSwa Created
//
//-----------------------------------------------------------------------------
void CAQMsgGuidList::Deinitialize(CAQSvrInst *paqinst) { PLIST_ENTRY pliCurrent = NULL; CAQMsgGuidListEntry *pmgle = NULL; CMsgRef *pmsgref = NULL;
m_slPrivateData.ExclusiveLock();
//Walk entire list and release all objects
while (!IsListEmpty(&m_liMsgGuidListHead)) { pliCurrent = m_liMsgGuidListHead.Flink; _ASSERT(pliCurrent); pmgle = CAQMsgGuidListEntry::pmgleGetEntry(pliCurrent); _ASSERT(pmgle); RemoveEntryList(pliCurrent); pliCurrent->Flink = NULL; pliCurrent->Blink = NULL; //we must unlock to Deinitalize and release won't deadlock
m_slPrivateData.ExclusiveUnlock(); //Send shutdown hint
if (paqinst) paqinst->ServerStopHintFunction();
pmsgref = pmgle->pmsgrefGetAndClearMsgRef(); if (pmsgref) pmsgref->Release();
pmgle->Release();
//Lock so we can check if list is empty
m_slPrivateData.ExclusiveLock(); } m_slPrivateData.ExclusiveUnlock(); }
//---[ CAQMsgGuidList::RemoveFromList ]----------------------------------------
//
//
// Description:
// Used by a CAQMsgGuidListEntry to remove itself from the list in a
// thread-safe manner. The CAQMsgGuidListEntry is called by the CMsgRef
// when it is completely handled.
// Parameters:
// pli PLIST_ENTRY to remove from list
// Returns:
// -
// History:
// 10/11/98 - MikeSwa Created
//
//-----------------------------------------------------------------------------
void CAQMsgGuidList::RemoveFromList(PLIST_ENTRY pli) { _ASSERT(pli); CAQMsgGuidListEntry *pmgle = CAQMsgGuidListEntry::pmgleGetEntry(pli); CMsgRef *pmsgref = NULL; m_slPrivateData.ExclusiveLock();
if (pli->Flink && pli->Blink) { //Only remove from list once
RemoveEntryList(pli); pli->Flink = NULL; pli->Blink = NULL; pmsgref = pmgle->pmsgrefGetAndClearMsgRef(); //Caller must still have reference
_VERIFY(pmgle->Release()); } m_slPrivateData.ExclusiveUnlock();
//Do not release while holding lock
if (pmsgref) pmsgref->Release(); }
|