<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/isteps/istep14/call_proc_exit_cache_contained.C $     */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2016                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
#include <errl/errlentry.H>
#include <errl/errlmanager.H>
#include <errl/errludtarget.H>

#include <isteps/hwpisteperror.H>
#include <initservice/isteps_trace.H>
#include <initservice/taskargs.H>

//  targeting support
#include <targeting/common/commontargeting.H>
#include <targeting/common/util.H>
#include <targeting/common/utilFilter.H>
#include <fapi2/target.H>

//HWP Invoker
#include    <fapi2/plat_hwp_invoker.H>

#include    <p9_exit_cache_contained.H>

#include <sys/mm.h>
#include <arch/pirformat.H>
#include <isteps/hwpf_reasoncodes.H>

// @TODO RTC:134082 remove below block
// Add P9 - Fake trigger for memory expansion
#include <kernel/console.H>                  // printk status
#include <devicefw/userif.H>
#include <config.h>
// @TODO RTC:134082 remove above block

using   namespace   ISTEP;
using   namespace   ISTEP_ERROR;
using   namespace   ERRORLOG;
using   namespace   TARGETING;

namespace ISTEP_14
{
void* call_proc_exit_cache_contained (void *io_pArgs)
{

    IStepError  l_stepError;

    TRACDCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
               "call_proc_exit_cache_contained entry" );

    // @@@@@    CUSTOM BLOCK:   @@@@@
    //  figure out what targets we need
    //  customize any other inputs
    //  set up loops to go through all targets (if parallel, spin off a task)
    //  extend the memory space from 8MEG to 32Meg

    //if mirrored then check that there is going to be memory at that location.
    //For sapphire with mirrored location flipped and at zero,
    //this also insures there is memory available to 'exit_cache' to.
    //Also set ATTR_PAYLOAD_BASE here.
    TARGETING::Target* l_sys = NULL;
    targetService().getTopLevelTarget(l_sys);
    assert( l_sys != NULL );

    errlHndl_t  l_errl  =   NULL;
    uint8_t l_mpipl = l_sys->getAttr<ATTR_IS_MPIPL_HB>();
    ATTR_PAYLOAD_BASE_type payloadBase = 0;

    TARGETING::TargetHandleList l_procList;
    getAllChips(l_procList, TYPE_PROC);

    if(!l_mpipl)
    {
        ATTR_PAYLOAD_IN_MIRROR_MEM_type l_mirrored = false;

        // In Sapphire mode disable mirroring for now - @todo-RTC:108314
        // and force payload to zero
        if(!is_sapphire_load())
        {
            payloadBase = l_sys->getAttr<ATTR_PAYLOAD_BASE>();
            l_mirrored = l_sys->getAttr<ATTR_PAYLOAD_IN_MIRROR_MEM>();
        }

        if(l_mirrored)
        {
            ATTR_MIRROR_BASE_ADDRESS_type l_mirrorBaseAddr = 0;
            if(!is_sapphire_load())
            {
                uint64_t hrmor_base =
                    l_sys->getAttr<TARGETING::ATTR_HB_HRMOR_NODAL_BASE>();

                l_mirrorBaseAddr =
                    l_sys->getAttr<TARGETING::ATTR_MIRROR_BASE_ADDRESS>();

                // For single-node systems, the non-master processors can be
                // in a different logical (powerbus) group.
                // Need to migrate task to master.
                task_affinity_pin();
                task_affinity_migrate_to_master();
                uint64_t this_node = PIR_t(task_getcpuid()).groupId;
                task_affinity_unpin();

                l_mirrorBaseAddr += (this_node * hrmor_base)/2;

            }

            // Verify there is memory at the mirrored location
            bool mirroredMemExists = false;

            for (TargetHandleList::const_iterator proc = l_procList.begin();
                 proc != l_procList.end() && !mirroredMemExists;
                 ++proc)
            {
                uint64_t mirrorBase[sizeof(fapi2::ATTR_PROC_MIRROR_BASES_Type)/sizeof(uint64_t)];
                uint64_t mirrorSize[sizeof(fapi2::ATTR_PROC_MIRROR_SIZES_Type)/sizeof(uint64_t)];
                bool rc = (*proc)->
                    tryGetAttr<TARGETING::ATTR_PROC_MIRROR_BASES>(mirrorBase);
                if(false == rc)
                {
                    TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                              "Failed to get ATTR_PROC_MIRROR_BASES");
                    assert(0);
                }

                rc = (*proc)->
                    tryGetAttr<TARGETING::ATTR_PROC_MIRROR_SIZES>(mirrorSize);
                if(false == rc)
                {
                    TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                              "Failed to get ATTR_PROC_MIRROR_SIZES");
                    assert(0);
                }

                for(uint64_t i = 0;
                i < sizeof(fapi2::ATTR_PROC_MIRROR_BASES_Type) && !mirroredMemExists;
                ++i)
                {
                    if(mirrorSize[i] != 0 &&
                       l_mirrorBaseAddr >= mirrorBase[i] &&
                       l_mirrorBaseAddr < (mirrorBase[i] + mirrorSize[i]))
                    {
                        mirroredMemExists = true;
                    }
                }
            }

            if (mirroredMemExists)
            {
                // ATTR_PAYLOAD_BASE is in MB
                payloadBase += l_mirrorBaseAddr/MEGABYTE;
            }
            else
            {
                TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, ERR_MRK
                          "Request to load payload into mirrored memory,"
                          " but no memory exists at address 0x%016lx",
                          l_mirrorBaseAddr);

                /*@
                 *  @errortype      ERRL_SEV_CRITICAL_SYS_TERM
                 *  @moduleid       fapi::MOD_EXIT_CACHE_CONTAINED,
                 *  @reasoncode     fapi::RC_NO_MIRRORED_MEMORY,
                 *  @userdata1      Mirrored Memory Address
                 *  @userdata2      0
                 *
                 *  @devdesc        Request given to load payload into mirrored
                 *                  memory, but no mirrored memory exists at
                 *                  that location.
                 */
                l_errl = new ERRORLOG::ErrlEntry
                    (
                     ERRORLOG::ERRL_SEV_CRITICAL_SYS_TERM,
                     fapi::MOD_EXIT_CACHE_CONTAINED,
                     fapi::RC_NO_MIRRORED_MEMORY,
                     l_mirrorBaseAddr,
                     0,
                     true); // callout firmware
            }
        }
        // If we're not mirrored, payloadBase is the lowest mem_base.
        // Note that if we are mirrored, finding the correct mirror
        // base yields the proper payloadBase. This should also work
        // for sapphire as a single (working) node will return 0 for
        // bottom_mem_addr.
        else {
            payloadBase += get_bottom_mem_addr()/MEGABYTE;
        }
    }

    if(!l_errl)
    {
        if(!l_mpipl)
        {
            TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                      "Payload base address is 0x%016lx",
                      payloadBase * MEGABYTE);

            l_sys->setAttr<ATTR_PAYLOAD_BASE>(payloadBase);
        }

        for (const auto & l_procChip: l_procList)
        {
            const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>
                l_fapi_cpu_target(l_procChip);
            // call p9_proc_exit_cache_contained.C HWP
            FAPI_INVOKE_HWP( l_errl,
                            p9_exit_cache_contained,
                            l_procChip);

            if(l_errl)
            {
                ErrlUserDetailsTarget(l_procChip).addToLog(l_errl);
                l_stepError.addErrorDetails( l_errl );
                errlCommit( l_errl, HWPF_COMP_ID );
                TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "call_proc_exit_cache_contained:: failed on proc with HUID : %d",TARGETING::get_huid(l_procChip)  );
            }
        }

        // no errors so extend VMM.
        if(!l_errl)
        {
            TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
                       "SUCCESS : call_proc_exit_cache_contained on all procs" );

            // @TODO RTC:134082 remove below block
#ifndef CONFIG_P9_VPO_COMPILE
            // Add P9 - Fake trigger for memory expansion
            TARGETING::Target* l_masterProc = NULL;
            TARGETING::targetService()
              .masterProcChipTargetHandle( l_masterProc );

            uint64_t l_top_addr = get_top_mem_addr();
            uint64_t l_bottom_addr = get_bottom_mem_addr();
            uint64_t l_mem_size = l_top_addr - l_bottom_addr;

            // aggregate scom data to write
            uint64_t l_data[] = {l_bottom_addr,  // Memory Base Address
                                 l_mem_size,     // Memory Size in bytes
                                 1};             // Memory Valid
            uint64_t l_addr = 0x05000000;
            size_t scom_size = sizeof(uint64_t);

            for(uint8_t i = 0;
                i < sizeof(l_data) / sizeof(uint64_t);
                i++)
            {
                l_errl = deviceWrite( l_masterProc,
                                      &(l_data[i]),
                                      scom_size,
                                      DEVICE_SCOM_ADDRESS(l_addr+i) );
                if( l_errl ) { break; }
            }

            if ( l_errl )
            {
                // Create IStep error log and cross reference to error that
                // occurred
                l_stepError.addErrorDetails( l_errl );

                // Commit Error
                errlCommit( l_errl, HWPF_COMP_ID );
            }

            printk("Fake Memory now set up.\n");

            // exit cache contained mode
            l_errl = deviceWrite( l_masterProc,
                                  &(l_data[2]),
                                  scom_size,
                                  DEVICE_SCOM_ADDRESS(l_addr+3) );

            if ( l_errl )
            {
                // Create IStep error log and cross reference to error that
                // occurred
                l_stepError.addErrorDetails( l_errl );

                // Commit Error
                errlCommit( l_errl, HWPF_COMP_ID );
            }

            printk("Cache contained mode has been exited.\n");
            // End of Add P9 - Fake trigger for memory expansion

            //Set PSI and FSP BARs, activate the PSI link BAR
            //TODO RTC 150260 Re-evaluate if this should be deleted or enabled
//            uint64_t psi = l_masterProc->getAttr<ATTR_PSI_BRIDGE_BASE_ADDR>();
            uint64_t fsp = l_masterProc->getAttr<ATTR_FSP_BASE_ADDR>();
//            psi |= 0x1; //turn on enable bit for PSI, FSP is in PSI Init HWP

