/*!
  @file           RTESync_RWRegion.cpp
  @author         RobinW
  @ingroup        Runtime
  @brief          critical regions that support exclusive ("write") and 
                  non-exclusive ("read") access - implementation of the 
                  RTESync_IRWRegion interface


\if EMIT_LICENCE

    ========== 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



\endif
*/

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

#include "RunTime/Synchronisation/RTESync_RWRegion.hpp"
#include "SAPDB/SAPDBCommon/MemoryManagement/SAPDBMem_NewDestroy.hpp"
#include "RunTime/RTE_CallDebugger.h"
#include "RunTime/System/RTESys_Spinlock.h"
#include "SAPDB/SAPDBCommon/SAPDB_sprintf.h"
#include "RunTime/RTE_Message.hpp"
#include "RunTime/RTE_MessageList.hpp"
#include "RunTime/Tasking/RTETask_Context.hpp"
#include "RunTime/Tasking/RTETask_IScheduling.hpp"
#include "SAPDBCommon/Tracing/SAPDBTrace_Usage.hpp"
#include "SAPDBCommon/Tracing/SAPDBTrace_Topic.hpp"
#include "RunTime/MemoryManagement/RTEMem_RteAllocator.hpp"
#include "RunTime/Synchronisation/RTESync_SpinlockPoolRegister.hpp"

#define USE_KGS
#include "geo50_0.h"    // for things like KGS, TASK_CTRL...
#include "geo002.h"     // for XPARAM()
#include "heo00.h"      // for TSK_*

extern SAPDBTrace_Topic RWRegion_Trace;

/*===========================================================================*
 *  DEFINES                                                                  *
 *===========================================================================*/

#define DEBUG_BREAK

#ifdef DEBUG_BREAK
#define DoDebugBreak RTE_DebugBreak
#else
#define DoDebugBreak()
#endif  // DEBUG_BREAK

#define USE_SEMALIST    RTESync_IRWRegion::WithSemalist

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

class RTESync_RWRegion;

class RTESync_RWRegionRegister : public RTE_ItemRegister<RTESync_RWRegion>
{
public:
    struct StatisticInfo
    {
        SAPDB_UTF8  PoolName[40+1];
        SAPDB_ULong Address;
        SAPDB_UInt4 CollisionCount;
        SAPDB_UInt4 WaitCount;
        SAPDB_ULong TasCount;
        SAPDB_UInt4 ExclusiveAccessCount;
        SAPDB_UInt4 NonExclusiveAccessCount;
        RTE_TaskId  TaskId;
        SAPDB_Int4  CurrentAccesses;
    };

