622 lines
16 KiB
C++
622 lines
16 KiB
C++
/*==========================================================================
|
|
*
|
|
* Copyright (C) 1999 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: innerque.cpp
|
|
* Content:
|
|
*
|
|
* History:
|
|
* Date By Reason
|
|
* ==== == ======
|
|
* 07/16/99 pnewson Created
|
|
* 07/27/99 pnewson Overhauled to support new message numbering method
|
|
* 08/03/99 pnewson General clean up
|
|
* 08/24/99 rodtoll Fixed for release builds -- removed m_wQueueId from debug block
|
|
* 10/28/99 pnewson Bug #113933 debug spew too verbose
|
|
* implement inner queue pool code
|
|
* 10/29/99 rodtoll Bug #113726 - Integrate Voxware Codecs. Plugged memory leak
|
|
* caused as a result of new architecture.
|
|
* 01/14/2000 rodtoll Updated to use new Frame SetEqual function
|
|
* 01/31/2000 pnewson replace SAssert with DNASSERT
|
|
* 06/28/2000 rodtoll Prefix Bug #38022
|
|
*
|
|
***************************************************************************/
|
|
|
|
#include "dxvutilspch.h"
|
|
|
|
|
|
#undef DPF_SUBCOMP
|
|
#define DPF_SUBCOMP DN_SUBCOMP_VOICE
|
|
|
|
|
|
#define MODULE_ID INNERQUEUE
|
|
|
|
// the number of slots reseved to account for
|
|
// out of order startup frames. For example, if the first
|
|
// three frames of a message arrive in the order 3, 2, 1, instead
|
|
// of 1, 2, 3, we must reserve 2 slots in front of the "first"
|
|
// frame (3) so we'll have a place to put the tardy 1 and 2.
|
|
const BYTE c_bNumStartSlots = 2;
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CInnerQueue::CInnerQueue"
|
|
CInnerQueue::CInnerQueue(
|
|
BYTE bNumSlots,
|
|
WORD wFrameSize,
|
|
CFramePool* pfpFramePool,
|
|
DNCRITICAL_SECTION* pcsQueue,
|
|
BYTE bMsgNum,
|
|
BYTE bHighWaterMark,
|
|
WORD wQueueId
|
|
)
|
|
: m_bNumSlots(bNumSlots)
|
|
, m_eState(CInnerQueue::empty)
|
|
, m_bHighWaterMark(bHighWaterMark)
|
|
, m_bQueueSize(0)
|
|
, m_bHeadSeqNum(0)
|
|
, m_fFirstDequeue(true)
|
|
//, m_rgeSlotStates(NULL)
|
|
, m_rgpfrSlots(NULL)
|
|
, m_bFillingDequeueReqs(0)
|
|
, m_wMissingFrames(0)
|
|
, m_wDuplicateFrames(0)
|
|
, m_wOverflowFrames(0)
|
|
, m_wLateFrames(0)
|
|
, m_wPossibleZeroLengthDequeues(0)
|
|
, m_wKnownZeroLengthDequeues(0)
|
|
, m_dwMsgLen(0)
|
|
, m_wQueueId(wQueueId)
|
|
, m_bMsgNum(bMsgNum)
|
|
, m_pfpFramePool(pfpFramePool)
|
|
, m_pcsQueue(pcsQueue)
|
|
, m_fInited(FALSE)
|
|
{
|
|
#if defined(DPVOICE_QUEUE_DEBUG)
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "** QUEUE ** %i:%i ** CInnerQueue::CInnerQueue() CFramePool: %p", m_wQueueId, m_bMsgNum, m_pfpFramePool);
|
|
#endif
|
|
|
|
// verify that bNumSlots is at least 8, and is a
|
|
// power of 2.
|
|
DNASSERT(bNumSlots == 0x08 ||
|
|
bNumSlots == 0x10 ||
|
|
bNumSlots == 0x20 ||
|
|
bNumSlots == 0x40 ||
|
|
bNumSlots == 0x80);
|
|
|
|
// Check to make sure the watermark is not larger
|
|
// than the number of slots. It should really be
|
|
// significantly less than bNumSlots, but oh well.
|
|
//
|
|
DNASSERT(bHighWaterMark < bNumSlots - c_bNumStartSlots);
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CInnerQueue::Init"
|
|
HRESULT CInnerQueue::Init()
|
|
{
|
|
int i;
|
|
|
|
/*
|
|
// allocate the slot state array
|
|
m_rgeSlotStates = new ESlotState[m_bNumSlots];
|
|
if (m_rgeSlotStates == NULL)
|
|
{
|
|
goto error;
|
|
}
|
|
*/
|
|
|
|
// allocate the slot array
|
|
m_rgpfrSlots = new CFrame*[m_bNumSlots];
|
|
if (m_rgpfrSlots == NULL)
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
// Initialize the slot states and the slots
|
|
for (i = 0; i < m_bNumSlots; ++i)
|
|
{
|
|
//m_rgeSlotStates[i] = essEmpty;
|
|
m_rgpfrSlots[i] = NULL;
|
|
}
|
|
|
|
m_fInited = TRUE;
|
|
return S_OK;
|
|
|
|
error:
|
|
/*
|
|
if (m_rgeSlotStates != NULL)
|
|
{
|
|
delete [] m_rgeSlotStates;
|
|
m_rgeSlotStates = NULL;
|
|
}
|
|
*/
|
|
if (m_rgpfrSlots != NULL)
|
|
{
|
|
delete [] m_rgpfrSlots;
|
|
m_rgpfrSlots = NULL;
|
|
}
|
|
m_fInited = FALSE;
|
|
return E_FAIL;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CInnerQueue::~CInnerQueue"
|
|
CInnerQueue::~CInnerQueue()
|
|
{
|
|
if (m_fInited)
|
|
{
|
|
/*
|
|
if (m_rgeSlotStates != NULL)
|
|
{
|
|
delete [] m_rgeSlotStates;
|
|
m_rgeSlotStates = NULL;
|
|
}
|
|
*/
|
|
if (m_rgpfrSlots != NULL)
|
|
{
|
|
// check to ensure that no frames are in use
|
|
for (int i = 0; i < m_bNumSlots; ++i)
|
|
{
|
|
if( m_rgpfrSlots[i] != NULL )
|
|
m_rgpfrSlots[i]->Return();
|
|
}
|
|
|
|
delete [] m_rgpfrSlots;
|
|
m_rgpfrSlots = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CInnerQueue::Reset"
|
|
void CInnerQueue::Reset()
|
|
{
|
|
if (!m_fInited)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// loop through and make sure none of the frames are currently locked and clear the slot states
|
|
for (int i = 0; i < m_bNumSlots; ++i)
|
|
{
|
|
if (m_rgpfrSlots[i] != NULL)
|
|
{
|
|
m_rgpfrSlots[i]->Return();
|
|
}
|
|
//m_rgeSlotStates[i] = essEmpty;
|
|
}
|
|
|
|
m_eState = CInnerQueue::empty;
|
|
m_bQueueSize = 0;
|
|
m_bHeadSeqNum = 0;
|
|
m_fFirstDequeue = true;
|
|
m_bFillingDequeueReqs = 0;
|
|
|
|
ResetStats();
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CInnerQueue::ResetStats"
|
|
void CInnerQueue::ResetStats()
|
|
{
|
|
if (!m_fInited)
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_wMissingFrames = 0;
|
|
m_wDuplicateFrames = 0;
|
|
m_wOverflowFrames = 0;
|
|
m_wLateFrames = 0;
|
|
m_dwMsgLen = 0;
|
|
m_wPossibleZeroLengthDequeues = 0;
|
|
m_wKnownZeroLengthDequeues = 0;
|
|
}
|
|
|
|
// This function is not inline because it needs the module id, sigh.
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CInnerQueue::SetHighWaterMark"
|
|
void CInnerQueue::SetHighWaterMark(BYTE bHighWaterMark)
|
|
{
|
|
if (!m_fInited)
|
|
{
|
|
return;
|
|
}
|
|
|
|
DNASSERT(bHighWaterMark < m_bNumSlots);
|
|
m_bHighWaterMark = bHighWaterMark;
|
|
}
|
|
|
|
// Note: this class does not have it's own critical
|
|
// section. The caller must ensure that enqueue and
|
|
// dequeue are not called at the same time. It is
|
|
// intended that this class is used only within
|
|
// the InputQueue2 class, which does have a critical
|
|
// section.
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CInnerQueue::Enqueue"
|
|
void CInnerQueue::Enqueue(const CFrame& frFrame)
|
|
{
|
|
if (!m_fInited)
|
|
{
|
|
return;
|
|
}
|
|
|
|
#if defined(DPVOICE_QUEUE_DEBUG)
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "** QUEUE ** %i:%i ** CInnerQueue::Enqueue() MsgNum[%i] SeqNum[%i]", m_wQueueId, m_bMsgNum, frFrame.GetMsgNum(), frFrame.GetSeqNum());
|
|
#endif
|
|
|
|
DNASSERT(m_eState != finished);
|
|
|
|
if (m_eState == empty)
|
|
{
|
|
// This is the first frame, so set the head of the queue.
|
|
// NOTE: It may seem strange to set the head of the
|
|
// queue to 2 frames before the first one we receive,
|
|
// but this covers the case where the first frame
|
|
// we receive is not the first frame of the message.
|
|
// By using this logic, if any of the first, second
|
|
// or third frames arrive first, we will not chop
|
|
// off the start of the message. When the user
|
|
// asks for the first dequeue, it will skip the
|
|
// empty slots at the head of the queue, assuming
|
|
// they haven't been filled in.
|
|
m_bHeadSeqNum = (frFrame.GetSeqNum() - c_bNumStartSlots);
|
|
#if defined(DPVOICE_QUEUE_DEBUG)
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "** QUEUE ** %i:%i ** CInnerQueue::Enqueue() new message - m_bHeadSeqNum[%i]", m_wQueueId, m_bMsgNum, m_bHeadSeqNum);
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "** QUEUE ** %i:%i ** CInnerQueue::Enqueue() state changed to filling", m_wQueueId, m_bMsgNum);
|
|
#endif
|
|
m_eState = filling;
|
|
}
|
|
|
|
// Check to see if we should put this frame into the queue.
|
|
//
|
|
// NOTE: The logic below implicitly checks for queue overflows.
|
|
// if the sequence number is out of the allowable range, one
|
|
// of two things may have happened.
|
|
// 1) queue overflow
|
|
// 2) frame arrived too late
|
|
//
|
|
// First we need to know if we are dealing with a wraparound
|
|
// problem.
|
|
bool fKeepFrame = false;
|
|
if ((BYTE)(m_bHeadSeqNum + m_bNumSlots) < m_bHeadSeqNum)
|
|
{
|
|
// we've got a wraparound problem, so use this alternate logic
|
|
if (frFrame.GetSeqNum() >= m_bHeadSeqNum
|
|
|| frFrame.GetSeqNum() < (BYTE)(m_bHeadSeqNum + m_bNumSlots))
|
|
{
|
|
fKeepFrame = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// no wraparound problem, so use the straightforward logic
|
|
if (frFrame.GetSeqNum() >= m_bHeadSeqNum
|
|
&& frFrame.GetSeqNum() < m_bHeadSeqNum + m_bNumSlots)
|
|
{
|
|
fKeepFrame = true;
|
|
}
|
|
}
|
|
|
|
// if we're supposed to keep this frame, copy it into the
|
|
// appropriate slot
|
|
if (fKeepFrame)
|
|
{
|
|
BYTE bSlot = frFrame.GetSeqNum() % m_bNumSlots;
|
|
|
|
// check to see if this slot is full
|
|
//if (m_rgeSlotStates[bSlot] == essFull)
|
|
if (m_rgpfrSlots[bSlot] != NULL)
|
|
{
|
|
// This is a duplicate frame, so don't do anything
|
|
// with it, but tell the debugger about it, and
|
|
// update our stats.
|
|
//
|
|
// NOTE: We know that this a duplicate frame and
|
|
// not a queue overflow because we have already
|
|
// checked for queue overflow above.
|
|
#if defined(DPVOICE_QUEUE_DEBUG)
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "** QUEUE ** %i:%i ** CInnerQueue::Enqueue() Ignoring duplicate frame, sequence number[%i], slot[%i]",
|
|
m_wQueueId, m_bMsgNum, frFrame.GetSeqNum(), bSlot);
|
|
#endif
|
|
m_wDuplicateFrames++;
|
|
}
|
|
else
|
|
{
|
|
#if defined(DPVOICE_QUEUE_DEBUG)
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "** QUEUE ** %i:%i ** CInnerQueue::Enqueue() putting frame in slot[%i]", m_wQueueId, m_bMsgNum, bSlot);
|
|
#endif
|
|
|
|
// if the frame previously occupying this slot has not
|
|
// yet been released, this slot will not have a null pointer.
|
|
DNASSERT(m_rgpfrSlots[bSlot] == NULL);
|
|
|
|
// get a frame from the pool
|
|
//m_rgpfrSlots[bSlot] = m_pfpFramePool->Get(m_pcsQueue, &m_rgpfrSlots[bSlot]);
|
|
m_rgpfrSlots[bSlot] = m_pfpFramePool->Get(m_pcsQueue, NULL);
|
|
|
|
#if defined(DPVOICE_QUEUE_DEBUG)
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "** QUEUE ** %i:%i ** CInnerQueue::Enqueue() got frame from pool, Addr:%p", m_wQueueId, m_bMsgNum, m_rgpfrSlots[bSlot]);
|
|
#endif
|
|
|
|
/* RMT -- Added new func to copy frames directly.
|
|
|
|
// the client number is the same
|
|
m_rgpfrSlots[bSlot]->SetClientId(frFrame.GetClientId());
|
|
|
|
// copy the target
|
|
m_rgpfrSlots[bSlot]->SetTarget(frFrame.GetTarget());
|
|
|
|
// No one but this function should be using
|
|
// the sequence number, so just zero it out.
|
|
m_rgpfrSlots[bSlot]->SetSeqNum(0);
|
|
|
|
// copy the frame's data, also sets the frame length
|
|
m_rgpfrSlots[bSlot]->CopyData(frFrame);
|
|
|
|
// set the silence flag
|
|
m_rgpfrSlots[bSlot]->SetIsSilence(frFrame.GetIsSilence()); */
|
|
|
|
HRESULT hr;
|
|
|
|
hr = m_rgpfrSlots[bSlot]->SetEqual(frFrame);
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
DNASSERT( FALSE );
|
|
DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to copy frame in innerque" );
|
|
}
|
|
|
|
// this buffer is now full
|
|
//m_rgeSlotStates[bSlot] = essFull;
|
|
|
|
// increment the queue size
|
|
++m_bQueueSize;
|
|
#if defined(DPVOICE_QUEUE_DEBUG)
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "** QUEUE ** %i:%i ** CInnerQueue::Enqueue() new queue size[%i]", m_wQueueId, m_bMsgNum, m_bQueueSize);
|
|
#endif
|
|
|
|
// if the queue is currently filling, check to see if we've
|
|
// passed the high water mark.
|
|
if (m_eState == filling && m_bQueueSize > m_bHighWaterMark)
|
|
{
|
|
#if defined(DPVOICE_QUEUE_DEBUG)
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "** QUEUE ** %i:%i ** CInnerQueue::Enqueue() High Water Mark hit, now in ready state", m_wQueueId, m_bMsgNum);
|
|
#endif
|
|
m_bFillingDequeueReqs = 0;
|
|
m_eState = ready;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Make a guess as to what caused this: overflow or late frame
|
|
// Sequence numbers are allowed to be in the range 0 to 255.
|
|
// if a sequence number is somewhere in the range 127 prior
|
|
// to the current queue head (accounting for wraparound) then
|
|
// assume it's a late frame. Otherwise, assume it's an overflow frame.
|
|
if ((frFrame.GetSeqNum() < m_bHeadSeqNum
|
|
&& frFrame.GetSeqNum() > (int)m_bHeadSeqNum - 127)
|
|
|| (frFrame.GetSeqNum() > (128 + m_bHeadSeqNum)))
|
|
{
|
|
#if defined(DPVOICE_QUEUE_DEBUG)
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "** QUEUE ** %i:%i ** CInnerQueue::Enqueue() Late frame, discarded", m_wQueueId, m_bMsgNum);
|
|
#endif
|
|
m_wLateFrames++;
|
|
}
|
|
else
|
|
{
|
|
#if defined(DPVOICE_QUEUE_DEBUG)
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "** QUEUE ** %i:%i ** CInnerQueue::Enqueue() Overflow frame, discarded", m_wQueueId, m_bMsgNum);
|
|
#endif
|
|
m_wOverflowFrames++;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// Note: this class does not have it's own critical
|
|
// section. The caller must ensure that enqueue and
|
|
// dequeue are not called at the same time. It is
|
|
// intended that this class is used only within
|
|
// the InputQueue2 class, which does have a critical
|
|
// section.
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CInnerQueue::Dequeue"
|
|
CFrame* CInnerQueue::Dequeue()
|
|
{
|
|
CFrame* pfrReturn;
|
|
|
|
if (!m_fInited)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// make sure that we're in the ready state
|
|
DNASSERT(m_eState == ready);
|
|
|
|
// The only class that should be using this one should
|
|
// never call dequeue when there's nothing to get, so assert
|
|
DNASSERT(m_bQueueSize != 0);
|
|
|
|
// If we get here, there is at least one frame in the queue, somewhere.
|
|
|
|
// increment the length of the message
|
|
++m_dwMsgLen;
|
|
|
|
// find the index of the oldest frame, starting with the frame at the
|
|
// head of the queue.
|
|
BYTE bSlot = m_bHeadSeqNum % m_bNumSlots;
|
|
int i = 0;
|
|
|
|
#if defined(DPVOICE_QUEUE_DEBUG)
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "** QUEUE ** %i:%i ** CInnerQueue::Dequeue() Checking slot[%i]", m_wQueueId, m_bMsgNum, bSlot);
|
|
#endif
|
|
//while (m_rgeSlotStates[bSlot] != essFull)
|
|
while (m_rgpfrSlots[bSlot] == NULL)
|
|
{
|
|
// if this is the first dequeue, then we want to skip any empty
|
|
// slots to find the first frame in the message. Otherwise, this
|
|
// is a lost frame, and should be treated accordingly.
|
|
if (m_fFirstDequeue == true)
|
|
{
|
|
// The current slot does not have a frame, try the
|
|
// next. Put in a little sanity check for infinite
|
|
// looping.
|
|
DNASSERT(i++ < m_bNumSlots);
|
|
++bSlot;
|
|
bSlot %= m_bNumSlots;
|
|
#if defined(DPVOICE_QUEUE_DEBUG)
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "** QUEUE ** %i:%i ** CInnerQueue::Dequeue() slot empty, checking slot[%i]", m_wQueueId, m_bMsgNum, bSlot);
|
|
#endif
|
|
|
|
// increment the head sequence number
|
|
++m_bHeadSeqNum;
|
|
}
|
|
else
|
|
{
|
|
// This is a lost frame
|
|
#if defined(DPVOICE_QUEUE_DEBUG)
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "** QUEUE ** %i:%i ** CInnerQueue::Dequeue() Frame Missing", m_wQueueId, m_bMsgNum);
|
|
#endif
|
|
++m_wMissingFrames;
|
|
|
|
// this missing frame is part of the message too, so
|
|
// increment the total message size
|
|
++m_dwMsgLen;
|
|
|
|
// increment the head sequence number
|
|
++m_bHeadSeqNum;
|
|
|
|
// this is no longer the first dequeue
|
|
m_fFirstDequeue = false;
|
|
|
|
// return a silent frame marked as lost
|
|
CFrame* pfr = m_pfpFramePool->Get(m_pcsQueue, NULL);
|
|
pfr->SetIsSilence(true);
|
|
pfr->SetIsLost(true);
|
|
|
|
return pfr;
|
|
}
|
|
}
|
|
|
|
m_fFirstDequeue = false;
|
|
|
|
// By now, bSlot points to a valid, useful frame, which
|
|
// we should return.
|
|
|
|
// mark the slot we are about to return as empty
|
|
//m_rgeSlotStates[bSlot] = essEmpty;
|
|
|
|
// decrement the queue size
|
|
--m_bQueueSize;
|
|
#if defined(DPVOICE_QUEUE_DEBUG)
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "** QUEUE ** %i:%i ** CInnerQueue::Dequeue() Returning frame in slot[%i]; New queue size[%i]", m_wQueueId, m_bMsgNum, bSlot, m_bQueueSize);
|
|
#endif
|
|
|
|
// increment the head sequence number
|
|
++m_bHeadSeqNum;
|
|
|
|
// this is not a lost frame
|
|
//m_rgpfrSlots[bSlot]->SetIsLost(false);
|
|
pfrReturn = m_rgpfrSlots[bSlot];
|
|
pfrReturn->SetIsLost(false);
|
|
m_rgpfrSlots[bSlot] = NULL;
|
|
|
|
//return(m_rgpfrSlots[bSlot]);
|
|
return(pfrReturn);
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CInnerQueuePool::CInnerQueuePool"
|
|
CInnerQueuePool::CInnerQueuePool(
|
|
BYTE bNumSlots,
|
|
WORD wFrameSize,
|
|
CFramePool* pfpFramePool,
|
|
DNCRITICAL_SECTION* pcsQueue)
|
|
: m_bNumSlots(bNumSlots)
|
|
, m_wFrameSize(wFrameSize)
|
|
, m_pfpFramePool(pfpFramePool)
|
|
, m_pcsQueue(pcsQueue)
|
|
, m_fCritSecInited(FALSE)
|
|
{
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CInnerQueuePool::~CInnerQueuePool"
|
|
CInnerQueuePool::~CInnerQueuePool()
|
|
{
|
|
for (std::vector<CInnerQueue *>::iterator iter1 = m_vpiqPool.begin(); iter1 < m_vpiqPool.end(); ++iter1)
|
|
{
|
|
delete *iter1;
|
|
}
|
|
if (m_fCritSecInited)
|
|
{
|
|
DNDeleteCriticalSection(&m_lock);
|
|
}
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CInnerQueuePool::Get"
|
|
CInnerQueue* CInnerQueuePool::Get(
|
|
BYTE bHighWaterMark,
|
|
WORD wQueueId,
|
|
BYTE bMsgNum
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
BFCSingleLock csl(&m_lock);
|
|
csl.Lock();
|
|
|
|
CInnerQueue* piq;
|
|
if (m_vpiqPool.empty())
|
|
{
|
|
// the pool is empty, return a new inner queue
|
|
piq = new CInnerQueue(
|
|
m_bNumSlots,
|
|
m_wFrameSize,
|
|
m_pfpFramePool,
|
|
m_pcsQueue,
|
|
bMsgNum,
|
|
bHighWaterMark,
|
|
wQueueId);
|
|
|
|
if( piq == NULL )
|
|
return NULL;
|
|
|
|
hr = piq->Init();
|
|
if (FAILED(hr))
|
|
{
|
|
delete piq;
|
|
return NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// there are some inner queues in the pool, pop
|
|
// the last one off the back of the vector
|
|
piq = m_vpiqPool.back();
|
|
m_vpiqPool.pop_back();
|
|
piq->SetMsgNum(bMsgNum);
|
|
piq->SetQueueId(wQueueId);
|
|
piq->SetHighWaterMark(bHighWaterMark);
|
|
piq->Reset();
|
|
}
|
|
|
|
return piq;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CInnerQueuePool::Return"
|
|
void CInnerQueuePool::Return(CInnerQueue* piq)
|
|
{
|
|
BFCSingleLock csl(&m_lock);
|
|
csl.Lock();
|
|
|
|
// drop this inner queue on the back for reuse
|
|
m_vpiqPool.push_back(piq);
|
|
}
|