//            l_errl = deviceWrite( l_masterProc,
//                                  &psi,
//                                  scom_size,
//                                  DEVICE_SCOM_ADDRESS(0x0501290a) );
            if ( l_errl )
            {
                // Create IStep error log and cross reference to error that
                // occurred
                l_stepError.addErrorDetails( l_errl );

                // Commit Error
                errlCommit( l_errl, HWPF_COMP_ID );
            }

            l_errl = deviceWrite( l_masterProc,
                                  &fsp,
                                  scom_size,
                                  DEVICE_SCOM_ADDRESS(0x0501290b) );
            if ( l_errl )
            {
                // Create IStep error log and cross reference to error that
                // occurred
                l_stepError.addErrorDetails( l_errl );

                // Commit Error
                errlCommit( l_errl, HWPF_COMP_ID );
            }

            //Need to default TOD registers to reasonable value
            // aggregate scom data to write
            uint64_t l_tod_data[] = {
                0x40000, 0x4083000000000000,0x4083000000000000,
                0x40001, 0x0008008011000000,0x8000000000000000,
                0x40002, 0x8000000000000000,0x0008008000000000,
                0x40003, 0x0008008000000000,0x8000000011000000,
                0x40004, 0x8000000000000000,0x00C3000000000000,
                0x40005, 0x0800c30000000000,0x00C3000000000000,
                0x40007, 0x6900000000000000,0x0B60000000000000,
                0x40008, 0x06661D0C00000000,0x06C06CCC00000000,
                0x40010, 0x003F000000000000,0x003F000000000000,
                0x40013, 0x8000000000000000,0x0000000000000000,
            };

            // Per Dean, this workaround should be run against all
            // processor chips.
            TARGETING::TargetHandleList l_cpuTargetList;
            getAllChips(l_cpuTargetList, TYPE_PROC);

            uint32_t l_proc_num = 0;
            for (const auto & l_cpu_target: l_cpuTargetList)
            {
                assert((l_proc_num < 2),
                       "TOD hack does not support more then 2 procs");

                for(uint8_t i = 0;
                    i < (sizeof(l_tod_data) / sizeof(uint64_t));
                    i+=3)
                {
                    l_errl = deviceWrite( l_cpu_target,
                                          &(l_tod_data[i+1+l_proc_num]),
                                          scom_size,
                                          DEVICE_SCOM_ADDRESS(l_tod_data[i]) );
                    if( l_errl ) { break; }
                }

                if ( l_errl )
                {
                    // Create IStep error log and cross reference to error that
                    // occurred
                    l_stepError.addErrorDetails( l_errl );

                    // Commit Error
                    errlCommit( l_errl, HWPF_COMP_ID );
                }
                l_proc_num++;
            }

            printk("Fake TOD Initialized\n");
#endif
            // @TODO RTC:134082 remove above block

            // Call the function to extend VMM to 32MEG
            int rc = mm_extend();

            if (rc!=0)
            {
                /*@
                 * @errortype
                 * @moduleid     fapi::MOD_EXIT_CACHE_CONTAINED
                 * @reasoncode   fapi::RC_MM_EXTEND_FAILED
                 * @userdata1    rc from mm_extend
                 * @userdata2    <UNUSED>
                 *
                 *   @devdesc  Failure extending memory to 32MEG after
                 *        exiting cache contained mode.
                 */
                l_errl = new ERRORLOG::ErrlEntry
                    (ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                     fapi::MOD_EXIT_CACHE_CONTAINED,
                     fapi::RC_MM_EXTEND_FAILED,
                     rc,
                     0);

                TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                          "ERROR : call_proc_exit_cache_contained"
                          " - extendVMM, rc=0x%x",
                          rc );
            }
            else
            {
                // trace out the extend VMM was successful
                TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                          "SUCCESS : call_proc_exit_cache_contained"
                          " - extendVMM");
            }
        }
    }
    if ( l_errl )
    {
        // Create IStep error log and cross reference to error that occurred
        l_stepError.addErrorDetails( l_errl );

        // Commit Error
        errlCommit( l_errl, HWPF_COMP_ID );
    }

    TRACDCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
               "call_proc_exit_cache_contained exit" );
    // @@@@@    END CUSTOM BLOCK:   @@@@@

    // end task, returning any errorlogs to IStepDisp
   return l_stepError.getErrorHandle();
}

};
<commit_msg>Remove Memory expansion and TOD hack from call_proc_exit_cache_contained<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/isteps/istep14/call_proc_exit_cache_contained.C $     */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2016                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
#include <errl/errlentry.H>
#include <errl/errlmanager.H>
#include <errl/errludtarget.H>

#include <isteps/hwpisteperror.H>
#include <initservice/isteps_trace.H>
#include <initservice/taskargs.H>

//  targeting support
#include <targeting/common/commontargeting.H>
#include <targeting/common/util.H>
#include <targeting/common/utilFilter.H>
#include <fapi2/target.H>

//HWP Invoker
#include    <fapi2/plat_hwp_invoker.H>
#include    <p9_misc_scom_addresses.H>
#include    <p9_exit_cache_contained.H>

#include <sys/mm.h>
#include <arch/pirformat.H>
#include <isteps/hwpf_reasoncodes.H>

// @TODO RTC:134082 remove below block
// Add P9 - Fake trigger for memory expansion
#include <kernel/console.H>                  // printk status
#include <devicefw/userif.H>
#include <config.h>
#include <util/misc.H>
// @TODO RTC:134082 remove above block

using   namespace   ISTEP;
using   namespace   ISTEP_ERROR;
using   namespace   ERRORLOG;
using   namespace   TARGETING;

//Simics only register to trigger exit of cache containment
#define EXIT_CACHE_CONTAINED_SCOM_ADDR 0x0000000005000003

namespace ISTEP_14
{
void* call_proc_exit_cache_contained (void *io_pArgs)
{

    IStepError  l_stepError;

    TRACDCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
               "call_proc_exit_cache_contained entry" );

    // @@@@@    CUSTOM BLOCK:   @@@@@
    //  figure out what targets we need
    //  customize any other inputs
    //  set up loops to go through all targets (if parallel, spin off a task)
    //  extend the memory space from 8MEG to 32Meg

    //if mirrored then check that there is going to be memory at that location.
    //For sapphire with mirrored location flipped and at zero,
    //this also insures there is memory available to 'exit_cache' to.
    //Also set ATTR_PAYLOAD_BASE here.
    TARGETING::Target* l_sys = NULL;
    targetService().getTopLevelTarget(l_sys);
    assert( l_sys != NULL );

    errlHndl_t  l_errl  =   NULL;
    uint8_t l_mpipl = l_sys->getAttr<ATTR_IS_MPIPL_HB>();
    ATTR_PAYLOAD_BASE_type payloadBase = 0;

    TARGETING::TargetHandleList l_procList;
    getAllChips(l_procList, TYPE_PROC);

    if(!l_mpipl)
    {
        ATTR_PAYLOAD_IN_MIRROR_MEM_type l_mirrored = false;

        // In Sapphire mode disable mirroring for now - @todo-RTC:108314
        // and force payload to zero
        if(!is_sapphire_load())
        {
            payloadBase = l_sys->getAttr<ATTR_PAYLOAD_BASE>();
            l_mirrored = l_sys->getAttr<ATTR_PAYLOAD_IN_MIRROR_MEM>();
        }

        if(l_mirrored)
        {
            ATTR_MIRROR_BASE_ADDRESS_type l_mirrorBaseAddr = 0;
            if(!is_sapphire_load())
            {
                uint64_t hrmor_base =
                    l_sys->getAttr<TARGETING::ATTR_HB_HRMOR_NODAL_BASE>();

                l_mirrorBaseAddr =
                    l_sys->getAttr<TARGETING::ATTR_MIRROR_BASE_ADDRESS>();

                // For single-node systems, the non-master processors can be
                // in a different logical (powerbus) group.
                // Need to migrate task to master.
                task_affinity_pin();
                task_affinity_migrate_to_master();
                uint64_t this_node = PIR_t(task_getcpuid()).groupId;
                task_affinity_unpin();

                l_mirrorBaseAddr += (this_node * hrmor_base)/2;

            }

            // Verify there is memory at the mirrored location
            bool mirroredMemExists = false;

            for (TargetHandleList::const_iterator proc = l_procList.begin();
                 proc != l_procList.end() && !mirroredMemExists;
                 ++proc)
            {
                uint64_t mirrorBase[sizeof(fapi2::ATTR_PROC_MIRROR_BASES_Type)/sizeof(uint64_t)];
                uint64_t mirrorSize[sizeof(fapi2::ATTR_PROC_MIRROR_SIZES_Type)/sizeof(uint64_t)];
                bool rc = (*proc)->
                    tryGetAttr<TARGETING::ATTR_PROC_MIRROR_BASES>(mirrorBase);
                if(false == rc)
                {
                    TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                              "Failed to get ATTR_PROC_MIRROR_BASES");
                    assert(0);
                }

                rc = (*proc)->
                    tryGetAttr<TARGETING::ATTR_PROC_MIRROR_SIZES>(mirrorSize);
                if(false == rc)
                {
                    TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                              "Failed to get ATTR_PROC_MIRROR_SIZES");
                    assert(0);
                }

                for(uint64_t i = 0;
                i < sizeof(fapi2::ATTR_PROC_MIRROR_BASES_Type) && !mirroredMemExists;
                ++i)
                {
                    if(mirrorSize[i] != 0 &&
                       l_mirrorBaseAddr >= mirrorBase[i] &&
                       l_mirrorBaseAddr < (mirrorBase[i] + mirrorSize[i]))
                    {
                        mirroredMemExists = true;
                    }
                }
            }

            if (mirroredMemExists)
            {
                // ATTR_PAYLOAD_BASE is in MB
                payloadBase += l_mirrorBaseAddr/MEGABYTE;
            }
            else
            {
                TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, ERR_MRK
                          "Request to load payload into mirrored memory,"
                          " but no memory exists at address 0x%016lx",
                          l_mirrorBaseAddr);

                /*@
                 *  @errortype      ERRL_SEV_CRITICAL_SYS_TERM
                 *  @moduleid       fapi::MOD_EXIT_CACHE_CONTAINED,
                 *  @reasoncode     fapi::RC_NO_MIRRORED_MEMORY,
                 *  @userdata1      Mirrored Memory Address
                 *  @userdata2      0
                 *
                 *  @devdesc        Request given to load payload into mirrored
                 *                  memory, but no mirrored memory exists at
                 *                  that location.
                 */
                l_errl = new ERRORLOG::ErrlEntry
                    (
                     ERRORLOG::ERRL_SEV_CRITICAL_SYS_TERM,
                     fapi::MOD_EXIT_CACHE_CONTAINED,
                     fapi::RC_NO_MIRRORED_MEMORY,
                     l_mirrorBaseAddr,
                     0,
                     true); // callout firmware
            }
        }
        // If we're not mirrored, payloadBase is the lowest mem_base.
        // Note that if we are mirrored, finding the correct mirror
        // base yields the proper payloadBase. This should also work
        // for sapphire as a single (working) node will return 0 for
        // bottom_mem_addr.
        else {
            payloadBase += get_bottom_mem_addr()/MEGABYTE;
        }
    }

    if(!l_errl)
    {
        if(!l_mpipl)
        {
            TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                      "Payload base address is 0x%016lx",
                      payloadBase * MEGABYTE);

            l_sys->setAttr<ATTR_PAYLOAD_BASE>(payloadBase);
        }

        for (const auto & l_procChip: l_procList)
        {
            const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>
                l_fapi_cpu_target(l_procChip);
            // call p9_proc_exit_cache_contained.C HWP
            FAPI_INVOKE_HWP( l_errl,
                            p9_exit_cache_contained,
                            l_procChip);

            if(l_errl)
            {
                ErrlUserDetailsTarget(l_procChip).addToLog(l_errl);
                l_stepError.addErrorDetails( l_errl );
                errlCommit( l_errl, HWPF_COMP_ID );
                TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "call_proc_exit_cache_contained:: failed on proc with HUID : %d",TARGETING::get_huid(l_procChip)  );
            }
        }

        // no errors so extend Virtual Memory Map
        if(!l_errl)
        {
            TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
                       "SUCCESS : call_proc_exit_cache_contained on all procs" );

            size_t scom_size = sizeof(uint64_t);
            TARGETING::Target* l_masterProc = NULL;
            TARGETING::targetService()
            .masterProcChipTargetHandle( l_masterProc );

            if(Util::isSimicsRunning())
            {
                uint64_t l_memory_valid = 1;
                // exit cache contained mode
                l_errl = deviceWrite( l_masterProc,
                                &l_memory_valid,  //Memory is valid
                                scom_size, //Size of Scom
                                DEVICE_SCOM_ADDRESS(EXIT_CACHE_CONTAINED_SCOM_ADDR));

                if ( l_errl )
                {
                    // Create IStep error log and cross reference to error that
                    // occurred
                    l_stepError.addErrorDetails( l_errl );

                    // Commit Error
                    errlCommit( l_errl, HWPF_COMP_ID );
                }
            }

            //Set PSI and FSP BARs, activate the PSI link BAR
            //TODO RTC 150260 Re-evaluate if this should be deleted or enabled