    /*!
        Function: Instance

        description: Return reference to single instance of RTESync_SpinlockRegister

        The InitializeInstance function must have been called before.

        Return value: Reference to singleton instance
     */
    static RTESync_RWRegionRegister & Instance( )
    {
        SAPDBMEM_STATIC_RAW_ALLOCATE(Space, sizeof(RTESync_RWRegionRegister));

        if ( !m_Instance )
        {
#if defined (SAPDB_SLOW)
            m_Instance = new ( Space ) RTESync_RWRegionRegister(true);
#else
            m_Instance = new ( Space ) RTESync_RWRegionRegister(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
     */
    SAPDB_Bool GetStatisticInfo(StatisticInfo * &pInfoArray, SAPDB_Int4 &itemCount,RTESync_IRWRegionReader::Mode mode,RTESync_IRWRegionReader::Selection  selection)
    {
        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,mode,selection) )
            {
                /* 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 FreeStatisticInfo(StatisticInfo *pInfoArray)
    {
        RTEMem_RteAllocator::Instance().Deallocate(pInfoArray);
    };

    SAPDB_UInt4 GetCount(void)
    {
        return m_Count;
    }
private:
    RTESync_RWRegionRegister(SAPDB_Bool makeBackupCopy):RTE_ItemRegister<RTESync_RWRegion>(makeBackupCopy) {}

    /*!
       Function: FillStatisticInfo
       Description: Fill the statistic informations
       
       Called by GetStatisticInfo, to call at least memory allocation outside of locked registration code

       Arguments: pInfoArray[in] Pointer to array of StatisticInfo
     */
    SAPDB_Bool FillStatisticInfo(StatisticInfo * &pInfoArray, SAPDB_Int4 maxCount, SAPDB_Int4 &itemCount,RTESync_IRWRegionReader::Mode mode,RTESync_IRWRegionReader::Selection  selection);

    static RTESync_RWRegionRegister *m_Instance;
};

RTESync_RWRegionRegister *RTESync_RWRegionRegister::m_Instance=NULL;

/*!
   @class RTESync_RWRegion
   @brief class containing methods common to all flavours of RWRegions
    RWRegions can be accessed from outside ONLY by using the interface RTESync_IRWRegion.
    The "flavours" of RWRegions (currently NoSemalist and WithSemalist) are implemented
    in different classes. The methods that are common to all flavours are implemented
    in the class RTESync_RWRegion.
*/
class RTESync_RWRegion : public RTESync_IRWRegion
{
public:
    /*!
      @brief

      @param <name> [in]
      @return [<type>]
     */
    RTESync_RWRegion(SAPDB_Int8 id,RTESync_BaseSpinlockPool &pool,SAPDB_Bool enterCollisionCounterInTcb=false);

    ~RTESync_RWRegion();
    /*!
      @brief

      @param <name> [in]
      @return [<type>]
     */
    void enter(SAPDB_Bool exclusive,RTE_TaskId pid=RTE_UnknownTaskId);

    /*!
      @brief

      @param <name> [in]
      @return [<type>]
     */
    bool tryEnter(bool exclusive,RTE_TaskId pid=RTE_UnknownTaskId);

    /*!
      @brief

      @param <name> [in]
      @return [<type>]
     */
    void leave(bool exclusive,RTE_TaskId pid=RTE_UnknownTaskId);

    /*!
      @brief

      @param <name> [in]
      @return [<type>]
     */

    void SwitchToNonExclusiveAccess(RTE_TaskId pid=RTE_UnknownTaskId);

    /*!
      @brief

      @param <name> [in]
      @return [<type>]
     */

    SAPDB_Int8 getId(void)
    {
        return m_id;
    };

    /*!
      @brief

      @param <name> [in]
      @return [<type>]
     */

    RTE_TaskId getLastEntered(void)
    {
        return m_lastEntered;
    };

    virtual SAPDB_UInt4 GetCollisionCounter(void)
    {
        return m_collisionCounter;
    }

    virtual SAPDB_UInt4 GetExclusiveAccessCounter(void)
    {
        return m_exclusiveAccessCounter;
    }

    virtual SAPDB_UInt4 GetNonExclusiveAccessCounter(void)
    {
        return m_nonExclusiveAccessCounter;
    }

    virtual SAPDB_UInt4 GetWaitCounter(void)
    {
        return m_waitCounter;
    }

    virtual SAPDB_UInt4 GetTasCounter(void)
    {
        return m_tasCounter;
    }

    virtual RTESync_SpinlockPool *GetSpinlockPool(void)
	{
		return (RTESync_SpinlockPool *)&m_pool;
	}

protected:
    SAPDB_Int8      m_id;
    RTE_TaskId      m_lastEntered;
    volatile int    m_nonExclusive;
    SAPDB_UInt      m_exclusiveRequests;
    SAPDB_ULong     m_tasCounter;
    SAPDB_UInt4     m_waitCounter;
/*
    SAPDB_ULong     m_attemptsToGetLockOnEnter;
    SAPDB_ULong     m_attemptsToGetLockOnLeave;
*/
    void get_lock(RTE_TCB &tcb,RTE_UKT &ukt, SAPDB_Bool busyWaiting,SAPDB_ULong &totalTasCnt);

    void free_lock();

private:
    RTESync_BaseSpinlockPool  & m_pool;
    SAPDB_Int4                  m_poolLockIndex;
    SAPDB_Bool                  m_enterCollisionCounterInTcb;   // only for vbegexcl()/vendexcl() emulation
    RTE_ItemRegister<RTESync_RWRegion>::Info    m_info;

    virtual void enterRegionExclusive(RTE_TCB tcb,RTE_UKT ukt,SAPDB_Long maxCollisions,SAPDB_Long &collisionCounter)=0;

    virtual void enterRegionNonExclusive(RTE_TCB tcb,RTE_UKT ukt,SAPDB_Long maxCollisions,SAPDB_Long &collisionCounter)=0;

    virtual void leaveRegionExclusive(RTE_TCB tcb,RTE_UKT ukt)=0;

    virtual void leaveRegionNonExclusive(RTE_TCB tcb,RTE_UKT ukt)=0;

    virtual void SwitchNonExclusive(RTE_TCB tcb,RTE_UKT ukt)=0;

    SAPDB_Bool tryEnterRegionExclusiveNonBlocking(RTE_TCB tcb,RTE_UKT ukt);

    SAPDB_Bool tryEnterRegionNonExclusiveNonBlocking(RTE_TCB tcb,RTE_UKT ukt);

    void check_indefinite_loop(SAPDB_ULong &tasCount,RTE_TCB tcb);

    SAPDB_UInt4 m_exclusiveAccessCounter;
    SAPDB_UInt4 m_nonExclusiveAccessCounter;
    SAPDB_UInt4 m_collisionCounter;
friend class RTESync_RWRegionRegister;
};

/*!
   @class RTESync_WaitQueueForRWRegionEntry
   @brief structure describing an entry of the wait queue
 */
struct RTESync_WaitQueueForRWRegionEntry
{
    SAPDB_Bool exclusive;
    TASK_CTRL pTaskCtrl;
};

/*!
   @class RTESync_WaitQueueForRWRegion
   @brief class implementing the wait queue in which tasks waiting for access to a RWRegion are stored
 */
class RTESync_WaitQueueForRWRegion
{
public:
    /*!
      @brief

      @param <name> [in]
      @return [<type>]
     */
    SAPDB_Bool empty(void);
    
    /*!
      @brief

      @param <name> [in]
      @return [<type>]
     */
    void insert(SAPDB_Bool exclusive,RTE_TCB tcb);

    /*!
      @brief

      @param <name> [in]
      @return [<type>]
     */
    RTE_TCB getFirst(void);

    /*!
      @brief

      @param <name> [in]
      @return [<type>]
     */
    void removeFirst(void);

    /*!
      @brief

      @param <name> [in]
      @return [<type>]
     */
    RTESync_WaitQueueForRWRegion();

private:
    RTE_TCB m_firstEntry;
    RTE_TCB m_lastEntry;
};

/*!
   @class RTESync_RWRegionWithSemalist
   @brief the implementation class for the "WithSemalist" flavour of RWRegions
 */
class RTESync_RWRegionWithSemalist : public RTESync_RWRegion
{
public:
    /*!
      @brief

      @param <name> [in]
      @return [<type>]
     */
    RTESync_RWRegionWithSemalist(SAPDB_Int8 id,RTESync_BaseSpinlockPool &pool);

private:

    void enterRegionExclusive(RTE_TCB tcb,RTE_UKT ukt,SAPDB_Long maxCollisions,SAPDB_Long &collisionCounter);

    void enterRegionNonExclusive(RTE_TCB tcb,RTE_UKT ukt,SAPDB_Long maxCollisions,SAPDB_Long &collisionCounter);

    void leaveRegionExclusive(RTE_TCB tcb,RTE_UKT ukt);

    void activateTaskInMyUKT(RTE_TCB tcb,RTE_UKT ukt,RTE_TCB nextTcb);

    void activateTaskInOtherUKT(RTE_TCB tcb,RTE_UKT ukt,RTE_TCB nextTcb);

    void leaveRegionNonExclusive(RTE_TCB tcb,RTE_UKT ukt);

    void SwitchNonExclusive(RTE_TCB tcb,RTE_UKT ukt);

    RTESync_WaitQueueForRWRegion m_waitQueue;

};

/*!
   @class RTESync_RWRegionNoSemalist
   @brief the implementation class for the "NoSemalist" flavour of RWRegions
 */
class RTESync_RWRegionNoSemalist : public RTESync_RWRegion
{
public:
    /*!
      @brief

      @param <name> [in]
      @return [<type>]
     */
    RTESync_RWRegionNoSemalist(SAPDB_Int8 id,RTESync_BaseSpinlockPool &pool);
private:
    void enterRegionExclusive(RTE_TCB tcb,RTE_UKT ukt,SAPDB_Long maxCollisions,SAPDB_Long &collisionCounter);

    void enterRegionNonExclusive(RTE_TCB tcb,RTE_UKT ukt,SAPDB_Long maxCollisions,SAPDB_Long &collisionCounter);
            
    void leaveRegionExclusive(RTE_TCB tcb,RTE_UKT ukt);

    void leaveRegionNonExclusive(RTE_TCB tcb,RTE_UKT ukt);

    void SwitchNonExclusive(RTE_TCB tcb,RTE_UKT ukt);
};

/*===========================================================================*
 *  LOCAL/INLINE FUNCTIONS, LOCAL CLASS METHODS (IMPLEMENTATION)             *
 *===========================================================================*/


RTESync_RWRegion::RTESync_RWRegion(SAPDB_Int8 id,RTESync_BaseSpinlockPool &pool,SAPDB_Bool enterCollisionCounterInTcb)
    : m_id(id)
    , m_nonExclusive(0)
    , m_pool(pool)
    , m_poolLockIndex(pool.GetLockIndex(id))
    , m_exclusiveRequests(0)
    , m_lastEntered(-1)
    , m_collisionCounter(0)
    , m_waitCounter(0)
    , m_tasCounter(0)
    , m_exclusiveAccessCounter(0)
    , m_nonExclusiveAccessCounter(0)
#ifdef RESET_STATISTICS_SUPPORTED
    , m_collisionCounterAtReset(0)
    , m_waitCounterAtReset(0)
    , m_tasCounterAtReset(0)
    , m_exclusiveAccessCounterAtReset(0)
    , m_nonExclusiveAccessCounterAtReset(0)
#endif
    , m_enterCollisionCounterInTcb(enterCollisionCounterInTcb)
    , m_info(NULL,NULL)
{
    if(0 == id)
    {
        RTE_Crash(SAPDBErr_MessageList(RTE_CONTEXT,RTEERR_SYNC_RWREGION_ID_ZERO,"","constructor"));
    }
    new ( ((void *)&m_info) ) RTE_ItemRegister<RTESync_RWRegion>::Info ( (const SAPDB_UTF8 *)"", this );
    RTESync_RWRegionRegister::Instance().Register(m_info);
}

/*---------------------------------------------------------------------------*/

RTESync_RWRegion::~RTESync_RWRegion()
{
    RTESync_RWRegionRegister::Instance().Deregister(m_info);
}

/*---------------------------------------------------------------------------*/

void RTESync_RWRegion::enter(SAPDB_Bool exclusive,RTE_TaskId pid)
{
    RTE_TCB tcb;
    RTE_UKT ukt;

    if(-1 == m_id)   /* dummy region */
        return;

    if(0 == m_id)
    {
        RTE_Crash(SAPDBErr_MessageList(RTE_CONTEXT,RTEERR_SYNC_RWREGION_ID_ZERO,SAPDB_ToString(pid),"enter"));
    }

    RTETask_getTCBandUKTCB( tcb, ukt, pid );

    tcb.beginExclusiveCalls()++;
    SAPDB_Long maxCollisions = XPARAM(ulRegionCollisionLoop);
    SAPDB_Long collisionCounter = 0;
    tcb.RWRegion() = this;
    tcb.inRegionID() = (RTE_RegionId)m_id;
    tcb.exclusiveNestingCount()++;
    tcb.beginExclusiveCount()++;
    tcb.taskState() = TSK_ENTERRWREGION_EO00;
    if(exclusive)
    {
        if(pid == m_lastEntered)
        {
            RTE_Crash(SAPDBErr_MessageList(RTE_CONTEXT,RTEERR_SYNC_RWREGION_ALREADY_ENTERED,SAPDB_ToString(tcb.taskIndex()),SAPDB_ToString(m_id)));
        }
        enterRegionExclusive(tcb,ukt,maxCollisions,collisionCounter);
        m_exclusiveAccessCounter++;
    }
    else
    {
        enterRegionNonExclusive(tcb,ukt,maxCollisions,collisionCounter);
        m_nonExclusiveAccessCounter++;
    }
    m_collisionCounter += collisionCounter;
    if(m_enterCollisionCounterInTcb)
    {
        tcb.regionCollisionCounter(m_id-1) += collisionCounter;
    }
    tcb.taskState() = TSK_RUNNING;
}

/*---------------------------------------------------------------------------*/

void RTESync_RWRegion::leave(SAPDB_Bool exclusive,RTE_TaskId pid)
{
    RTE_TCB tcb;
    RTE_UKT ukt;

    if(-1 == m_id)   /* dummy region */
        return;
    
    if(0 == m_id)
    {
        RTE_Crash(SAPDBErr_MessageList(RTE_CONTEXT,RTEERR_SYNC_RWREGION_ID_ZERO,SAPDB_ToString(pid),"leave"));
    }

    RTETask_getTCBandUKTCB( tcb, ukt, pid );

    tcb.taskState() = TSK_LEAVERWREGION_EO00;

    if(exclusive)
    {
        if(pid != m_lastEntered)
        {
            RTE_Crash(SAPDBErr_MessageList(RTE_CONTEXT,RTEERR_SYNC_RWREGION_LEAVE_WITHOUT_ENTER,SAPDB_ToString(tcb.taskIndex()),SAPDB_ToString(m_id)));
        }
        leaveRegionExclusive(tcb,ukt);
    }
    else
    {
        leaveRegionNonExclusive(tcb,ukt);
    }

    tcb.exclusiveNestingCount()--;

    if (( tcb.beginExclusiveCount() > XPARAM(ulRegLockSlice) ||
            ukt.selfDispatchCounter() ) &&
            0 == tcb.exclusiveNestingCount() && !tcb.prioFlag())
    {
        if ( ukt.selfDispatchCounter() )
            ukt.selfDispatchCounter()--;
        tcb.taskState() = TSK_RUNNABLE;
        tcb.selfSuspendCount()++;
        (RTETask_IScheduling::Instance()).PutTaskToRexQueue(tcb,ukt,REQ_RESCHEDULE,false);
        (RTETask_IScheduling::Instance()).Reschedule( ukt );
    }

    tcb.inRegionID() = 0;
    tcb.RWRegion() = NULL;
    tcb.taskState() = TSK_RUNNING;
}

/*---------------------------------------------------------------------------*/

SAPDB_Bool RTESync_RWRegion::tryEnter(SAPDB_Bool exclusive,RTE_TaskId pid)
{
    RTE_TCB tcb;
    RTE_UKT ukt;

    if(-1 == m_id)   /* dummy region */
        return true;

    if(0 == m_id)
    {
        RTE_Crash(SAPDBErr_MessageList(RTE_CONTEXT,RTEERR_SYNC_RWREGION_ID_ZERO,SAPDB_ToString(pid),"tryEnter"));
    }

    RTETask_getTCBandUKTCB ( tcb, ukt, pid );

    tcb.inRegionID() = (RTE_RegionId)m_id;
    tcb.taskState()   = TSK_ENTERRWREGION_EO00;

    SAPDB_Bool canEnter;
    if(exclusive)
        canEnter = tryEnterRegionExclusiveNonBlocking(tcb,ukt);
    else
        canEnter = tryEnterRegionNonExclusiveNonBlocking(tcb,ukt);

    if(canEnter)
    {
        tcb.beginExclusiveCalls()++;
        tcb.beginExclusiveCount()++;
        tcb.exclusiveNestingCount()++;
    }
    tcb.taskState() = TSK_RUNNING;
    return canEnter;
}

/*---------------------------------------------------------------------------*/
void RTESync_RWRegion::SwitchToNonExclusiveAccess(RTE_TaskId pid)
{
    RTE_TCB tcb;
    RTE_UKT ukt;

    if(-1 == m_id)   /* dummy region */
        return;

    if(0 == m_id)
    {
        RTE_Crash(SAPDBErr_MessageList(RTE_CONTEXT,RTEERR_SYNC_RWREGION_ID_ZERO,SAPDB_ToString(pid),"tryEnter"));
    }

    RTETask_getTCBandUKTCB ( tcb, ukt, pid );
    SwitchNonExclusive( tcb, ukt );
}


/*---------------------------------------------------------------------------*/
SAPDB_Bool RTESync_RWRegion::tryEnterRegionExclusiveNonBlocking(RTE_TCB tcb,RTE_UKT ukt)
{
    get_lock(tcb,ukt,false,m_tasCounter);
    if(m_nonExclusive != 0) // the region has been locked ("exclusive" or "non-exclusive") -> can't enter
    {
        free_lock();
        return false;
    }
    else
    {
        m_exclusiveRequests++;
        m_nonExclusive = -1;
        m_lastEntered = tcb.taskIndex();
        free_lock();
        return true;
    }
}

/*---------------------------------------------------------------------------*/

SAPDB_Bool RTESync_RWRegion::tryEnterRegionNonExclusiveNonBlocking(RTE_TCB tcb,RTE_UKT ukt)
{
    get_lock(tcb,ukt,false,m_tasCounter);
    if(m_nonExclusive < 0)  // the region has been locked "exclusive" -> can't enter
    {
        free_lock();
        return false;
    }
    else
    {
        m_nonExclusive++;
        m_lastEntered = tcb.taskIndex();
        free_lock();
        return true;
    }
}

/*---------------------------------------------------------------------------*/

#define MAX_TAS_COUNT ((SAPDB_ULong)-1)   // currently the biggest possible number, may be adjusted if necessary

void RTESync_RWRegion::check_indefinite_loop(SAPDB_ULong &tasCount,RTE_TCB tcb)
{
    if ( MAX_TAS_COUNT == tasCount )
    {
        RTE_UKT ukt(tcb.ukt());
        if ( tcb.taskType() == TT_TW && ukt.activeTasks() == 1 )
        {
            RTE_Message(SAPDBErr_MessageList(RTE_CONTEXT,RTEINFO_SYNC_RWREGION_TW_SLEEPING));
            RTETask_Context taskContext(tcb.taskIndex());
            taskContext.Sleep(1);
            tasCount = 0;
        }
        else
        {
            RTE_Crash(SAPDBErr_MessageList(RTE_CONTEXT,RTEERR_SYNC_RWREGION_INDEFINITE_LOOP,SAPDB_ToString(m_id)));
        }
    }
}

/*---------------------------------------------------------------------------*/

void RTESync_RWRegion::get_lock(RTE_TCB &tcb,RTE_UKT &ukt,SAPDB_Bool busyWaiting,SAPDB_ULong &totalTasCnt)
{
    SAPDB_ULong tasCount;

    if ( m_pool.TryLock(m_poolLockIndex) )
    {
        tasCount = 0;

        while ( m_pool.TryLock(m_poolLockIndex) )
        {
            tasCount++;
            check_indefinite_loop(tasCount, tcb );
            if ( KGS->fBusyWaitingForbidden )
            {
                RTE_ISystem::DoSleep( 0 ); // reschedule ukt
            }
            else if ( !busyWaiting )
            {
            /* --- reschedule myself (task) via rex queue  */
                (RTETask_IScheduling::Instance()).PutTaskToRexQueue(tcb,ukt,REQ_RESCHEDULE,true);
                (RTETask_IScheduling::Instance()).Reschedule(ukt);
            }
        }
        totalTasCnt += tasCount;
    }
}

/*---------------------------------------------------------------------------*/

void RTESync_RWRegion::free_lock()
{
    m_pool.Unlock(m_poolLockIndex);
}

/*---------------------------------------------------------------------------*/

RTESync_RWRegionNoSemalist::RTESync_RWRegionNoSemalist(SAPDB_Int8 id,RTESync_BaseSpinlockPool &pool)
    :
    RTESync_RWRegion(id,pool)
{
}

/*---------------------------------------------------------------------------*/

void RTESync_RWRegionNoSemalist::enterRegionExclusive(RTE_TCB tcb,RTE_UKT ukt,SAPDB_Long maxCollisions,SAPDB_Long &collisionCounter)
{
    SAPDB_Bool fRegionFree;
    if(XPARAM(ulRegionCollisionLoop)  &&
       ( !tcb.prioFlag() || !XPARAM(fBegExclQueWhenPrio)))
    {
        get_lock(tcb,ukt,false,m_tasCounter);
    }
    else
    {
        do
        {
            fRegionFree = (0==m_nonExclusive); /* dirty read */
            if ( fRegionFree )
            {
                get_lock(tcb,ukt,false,m_tasCounter);
                fRegionFree = (0==m_nonExclusive); /* real read */
                if ( !fRegionFree )
                    free_lock();
            }

            if ( !fRegionFree )
            {
                collisionCounter++;

                (RTETask_IScheduling::Instance()).PutTaskToRexQueue(tcb,ukt,REQ_RESCHEDULE,collisionCounter < maxCollisions || tcb.exclusiveNestingCount() > 1);
                (RTETask_IScheduling::Instance()).Reschedule(ukt);
            }
        }
        while ( !fRegionFree ) ;
    }

    m_nonExclusive = -1;
    m_lastEntered = tcb.taskIndex();
    free_lock();
    /*
    * we are alone now
    */

}

/*---------------------------------------------------------------------------*/

void RTESync_RWRegionNoSemalist::enterRegionNonExclusive(RTE_TCB tcb,RTE_UKT ukt,SAPDB_Long maxCollisions,SAPDB_Long &collisionCounter)
{
    do
    {
        get_lock(tcb,ukt,false,m_tasCounter);
        if(m_nonExclusive < 0)
        {
            free_lock();
            collisionCounter++;
            (RTETask_IScheduling::Instance()).PutTaskToRexQueue(tcb,ukt,REQ_RESCHEDULE,collisionCounter < maxCollisions || tcb.exclusiveNestingCount() > 1);
            (RTETask_IScheduling::Instance()).Reschedule(ukt);
        }
        else
        {
            break;
        }
    }
    while(1);

    /*
    * we are alone now
    */

    m_lastEntered = tcb.taskIndex();
    m_nonExclusive++;
    if(0 == m_nonExclusive)
    {
        SAPDB_Char msg[256];
        SAPDB_sprintf(msg,256," m_nonExclusive is 0 after enter (non-Exclusive)!!(pid is %d region id is %d)\n",tcb.taskIndex(),m_id);
        RTE_Crash(SAPDBErr_MessageList(RTE_CONTEXT,RTEERR_SYNC_RWREGION_INCONSISTENCY,msg));
    }
    free_lock();
}

/*---------------------------------------------------------------------------*/

void RTESync_RWRegionNoSemalist::leaveRegionExclusive(RTE_TCB tcb,RTE_UKT ukt)
{
    m_nonExclusive = 0;   /* the no-sema-list case works without a lock */
}

/*---------------------------------------------------------------------------*/

void RTESync_RWRegionNoSemalist::leaveRegionNonExclusive(RTE_TCB tcb,RTE_UKT ukt)
{
    m_nonExclusive--;
}

/*---------------------------------------------------------------------------*/
void RTESync_RWRegionNoSemalist::SwitchNonExclusive(RTE_TCB tcb,RTE_UKT ukt)
{
    get_lock(tcb,ukt,false,m_tasCounter);
    if(-1 != m_nonExclusive)
    {
        SAPDB_Char msg[256];
        SAPDB_sprintf(msg,256,"SwitchToNonExclusiveAccess() called but m_nonExclusive is != -1 (%d)!!(pid is %d region id is %d)\n",m_nonExclusive,tcb.taskIndex(),m_id);
        RTE_Crash(SAPDBErr_MessageList(RTE_CONTEXT,RTEERR_SYNC_RWREGION_INCONSISTENCY,msg));
    }
    m_nonExclusive = 1;
    free_lock();
}


/*---------------------------------------------------------------------------*/

SAPDB_Bool RTESync_WaitQueueForRWRegion::empty(void)
{
    return ((TASK_CTRL)NULL == m_firstEntry);
}

/*---------------------------------------------------------------------------*/

void RTESync_WaitQueueForRWRegion::insert(SAPDB_Bool exclusive,RTE_TCB tcb)
{
    tcb.taskIsWaitingForExclusiveAccess()   = exclusive;
    tcb.nextTaskInWaitQueue()               = NULL;
    if(empty()) // empty list?
    {           // then this one is the first and last entry
        m_firstEntry = m_lastEntry = tcb;
    }
    else
    {           // else add this tcb after the last entry
        m_lastEntry.nextTaskInWaitQueue()   = tcb;
        m_lastEntry                         = tcb;
    }
}

/*---------------------------------------------------------------------------*/

RTE_TCB RTESync_WaitQueueForRWRegion::getFirst(void)
{
    return m_firstEntry;
}

/*---------------------------------------------------------------------------*/

void RTESync_WaitQueueForRWRegion::removeFirst(void)
{
    RTE_TCB tcb                 = m_firstEntry;
    m_firstEntry                = tcb.nextTaskInWaitQueue();
    tcb.nextTaskInWaitQueue()   = NULL;
}

/*---------------------------------------------------------------------------*/

RTESync_WaitQueueForRWRegion::RTESync_WaitQueueForRWRegion()
    : m_firstEntry(NULL)
    , m_lastEntry(NULL)
{
}

/*---------------------------------------------------------------------------*/

RTESync_RWRegionWithSemalist::RTESync_RWRegionWithSemalist(SAPDB_Int8 id,RTESync_BaseSpinlockPool &pool)
    : RTESync_RWRegion(id,pool)
{
}

/*---------------------------------------------------------------------------*/

void RTESync_RWRegionWithSemalist::enterRegionExclusive(RTE_TCB tcb,RTE_UKT ukt,SAPDB_Long maxCollisions,SAPDB_Long &collisionCounter)
{
    do
    {
        get_lock(tcb,ukt,false,m_tasCounter);
        if(m_nonExclusive != 0)   // not free?
        {
            collisionCounter++;
            if(collisionCounter >= maxCollisions)
                break;
            free_lock();
            (RTETask_IScheduling::Instance()).PutTaskToRexQueue(tcb,ukt,REQ_RESCHEDULE,(0 != tcb.prioFlag()));
            (RTETask_IScheduling::Instance()).Reschedule(ukt);
        }
        else
        {
            break;
        }
    }
    while(true);
    m_exclusiveRequests++;
    if(m_nonExclusive != 0)
    {
        m_waitCounter++;
        m_waitQueue.insert(true,tcb);
        free_lock();
        (RTETask_IScheduling::Instance()).Reschedule(ukt);
    }
    else
    {
        m_nonExclusive = -1;
        m_lastEntered = tcb.taskIndex();
        free_lock();
    }
}

/*---------------------------------------------------------------------------*/

void RTESync_RWRegionWithSemalist::enterRegionNonExclusive(RTE_TCB tcb,RTE_UKT ukt,SAPDB_Long maxCollisions,SAPDB_Long &collisionCounter)
{
    do
    {
        get_lock(tcb,ukt,false,m_tasCounter);
        if(m_nonExclusive < 0)   // not free?
        {
            collisionCounter++;
            if(collisionCounter >= maxCollisions)
                break;
            free_lock();
            (RTETask_IScheduling::Instance()).PutTaskToRexQueue(tcb,ukt,REQ_RESCHEDULE,(0 != tcb.prioFlag()));
            (RTETask_IScheduling::Instance()).Reschedule(ukt);
        }
        else
        {
            break;
        }
    }
    while(true);
    if(m_nonExclusive < 0 || m_exclusiveRequests > 0)
    {
        m_waitCounter++;
        m_waitQueue.insert(false,tcb);
        free_lock();
        (RTETask_IScheduling::Instance()).Reschedule(ukt);
    }
    else
    {
        m_nonExclusive++;
        m_lastEntered = tcb.taskIndex();
        if(0 == m_nonExclusive)
        {
            SAPDB_Char msg[256];
            SAPDB_sprintf(msg,256," m_nonExclusive is 0 after enter (non-Exclusive)!!(pid is %d, region id is %d)\n",tcb.taskIndex(),m_id);
            RTE_Crash(SAPDBErr_MessageList(RTE_CONTEXT,RTEERR_SYNC_RWREGION_INCONSISTENCY,msg));
        }
        free_lock();
    }
}

/*---------------------------------------------------------------------------*/

void RTESync_RWRegionWithSemalist::leaveRegionExclusive(RTE_TCB tcb,RTE_UKT ukt)
{
    SAPDB_Bool readerActivated = false;   // indicate that at least one reader has been activated. In this case, no writer must be activated
    get_lock(tcb,ukt,false,m_tasCounter);
    if(0 <= m_nonExclusive)
    {
        RTE_Crash(SAPDBErr_MessageList(RTE_CONTEXT,RTEERR_SYNC_RWREGION_LEAVE_WITHOUT_ENTER,SAPDB_ToString(tcb.taskIndex()),SAPDB_ToString(m_id)));
    }
    m_nonExclusive = 0;
    m_exclusiveRequests--;
    m_lastEntered = -1;     // at first assume that no task can be activated

    do
    {
        if(m_waitQueue.empty()) // no tasks that could be activated -> leave
        {
            free_lock();
            break;
        }
        else
        {
            RTE_TCB entryTcb = m_waitQueue.getFirst();
            if (readerActivated && entryTcb.taskIsWaitingForExclusiveAccess())   // already readers activated and the next one would be a writer -> leave
            {
                free_lock();
                break;
            }
            else
            {
                m_waitQueue.removeFirst();
                m_waitCounter--;
                if(entryTcb.taskIsWaitingForExclusiveAccess())
                {
                    m_nonExclusive = -1;
                }
                else
                {
                    m_nonExclusive++;
                    if(0 == m_nonExclusive)
                    {
                        SAPDB_Char msg[256];
                        SAPDB_sprintf(msg,256," m_nonExclusive is 0 after enter-after-leave (Exclusive)!!(pid is %d region id is %d)\n",tcb.taskIndex(),m_id);
                        RTE_Crash(SAPDBErr_MessageList(RTE_CONTEXT,RTEERR_SYNC_RWREGION_INCONSISTENCY,msg));
                    }
                }
                m_lastEntered = entryTcb.taskIndex();
                if(entryTcb.ukt() == ukt)   // the waiting task is in my UKT -> activate it (incl. a goto_disp()) and leave
                {
                    free_lock();
                    activateTaskInMyUKT(tcb,ukt,entryTcb);
                    break;
                }
                else
                {
                    SAPDB_Bool nextTaskIsWaitingForExclusiveAccess = entryTcb.taskIsWaitingForExclusiveAccess();
                    activateTaskInOtherUKT(tcb,ukt,entryTcb);
                    if(nextTaskIsWaitingForExclusiveAccess)
                    {
                        free_lock();
                        break;
                    }
                    else
                    {
                        // in fact, this is the only case in which the loop is continued: a reader task has been activated in another UKT. In this case, other reader tasks can also be activated
                        readerActivated = true;
                    }
                }
            }
        }
    }
    while(1);
}

/*---------------------------------------------------------------------------*/

void RTESync_RWRegionWithSemalist::leaveRegionNonExclusive(RTE_TCB tcb,RTE_UKT ukt)
{
    SAPDB_Bool readerActivated = false;   // indicate that at least one reader has been activated. In this case, no writer must be activated
    get_lock(tcb,ukt,false,m_tasCounter);
    if(0 >= m_nonExclusive)
    {
        RTE_Crash(SAPDBErr_MessageList(RTE_CONTEXT,RTEERR_SYNC_RWREGION_LEAVE_WITHOUT_ENTER,SAPDB_ToString(tcb.taskIndex()),SAPDB_ToString(m_id)));
    }
    m_nonExclusive--;
    m_lastEntered = -1;     // at first assume that no task can be activated
    do
    {
        if( m_waitQueue.empty()) // no tasks that could be activated -> leave
        {
            free_lock();
            break;
        }
        else
        {
            RTE_TCB entryTcb = m_waitQueue.getFirst();
            if(( ( m_nonExclusive != 0 ) && entryTcb.taskIsWaitingForExclusiveAccess() )   // there is still someone in the region and the next one would be a writer -> leave
               ||( readerActivated && entryTcb.taskIsWaitingForExclusiveAccess() ))   // already readers activated and the next one would be a writer -> leave
            {
                free_lock();
                break;
            }
            else
            {
                m_waitQueue.removeFirst();
                m_waitCounter--;
                if(entryTcb.taskIsWaitingForExclusiveAccess())
                    m_nonExclusive = -1;
                else
                {
                    m_nonExclusive++;
                    if(0 == m_nonExclusive)
                    {
                        SAPDB_Char msg[256];
                        SAPDB_sprintf(msg,256," m_nonExclusive is 0 after enter-after-leave (non-Exclusive)!!(pid is %d region is is %d)\n",tcb.taskIndex(),m_id);
                        RTE_Crash(SAPDBErr_MessageList(RTE_CONTEXT,RTEERR_SYNC_RWREGION_INCONSISTENCY,msg));
                    }
                }
                m_lastEntered = entryTcb.taskIndex();
                if(entryTcb.ukt() == ukt)   // the waiting task is in my UKT -> activate it (incl. a goto_disp()) and leave
                {
                    free_lock();
                    activateTaskInMyUKT(tcb,ukt,entryTcb);
                    break;
                }
                else
                {
                    SAPDB_Bool nextTaskIsWaitingForExclusiveAccess = entryTcb.taskIsWaitingForExclusiveAccess();
                    activateTaskInOtherUKT(tcb,ukt,entryTcb);
                    if(nextTaskIsWaitingForExclusiveAccess)
                    {
                        free_lock();
                        break;
                    }
                    else
                    {
                        // in fact, this is the only case in which the loop is continued: a reader task has been activated in another UKT. In this case, other reader tasks can also be activated
                        readerActivated = true;
                    }
                }
            }
        }
    }
    while(1);
}

/*---------------------------------------------------------------------------*/
void RTESync_RWRegionWithSemalist::SwitchNonExclusive(RTE_TCB tcb,RTE_UKT ukt)
{
    get_lock(tcb,ukt,false,m_tasCounter);
    if(-1 != m_nonExclusive)
    {
        SAPDB_Char msg[256];
        SAPDB_sprintf(msg,256,"SwitchToNonExclusiveAccess() called but m_nonExclusive is != -1 (%d)!!(pid is %d region id is %d)\n",m_nonExclusive,tcb.taskIndex(),m_id);
        RTE_Crash(SAPDBErr_MessageList(RTE_CONTEXT,RTEERR_SYNC_RWREGION_INCONSISTENCY,msg));
    }
    m_nonExclusive = 1;
    m_exclusiveRequests--;
    do
    {
        if(m_waitQueue.empty()) // no tasks that could be activated -> leave
        {
            free_lock();
            break;
        }
        else
        {
            RTE_TCB entryTcb = m_waitQueue.getFirst();
            if (entryTcb.taskIsWaitingForExclusiveAccess())   // next one would be a writer -> leave
            {
                free_lock();
                break;
            }
            else
            {
                if(entryTcb.ukt() != ukt)   // the waiting task is in another UKT -> activate it
                {
                    m_waitQueue.removeFirst();
                    m_waitCounter--;
                    m_nonExclusive++;
                    activateTaskInOtherUKT(tcb,ukt,entryTcb);
                }
                else
                {
                    free_lock();
//http://pts:1080/webpts?wptsdetail=yes&ErrorType=0&ErrorID=1129806:
// activate tasks in my own task scheduler, too
                    activateTaskInMyUKT(tcb,ukt,entryTcb);
                    break;
                }
            }
        }
    }
    while(1);
}

/*---------------------------------------------------------------------------*/

void RTESync_RWRegionWithSemalist::activateTaskInMyUKT(RTE_TCB tcb,RTE_UKT ukt,RTE_TCB nextTcb)
{
    (RTETask_IScheduling::Instance()).PutTaskToRavQueue(nextTcb,ukt,REQ_RESCHEDULE);
    if ( !tcb.prioFlag() )
    {
        (RTETask_IScheduling::Instance()).PutTaskToRexQueue(tcb,ukt,REQ_RESCHEDULE,false);
        (RTETask_IScheduling::Instance()).Reschedule(ukt);
    }
}

/*---------------------------------------------------------------------------*/

void RTESync_RWRegionWithSemalist::activateTaskInOtherUKT(RTE_TCB tcb,RTE_UKT ukt,RTE_TCB nextTcb)
{
    (RTETask_IScheduling::Instance()).ActivateTaskInOtherUKT(tcb,ukt,nextTcb);

    if ( KGS->fBusyWaitingForbidden )
    {
        RTE_ISystem::DoSleep( 0 ); // reschedule 
    }
}


/*===========================================================================*
 *  EXPORTED FUNCTIONS, EXPORTED CLASS METHODS (IMPLEMENTATION)              *
 *===========================================================================*/

RTESync_SpinlockPool::RTESync_SpinlockPool(SAPDB_UTF8 const *poolIdentifier,SAPDB_Int4 numberOfElements)
: RTESync_BaseSpinlockPool(poolIdentifier, numberOfElements, RTEMem_RteAllocator::Instance())
{}

// On Alpha processors there must not be more than one spinlock within a cache line.
// This is no problem for the spinlocks in the pool, because the pool is an array
// of RTESync_NamedSpinlocks, which are 160 bytes in size on Alpha, while a cache
// line is 128 bytes in size. The only problem may occur, when a (not-named) spinlock 
// is placed just before a spinlock pool. To avoid this, a security buffer the size
// of a cache line is created before each spinlock pool.

#if defined(ALPHA)
#define SAFETY_OFFSET_ SAPDB_CACHELINE_SIZE
#else
#define SAFETY_OFFSET_ 0
#endif

RTESync_BaseSpinlockPool::RTESync_BaseSpinlockPool( SAPDB_UTF8 const *poolIdentifier,
                                                    SAPDB_Int4 numberOfElements,
                                                    SAPDBMem_IRawAllocator &allocator)
    : m_numberOfElements(numberOfElements)
    , m_allocator(allocator)
    , m_info(0,0)   // must be done this way, because we do not know "this" at this point
{
    strncpy((char *)&m_Name[0], (const char *)poolIdentifier, sizeof(m_Name)-1);
    m_Name[sizeof(m_Name)-1] = 0;

    m_pool = (RTESync_NamedSpinlock *)((SAPDB_Byte *)m_allocator.Allocate(sizeof(RTESync_NamedSpinlock) * m_numberOfElements + 2 * SAFETY_OFFSET_)+SAFETY_OFFSET_);
    if ( !m_pool )
    {
        RTE_Crash(SAPDBErr_MessageList(RTE_CONTEXT,RTEERR_ALLOCATION_FAILED,"Spinlock Pool" ));
    }

    for( SAPDB_Int4 i=0 ; i<m_numberOfElements ; i++)
    {
        SAPDB_UTF8 myName[40+1];
        SAPDB_sprintf((SAPDB_Char *)myName, sizeof(myName), "%s%d", poolIdentifier, i);
        new(&m_pool[i])RTESync_NamedSpinlock(myName);
    }
    new ( ((void *)&m_info) ) RTE_ItemRegister<RTESync_BaseSpinlockPool>::Info ( (const SAPDB_UTF8 *)&m_Name[0], this );
    RTESync_SpinlockPoolRegister::Instance().Register(m_info);
}

/*---------------------------------------------------------------------------*/

RTESync_BaseSpinlockPool::~RTESync_BaseSpinlockPool()
{
/*
    for( SAPDB_Int4 i=0 ; i<m_numberOfElements ; i++)
    {
        m_pool[i].~RTESync_NamedSpinlock();
    }
*/
    m_allocator.Deallocate(m_pool);
}

/*---------------------------------------------------------------------------*/

SAPDB_Int4 RTESync_BaseSpinlockPool::GetLockIndex(SAPDB_Int8 id)
{
    return (SAPDB_Int4)(id % m_numberOfElements);
}

/*---------------------------------------------------------------------------*/

SAPDB_Int4 RTESync_BaseSpinlockPool::GetLockIndex(void *memoryAddress)
{
    // shifting is due to most likely aligned integer or pointer references used...
    return ((SAPDB_Int4)(( (((SAPDB_Byte *)memoryAddress) - (SAPDB_Byte *)0) >> 3 )) % m_numberOfElements);
}

/*---------------------------------------------------------------------------*/

SAPDB_Bool RTESync_BaseSpinlockPool::TryLock(SAPDB_Int4 poolIndex)
{
    return m_pool[poolIndex].TryLock();
}

/*---------------------------------------------------------------------------*/

void RTESync_BaseSpinlockPool::Unlock(SAPDB_Int4 poolIndex)
{
    m_pool[poolIndex].Unlock();
}

/*---------------------------------------------------------------------------*/

/*! 
    the factory method used to obtain a RWRegion 
*/
RTESync_IRWRegion *RTESync_CreateRWRegion(SAPDB_Int8 id,RTESync_BaseSpinlockPool &pool,SAPDBMem_IRawAllocator &allocator,RTESync_IRWRegion::flavours flavour)
{
    if(RTESync_IRWRegion::WithSemalist == flavour)
        return  new (allocator) RTESync_RWRegionWithSemalist (id,pool);
    else
        return  new (allocator) RTESync_RWRegionNoSemalist   (id,pool);
}

/*!
    and the counterpart to destroy a RWRegion created by the routine above
*/

void RTESync_DestroyRWRegion(RTESync_IRWRegion *region,SAPDBMem_IRawAllocator &allocator)
{
    ((RTESync_RWRegion *)region)->~RTESync_RWRegion();
    allocator.Deallocate(region);
}

SAPDB_Bool RTESync_RWRegionRegister::FillStatisticInfo(StatisticInfo * &pInfoArray, SAPDB_Int4 maxCount, SAPDB_Int4 &itemCount,RTESync_IRWRegionReader::Mode mode,RTESync_IRWRegionReader::Selection  selection)
{
    RTESync_LockedScope lock(Spinlock());

    if ( this->m_Count > maxCount )
    {
        return false;
    }
    itemCount = 0;
    StatisticInfo *pFill = pInfoArray;

    for ( RTE_ItemRegister<RTESync_RWRegion>::Info * pInfo = this->m_First; 0 != pInfo; pInfo = pInfo->GetSuccessor() )
    {
        RTESync_RWRegion *pCurrent = &(pInfo->GetItem());
        if( (selection == RTESync_IRWRegionReader::all) || (pCurrent->m_nonExclusive != 0)/*(pCurrent->m_lastEntered != -1)*/ )
        {
            pFill->ExclusiveAccessCount     = pCurrent->m_exclusiveAccessCounter;
            pFill->NonExclusiveAccessCount  = pCurrent->m_nonExclusiveAccessCounter;
            pFill->CollisionCount           = pCurrent->m_collisionCounter;
            pFill->WaitCount                = pCurrent->m_waitCounter;
            pFill->TasCount                 = pCurrent->m_tasCounter;
            pFill->CurrentAccesses          = pCurrent->m_nonExclusive;
#ifdef RESET_STATISTICS_SUPPORTED
            if(RTESync_IRWRegionReader::reset == mode)
            {
                pFill->ExclusiveAccessCount     -= pCurrent->m_exclusiveAccessCounterAtReset;
                pFill->NonExclusiveAccessCount  -= pCurrent->m_nonExclusiveAccessCounterAtReset;
                pFill->CollisionCount           -= pCurrent->m_collisionCounterAtReset;
                pFill->WaitCount                -= pCurrent->m_waitCounterAtReset;
                pFill->CollisionCount           -= pCurrent->m_tasCounterAtReset;
            }
#endif
            strcpy((SAPDB_Char *)pFill->PoolName, (SAPDB_Char *)pCurrent->m_pool.Name());
            pFill->TaskId = pCurrent->m_lastEntered;
    #ifdef ADD_WAITERS_
            pFill->Waiters[0]=0;
            if(-1 != pFill->TaskId)
            {
                if(pCurrent->getWaitQueue())
                {
                    RTETask_Task *pCurrenWaitQueueEntry = pCurrent->getWaitQueue()->getFirst();
                    if(pCurrenWaitQueueEntry)
                    {
                        SAPDB_sprintf(&pFill->Waiters[0],sizeof(pFill->Waiters),"%d",pCurrenWaitQueueEntry->ID());
                        pCurrenWaitQueueEntry = pCurrenWaitQueueEntry->NextTaskInWaitQueue();
                    }
                    while(pCurrenWaitQueueEntry)
                    {
                        SAPDB_sprintf(&pFill->Waiters[0],sizeof(pFill->Waiters),"%s,%d",pFill->Waiters,pCurrenWaitQueueEntry->ID());
                        pCurrenWaitQueueEntry = pCurrenWaitQueueEntry->NextTaskInWaitQueue();
                    }
                }
            }
    #endif
            pFill->Address = (SAPDB_ULong)pCurrent;
            pFill++;
            itemCount++;
        }
    }
    return true;
        
}


class RTESync_RWRegionReader : public RTESync_IRWRegionReader
{

public:

    /* -----------------------------------------------------------------------*/
    /*! chapter: Constructors and initialization                              */
    /* -----------------------------------------------------------------------*/

    RTESync_RWRegionReader (void)
    {
    }
    
    ~RTESync_RWRegionReader (void)
    {
    }

    /* -----------------------------------------------------------------------*/
    /*! endchapter: Constructors and initialization                           */
    /* -----------------------------------------------------------------------*/

    /* -----------------------------------------------------------------------*/
    /*! chapter: Iteration                                                    */
    /* -----------------------------------------------------------------------*/

    SAPDB_Bool First (
        RTESync_IRWRegionReader::Mode       mode        = RTESync_IRWRegionReader::normal,
        RTESync_IRWRegionReader::Selection  selection   = RTESync_IRWRegionReader::all
    )
       {
        if ( RTESync_RWRegionRegister::Instance().GetStatisticInfo(m_pInfoArray, m_Elements,mode,selection) )
        {
            m_Current = -1;
            return (true);
        }
        else
        {
            return (false);
        }
    }

    SAPDB_Bool Next (void)
    {
        m_Current ++;

        if ((!m_pInfoArray) || (m_Current >= m_Elements))
        {
            FreeArray();
            return (false);
        }
        else
        {
            return (true);
        }
    }

    /* -----------------------------------------------------------------------*/
    /*! endchapter: Iteration                                                 */
    /* -----------------------------------------------------------------------*/

    /* -----------------------------------------------------------------------*/
    /*! chapter: Data Access                                                  */
    /* -----------------------------------------------------------------------*/

    SAPDB_Bool SpinlockPoolName         (SAPDB_UTF8 name[])
    {
        if ((m_pInfoArray) && (m_Current < m_Elements))
        {
            strcpy((SAPDB_Char *)name, (SAPDB_Char *)m_pInfoArray[m_Current].PoolName);
            return (true);
        }
        else
        {
            return (true);
        }
    }

    SAPDB_Bool Address                  (SAPDB_UInt8 &address)
    {
        if ((m_pInfoArray) && (m_Current < m_Elements))
        {
            address = m_pInfoArray[m_Current].Address;
            return (true);
        }
        else
        {
            return (true);
        }
    }

    SAPDB_Bool CollisionCount           (SAPDB_UInt8 &collisioncount)
    {
        if ((m_pInfoArray) && (m_Current < m_Elements))
        {
            collisioncount = m_pInfoArray[m_Current].CollisionCount;
            return (true);
        }
        else
        {
            return (true);
        }
    }

    SAPDB_Bool WaitCount           (SAPDB_UInt8 &waitcount)
    {
        if ((m_pInfoArray) && (m_Current < m_Elements))
        {
            waitcount = m_pInfoArray[m_Current].WaitCount;
            return (true);
        }
        else
        {
            return (true);
        }
    }

    SAPDB_Bool SpinLockCollisionCount   (SAPDB_UInt8 &tascount)
    {
        if ((m_pInfoArray) && (m_Current < m_Elements))
        {
            tascount = m_pInfoArray[m_Current].TasCount;
            return (true);
        }
        else
        {
            return (true);
        }
    }

    SAPDB_Bool ExclusiveAccessCount     (SAPDB_UInt8 &exclusiveaccesscount)
    {
        if ((m_pInfoArray) && (m_Current < m_Elements))
        {
            exclusiveaccesscount = m_pInfoArray[m_Current].ExclusiveAccessCount;
            return (true);
        }
        else
        {
            return (true);
        }
    }

    SAPDB_Bool NonExclusiveAccessCount  (SAPDB_UInt8 &nonexclusiveaccesscount)
    {
        if ((m_pInfoArray) && (m_Current < m_Elements))
        {
            nonexclusiveaccesscount = m_pInfoArray[m_Current].NonExclusiveAccessCount;
            return (true);
        }
        else
        {
            return (true);
        }
    }

    SAPDB_Bool LastEnteredTask          (SAPDB_Int4 &taskId)
    {
        if ((m_pInfoArray) && (m_Current < m_Elements))
        {
            taskId = m_pInfoArray[m_Current].TaskId;
            return (true);
        }
        else
        {
            return (true);
        }
    }

    SAPDB_Bool CurrentAccesses          (SAPDB_Int4 &currentAccesses)
    {
        if ((m_pInfoArray) && (m_Current < m_Elements))
        {
            currentAccesses = m_pInfoArray[m_Current].CurrentAccesses;
            return (true);
        }
        else
        {
            return (true);
        }
    }

    SAPDB_UInt4 GetNumberOfItems(void)
    {
        return RTESync_RWRegionRegister::Instance().GetCount();
    }
    /* -----------------------------------------------------------------------*/
    /*! endchapter: Data Access                                               */
    /* -----------------------------------------------------------------------*/


private:

    void FreeArray (void)
    {
        if (m_pInfoArray)
        {
            RTESync_RWRegionRegister::Instance().FreeStatisticInfo(m_pInfoArray);
            m_pInfoArray  = NULL;
            m_Elements    = 0;
            m_Current     = 0;
        }
    };

    RTESync_RWRegionRegister::StatisticInfo *m_pInfoArray;
    SAPDB_Int4                               m_Elements;
    SAPDB_Int4                               m_Current;
};

RTESync_IRWRegionReader *RTESync_GetRWRegionReader(SAPDBMem_IRawAllocator &allocator)
{
    return new (allocator) RTESync_RWRegionReader();
}

/*---------------------------------------------------------------------------*/
/*!
    The following code can be used to redirect calls to vbegexcl()/vendexcl()/visexcl() 
    to RWRegions for testing purposes. To use it, replace the vbegexcl() code with:

     void RTESync_RWRegionvbegexcl ( tsp00_TaskId pid, tsp00_RegionId sid  );
     void vbegexcl ( tsp00_TaskId pid, tsp00_RegionId sid  )
     {
        RTESync_RWRegionvbegexcl ( pid, sid  );
     }

     and the code for vendexcl() and visexcl() the same way.
*/
class RTESync_RegionSimulator
{
public:
    static RTESync_RegionSimulator &Instance()
    {
        if(NULL == m_Instance)
        {
            m_Instance = new (RTEMem_RteAllocator::Instance()) RTESync_RegionSimulator;
        }
        return *m_Instance;
    }
    RTESync_IRWRegion    **m_Regions;
private:
    RTESync_RegionSimulator()
    {
        m_Spinlocks = new (RTEMem_RteAllocator::Instance()) RTESync_SpinlockPool((SAPDB_UTF8 *)"RegionSimulationPool",XPARAM(ulNoOfRegions));
        m_Regions = (RTESync_IRWRegion **)(RTEMem_RteAllocator::Instance()).Allocate( sizeof(RTESync_RWRegion*) * XPARAM(ulNoOfRegions) );
        for(SAPDB_UInt4 i=0 ; i<XPARAM(ulNoOfRegions); i++)
        {
            m_Regions[i] = RTESync_CreateRWRegion(i+1, *m_Spinlocks, RTEMem_RteAllocator::Instance(),USE_SEMALIST);
        }
    }
    static RTESync_RegionSimulator *m_Instance;
    RTESync_SpinlockPool    *m_Spinlocks;
};
RTESync_RegionSimulator *RTESync_RegionSimulator::m_Instance;

/*---------------------------------------------------------------------------*/

extern "C" void RTESync_RWRegionvbegexcl ( tsp00_TaskId pid, tsp00_RegionId sid  )
{
    (RTESync_RegionSimulator::Instance()).m_Regions[sid-1]->enter(true,pid);
}

/*---------------------------------------------------------------------------*/

extern "C" void RTESync_RWRegionvendexcl ( tsp00_TaskId pid, tsp00_RegionId sid )
{
    (RTESync_RegionSimulator::Instance()).m_Regions[sid-1]->leave(true,pid);
}

/*---------------------------------------------------------------------------*/

extern "C" BOOLEAN RTESync_RWRegionvisexcl ( tsp00_TaskId pid, tsp00_RegionId  sid )
{
    if(-1 == sid)   /* dummy region */
        return true;

    if ( sid < 1 || sid > (tsp00_RegionId)XPARAM(ulNoOfRegions) )
    {
        RTE_Crash(SAPDBErr_MessageList(RTE_CONTEXT,RTEERR_SYNC_VISEXCL_INVALID_REGION,SAPDB_ToString(pid),SAPDB_ToString(sid)));
    }
    if(pid == (RTESync_RegionSimulator::Instance()).m_Regions[sid-1]->getLastEntered())
    {
        return true;
    }
    else
    {
        return false;
    }
}

/*---------------------------------------------------------------------------*/
