/*!***************************************************************************

  module      : RTESync_SpinlockRegister.hpp

  -------------------------------------------------------------------------

  responsible : JoergM

  special area: RTE
  description : Spinlock registration 
  
                This class implements a singleton, that allows to register named spinlocks.
                This allows to collect the spinlock statistic information for all registered
                spinlocks.

  last changed: 2001-01-10  11:04
  see also    : <class>RTE_ItemRegister</class>
  first created:2000-03-09  18:21

  -------------------------------------------------------------------------



    ========== licence begin  GPL
    Copyright (c) 2001-2005 SAP AG

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    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, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end




*****************************************************************************/

/*===========================================================================*
 *  INCLUDES                                                                 *
 *===========================================================================*/

#include "RunTime/Synchronisation/RTESync_SpinlockRegister.hpp"
#include "RunTime/MemoryManagement/RTEMem_RteAllocator.hpp"
#include "SAPDBCommon/MemoryManagement/SAPDBMem_NewDestroy.hpp"

/*===========================================================================*
 *  CLASSES, STRUCTURES, TYPES, UNIONS ...                                   *
 *===========================================================================*/

RTESync_SpinlockRegister * RTESync_SpinlockRegister::m_Instance = 0;
const SAPDB_Int4 RTESync_SpinlockRegister::m_MaxIdentfierLength = 40;

RTESync_SpinlockRegister & RTESync_SpinlockRegister::Instance()
{
    SAPDBMEM_STATIC_RAW_ALLOCATE(Space, sizeof(RTESync_SpinlockRegister));

    if ( !m_Instance )
    {
#if defined (SAPDB_SLOW)
        m_Instance = new ( Space ) RTESync_SpinlockRegister(true);
#else
        m_Instance = new ( Space ) RTESync_SpinlockRegister(false);
#endif
    }

    return *m_Instance;
}

/*!
   Function: GetStatisticInfo
   Description: Get a snapshot of all statistic informations
   Arguments: pInfoArray[out] Pointer to array of StatisticInfo

   Return value: True if info array fill, false if not not enough memory or nothing registered
 */
SAPDB_Bool RTESync_SpinlockRegister::GetStatisticInfo(StatisticInfo * &pInfoArray, SAPDB_Int4 &itemCount)
{
    SAPDB_Int4 currentCount;
    StatisticInfo *pSnapshotInfoArray = 0;

    while ( 0 == pSnapshotInfoArray )
    {
        currentCount = m_Count; // dirty read... this leads to the necessity of 'while()' loop. See below
        if ( 0 == currentCount )
        {
            return false;
        }

        pSnapshotInfoArray = reinterpret_cast<StatisticInfo *>(RTEMem_RteAllocator::Instance().Allocate(currentCount * sizeof(StatisticInfo)));
        if ( 0 == pSnapshotInfoArray )
        {
            return false;
        }

        memset( pSnapshotInfoArray, 0, currentCount * sizeof(StatisticInfo));

        /* This is using a locked scope... */
        if ( !FillStatisticInfo(pSnapshotInfoArray, currentCount, itemCount) )
        {
            /* FillInfoArray() only reason to fail, is that the most unlikely case happened and */
            /* in the meantime more allocators were registered. This is handled with forcing a loop here... */
            RTEMem_RteAllocator::Instance().Deallocate(pSnapshotInfoArray);
            pSnapshotInfoArray = 0;
        }
    }

    pInfoArray = pSnapshotInfoArray;

    return true;
}

/*!
   Function: FreeStatisticInfo
   Description: Free the snapshot of all statistic informations collected by GetStatisticInfo

   Arguments: pInfoArray[in] Pointer to array of StatisticInfo
 */
void RTESync_SpinlockRegister::FreeStatisticInfo(StatisticInfo *pInfoArray)
{
    RTEMem_RteAllocator::Instance().Deallocate(pInfoArray);
}

SAPDB_Bool RTESync_SpinlockRegister::FillStatisticInfo(StatisticInfo * &pInfoArray, SAPDB_Int4 maxCount, SAPDB_Int4 &itemCount)
{
    RTESync_LockedScope lock(Spinlock());

    if ( this->m_Count > maxCount )
    {
        return false;
    }

    StatisticInfo *pFill = pInfoArray;

    for ( RTESync_SpinlockInfo * pInfo = this->m_First; 0 != pInfo; pInfo = pInfo->GetSuccessor() )
    {
        memcpy(&(pFill->StatisticRecord), pInfo->GetItem().GetStatisticRecord(), sizeof(RTE_SpinlockStatistic));
        strncpy((char *)pFill->SpinlockName, (char *)pInfo->GetIdentifier(), RTESync_SpinlockRegister::m_MaxIdentfierLength);

        ++pFill;
    }

    itemCount = this->m_Count;

    return true;
}