//            uint64_t psi = l_masterProc->getAttr<ATTR_PSI_BRIDGE_BASE_ADDR>();
            uint64_t fsp = l_masterProc->getAttr<ATTR_FSP_BASE_ADDR>();
//            psi |= 0x1; //turn on enable bit for PSI, FSP is in PSI Init HWP

//            l_errl = deviceWrite( l_masterProc,
//                                  &psi,
//                                  scom_size,
//                                  DEVICE_SCOM_ADDRESS(PU_PSI_BRIDGE_BAR_REG) );
            if ( l_errl )
            {
                // Create IStep error log and cross reference to error that
                // occurred
                l_stepError.addErrorDetails( l_errl );

                // Commit Error
                errlCommit( l_errl, HWPF_COMP_ID );
            }

            l_errl = deviceWrite( l_masterProc,
                                  &fsp,
                                  scom_size,
                                  DEVICE_SCOM_ADDRESS(PU_PSI_BRIDGE_FSP_BAR_REG) );
            if ( l_errl )
            {
                // Create IStep error log and cross reference to error that
                // occurred
                l_stepError.addErrorDetails( l_errl );

                // Commit Error
                errlCommit( l_errl, HWPF_COMP_ID );
            }

            // Call the function to extend VMM to 32MEG
            int rc = mm_extend();

            if (rc!=0)
            {
                /*@
                 * @errortype
                 * @moduleid     fapi::MOD_EXIT_CACHE_CONTAINED
                 * @reasoncode   fapi::RC_MM_EXTEND_FAILED
                 * @userdata1    rc from mm_extend
                 * @userdata2    <UNUSED>
                 *
                 *   @devdesc  Failure extending memory to 32MEG after
                 *        exiting cache contained mode.
                 */
                l_errl = new ERRORLOG::ErrlEntry
                    (ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                     fapi::MOD_EXIT_CACHE_CONTAINED,
                     fapi::RC_MM_EXTEND_FAILED,
                     rc,
                     0);

                TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                          "ERROR : call_proc_exit_cache_contained"
                          " - extendVMM, rc=0x%x",
                          rc );
            }
            else
            {
                // trace out the extend VMM was successful
                TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                          "SUCCESS : call_proc_exit_cache_contained"
                          " - extendVMM");
            }
        }
    }
    if ( l_errl )
    {
        // Create IStep error log and cross reference to error that occurred
        l_stepError.addErrorDetails( l_errl );

        // Commit Error
        errlCommit( l_errl, HWPF_COMP_ID );
    }

    TRACDCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
               "call_proc_exit_cache_contained exit" );
    // @@@@@    END CUSTOM BLOCK:   @@@@@

    // end task, returning any errorlogs to IStepDisp
   return l_stepError.getErrorHandle();
}

};
<|endoftext|>


<commit_before>/* Copyright 2016 Google Inc. 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.
==============================================================================*/

// Run with:
// bazel run -c opt --dynamic_mode=off \
// tensorflow_serving/core:aspired_versions_manager_benchmark --
// --benchmarks=.
// For a longer run time and more consistent results, consider a min time
// e.g.: --benchmark_min_time=60.0

#include <algorithm>
#include <functional>
#include <memory>
#include <string>
#include <vector>

#include "tensorflow/core/kernels/batching_util/periodic_function.h"
#include "tensorflow/core/lib/core/notification.h"
#include "tensorflow/core/lib/core/status.h"
#include "tensorflow/core/lib/core/threadpool.h"
#include "tensorflow/core/lib/random/philox_random.h"
#include "tensorflow/core/lib/random/simple_philox.h"
#include "tensorflow/core/lib/strings/strcat.h"
#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/platform/init_main.h"
#include "tensorflow/core/platform/logging.h"
#include "tensorflow/core/platform/mutex.h"
#include "tensorflow/core/platform/test.h"
#include "tensorflow/core/platform/test_benchmark.h"
#include "tensorflow/core/platform/types.h"
#include "tensorflow_serving/core/aspired_version_policy.h"
#include "tensorflow_serving/core/aspired_versions_manager.h"
#include "tensorflow_serving/core/availability_preserving_policy.h"
#include "tensorflow_serving/core/loader.h"
#include "tensorflow_serving/core/manager.h"
#include "tensorflow_serving/core/servable_data.h"
#include "tensorflow_serving/core/servable_handle.h"
#include "tensorflow_serving/core/simple_loader.h"
#include "tensorflow_serving/core/test_util/manager_test_util.h"

namespace tensorflow {
namespace serving {
namespace {

constexpr char kServableName[] = "kServableName";

// Benchmarks for read performance of the AspiredVersionsManager class both with
// and without concurrent updates. These simulate the common expected access
// pattern of AspiredVersionsManager for systems with high read rates and low
// update rates.
//
// This class maintains all state for a benchmark and handles the concurrency
// concerns around the concurrent read and update threads.
//
// Example:
//    BenchmarkState state;
//    state.RunBenchmark(42 /* iters */, 5 /* num_threads */);
class BenchmarkState {
 public:
  BenchmarkState(const int interval_micros, const bool do_work)
      : interval_micros_(interval_micros), do_work_(do_work) {
    AspiredVersionsManager::Options options;
    // Do policy thread won't be run automatically.
    options.manage_state_interval_micros = -1;
    options.aspired_version_policy.reset(new AvailabilityPreservingPolicy());
    TF_CHECK_OK(AspiredVersionsManager::Create(std::move(options), &manager_));
  }

  // Actually perform iters reads on the fast read ptr.
  void RunBenchmark(::testing::benchmark::State& state, int num_threads);

 private:
  void SetUp();
  void TearDown();

  // Runs iters number of reads.
  void RunReads(int iters);

  // Runs continuously after setup and until teardown, if interval_micros was
  // greater than 0.
  void RunUpdate();

  // Starts serving this loader version.
  void StartServing(int64 loader_version);

  // Gets the latest version of the loader available for serving.
  int64 GetLatestVersion(bool do_work);

  // To avoid having the benchmark timing include time spent scheduling threads,
  // we use this notification to notify when the read threads should begin.
  // This is notified immediately after the benchmark timing is started.
  Notification all_read_threads_scheduled_;

  // Store the update thread as it is only safe to complete teardown and
  // destruct state after it has exited.
  std::unique_ptr<PeriodicFunction> update_thread_;

  // The AspiredVersionsManager being benchmarked primarily for read
  // performance.
  std::unique_ptr<AspiredVersionsManager> manager_;

  // Interval in microseconds for running the update thread.
  const int interval_micros_;

