Files
mars-flaim/ftk/src/ftkiobuf.cpp

533 lines
12 KiB
C++

//------------------------------------------------------------------------------
// Desc: This file contains the F_IOBuffer and F_IOBufferMgr classes.
//
// Tabs: 3
//
// Copyright (c) 2001-2006 Novell, Inc. All Rights Reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of version 2 of the GNU General Public
// License as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, contact Novell, Inc.
//
// To contact Novell about this file by physical or electronic mail,
// you may find current contact information at www.novell.com
//
// $Id: fbuff.cpp 3111 2006-01-19 13:10:50 -0700 (Thu, 19 Jan 2006) dsanders $
//------------------------------------------------------------------------------
#include "ftksys.h"
/****************************************************************************
Desc:
****************************************************************************/
class F_IOBufferMgr : public IF_IOBufferMgr
{
public:
F_IOBufferMgr();
virtual ~F_IOBufferMgr();
RCODE setupBufferMgr(
FLMUINT uiMaxBuffers,
FLMUINT uiMaxBytes,
FLMBOOL bReuseBuffers);
RCODE FLMAPI getBuffer(
FLMUINT uiBufferSize,
IF_IOBuffer ** ppIOBuffer);
RCODE FLMAPI waitForAllPendingIO( void);
FINLINE FLMBOOL FLMAPI isIOPending( void)
{
return( m_pFirstPending ? TRUE : FALSE);
}
void linkToList(
F_IOBuffer ** ppListHead,
F_IOBuffer * pIOBuffer);
void unlinkFromList(
F_IOBuffer * pIOBuffer);
private:
FLMUINT m_uiMaxBuffers;
FLMUINT m_uiMaxBufferBytes;
FLMUINT m_uiTotalBuffers;
FLMUINT m_uiTotalBufferBytes;
F_IOBuffer * m_pFirstPending;
F_IOBuffer * m_pFirstAvail;
F_IOBuffer * m_pFirstUsed;
FLMBOOL m_bReuseBuffers;
RCODE m_completionRc;
friend class F_IOBuffer;
};
/****************************************************************************
Desc:
****************************************************************************/
RCODE FLMAPI FlmAllocIOBufferMgr(
FLMUINT uiMaxBuffers,
FLMUINT uiMaxBytes,
FLMBOOL bReuseBuffers,
IF_IOBufferMgr ** ppIOBufferMgr)
{
RCODE rc = NE_FLM_OK;
F_IOBufferMgr * pBufferMgr = NULL;
if( (pBufferMgr = f_new F_IOBufferMgr) == NULL)
{
rc = RC_SET( NE_FLM_MEM);
goto Exit;
}
if( RC_BAD( pBufferMgr->setupBufferMgr( uiMaxBuffers,
uiMaxBytes, bReuseBuffers)))
{
goto Exit;
}
*ppIOBufferMgr = pBufferMgr;
pBufferMgr = NULL;
Exit:
if( pBufferMgr)
{
pBufferMgr->Release();
}
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
F_IOBufferMgr::F_IOBufferMgr()
{
m_uiMaxBuffers = 0;
m_uiMaxBufferBytes = 0;
m_uiTotalBuffers = 0;
m_uiTotalBufferBytes = 0;
m_pFirstPending = NULL;
m_pFirstAvail = NULL;
m_pFirstUsed = NULL;
m_bReuseBuffers = FALSE;
m_completionRc = NE_FLM_OK;
}
/****************************************************************************
Desc:
****************************************************************************/
F_IOBufferMgr::~F_IOBufferMgr()
{
f_assert( !m_pFirstPending);
f_assert( !m_pFirstUsed);
while( m_pFirstAvail)
{
m_pFirstAvail->Release();
}
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE F_IOBufferMgr::setupBufferMgr(
FLMUINT uiMaxBuffers,
FLMUINT uiMaxBytes,
FLMBOOL bReuseBuffers)
{
f_assert( uiMaxBuffers);
f_assert( uiMaxBytes);
m_uiMaxBuffers = uiMaxBuffers;
m_uiMaxBufferBytes = uiMaxBytes;
m_bReuseBuffers = bReuseBuffers;
return( NE_FLM_OK);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE FLMAPI F_IOBufferMgr::getBuffer(
FLMUINT uiBufferSize,
IF_IOBuffer ** ppIOBuffer)
{
RCODE rc = NE_FLM_OK;
F_IOBuffer * pIOBuffer = NULL;
f_assert( *ppIOBuffer == NULL);
if( RC_BAD( m_completionRc))
{
rc = m_completionRc;
goto Exit;
}
Retry:
if( m_pFirstAvail)
{
pIOBuffer = m_pFirstAvail;
unlinkFromList( pIOBuffer);
pIOBuffer->resetBuffer();
f_assert( pIOBuffer->getBufferSize() == uiBufferSize);
}
else if( !m_uiTotalBuffers ||
(m_uiTotalBufferBytes + uiBufferSize <= m_uiMaxBufferBytes &&
m_uiTotalBuffers < m_uiMaxBuffers))
{
if( m_uiTotalBufferBytes + uiBufferSize > m_uiMaxBufferBytes)
{
rc = RC_SET_AND_ASSERT( NE_FLM_MEM);
goto Exit;
}
if( (pIOBuffer = f_new F_IOBuffer) == NULL)
{
rc = RC_SET( NE_FLM_MEM);
goto Exit;
}
if (RC_BAD( rc = pIOBuffer->setupBuffer( uiBufferSize, this)))
{
goto Exit;
}
m_uiTotalBufferBytes += uiBufferSize;
m_uiTotalBuffers++;
}
else if( m_pFirstPending)
{
if( RC_BAD( rc = m_pFirstPending->waitToComplete()))
{
goto Exit;
}
goto Retry;
}
else
{
rc = RC_SET_AND_ASSERT( NE_FLM_MEM);
goto Exit;
}
pIOBuffer->AddRef();
linkToList( &m_pFirstUsed, pIOBuffer);
*ppIOBuffer = pIOBuffer;
pIOBuffer = NULL;
Exit:
if( pIOBuffer)
{
pIOBuffer->Release();
}
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE FLMAPI F_IOBufferMgr::waitForAllPendingIO( void)
{
RCODE rc;
RCODE tmpRc;
F_IOBuffer * pBuf;
while( (pBuf = m_pFirstPending) != NULL)
{
if( RC_BAD( tmpRc = pBuf->waitToComplete()))
{
if( RC_OK( m_completionRc))
{
m_completionRc = tmpRc;
}
}
}
rc = m_completionRc;
m_completionRc = NE_FLM_OK;
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
void F_IOBufferMgr::linkToList(
F_IOBuffer ** ppListHead,
F_IOBuffer * pIOBuffer)
{
f_assert( pIOBuffer->m_eList == MGR_LIST_NONE);
pIOBuffer->m_pPrev = NULL;
if( (pIOBuffer->m_pNext = *ppListHead) != NULL)
{
(*ppListHead)->m_pPrev = pIOBuffer;
}
*ppListHead = pIOBuffer;
if( ppListHead == &m_pFirstPending || ppListHead == &m_pFirstUsed)
{
pIOBuffer->m_eList = (ppListHead == &m_pFirstPending
? MGR_LIST_PENDING
: MGR_LIST_USED);
}
else
{
pIOBuffer->m_eList = MGR_LIST_AVAIL;
}
}
/****************************************************************************
Desc:
****************************************************************************/
void F_IOBufferMgr::unlinkFromList(
F_IOBuffer * pIOBuffer)
{
if( pIOBuffer->m_pNext)
{
pIOBuffer->m_pNext->m_pPrev = pIOBuffer->m_pPrev;
}
if( pIOBuffer->m_pPrev)
{
pIOBuffer->m_pPrev->m_pNext = pIOBuffer->m_pNext;
}
else if( pIOBuffer->m_eList == MGR_LIST_AVAIL)
{
m_pFirstAvail = pIOBuffer->m_pNext;
}
else if( pIOBuffer->m_eList == MGR_LIST_PENDING)
{
m_pFirstPending = pIOBuffer->m_pNext;
}
else if( pIOBuffer->m_eList == MGR_LIST_USED)
{
m_pFirstUsed = pIOBuffer->m_pNext;
}
pIOBuffer->m_eList = MGR_LIST_NONE;
}
/****************************************************************************
Desc:
****************************************************************************/
FLMINT FLMAPI F_IOBuffer::Release( void)
{
FLMINT iRefCnt;
if( m_refCnt <= 2)
{
if( m_pBufferMgr && m_eList != MGR_LIST_NONE)
{
m_pBufferMgr->unlinkFromList( this);
}
}
if( m_refCnt == 2)
{
if( m_pBufferMgr)
{
if( m_pBufferMgr->m_bReuseBuffers)
{
m_pBufferMgr->linkToList( &m_pBufferMgr->m_pFirstAvail, this);
}
else
{
f_assert( m_pBufferMgr->m_uiTotalBuffers);
f_assert( m_pBufferMgr->m_uiTotalBufferBytes >= m_uiBufferSize);
m_refCnt--;
m_pBufferMgr->m_uiTotalBuffers--;
m_pBufferMgr->m_uiTotalBufferBytes -= m_uiBufferSize;
m_pBufferMgr = NULL;
}
}
}
iRefCnt = --m_refCnt;
if( !iRefCnt)
{
delete this;
}
return( iRefCnt);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE F_IOBuffer::setupBuffer(
FLMUINT uiBufferSize,
F_IOBufferMgr * pBufferMgr)
{
RCODE rc = NE_FLM_OK;
if( RC_BAD( rc = f_allocAlignedBuffer( uiBufferSize,
(void **)&m_pucBuffer)))
{
goto Exit;
}
m_uiBufferSize = uiBufferSize;
m_pBufferMgr = pBufferMgr;
Exit:
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
void FLMAPI F_IOBuffer::setPending( void)
{
f_assert( !m_bPending);
m_bPending = TRUE;
m_uiStartTime = FLM_GET_TIMER();
if( m_pBufferMgr)
{
f_assert( m_eList == MGR_LIST_USED);
m_pBufferMgr->unlinkFromList( this);
m_pBufferMgr->linkToList( &m_pBufferMgr->m_pFirstPending, this);
}
}
/****************************************************************************
Desc:
****************************************************************************/
void FLMAPI F_IOBuffer::clearPending( void)
{
f_assert( m_bPending);
m_bPending = FALSE;
m_uiStartTime = 0;
if( m_pBufferMgr)
{
f_assert( m_eList == MGR_LIST_PENDING);
m_pBufferMgr->unlinkFromList( this);
m_pBufferMgr->linkToList( &m_pBufferMgr->m_pFirstUsed, this);
}
}
/****************************************************************************
Desc:
****************************************************************************/
void F_IOBuffer::notifyComplete(
RCODE completionRc)
{
f_assert( m_bPending);
m_bPending = FALSE;
m_bCompleted = TRUE;
m_completionRc = completionRc;
m_uiEndTime = FLM_GET_TIMER();
m_uiElapsedTime = FLM_TIMER_UNITS_TO_MILLI(
FLM_ELAPSED_TIME( m_uiEndTime, m_uiStartTime));
if( m_fnCompletion)
{
m_fnCompletion( this, m_pvData);
m_fnCompletion = NULL;
m_pvData = NULL;
}
if( m_pBufferMgr)
{
f_assert( m_eList == MGR_LIST_PENDING);
m_pBufferMgr->unlinkFromList( this);
m_pBufferMgr->linkToList( &m_pBufferMgr->m_pFirstUsed, this);
if( RC_OK( m_pBufferMgr->m_completionRc) && RC_BAD( completionRc))
{
m_pBufferMgr->m_completionRc = completionRc;
}
}
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE FLMAPI F_IOBuffer::addCallbackData(
void * pvData)
{
RCODE rc = NE_FLM_OK;
if( m_uiCallbackDataCount >= m_uiMaxCallbackData)
{
if( m_ppCallbackData == m_callbackData)
{
void ** pNewTable;
if( RC_BAD( rc = f_alloc(
(m_uiCallbackDataCount + 1) * sizeof( void *), &pNewTable)))
{
goto Exit;
}
f_memcpy( pNewTable, m_ppCallbackData,
m_uiMaxCallbackData * sizeof( void *));
m_ppCallbackData = pNewTable;
}
else
{
if( RC_BAD( rc = f_realloc(
(m_uiCallbackDataCount + 1) * sizeof( void *), &m_ppCallbackData)))
{
goto Exit;
}
}
m_uiMaxCallbackData = m_uiCallbackDataCount + 1;
}
m_ppCallbackData[ m_uiCallbackDataCount] = pvData;
m_uiCallbackDataCount++;
Exit:
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
void * FLMAPI F_IOBuffer::getCallbackData(
FLMUINT uiSlot)
{
if( uiSlot < m_uiCallbackDataCount)
{
return( m_ppCallbackData[ uiSlot]);
}
return( NULL);
}