  // In each iteration, to simulate a more realistic access pattern that does
  // more than content for the mutex.
  bool do_work_;
};

void BenchmarkState::StartServing(const int64 loader_version) {
  std::unique_ptr<Loader> loader(new SimpleLoader<int64>(
      [loader_version](std::unique_ptr<int64>* const servable) {
        servable->reset(new int64);
        **servable = loader_version;
        return Status::OK();
      },
      SimpleLoader<int64>::EstimateNoResources()));
  std::vector<ServableData<std::unique_ptr<Loader>>> versions;
  versions.push_back({{kServableName, loader_version}, std::move(loader)});
  manager_->GetAspiredVersionsCallback()(kServableName, std::move(versions));
  test_util::AspiredVersionsManagerTestAccess(manager_.get())
      .HandlePendingAspiredVersionsRequests();
  // Will load the latest.
  test_util::AspiredVersionsManagerTestAccess(manager_.get())
      .InvokePolicyAndExecuteAction();
  // Will quiesce the previous.
  test_util::AspiredVersionsManagerTestAccess(manager_.get())
      .InvokePolicyAndExecuteAction();
  // Will delete the previous.
  test_util::AspiredVersionsManagerTestAccess(manager_.get())
      .InvokePolicyAndExecuteAction();
  CHECK_EQ(1, manager_->ListAvailableServableIds().size());
}

int64 BenchmarkState::GetLatestVersion(const bool do_work) {
  ServableHandle<int64> handle;
  const Status status = manager_->GetServableHandle(
      ServableRequest::Latest(kServableName), &handle);
  TF_CHECK_OK(status) << status;
  if (do_work) {
    // Let's do some work, so that we are not just measuring contention in the
    // mutex.
    float count = 0;
    for (int i = 1; i < 10000; ++i) {
      count *= i;
    }
    CHECK_GE(count, 0);
  }

  return *handle;
}

void BenchmarkState::RunUpdate() { StartServing(GetLatestVersion(false) + 1); }

void BenchmarkState::SetUp() {
  StartServing(0);
  if (interval_micros_ > 0) {
    PeriodicFunction::Options pf_options;
    pf_options.thread_name_prefix =
        "AspiredVersionsManager_Benchmark_Update_Thread";
    update_thread_.reset(new PeriodicFunction([this] { RunUpdate(); },
                                              interval_micros_, pf_options));
  }
}

void BenchmarkState::TearDown() {
  // Destruct the update thread which blocks until it exits.
  update_thread_.reset();
}

void BenchmarkState::RunReads(int iters) {
  for (int i = 0; i < iters; ++i) {
    // Prevents the compiler from optimizing this away.
    CHECK_GE(GetLatestVersion(do_work_), 0);
  }
}

void BenchmarkState::RunBenchmark(::testing::benchmark::State& state,
                                  int num_threads) {
  SetUp();

  // To be compatible with the Google benchmark framework, the tensorflow new
  // benchmark API requires that each benchmark routine has exactly one.
  // `for (auto s : state)` benchmark loop (in all threads).
  // Therefore we cannot have multiple threads executing the same for-each loop.
  // We need to introduce a new parameter for the fixed number of iteration in
  // each thread.

  // Pick a reasonably large value.
  const int kSubIters = 500;

  // The benchmark timing loop. Timer automatically starts/stops.
  // In each iteration, we spin up a thread-pool and execute kSubIters in each
  // thread.
  for (auto s : state) {
    // Exclude the scheduling setup time.
    state.PauseTiming();
    std::unique_ptr<thread::ThreadPool> pool(new thread::ThreadPool(
        Env::Default(), "RunBenchmarkReadThread", num_threads));
    for (int thread_index = 0; thread_index < num_threads; ++thread_index) {
      std::function<void()> run_reads_fn = [&]() {
        // Wait until all_read_threads_scheduled_ has been notified.
        all_read_threads_scheduled_.WaitForNotification();
        RunReads(kSubIters);
      };
      pool->Schedule(run_reads_fn);
    }
    state.ResumeTiming();
    all_read_threads_scheduled_.Notify();

    // Note that destructing the threadpool blocks on completion of all
    // scheduled execution.  This is intentional as we want all threads to
    // complete iters iterations.  It also means that the timing may be off
    // (work done == iters * num_threads) and includes time scheduling work on
    // the threads.
    pool.reset();
  }

  state.SetItemsProcessed(num_threads * kSubIters * state.iterations());
  TearDown();
}

void BenchmarkReadsAndUpdates(::testing::benchmark::State& state,
                              int num_threads, int interval_micros,
                              bool do_work) {
  BenchmarkState bm_state(interval_micros, do_work);
  bm_state.RunBenchmark(state, num_threads);
}

void BM_Work_NoUpdates_Reads(::testing::benchmark::State& state) {
  const int num_threads = state.range(0);

  // No updates. 0 interval_micros signals not to update at all.
  BenchmarkReadsAndUpdates(state, num_threads, 0, true);
}

void BM_Work_FrequentUpdates_Reads(::testing::benchmark::State& state) {
  const int num_threads = state.range(0);

  // Frequent updates: 1000 micros == 1 millisecond or 1000qps of updates
  BenchmarkReadsAndUpdates(state, num_threads, 1000, true);
}

void BM_NoWork_NoUpdates_Reads(::testing::benchmark::State& state) {
  const int num_threads = state.range(0);

  // No updates. 0 interval_micros signals not to update at all.
  BenchmarkReadsAndUpdates(state, num_threads, 0, false);
}

void BM_NoWork_FrequentUpdates_Reads(::testing::benchmark::State& state) {
  const int num_threads = state.range(0);

  // Frequent updates: 1000 micros == 1 millisecond or 1000qps of updates
  BenchmarkReadsAndUpdates(state, num_threads, 1000, false);
}

// The benchmarking system by default uses cpu time to calculate items per
// second, which would include time spent by all the threads on the cpu.
// Instead of that we use real-time here so that we can see items/s increasing
// with increasing threads, which is easier to understand.
BENCHMARK(BM_Work_NoUpdates_Reads)
    ->UseRealTime()
    ->Arg(1)
    ->Arg(2)
    ->Arg(4)
    ->Arg(8)
    ->Arg(16)
    ->Arg(32)
    ->Arg(64);

BENCHMARK(BM_Work_FrequentUpdates_Reads)
    ->UseRealTime()
    ->Arg(1)
    ->Arg(2)
    ->Arg(4)
    ->Arg(8)
    ->Arg(16)
    ->Arg(32)
    ->Arg(64);

BENCHMARK(BM_NoWork_NoUpdates_Reads)
    ->UseRealTime()
    ->Arg(1)
    ->Arg(2)
    ->Arg(4)
    ->Arg(8)
    ->Arg(16)
    ->Arg(32)
    ->Arg(64);

BENCHMARK(BM_NoWork_FrequentUpdates_Reads)
    ->UseRealTime()
    ->Arg(1)
    ->Arg(2)
    ->Arg(4)
    ->Arg(8)
    ->Arg(16)
    ->Arg(32)
    ->Arg(64);

void BM_GetServableHandle(::testing::benchmark::State& state) {
  // Number of different servable streams.
  constexpr int kNumServableStreams = 10;
  // Number of versions of a particular servable stream.
  constexpr int kNumServableVersions = 2;

  static AspiredVersionsManager* const manager = []() {
    AspiredVersionsManager::Options options;
    // Do policy thread won't be run automatically.
    options.manage_state_interval_micros = -1;
    options.aspired_version_policy.reset(new AvailabilityPreservingPolicy());
    std::unique_ptr<AspiredVersionsManager> manager;
    TF_CHECK_OK(AspiredVersionsManager::Create(std::move(options), &manager));
    auto aspired_versions_callback = manager->GetAspiredVersionsCallback();
    for (int i = 0; i < kNumServableStreams; ++i) {
      const string servable_name = strings::StrCat(kServableName, i);
      std::vector<ServableData<std::unique_ptr<Loader>>> versions;
      for (int j = 0; j < kNumServableVersions; ++j) {
        std::unique_ptr<Loader> loader(new SimpleLoader<int64>(
            [j](std::unique_ptr<int64>* const servable) {
              servable->reset(new int64);
              **servable = j;
              return Status::OK();
            },
            SimpleLoader<int64>::EstimateNoResources()));
        versions.push_back({{servable_name, j}, std::move(loader)});
      }

      aspired_versions_callback(servable_name, std::move(versions));
      test_util::AspiredVersionsManagerTestAccess(manager.get())
          .HandlePendingAspiredVersionsRequests();
      for (int j = 0; j < kNumServableVersions; ++j) {
        test_util::AspiredVersionsManagerTestAccess(manager.get())
            .InvokePolicyAndExecuteAction();
      }
    }
    return manager.release();
  }();
  CHECK_EQ(kNumServableStreams * kNumServableVersions,
           manager->ListAvailableServableIds().size());

  constexpr int kNumRequests = 1024;
  // Ratio of requests which are asking for the latest servable as opposed to a
  // specific version.
  constexpr float kLatestRatio = 0.8;
  static const std::vector<ServableRequest>& requests = []() {
    std::unique_ptr<std::vector<ServableRequest>> requests(
        new std::vector<ServableRequest>());
    random::PhiloxRandom philox(testing::RandomSeed());
    random::SimplePhilox random(&philox);
    for (int i = 0; i < kNumRequests; ++i) {
      const string name =
          strings::StrCat(kServableName, random.Uniform(kNumServableStreams));
      if (random.RandFloat() > kLatestRatio) {
        const int64 version = random.Uniform(kNumServableVersions);
        requests->push_back(ServableRequest::Specific(name, version));
      } else {
        requests->push_back(ServableRequest::Latest(name));
      }
    }
    return *requests.release();
  }();

  ServableHandle<int64> handle;
  int i = 0;
  for (auto s : state) {
    const Status status =
        manager->GetServableHandle(requests[i % kNumRequests], &handle);
    TF_CHECK_OK(status) << status;
    ++i;
  }
  state.SetItemsProcessed(state.iterations());
}
BENCHMARK(BM_GetServableHandle);

}  // namespace
}  // namespace serving
}  // namespace tensorflow

int main(int argc, char** argv) {
  tensorflow::port::InitMain(argv[0], &argc, &argv);
  tensorflow::testing::RunBenchmarks();
  return 0;
}
<commit_msg>Fix aspired_versions_manager_benchmark test failure - eliminate redundant notification<commit_after>/* Copyright 2016 Google Inc. 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.
==============================================================================*/

// Run with:
// bazel run -c opt --dynamic_mode=off \
// tensorflow_serving/core:aspired_versions_manager_benchmark --
// --benchmarks=.
// For a longer run time and more consistent results, consider a min time
// e.g.: --benchmark_min_time=60.0

#include <algorithm>
#include <functional>
#include <memory>
#include <string>
#include <vector>

#include "tensorflow/core/kernels/batching_util/periodic_function.h"
#include "tensorflow/core/lib/core/notification.h"
#include "tensorflow/core/lib/core/status.h"
#include "tensorflow/core/lib/core/threadpool.h"
#include "tensorflow/core/lib/random/philox_random.h"
#include "tensorflow/core/lib/random/simple_philox.h"
#include "tensorflow/core/lib/strings/strcat.h"
#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/platform/init_main.h"
#include "tensorflow/core/platform/logging.h"
#include "tensorflow/core/platform/mutex.h"
#include "tensorflow/core/platform/test.h"
#include "tensorflow/core/platform/test_benchmark.h"
#include "tensorflow/core/platform/types.h"
#include "tensorflow_serving/core/aspired_version_policy.h"
#include "tensorflow_serving/core/aspired_versions_manager.h"
#include "tensorflow_serving/core/availability_preserving_policy.h"
#include "tensorflow_serving/core/loader.h"
#include "tensorflow_serving/core/manager.h"
#include "tensorflow_serving/core/servable_data.h"
#include "tensorflow_serving/core/servable_handle.h"
#include "tensorflow_serving/core/simple_loader.h"
#include "tensorflow_serving/core/test_util/manager_test_util.h"

namespace tensorflow {
namespace serving {
namespace {

constexpr char kServableName[] = "kServableName";

// Benchmarks for read performance of the AspiredVersionsManager class both with
// and without concurrent updates. These simulate the common expected access
// pattern of AspiredVersionsManager for systems with high read rates and low
// update rates.
//
// This class maintains all state for a benchmark and handles the concurrency
// concerns around the concurrent read and update threads.
//
// Example:
//    BenchmarkState state;
//    state.RunBenchmark(42 /* iters */, 5 /* num_threads */);
class BenchmarkState {
 public:
  BenchmarkState(const int interval_micros, const bool do_work)
      : interval_micros_(interval_micros), do_work_(do_work) {
    AspiredVersionsManager::Options options;
    // Do policy thread won't be run automatically.
    options.manage_state_interval_micros = -1;
    options.aspired_version_policy.reset(new AvailabilityPreservingPolicy());
    TF_CHECK_OK(AspiredVersionsManager::Create(std::move(options), &manager_));
  }

  // Actually perform iters reads on the fast read ptr.
  void RunBenchmark(::testing::benchmark::State& state, int num_threads);

 private:
  void SetUp();
  void TearDown();

  // Runs iters number of reads.
  void RunReads(int iters);

  // Runs continuously after setup and until teardown, if interval_micros was
  // greater than 0.
  void RunUpdate();

  // Starts serving this loader version.
  void StartServing(int64 loader_version);

  // Gets the latest version of the loader available for serving.
  int64 GetLatestVersion(bool do_work);

  // To avoid having the benchmark timing include time spent scheduling threads,
  // we use this notification to notify when the read threads should begin.
  // This is notified immediately after the benchmark timing is started.
  Notification all_read_threads_scheduled_;

  // Store the update thread as it is only safe to complete teardown and
  // destruct state after it has exited.
  std::unique_ptr<PeriodicFunction> update_thread_;

  // The AspiredVersionsManager being benchmarked primarily for read
  // performance.
  std::unique_ptr<AspiredVersionsManager> manager_;

  // Interval in microseconds for running the update thread.
  const int interval_micros_;

  // In each iteration, to simulate a more realistic access pattern that does
  // more than content for the mutex.
  bool do_work_;
};

void BenchmarkState::StartServing(const int64 loader_version) {
  std::unique_ptr<Loader> loader(new SimpleLoader<int64>(
      [loader_version](std::unique_ptr<int64>* const servable) {
        servable->reset(new int64);
        **servable = loader_version;
        return Status::OK();
      },
      SimpleLoader<int64>::EstimateNoResources()));
  std::vector<ServableData<std::unique_ptr<Loader>>> versions;
  versions.push_back({{kServableName, loader_version}, std::move(loader)});
  manager_->GetAspiredVersionsCallback()(kServableName, std::move(versions));
  test_util::AspiredVersionsManagerTestAccess(manager_.get())
      .HandlePendingAspiredVersionsRequests();
  // Will load the latest.
  test_util::AspiredVersionsManagerTestAccess(manager_.get())
      .InvokePolicyAndExecuteAction();
  // Will quiesce the previous.
  test_util::AspiredVersionsManagerTestAccess(manager_.get())
      .InvokePolicyAndExecuteAction();
  // Will delete the previous.
  test_util::AspiredVersionsManagerTestAccess(manager_.get())
      .InvokePolicyAndExecuteAction();
  CHECK_EQ(1, manager_->ListAvailableServableIds().size());
}

int64 BenchmarkState::GetLatestVersion(const bool do_work) {
  ServableHandle<int64> handle;
  const Status status = manager_->GetServableHandle(
      ServableRequest::Latest(kServableName), &handle);
  TF_CHECK_OK(status) << status;
  if (do_work) {
    // Let's do some work, so that we are not just measuring contention in the
    // mutex.
    float count = 0;
    for (int i = 1; i < 10000; ++i) {
      count *= i;
    }
    CHECK_GE(count, 0);
  }

  return *handle;
}

void BenchmarkState::RunUpdate() { StartServing(GetLatestVersion(false) + 1); }

void BenchmarkState::SetUp() {
  StartServing(0);
  if (interval_micros_ > 0) {
    PeriodicFunction::Options pf_options;
    pf_options.thread_name_prefix =
        "AspiredVersionsManager_Benchmark_Update_Thread";
    update_thread_.reset(new PeriodicFunction([this] { RunUpdate(); },
                                              interval_micros_, pf_options));
  }
}

void BenchmarkState::TearDown() {
  // Destruct the update thread which blocks until it exits.
  update_thread_.reset();
}

void BenchmarkState::RunReads(int iters) {
  for (int i = 0; i < iters; ++i) {
    // Prevents the compiler from optimizing this away.
    CHECK_GE(GetLatestVersion(do_work_), 0);
  }
}

void BenchmarkState::RunBenchmark(::testing::benchmark::State& state,
                                  int num_threads) {
  SetUp();

  // To be compatible with the Google benchmark framework, the tensorflow new
  // benchmark API requires that each benchmark routine has exactly one.
  // `for (auto s : state)` benchmark loop (in all threads).
  // Therefore we cannot have multiple threads executing the same for-each loop.
  // We need to introduce a new parameter for the fixed number of iteration in
  // each thread.

  // Pick a reasonably large value.
  const int kSubIters = 500;

  // The benchmark timing loop. Timer automatically starts/stops.
  // In each iteration, we spin up a thread-pool and execute kSubIters in each
  // thread.
  for (auto s : state) {
    // Exclude the scheduling setup time.
    state.PauseTiming();
    std::unique_ptr<thread::ThreadPool> pool(new thread::ThreadPool(
        Env::Default(), "RunBenchmarkReadThread", num_threads));
    for (int thread_index = 0; thread_index < num_threads; ++thread_index) {
      std::function<void()> run_reads_fn = [&]() {
        // Wait until all_read_threads_scheduled_ has been notified.
        all_read_threads_scheduled_.WaitForNotification();
        RunReads(kSubIters);
      };
      pool->Schedule(run_reads_fn);
    }
    state.ResumeTiming();
    if (!all_read_threads_scheduled_.HasBeenNotified())
      all_read_threads_scheduled_.Notify();

    // Note that destructing the threadpool blocks on completion of all
    // scheduled execution.  This is intentional as we want all threads to
    // complete iters iterations.  It also means that the timing may be off
    // (work done == iters * num_threads) and includes time scheduling work on
    // the threads.
    pool.reset();
  }

  state.SetItemsProcessed(num_threads * kSubIters * state.iterations());
  TearDown();
}

void BenchmarkReadsAndUpdates(::testing::benchmark::State& state,
                              int num_threads, int interval_micros,
                              bool do_work) {
  BenchmarkState bm_state(interval_micros, do_work);
  bm_state.RunBenchmark(state, num_threads);
}

void BM_Work_NoUpdates_Reads(::testing::benchmark::State& state) {
  const int num_threads = state.range(0);

  // No updates. 0 interval_micros signals not to update at all.
  BenchmarkReadsAndUpdates(state, num_threads, 0, true);
}

void BM_Work_FrequentUpdates_Reads(::testing::benchmark::State& state) {
  const int num_threads = state.range(0);

  // Frequent updates: 1000 micros == 1 millisecond or 1000qps of updates
  BenchmarkReadsAndUpdates(state, num_threads, 1000, true);
}

void BM_NoWork_NoUpdates_Reads(::testing::benchmark::State& state) {
  const int num_threads = state.range(0);

  // No updates. 0 interval_micros signals not to update at all.
  BenchmarkReadsAndUpdates(state, num_threads, 0, false);
}

void BM_NoWork_FrequentUpdates_Reads(::testing::benchmark::State& state) {
  const int num_threads = state.range(0);

  // Frequent updates: 1000 micros == 1 millisecond or 1000qps of updates
  BenchmarkReadsAndUpdates(state, num_threads, 1000, false);
}

// The benchmarking system by default uses cpu time to calculate items per
// second, which would include time spent by all the threads on the cpu.
// Instead of that we use real-time here so that we can see items/s increasing
// with increasing threads, which is easier to understand.
BENCHMARK(BM_Work_NoUpdates_Reads)
    ->UseRealTime()
    ->Arg(1)
    ->Arg(2)
    ->Arg(4)
    ->Arg(8)
    ->Arg(16)
    ->Arg(32)
    ->Arg(64);

BENCHMARK(BM_Work_FrequentUpdates_Reads)
    ->UseRealTime()
    ->Arg(1)
    ->Arg(2)
    ->Arg(4)
    ->Arg(8)
    ->Arg(16)
    ->Arg(32)
    ->Arg(64);

BENCHMARK(BM_NoWork_NoUpdates_Reads)
    ->UseRealTime()
    ->Arg(1)
    ->Arg(2)
    ->Arg(4)
    ->Arg(8)
    ->Arg(16)
    ->Arg(32)
    ->Arg(64);

BENCHMARK(BM_NoWork_FrequentUpdates_Reads)
    ->UseRealTime()
    ->Arg(1)
    ->Arg(2)
    ->Arg(4)
    ->Arg(8)
    ->Arg(16)
    ->Arg(32)
    ->Arg(64);

void BM_GetServableHandle(::testing::benchmark::State& state) {
  // Number of different servable streams.
  constexpr int kNumServableStreams = 10;
  // Number of versions of a particular servable stream.
  constexpr int kNumServableVersions = 2;

  static AspiredVersionsManager* const manager = []() {
    AspiredVersionsManager::Options options;
    // Do policy thread won't be run automatically.
    options.manage_state_interval_micros = -1;
    options.aspired_version_policy.reset(new AvailabilityPreservingPolicy());
    std::unique_ptr<AspiredVersionsManager> manager;
    TF_CHECK_OK(AspiredVersionsManager::Create(std::move(options), &manager));
    auto aspired_versions_callback = manager->GetAspiredVersionsCallback();
    for (int i = 0; i < kNumServableStreams; ++i) {
      const string servable_name = strings::StrCat(kServableName, i);
      std::vector<ServableData<std::unique_ptr<Loader>>> versions;
      for (int j = 0; j < kNumServableVersions; ++j) {
        std::unique_ptr<Loader> loader(new SimpleLoader<int64>(
            [j](std::unique_ptr<int64>* const servable) {
              servable->reset(new int64);
              **servable = j;
              return Status::OK();
            },
            SimpleLoader<int64>::EstimateNoResources()));
        versions.push_back({{servable_name, j}, std::move(loader)});
      }

      aspired_versions_callback(servable_name, std::move(versions));
      test_util::AspiredVersionsManagerTestAccess(manager.get())
          .HandlePendingAspiredVersionsRequests();
      for (int j = 0; j < kNumServableVersions; ++j) {
        test_util::AspiredVersionsManagerTestAccess(manager.get())
            .InvokePolicyAndExecuteAction();
      }
    }
    return manager.release();
  }();
  CHECK_EQ(kNumServableStreams * kNumServableVersions,
           manager->ListAvailableServableIds().size());

  constexpr int kNumRequests = 1024;
  // Ratio of requests which are asking for the latest servable as opposed to a
  // specific version.
  constexpr float kLatestRatio = 0.8;
  static const std::vector<ServableRequest>* requests = []() {
    std::vector<ServableRequest>* requests(new std::vector<ServableRequest>());
    random::PhiloxRandom philox(testing::RandomSeed());
    random::SimplePhilox random(&philox);
    for (int i = 0; i < kNumRequests; ++i) {
      const string name =
          strings::StrCat(kServableName, random.Uniform(kNumServableStreams));
      if (random.RandFloat() > kLatestRatio) {
        const int64 version = random.Uniform(kNumServableVersions);
        requests->push_back(ServableRequest::Specific(name, version));
      } else {
        requests->push_back(ServableRequest::Latest(name));
      }
    }
    return requests;
  }();

  ServableHandle<int64> handle;
  int i = 0;
  for (auto s : state) {
    const Status status =
        manager->GetServableHandle(requests->at(i % kNumRequests), &handle);
    TF_CHECK_OK(status) << status;
    ++i;
  }
  state.SetItemsProcessed(state.iterations());
}
BENCHMARK(BM_GetServableHandle);

}  // namespace
}  // namespace serving
}  // namespace tensorflow

int main(int argc, char** argv) {
  tensorflow::port::InitMain(argv[0], &argc, &argv);
  tensorflow::testing::RunBenchmarks();
  return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 Intel Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "xwalk/extensions/extension_process/xwalk_extension_process.h"

#include <string>

#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/message_loop/message_loop.h"
#include "ipc/ipc_switches.h"
#include "ipc/ipc_message_macros.h"
#include "ipc/ipc_sync_channel.h"
#include "xwalk/extensions/common/xwalk_extension_messages.h"

namespace xwalk {
namespace extensions {

XWalkExtensionProcess::XWalkExtensionProcess(
    const IPC::ChannelHandle& channel_handle)
    : shutdown_event_(false, false),
      io_thread_("XWalkExtensionProcess_IOThread") {
  io_thread_.StartWithOptions(
      base::Thread::Options(base::MessageLoop::TYPE_IO, 0));

  extensions_server_.set_permissions_delegate(this);
  CreateBrowserProcessChannel(channel_handle);
}

XWalkExtensionProcess::~XWalkExtensionProcess() {
  // FIXME(jeez): Move this to OnChannelClosing/Error/Disconnected when we have
  // our MessageFilter set.
  extensions_server_.Invalidate();

  shutdown_event_.Signal();
  io_thread_.Stop();
}

bool XWalkExtensionProcess::OnMessageReceived(const IPC::Message& message) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(XWalkExtensionProcess, message)
    IPC_MESSAGE_HANDLER(XWalkExtensionProcessMsg_RegisterExtensions,
                        OnRegisterExtensions)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

namespace {

void ToValueMap(base::ListValue* lv, base::ValueMap* vm) {
  vm->clear();

  for (base::ListValue::iterator it = lv->begin(); it != lv->end(); it++) {
    base::DictionaryValue* dv;
    if (!(*it)->GetAsDictionary(&dv))
      continue;
    for (base::DictionaryValue::Iterator dit(*dv);
        !dit.IsAtEnd(); dit.Advance())
      (*vm)[dit.key()] = dit.value().DeepCopy();
  }
}

}  // namespace

void XWalkExtensionProcess::OnRegisterExtensions(
    const base::FilePath& path, const base::ListValue& browser_variables_lv) {
  if (!path.empty()) {
    std::unique_ptr<base::ValueMap> browser_variables(new base::ValueMap);

    ToValueMap(&const_cast<base::ListValue&>(browser_variables_lv),
          browser_variables.get());

    RegisterExternalExtensionsInDirectory(&extensions_server_, path,
                                          std::move(browser_variables));
  }
  CreateRenderProcessChannel();
}

void XWalkExtensionProcess::CreateBrowserProcessChannel(
    const IPC::ChannelHandle& channel_handle) {
  if (channel_handle.name.empty()) {
    std::string channel_id =
        base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
            switches::kProcessChannelID);
    browser_process_channel_ = IPC::SyncChannel::Create(
        channel_id, IPC::Channel::MODE_CLIENT, this,
        io_thread_.task_runner(), true, &shutdown_event_);
  } else {
    browser_process_channel_ = IPC::SyncChannel::Create(
        channel_handle, IPC::Channel::MODE_CLIENT, this,
        io_thread_.task_runner(), true, &shutdown_event_);
  }
}

void XWalkExtensionProcess::CreateRenderProcessChannel() {
  IPC::ChannelHandle handle(IPC::Channel::GenerateVerifiedChannelID(
      std::string()));
  rp_channel_handle_ = handle;

  render_process_channel_ = IPC::SyncChannel::Create(rp_channel_handle_,
      IPC::Channel::MODE_SERVER, &extensions_server_,
      io_thread_.task_runner(), true, &shutdown_event_);

#if defined(OS_POSIX)
    // On POSIX, pass the server-side file descriptor. We use
    // TakeClientFileDescriptor() instead of GetClientFileDescriptor()
    // since the client-side channel will take ownership of the fd.
    rp_channel_handle_.socket = base::FileDescriptor(
      render_process_channel_->TakeClientFileDescriptor());
#endif

  extensions_server_.Initialize(render_process_channel_.get());

  browser_process_channel_->Send(
      new XWalkExtensionProcessHostMsg_RenderProcessChannelCreated(
          rp_channel_handle_));
}

bool XWalkExtensionProcess::CheckAPIAccessControl(
    const std::string& extension_name,
    const std::string& api_name) {
  PermissionCacheType::iterator iter =
      permission_cache_.find(extension_name + api_name);
  if (iter != permission_cache_.end())
    return iter->second != ALLOW_ONCE;

  RuntimePermission result = UNDEFINED_RUNTIME_PERM;
  browser_process_channel_->Send(
      new XWalkExtensionProcessHostMsg_CheckAPIAccessControl(
          extension_name, api_name, &result));
  DLOG(INFO) << extension_name << "." << api_name << "() --> " << result;
  if (result == ALLOW_SESSION ||
      result == ALLOW_ALWAYS ||
      result == DENY_SESSION ||
      result == DENY_ALWAYS) {
    permission_cache_[extension_name+api_name] = result;
    return (result == ALLOW_SESSION || result == ALLOW_ALWAYS);
  }

  // Could be allow/deny once or undefined here.
  return (result == ALLOW_ONCE);
}

bool XWalkExtensionProcess::RegisterPermissions(
    const std::string& extension_name,
    const std::string& perm_table) {
  bool result = false;
  browser_process_channel_->Send(
      new XWalkExtensionProcessHostMsg_RegisterPermissions(
          extension_name, perm_table, &result));
  return result;
}

}  // namespace extensions
}  // namespace xwalk
<commit_msg>Init IPC attachment broker for extension process<commit_after>// Copyright (c) 2013 Intel Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "xwalk/extensions/extension_process/xwalk_extension_process.h"

#include <string>

#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/message_loop/message_loop.h"
#include "ipc/attachment_broker_privileged.h"
#include "ipc/ipc_switches.h"
#include "ipc/ipc_message_macros.h"
#include "ipc/ipc_sync_channel.h"
#include "xwalk/extensions/common/xwalk_extension_messages.h"

namespace xwalk {
namespace extensions {

XWalkExtensionProcess::XWalkExtensionProcess(
    const IPC::ChannelHandle& channel_handle)
    : shutdown_event_(false, false),
      io_thread_("XWalkExtensionProcess_IOThread") {
  io_thread_.StartWithOptions(
      base::Thread::Options(base::MessageLoop::TYPE_IO, 0));

  extensions_server_.set_permissions_delegate(this);
  CreateBrowserProcessChannel(channel_handle);
}

XWalkExtensionProcess::~XWalkExtensionProcess() {
  // FIXME(jeez): Move this to OnChannelClosing/Error/Disconnected when we have
  // our MessageFilter set.
  extensions_server_.Invalidate();

  shutdown_event_.Signal();
  io_thread_.Stop();
}

bool XWalkExtensionProcess::OnMessageReceived(const IPC::Message& message) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(XWalkExtensionProcess, message)
    IPC_MESSAGE_HANDLER(XWalkExtensionProcessMsg_RegisterExtensions,
                        OnRegisterExtensions)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

namespace {

void ToValueMap(base::ListValue* lv, base::ValueMap* vm) {
  vm->clear();

  for (base::ListValue::iterator it = lv->begin(); it != lv->end(); it++) {
    base::DictionaryValue* dv;
    if (!(*it)->GetAsDictionary(&dv))
      continue;
    for (base::DictionaryValue::Iterator dit(*dv);
        !dit.IsAtEnd(); dit.Advance())
      (*vm)[dit.key()] = dit.value().DeepCopy();
  }
}

}  // namespace

void XWalkExtensionProcess::OnRegisterExtensions(
    const base::FilePath& path, const base::ListValue& browser_variables_lv) {
  if (!path.empty()) {
    std::unique_ptr<base::ValueMap> browser_variables(new base::ValueMap);

    ToValueMap(&const_cast<base::ListValue&>(browser_variables_lv),
          browser_variables.get());

    RegisterExternalExtensionsInDirectory(&extensions_server_, path,
                                          std::move(browser_variables));
  }
  CreateRenderProcessChannel();
}

void XWalkExtensionProcess::CreateBrowserProcessChannel(
    const IPC::ChannelHandle& channel_handle) {
#if USE_ATTACHMENT_BROKER
  IPC::AttachmentBrokerPrivileged::CreateBrokerIfNeeded();
#endif  // USE_ATTACHMENT_BROKER
  if (channel_handle.name.empty()) {
    std::string channel_id =
        base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
            switches::kProcessChannelID);
    browser_process_channel_ = IPC::SyncChannel::Create(
        channel_id, IPC::Channel::MODE_CLIENT, this,
        io_thread_.task_runner(), true, &shutdown_event_);
  } else {
    browser_process_channel_ = IPC::SyncChannel::Create(
        channel_handle, IPC::Channel::MODE_CLIENT, this,
        io_thread_.task_runner(), true, &shutdown_event_);
  }
}

void XWalkExtensionProcess::CreateRenderProcessChannel() {
  IPC::ChannelHandle handle(IPC::Channel::GenerateVerifiedChannelID(
      std::string()));
  rp_channel_handle_ = handle;

  render_process_channel_ = IPC::SyncChannel::Create(rp_channel_handle_,
      IPC::Channel::MODE_SERVER, &extensions_server_,
      io_thread_.task_runner(), true, &shutdown_event_);

#if defined(OS_POSIX)
    // On POSIX, pass the server-side file descriptor. We use
    // TakeClientFileDescriptor() instead of GetClientFileDescriptor()
    // since the client-side channel will take ownership of the fd.
    rp_channel_handle_.socket = base::FileDescriptor(
      render_process_channel_->TakeClientFileDescriptor());
#endif

  extensions_server_.Initialize(render_process_channel_.get());

  browser_process_channel_->Send(
      new XWalkExtensionProcessHostMsg_RenderProcessChannelCreated(
          rp_channel_handle_));
}

bool XWalkExtensionProcess::CheckAPIAccessControl(
    const std::string& extension_name,
    const std::string& api_name) {
  PermissionCacheType::iterator iter =
      permission_cache_.find(extension_name + api_name);
  if (iter != permission_cache_.end())
    return iter->second != ALLOW_ONCE;

  RuntimePermission result = UNDEFINED_RUNTIME_PERM;
  browser_process_channel_->Send(
      new XWalkExtensionProcessHostMsg_CheckAPIAccessControl(
          extension_name, api_name, &result));
  DLOG(INFO) << extension_name << "." << api_name << "() --> " << result;
  if (result == ALLOW_SESSION ||
      result == ALLOW_ALWAYS ||
      result == DENY_SESSION ||
      result == DENY_ALWAYS) {
    permission_cache_[extension_name+api_name] = result;
    return (result == ALLOW_SESSION || result == ALLOW_ALWAYS);
  }

  // Could be allow/deny once or undefined here.
  return (result == ALLOW_ONCE);
}

bool XWalkExtensionProcess::RegisterPermissions(
    const std::string& extension_name,
    const std::string& perm_table) {
  bool result = false;
  browser_process_channel_->Send(
      new XWalkExtensionProcessHostMsg_RegisterPermissions(
          extension_name, perm_table, &result));
  return result;
}

}  // namespace extensions
}  // namespace xwalk
<|endoftext|>


<commit_before>//===- SymbolTable.cpp ----------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "SymbolTable.h"
#include "Config.h"
#include "Error.h"
#include "Symbols.h"
#include "Target.h"

using namespace llvm;
using namespace llvm::object;
using namespace llvm::ELF;

using namespace lld;
using namespace lld::elf2;

SymbolTable::SymbolTable() {}

bool SymbolTable::shouldUseRela() const {
  ELFKind K = getFirstELF()->getELFKind();
  return K == ELF64LEKind || K == ELF64BEKind;
}

void SymbolTable::addFile(std::unique_ptr<InputFile> File) {
  File->parse();
  InputFile *FileP = File.release();
  if (auto *AF = dyn_cast<ArchiveFile>(FileP)) {
    ArchiveFiles.emplace_back(AF);
    for (Lazy &Sym : AF->getLazySymbols())
      addLazy(&Sym);
    return;
  }
  addELFFile(cast<ELFFileBase>(FileP));
}

static TargetInfo *createTarget(uint16_t EMachine) {
  switch (EMachine) {
  case EM_PPC:
    return new PPCTargetInfo();
  case EM_ARM:
    return new ARMTargetInfo();
  case EM_AARCH64:
    return new AArch64TargetInfo();
  case EM_PPC64:
    return new PPC64TargetInfo();
  case EM_X86_64:
    return new X86_64TargetInfo();
  case EM_386:
    return new X86TargetInfo();
  }
  error("Unknown target machine");
}

template <class ELFT>
void SymbolTable::addSyntheticSym(StringRef Name, OutputSection<ELFT> &Section,
                                  typename ELFFile<ELFT>::uintX_t Value) {
  typedef typename DefinedSynthetic<ELFT>::Elf_Sym Elf_Sym;
  auto ESym = new (Alloc) Elf_Sym;
  memset(ESym, 0, sizeof(Elf_Sym));
  ESym->st_value = Value;
  auto Sym = new (Alloc) DefinedSynthetic<ELFT>(Name, *ESym, Section);
  resolve<ELFT>(Sym);
}

template <class ELFT> void SymbolTable::init(uint16_t EMachine) {
  Target.reset(createTarget(EMachine));
  if (Config->Shared)
    return;
  EntrySym = new (Alloc) Undefined<ELFT>("_start", Undefined<ELFT>::Synthetic);
  resolve<ELFT>(EntrySym);

  // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol is magical
  // and is used to produce a R_386_GOTPC relocation.
  // The R_386_GOTPC relocation value doesn't actually depend on the
  // symbol value, so it could use an index of STN_UNDEF which, according to the
  // spec, means the symbol value is 0.
  // Unfortunately both gas and MC keep the _GLOBAL_OFFSET_TABLE_ symbol in
  // the object file.
  // The situation is even stranger on x86_64 where the assembly doesn't
  // need the magical symbol, but gas still puts _GLOBAL_OFFSET_TABLE_ as
  // an undefined symbol in the .o files.
  // Given that the symbol is effectively unused, we just create a dummy
  // hidden one to avoid the undefined symbol error.
  DefinedAbsolute<ELFT>::IgnoreUndef.setVisibility(STV_HIDDEN);
  auto Got = new (Alloc) DefinedAbsolute<ELFT>(
      "_GLOBAL_OFFSET_TABLE_", DefinedAbsolute<ELFT>::IgnoreUndef);
  resolve<ELFT>(Got);
}

template <class ELFT> void SymbolTable::addELFFile(ELFFileBase *File) {
  if (const ELFFileBase *Old = getFirstELF()) {
    if (!Old->isCompatibleWith(*File))
      error(Twine(Old->getName() + " is incompatible with " + File->getName()));
  } else {
    init<ELFT>(File->getEMachine());
  }

  if (auto *O = dyn_cast<ObjectFileBase>(File)) {
    ObjectFiles.emplace_back(O);
    for (SymbolBody *Body : O->getSymbols())
      resolve<ELFT>(Body);
  }

  if (auto *S = dyn_cast<SharedFile<ELFT>>(File)) {
    SharedFiles.emplace_back(S);
    for (SharedSymbol<ELFT> &Body : S->getSharedSymbols())
      resolve<ELFT>(&Body);
  }
}

void SymbolTable::addELFFile(ELFFileBase *File) {
  switch (File->getELFKind()) {
  case ELF32LEKind:
    addELFFile<ELF32LE>(File);
    break;
  case ELF32BEKind:
    addELFFile<ELF32BE>(File);
    break;
  case ELF64LEKind:
    addELFFile<ELF64LE>(File);
    break;
  case ELF64BEKind:
    addELFFile<ELF64BE>(File);
    break;
  }
}

template <class ELFT>
void SymbolTable::dupError(const SymbolBody &Old, const SymbolBody &New) {
  typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym;
  typedef typename ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range;

  const Elf_Sym &OldE = cast<ELFSymbolBody<ELFT>>(Old).Sym;
  const Elf_Sym &NewE = cast<ELFSymbolBody<ELFT>>(New).Sym;
  ELFFileBase *OldFile = nullptr;
  ELFFileBase *NewFile = nullptr;

  for (const std::unique_ptr<ObjectFileBase> &F : ObjectFiles) {
    const auto &File = cast<ObjectFile<ELFT>>(*F);
    Elf_Sym_Range Syms = File.getObj().symbols(File.getSymbolTable());
    if (&OldE > Syms.begin() && &OldE < Syms.end())
      OldFile = F.get();
    if (&NewE > Syms.begin() && &NewE < Syms.end())
      NewFile = F.get();
  }

  error(Twine("duplicate symbol: ") + Old.getName() + " in " +
        OldFile->getName() + " and " + NewFile->getName());
}

// This function resolves conflicts if there's an existing symbol with
// the same name. Decisions are made based on symbol type.
template <class ELFT> void SymbolTable::resolve(SymbolBody *New) {
  Symbol *Sym = insert(New);
  if (Sym->Body == New)
    return;

  SymbolBody *Existing = Sym->Body;

  if (Lazy *L = dyn_cast<Lazy>(Existing)) {
    if (New->isUndefined()) {
      addMemberFile(L);
      return;
    }

    // Found a definition for something also in an archive. Ignore the archive
    // definition.
    Sym->Body = New;
    return;
  }

  // compare() returns -1, 0, or 1 if the lhs symbol is less preferable,
  // equivalent (conflicting), or more preferable, respectively.
  int comp = Existing->compare<ELFT>(New);
  if (comp < 0)
    Sym->Body = New;
  else if (comp == 0)
    dupError<ELFT>(*Existing, *New);
}

Symbol *SymbolTable::insert(SymbolBody *New) {
  // Find an existing Symbol or create and insert a new one.
  StringRef Name = New->getName();
  Symbol *&Sym = Symtab[Name];
  if (!Sym) {
    Sym = new (Alloc) Symbol(New);
    New->setBackref(Sym);
    return Sym;
  }
  New->setBackref(Sym);
  return Sym;
}

void SymbolTable::addLazy(Lazy *New) {
  Symbol *Sym = insert(New);
  if (Sym->Body == New)
    return;
  SymbolBody *Existing = Sym->Body;
  if (Existing->isDefined() || Existing->isLazy())
    return;
  Sym->Body = New;
  assert(Existing->isUndefined() && "Unexpected symbol kind.");
  addMemberFile(New);
}

void SymbolTable::addMemberFile(Lazy *Body) {
  std::unique_ptr<InputFile> File = Body->getMember();

  // getMember returns nullptr if the member was already read from the library.
  if (!File)
    return;

  addFile(std::move(File));
}

namespace lld {
namespace elf2 {
template void SymbolTable::addSyntheticSym(StringRef Name,
                                           OutputSection<ELF32LE> &Section,
                                           ELFFile<ELF32LE>::uintX_t Value);
template void SymbolTable::addSyntheticSym(StringRef Name,
                                           OutputSection<ELF32BE> &Section,
                                           ELFFile<ELF32BE>::uintX_t Value);
template void SymbolTable::addSyntheticSym(StringRef Name,
                                           OutputSection<ELF64LE> &Section,
                                           ELFFile<ELF64LE>::uintX_t Value);
template void SymbolTable::addSyntheticSym(StringRef Name,
                                           OutputSection<ELF64BE> &Section,
                                           ELFFile<ELF64BE>::uintX_t Value);
}
}
<commit_msg>[ELF] Sort a list of cases alphabetically for consistency/clarity. NFC.<commit_after>//===- SymbolTable.cpp ----------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "SymbolTable.h"
#include "Config.h"
#include "Error.h"
#include "Symbols.h"
#include "Target.h"

using namespace llvm;
using namespace llvm::object;
using namespace llvm::ELF;

using namespace lld;
using namespace lld::elf2;

SymbolTable::SymbolTable() {}

bool SymbolTable::shouldUseRela() const {
  ELFKind K = getFirstELF()->getELFKind();
  return K == ELF64LEKind || K == ELF64BEKind;
}

void SymbolTable::addFile(std::unique_ptr<InputFile> File) {
  File->parse();
  InputFile *FileP = File.release();
  if (auto *AF = dyn_cast<ArchiveFile>(FileP)) {
    ArchiveFiles.emplace_back(AF);
    for (Lazy &Sym : AF->getLazySymbols())
      addLazy(&Sym);
    return;
  }
  addELFFile(cast<ELFFileBase>(FileP));
}

static TargetInfo *createTarget(uint16_t EMachine) {
  switch (EMachine) {
  case EM_386:
    return new X86TargetInfo();
  case EM_AARCH64:
    return new AArch64TargetInfo();
  case EM_ARM:
    return new ARMTargetInfo();
  case EM_PPC:
    return new PPCTargetInfo();
  case EM_PPC64:
    return new PPC64TargetInfo();
  case EM_X86_64:
    return new X86_64TargetInfo();
  }
  error("Unknown target machine");
}

template <class ELFT>
void SymbolTable::addSyntheticSym(StringRef Name, OutputSection<ELFT> &Section,
                                  typename ELFFile<ELFT>::uintX_t Value) {
  typedef typename DefinedSynthetic<ELFT>::Elf_Sym Elf_Sym;
  auto ESym = new (Alloc) Elf_Sym;
  memset(ESym, 0, sizeof(Elf_Sym));
  ESym->st_value = Value;
  auto Sym = new (Alloc) DefinedSynthetic<ELFT>(Name, *ESym, Section);
  resolve<ELFT>(Sym);
}

template <class ELFT> void SymbolTable::init(uint16_t EMachine) {
  Target.reset(createTarget(EMachine));
  if (Config->Shared)
    return;
  EntrySym = new (Alloc) Undefined<ELFT>("_start", Undefined<ELFT>::Synthetic);
  resolve<ELFT>(EntrySym);

  // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol is magical
  // and is used to produce a R_386_GOTPC relocation.
  // The R_386_GOTPC relocation value doesn't actually depend on the
  // symbol value, so it could use an index of STN_UNDEF which, according to the
  // spec, means the symbol value is 0.
  // Unfortunately both gas and MC keep the _GLOBAL_OFFSET_TABLE_ symbol in
  // the object file.
  // The situation is even stranger on x86_64 where the assembly doesn't
  // need the magical symbol, but gas still puts _GLOBAL_OFFSET_TABLE_ as
  // an undefined symbol in the .o files.
  // Given that the symbol is effectively unused, we just create a dummy
  // hidden one to avoid the undefined symbol error.
  DefinedAbsolute<ELFT>::IgnoreUndef.setVisibility(STV_HIDDEN);
  auto Got = new (Alloc) DefinedAbsolute<ELFT>(
      "_GLOBAL_OFFSET_TABLE_", DefinedAbsolute<ELFT>::IgnoreUndef);
  resolve<ELFT>(Got);
}

template <class ELFT> void SymbolTable::addELFFile(ELFFileBase *File) {
  if (const ELFFileBase *Old = getFirstELF()) {
    if (!Old->isCompatibleWith(*File))
      error(Twine(Old->getName() + " is incompatible with " + File->getName()));
  } else {
    init<ELFT>(File->getEMachine());
  }

  if (auto *O = dyn_cast<ObjectFileBase>(File)) {
    ObjectFiles.emplace_back(O);
    for (SymbolBody *Body : O->getSymbols())
      resolve<ELFT>(Body);
  }

  if (auto *S = dyn_cast<SharedFile<ELFT>>(File)) {
    SharedFiles.emplace_back(S);
    for (SharedSymbol<ELFT> &Body : S->getSharedSymbols())
      resolve<ELFT>(&Body);
  }
}

void SymbolTable::addELFFile(ELFFileBase *File) {
  switch (File->getELFKind()) {
  case ELF32LEKind:
    addELFFile<ELF32LE>(File);
    break;
  case ELF32BEKind:
    addELFFile<ELF32BE>(File);
    break;
  case ELF64LEKind:
    addELFFile<ELF64LE>(File);
    break;
  case ELF64BEKind:
    addELFFile<ELF64BE>(File);
    break;
  }
}

template <class ELFT>
void SymbolTable::dupError(const SymbolBody &Old, const SymbolBody &New) {
  typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym;
  typedef typename ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range;

  const Elf_Sym &OldE = cast<ELFSymbolBody<ELFT>>(Old).Sym;
  const Elf_Sym &NewE = cast<ELFSymbolBody<ELFT>>(New).Sym;
  ELFFileBase *OldFile = nullptr;
  ELFFileBase *NewFile = nullptr;

  for (const std::unique_ptr<ObjectFileBase> &F : ObjectFiles) {
    const auto &File = cast<ObjectFile<ELFT>>(*F);
    Elf_Sym_Range Syms = File.getObj().symbols(File.getSymbolTable());
    if (&OldE > Syms.begin() && &OldE < Syms.end())
      OldFile = F.get();
    if (&NewE > Syms.begin() && &NewE < Syms.end())
      NewFile = F.get();
  }

  error(Twine("duplicate symbol: ") + Old.getName() + " in " +
        OldFile->getName() + " and " + NewFile->getName());
}

// This function resolves conflicts if there's an existing symbol with
// the same name. Decisions are made based on symbol type.
template <class ELFT> void SymbolTable::resolve(SymbolBody *New) {
  Symbol *Sym = insert(New);
  if (Sym->Body == New)
    return;

  SymbolBody *Existing = Sym->Body;

  if (Lazy *L = dyn_cast<Lazy>(Existing)) {
    if (New->isUndefined()) {
      addMemberFile(L);
      return;
    }

    // Found a definition for something also in an archive. Ignore the archive
    // definition.
    Sym->Body = New;
    return;
  }

  // compare() returns -1, 0, or 1 if the lhs symbol is less preferable,
  // equivalent (conflicting), or more preferable, respectively.
  int comp = Existing->compare<ELFT>(New);
  if (comp < 0)
    Sym->Body = New;
  else if (comp == 0)
    dupError<ELFT>(*Existing, *New);
}

Symbol *SymbolTable::insert(SymbolBody *New) {
  // Find an existing Symbol or create and insert a new one.
  StringRef Name = New->getName();
  Symbol *&Sym = Symtab[Name];
  if (!Sym) {
    Sym = new (Alloc) Symbol(New);
    New->setBackref(Sym);
    return Sym;
  }
  New->setBackref(Sym);
  return Sym;
}

void SymbolTable::addLazy(Lazy *New) {
  Symbol *Sym = insert(New);
  if (Sym->Body == New)
    return;
  SymbolBody *Existing = Sym->Body;
  if (Existing->isDefined() || Existing->isLazy())
    return;
  Sym->Body = New;
  assert(Existing->isUndefined() && "Unexpected symbol kind.");
  addMemberFile(New);
}

void SymbolTable::addMemberFile(Lazy *Body) {
  std::unique_ptr<InputFile> File = Body->getMember();

  // getMember returns nullptr if the member was already read from the library.
  if (!File)
    return;

  addFile(std::move(File));
}

namespace lld {
namespace elf2 {
template void SymbolTable::addSyntheticSym(StringRef Name,
                                           OutputSection<ELF32LE> &Section,
                                           ELFFile<ELF32LE>::uintX_t Value);
template void SymbolTable::addSyntheticSym(StringRef Name,
                                           OutputSection<ELF32BE> &Section,
                                           ELFFile<ELF32BE>::uintX_t Value);
template void SymbolTable::addSyntheticSym(StringRef Name,
                                           OutputSection<ELF64LE> &Section,
                                           ELFFile<ELF64LE>::uintX_t Value);
template void SymbolTable::addSyntheticSym(StringRef Name,
                                           OutputSection<ELF64BE> &Section,
                                           ELFFile<ELF64BE>::uintX_t Value);
}
}
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Id$
 */

#pragma once

#include <xercesc/util/XercesDefs.hpp>
#include <cstdlib>

#if defined(__APPLE__)
    //	Framework includes from ProjectBuilder
    #include <CoreServices/CoreServices.h>
#else
    //	Classic includes otherwise
    #include <Files.h>
#endif

//	Abstract class for files. This could be used to allow multiple file paradigms.
class XMLMacAbstractFile
{
    public:
        XMLMacAbstractFile() {}
        virtual ~XMLMacAbstractFile() {}

        virtual unsigned int currPos() = 0;
        virtual void close() = 0;
        virtual unsigned int size() = 0;
        virtual void open(const XMLCh* const) = 0;
        virtual void openFileToWrite(const XMLCh* const) = 0;
        virtual unsigned int read(const unsigned int, XMLByte* const) = 0;
        virtual void write(const long byteCount, const XMLByte* const buffer) = 0;
        virtual void reset() = 0;
};

//	Concrete file class implemented using raw Carbon file system calls.
class XMLMacFile : public XMLMacAbstractFile
{
    public:
        XMLMacFile() : mFileRefNum(0), mFileValid(false) {}
        virtual ~XMLMacFile();

        unsigned int currPos();
        void close();
        unsigned int size();
        void open(const XMLCh* const);
        void openFileToWrite(const XMLCh* const);
        unsigned int read(const unsigned int, XMLByte* const);
        void write(const long byteCount, const XMLByte* const buffer);
        void reset();

    protected:
        void create(const XMLCh* const);
        void openWithPermission(const XMLCh* const, int macPermission);

        short	mFileRefNum;
        bool	mFileValid;
};

//
//	Support for customized panic handling:
//  The default handling of panics is not very friendly.
//	To replace it with something more friendly, you'll need to:
//		- #define XML_USE_CUSTOM_PANIC_PROC
//		- Write, and link with, XMLCustomPanicProc
//		- Implement your panic handling within XMLCustomPanicProc.
//
extern "C" void XMLCustomPanicProc(XMLPlatformUtils::PanicReasons panicReason, const char* reasonStr);

//	Notes on our Xerces/Mac paths:
//
//	Wherever paths are used in Xerces, this Macintosh port assumes that they'll
//	be in "unix" format, or at least as close as you can get to that on the particular
//	OS. On classic, this means that a path will be a unix style path, separated by '/' and
//	starting with the Mac OS volume name. Since slash is used as the segment separator,
//	any slashes that actually exist in the segment name will be converted to colons
//	(since colon is the Mac OS path separator and would be illegal in a segment name).
//	For Mac OS X, paths are created and parsed using the FSRefMakePath, etc, routines:
//	the major difference will be location of the volume name within the path.
//
//	The routines below help to create and interpret these pathnames for these cases.
//	While the port itself never creates such paths, it does use these same routines to
//	parse them.

//	Convert fom FSRef/FSSpec to a Unicode character string path.
//	Note that you'll need to delete [] that string after you're done with it!
XMLCh*	XMLCreateFullPathFromFSRef(const FSRef& startingRef);
XMLCh*	XMLCreateFullPathFromFSSpec(const FSSpec& startingSpec);

//	Convert from path to FSRef/FSSpec
//	You retain ownership of the pathName.
bool	XMLParsePathToFSRef(const XMLCh* const pathName, FSRef& ref);
bool	XMLParsePathToFSSpec(const XMLCh* const pathName, FSSpec& spec);

//	These routines copy characters between their representation in the Unicode Converter
//	and the representation used by XMLCh. Until a recent change in Xerces, these were
//	sometimes different on the Macintosh (with GCC), but XMLCh is now fixed at 16 bits.
//	Code utilitizing these routines may be phased out in time, as a conversion is no
//	longer necessary.
XMLCh*		CopyUniCharsToXMLChs(const UniChar* src, XMLCh* dst, std::size_t charCount, std::size_t maxChars);
UniChar*	CopyXMLChsToUniChars(const XMLCh* src, UniChar* dst, std::size_t charCount, std::size_t maxChars);
<commit_msg>Add export directives for Mac OS path utility routines (thanks to Urs Muff & Mike Garcia at Quark)<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Id$
 */

#pragma once

#include <xercesc/util/XercesDefs.hpp>
#include <cstdlib>

#if defined(__APPLE__)
    //	Framework includes from ProjectBuilder
    #include <CoreServices/CoreServices.h>
#else
    //	Classic includes otherwise
    #include <Files.h>
#endif

//	Abstract class for files. This could be used to allow multiple file paradigms.
class XMLMacAbstractFile
{
    public:
        XMLMacAbstractFile() {}
        virtual ~XMLMacAbstractFile() {}

        virtual unsigned int currPos() = 0;
        virtual void close() = 0;
        virtual unsigned int size() = 0;
        virtual void open(const XMLCh* const) = 0;
        virtual void openFileToWrite(const XMLCh* const) = 0;
        virtual unsigned int read(const unsigned int, XMLByte* const) = 0;
        virtual void write(const long byteCount, const XMLByte* const buffer) = 0;
        virtual void reset() = 0;
};

//	Concrete file class implemented using raw Carbon file system calls.
class XMLMacFile : public XMLMacAbstractFile
{
    public:
        XMLMacFile() : mFileRefNum(0), mFileValid(false) {}
        virtual ~XMLMacFile();

        unsigned int currPos();
        void close();
        unsigned int size();
        void open(const XMLCh* const);
        void openFileToWrite(const XMLCh* const);
        unsigned int read(const unsigned int, XMLByte* const);
        void write(const long byteCount, const XMLByte* const buffer);
        void reset();

    protected:
        void create(const XMLCh* const);
        void openWithPermission(const XMLCh* const, int macPermission);

        short	mFileRefNum;
        bool	mFileValid;
};

//
//	Support for customized panic handling:
//  The default handling of panics is not very friendly.
//	To replace it with something more friendly, you'll need to:
//		- #define XML_USE_CUSTOM_PANIC_PROC
//		- Write, and link with, XMLCustomPanicProc
//		- Implement your panic handling within XMLCustomPanicProc.
//
extern "C" void XMLCustomPanicProc(XMLPlatformUtils::PanicReasons panicReason, const char* reasonStr);

//	Notes on our Xerces/Mac paths:
//
//	Wherever paths are used in Xerces, this Macintosh port assumes that they'll
//	be in "unix" format, or at least as close as you can get to that on the particular
//	OS. On classic, this means that a path will be a unix style path, separated by '/' and
//	starting with the Mac OS volume name. Since slash is used as the segment separator,
//	any slashes that actually exist in the segment name will be converted to colons
//	(since colon is the Mac OS path separator and would be illegal in a segment name).
//	For Mac OS X, paths are created and parsed using the FSRefMakePath, etc, routines:
//	the major difference will be location of the volume name within the path.
//
//	The routines below help to create and interpret these pathnames for these cases.
//	While the port itself never creates such paths, it does use these same routines to
//	parse them.

//	Convert fom FSRef/FSSpec to a Unicode character string path.
//	Note that you'll need to delete [] that string after you're done with it!
XMLUTIL_EXPORT XMLCh*	XMLCreateFullPathFromFSRef(const FSRef& startingRef);
XMLUTIL_EXPORT XMLCh*	XMLCreateFullPathFromFSSpec(const FSSpec& startingSpec);

//	Convert from path to FSRef/FSSpec
//	You retain ownership of the pathName.
XMLUTIL_EXPORT bool	XMLParsePathToFSRef(const XMLCh* const pathName, FSRef& ref);
XMLUTIL_EXPORT bool	XMLParsePathToFSSpec(const XMLCh* const pathName, FSSpec& spec);

//	These routines copy characters between their representation in the Unicode Converter
//	and the representation used by XMLCh. Until a recent change in Xerces, these were
//	sometimes different on the Macintosh (with GCC), but XMLCh is now fixed at 16 bits.
//	Code utilitizing these routines may be phased out in time, as a conversion is no
//	longer necessary.
XMLUTIL_EXPORT XMLCh*
CopyUniCharsToXMLChs(const UniChar* src, XMLCh* dst, std::size_t charCount, std::size_t maxChars);
XMLUTIL_EXPORT UniChar*
CopyXMLChsToUniChars(const XMLCh* src, UniChar* dst, std::size_t charCount, std::size_t maxChars);
<|endoftext|>