<commit_before>// Copyright (c) 2017 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <wallet/coinselection.h>
#include <privatesend.h>
#include <util.h>
#include <utilmoneystr.h>

// Descending order comparator
struct {
    bool operator()(const OutputGroup& a, const OutputGroup& b) const
    {
        return a.effective_value > b.effective_value;
    }
} descending;

/*
 * This is the Branch and Bound Coin Selection algorithm designed by Murch. It searches for an input
 * set that can pay for the spending target and does not exceed the spending target by more than the
 * cost of creating and spending a change output. The algorithm uses a depth-first search on a binary
 * tree. In the binary tree, each node corresponds to the inclusion or the omission of a UTXO. UTXOs
 * are sorted by their effective values and the trees is explored deterministically per the inclusion
 * branch first. At each node, the algorithm checks whether the selection is within the target range.
 * While the selection has not reached the target range, more UTXOs are included. When a selection's
 * value exceeds the target range, the complete subtree deriving from this selection can be omitted.
 * At that point, the last included UTXO is deselected and the corresponding omission branch explored
 * instead. The search ends after the complete tree has been searched or after a limited number of tries.
 *
 * The search continues to search for better solutions after one solution has been found. The best
 * solution is chosen by minimizing the waste metric. The waste metric is defined as the cost to
 * spend the current inputs at the given fee rate minus the long term expected cost to spend the
 * inputs, plus the amount the selection exceeds the spending target:
 *
 * waste = selectionTotal - target + inputs × (currentFeeRate - longTermFeeRate)
 *
 * The algorithm uses two additional optimizations. A lookahead keeps track of the total value of
 * the unexplored UTXOs. A subtree is not explored if the lookahead indicates that the target range
 * cannot be reached. Further, it is unnecessary to test equivalent combinations. This allows us
 * to skip testing the inclusion of UTXOs that match the effective value and waste of an omitted
 * predecessor.
 *
 * The Branch and Bound algorithm is described in detail in Murch's Master Thesis:
 * https://murch.one/wp-content/uploads/2016/11/erhardt2016coinselection.pdf
 *
 * @param const std::vector<CInputCoin>& utxo_pool The set of UTXOs that we are choosing from.
 *        These UTXOs will be sorted in descending order by effective value and the CInputCoins'
 *        values are their effective values.
 * @param const CAmount& target_value This is the value that we want to select. It is the lower
 *        bound of the range.
 * @param const CAmount& cost_of_change This is the cost of creating and spending a change output.
 *        This plus target_value is the upper bound of the range.
 * @param std::set<CInputCoin>& out_set -> This is an output parameter for the set of CInputCoins
 *        that have been selected.
 * @param CAmount& value_ret -> This is an output parameter for the total value of the CInputCoins
 *        that were selected.
 * @param CAmount not_input_fees -> The fees that need to be paid for the outputs and fixed size
 *        overhead (version, locktime, marker and flag)
 */

static const size_t TOTAL_TRIES = 100000;

bool SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool, const CAmount& target_value, const CAmount& cost_of_change, std::set<CInputCoin>& out_set, CAmount& value_ret, CAmount not_input_fees)
{
    out_set.clear();
    CAmount curr_value = 0;

    std::vector<bool> curr_selection; // select the utxo at this index
    curr_selection.reserve(utxo_pool.size());
    CAmount actual_target = not_input_fees + target_value;

    // Calculate curr_available_value
    CAmount curr_available_value = 0;
    for (const OutputGroup& utxo : utxo_pool) {
        // Assert that this utxo is not negative. It should never be negative, effective value calculation should have removed it
        assert(utxo.effective_value > 0);
        curr_available_value += utxo.effective_value;
    }
    if (curr_available_value < actual_target) {
        return false;
    }

    // Sort the utxo_pool
    std::sort(utxo_pool.begin(), utxo_pool.end(), descending);

    CAmount curr_waste = 0;
    std::vector<bool> best_selection;
    CAmount best_waste = MAX_MONEY;

    // Depth First search loop for choosing the UTXOs
    for (size_t i = 0; i < TOTAL_TRIES; ++i) {
        // Conditions for starting a backtrack
        bool backtrack = false;
        if (curr_value + curr_available_value < actual_target ||                // Cannot possibly reach target with the amount remaining in the curr_available_value.
            curr_value > actual_target + cost_of_change ||    // Selected value is out of range, go back and try other branch
            (curr_waste > best_waste && (utxo_pool.at(0).fee - utxo_pool.at(0).long_term_fee) > 0)) { // Don't select things which we know will be more wasteful if the waste is increasing
            backtrack = true;
        } else if (curr_value >= actual_target) {       // Selected value is within range
            curr_waste += (curr_value - actual_target); // This is the excess value which is added to the waste for the below comparison
            // Adding another UTXO after this check could bring the waste down if the long term fee is higher than the current fee.
            // However we are not going to explore that because this optimization for the waste is only done when we have hit our target
            // value. Adding any more UTXOs will be just burning the UTXO; it will go entirely to fees. Thus we aren't going to
            // explore any more UTXOs to avoid burning money like that.
            if (curr_waste <= best_waste) {
                best_selection = curr_selection;
                best_selection.resize(utxo_pool.size());
                best_waste = curr_waste;
            }
            curr_waste -= (curr_value - actual_target); // Remove the excess value as we will be selecting different coins now
            backtrack = true;
        }

        // Backtracking, moving backwards
        if (backtrack) {
            // Walk backwards to find the last included UTXO that still needs to have its omission branch traversed.
            while (!curr_selection.empty() && !curr_selection.back()) {
                curr_selection.pop_back();
                curr_available_value += utxo_pool.at(curr_selection.size()).effective_value;
            }

            if (curr_selection.empty()) { // We have walked back to the first utxo and no branch is untraversed. All solutions searched
                break;
            }

            // Output was included on previous iterations, try excluding now.
            curr_selection.back() = false;
            OutputGroup& utxo = utxo_pool.at(curr_selection.size() - 1);
            curr_value -= utxo.effective_value;
            curr_waste -= utxo.fee - utxo.long_term_fee;
        } else { // Moving forwards, continuing down this branch
            OutputGroup& utxo = utxo_pool.at(curr_selection.size());

            // Remove this utxo from the curr_available_value utxo amount
            curr_available_value -= utxo.effective_value;

            // Avoid searching a branch if the previous UTXO has the same value and same waste and was excluded. Since the ratio of fee to
            // long term fee is the same, we only need to check if one of those values match in order to know that the waste is the same.
            if (!curr_selection.empty() && !curr_selection.back() &&
                utxo.effective_value == utxo_pool.at(curr_selection.size() - 1).effective_value &&
                utxo.fee == utxo_pool.at(curr_selection.size() - 1).fee) {
                curr_selection.push_back(false);
            } else {
                // Inclusion branch first (Largest First Exploration)
                curr_selection.push_back(true);
                curr_value += utxo.effective_value;
                curr_waste += utxo.fee - utxo.long_term_fee;
            }
        }
    }

    // Check for solution
    if (best_selection.empty()) {
        return false;
    }

    // Set output set
    value_ret = 0;
    for (size_t i = 0; i < best_selection.size(); ++i) {
        if (best_selection.at(i)) {
            util::insert(out_set, utxo_pool.at(i).m_outputs);
            value_ret += utxo_pool.at(i).m_value;
        }
    }

    return true;
}

static void ApproximateBestSubset(const std::vector<OutputGroup>& groups, const CAmount& nTotalLower, const CAmount& nTargetValue,
                                  std::vector<char>& vfBest, CAmount& nBest, int iterations = 1000)
{
    std::vector<char> vfIncluded;

    vfBest.assign(groups.size(), true);
    nBest = nTotalLower;

    FastRandomContext insecure_rand;

    for (int nRep = 0; nRep < iterations && nBest != nTargetValue; nRep++)
    {
        vfIncluded.assign(groups.size(), false);
        CAmount nTotal = 0;
        bool fReachedTarget = false;
        for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
        {
            for (unsigned int i = 0; i < groups.size(); i++)
            {
                //The solver here uses a randomized algorithm,
                //the randomness serves no real security purpose but is just
                //needed to prevent degenerate behavior and it is important
                //that the rng is fast. We do not use a constant random sequence,
                //because there may be some privacy improvement by making
                //the selection random.
                if (nPass == 0 ? insecure_rand.randbool() : !vfIncluded[i])
                {
                    nTotal += groups[i].m_value;
                    vfIncluded[i] = true;
                    if (nTotal >= nTargetValue)
                    {
                        fReachedTarget = true;
                        if (nTotal < nBest)
                        {
                            nBest = nTotal;
                            vfBest = vfIncluded;
                        }
                        nTotal -= groups[i].m_value;
                        vfIncluded[i] = false;
                    }
                }
            }
        }
    }
}

bool less_then_denom(const CInputCoin& pcoin1, const CInputCoin& pcoin2)
{
    bool found1 = false;
    bool found2 = false;
    for (const auto& d : CPrivateSend::GetStandardDenominations()) // loop through predefined denoms
    {
        if(pcoin1.txout.nValue == d) found1 = true;
        if(pcoin2.txout.nValue == d) found2 = true;
    }
    return (!found1 && found2);
}

bool KnapsackSolver(const CAmount& nTargetValue, std::vector<OutputGroup>& groups, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet)
{
    setCoinsRet.clear();
    nValueRet = 0;

    // List of values less than target
    boost::optional<OutputGroup> lowest_larger;
    std::vector<OutputGroup> applicable_groups;
    CAmount nTotalLower = 0;

    random_shuffle(groups.begin(), groups.end(), GetRandInt);

    for (const OutputGroup& group : groups) {
        if (group.m_value == nTargetValue) {
            util::insert(setCoinsRet, group.m_outputs);
            nValueRet += group.m_value;
            return true;
        } else if (group.m_value < nTargetValue + MIN_CHANGE) {
            applicable_groups.push_back(group);
            nTotalLower += group.m_value;
        } else if (!lowest_larger || group.m_value < lowest_larger->m_value) {
            lowest_larger = group;
        }
    }

    if (nTotalLower == nTargetValue) {
        for (const auto& group : applicable_groups) {
            util::insert(setCoinsRet, group.m_outputs);
            nValueRet += group.m_value;
        }
        return true;
    }

    if (nTotalLower < nTargetValue) {
        if (!lowest_larger) return false;
        util::insert(setCoinsRet, lowest_larger->m_outputs);
        nValueRet += lowest_larger->m_value;
        return true;
    }

    // Solve subset sum by stochastic approximation
    std::sort(applicable_groups.begin(), applicable_groups.end(), descending);
    std::vector<char> vfBest;
    CAmount nBest;

    ApproximateBestSubset(applicable_groups, nTotalLower, nTargetValue, vfBest, nBest);
    if (nBest != nTargetValue && nTotalLower >= nTargetValue + MIN_CHANGE) {
        ApproximateBestSubset(applicable_groups, nTotalLower, nTargetValue + MIN_CHANGE, vfBest, nBest);
    }

    // If we have a bigger coin and (either the stochastic approximation didn't find a good solution,
    //                                   or the next bigger coin is closer), return the bigger coin
    if (lowest_larger &&
        ((nBest != nTargetValue && nBest < nTargetValue + MIN_CHANGE) || lowest_larger->m_value <= nBest)) {
        util::insert(setCoinsRet, lowest_larger->m_outputs);
        nValueRet += lowest_larger->m_value;
    } else {
        for (unsigned int i = 0; i < applicable_groups.size(); i++) {
            if (vfBest[i]) {
                util::insert(setCoinsRet, applicable_groups[i].m_outputs);
                nValueRet += applicable_groups[i].m_value;
            }
        }

        if (LogAcceptCategory(BCLog::SELECTCOINS)) {
            LogPrint(BCLog::SELECTCOINS, "SelectCoins() best subset: "); /* Continued */
            for (unsigned int i = 0; i < applicable_groups.size(); i++) {
                if (vfBest[i]) {
                    LogPrint(BCLog::SELECTCOINS, "%s ", FormatMoney(applicable_groups[i].m_value)); /* Continued */
                }
            }
            LogPrint(BCLog::SELECTCOINS, "total %s\n", FormatMoney(nBest));
        }
    }

    return true;
}

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

 OutputGroup

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

void OutputGroup::Insert(const CInputCoin& output, int depth, bool from_me, size_t ancestors, size_t descendants) {
    m_outputs.push_back(output);
    m_from_me &= from_me;
    m_value += output.effective_value;
    m_depth = std::min(m_depth, depth);
    // m_ancestors is currently the max ancestor count for all coins in the group; however, this is
    // not ideal, as a wallet will consider e.g. thirty 2-ancestor coins as having two ancestors,
    // when in reality it has 60 ancestors.
    m_ancestors = std::max(m_ancestors, ancestors);
    // m_descendants is the count as seen from the top ancestor, not the descendants as seen from the
    // coin itself; thus, this value is accurate
    m_descendants = std::max(m_descendants, descendants);
    effective_value = m_value;
}

std::vector<CInputCoin>::iterator OutputGroup::Discard(const CInputCoin& output) {
    auto it = m_outputs.begin();
    while (it != m_outputs.end() && it->outpoint != output.outpoint) ++it;
    if (it == m_outputs.end()) return it;
    m_value -= output.effective_value;
    effective_value -= output.effective_value;
    return m_outputs.erase(it);
}

bool OutputGroup::EligibleForSpending(const CoinEligibilityFilter& eligibility_filter) const
{
    return m_depth >= (m_from_me ? eligibility_filter.conf_mine : eligibility_filter.conf_theirs)
        && m_ancestors <= eligibility_filter.max_ancestors
        && m_descendants <= eligibility_filter.max_descendants;
}
<commit_msg>wallet: sum ancestors rather than taking max in output groups<commit_after>// Copyright (c) 2017 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <wallet/coinselection.h>
#include <privatesend.h>
#include <util.h>
#include <utilmoneystr.h>

// Descending order comparator
struct {
    bool operator()(const OutputGroup& a, const OutputGroup& b) const
    {
        return a.effective_value > b.effective_value;
    }
} descending;

/*
 * This is the Branch and Bound Coin Selection algorithm designed by Murch. It searches for an input
 * set that can pay for the spending target and does not exceed the spending target by more than the
 * cost of creating and spending a change output. The algorithm uses a depth-first search on a binary
 * tree. In the binary tree, each node corresponds to the inclusion or the omission of a UTXO. UTXOs
 * are sorted by their effective values and the trees is explored deterministically per the inclusion
 * branch first. At each node, the algorithm checks whether the selection is within the target range.
 * While the selection has not reached the target range, more UTXOs are included. When a selection's
 * value exceeds the target range, the complete subtree deriving from this selection can be omitted.
 * At that point, the last included UTXO is deselected and the corresponding omission branch explored
 * instead. The search ends after the complete tree has been searched or after a limited number of tries.
 *
 * The search continues to search for better solutions after one solution has been found. The best
 * solution is chosen by minimizing the waste metric. The waste metric is defined as the cost to
 * spend the current inputs at the given fee rate minus the long term expected cost to spend the
 * inputs, plus the amount the selection exceeds the spending target:
 *
 * waste = selectionTotal - target + inputs × (currentFeeRate - longTermFeeRate)
 *
 * The algorithm uses two additional optimizations. A lookahead keeps track of the total value of
 * the unexplored UTXOs. A subtree is not explored if the lookahead indicates that the target range
 * cannot be reached. Further, it is unnecessary to test equivalent combinations. This allows us
 * to skip testing the inclusion of UTXOs that match the effective value and waste of an omitted
 * predecessor.
 *
 * The Branch and Bound algorithm is described in detail in Murch's Master Thesis:
 * https://murch.one/wp-content/uploads/2016/11/erhardt2016coinselection.pdf
 *
 * @param const std::vector<CInputCoin>& utxo_pool The set of UTXOs that we are choosing from.
 *        These UTXOs will be sorted in descending order by effective value and the CInputCoins'
 *        values are their effective values.
 * @param const CAmount& target_value This is the value that we want to select. It is the lower
 *        bound of the range.
 * @param const CAmount& cost_of_change This is the cost of creating and spending a change output.
 *        This plus target_value is the upper bound of the range.
 * @param std::set<CInputCoin>& out_set -> This is an output parameter for the set of CInputCoins
 *        that have been selected.
 * @param CAmount& value_ret -> This is an output parameter for the total value of the CInputCoins
 *        that were selected.
 * @param CAmount not_input_fees -> The fees that need to be paid for the outputs and fixed size
 *        overhead (version, locktime, marker and flag)
 */

static const size_t TOTAL_TRIES = 100000;

bool SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool, const CAmount& target_value, const CAmount& cost_of_change, std::set<CInputCoin>& out_set, CAmount& value_ret, CAmount not_input_fees)
{
    out_set.clear();
    CAmount curr_value = 0;

    std::vector<bool> curr_selection; // select the utxo at this index
    curr_selection.reserve(utxo_pool.size());
    CAmount actual_target = not_input_fees + target_value;

    // Calculate curr_available_value
    CAmount curr_available_value = 0;
    for (const OutputGroup& utxo : utxo_pool) {
        // Assert that this utxo is not negative. It should never be negative, effective value calculation should have removed it
        assert(utxo.effective_value > 0);
        curr_available_value += utxo.effective_value;
    }
    if (curr_available_value < actual_target) {
        return false;
    }

    // Sort the utxo_pool
    std::sort(utxo_pool.begin(), utxo_pool.end(), descending);

    CAmount curr_waste = 0;
    std::vector<bool> best_selection;
    CAmount best_waste = MAX_MONEY;

    // Depth First search loop for choosing the UTXOs
    for (size_t i = 0; i < TOTAL_TRIES; ++i) {
        // Conditions for starting a backtrack
        bool backtrack = false;
        if (curr_value + curr_available_value < actual_target ||                // Cannot possibly reach target with the amount remaining in the curr_available_value.
            curr_value > actual_target + cost_of_change ||    // Selected value is out of range, go back and try other branch
            (curr_waste > best_waste && (utxo_pool.at(0).fee - utxo_pool.at(0).long_term_fee) > 0)) { // Don't select things which we know will be more wasteful if the waste is increasing
            backtrack = true;
        } else if (curr_value >= actual_target) {       // Selected value is within range
            curr_waste += (curr_value - actual_target); // This is the excess value which is added to the waste for the below comparison
            // Adding another UTXO after this check could bring the waste down if the long term fee is higher than the current fee.
            // However we are not going to explore that because this optimization for the waste is only done when we have hit our target
            // value. Adding any more UTXOs will be just burning the UTXO; it will go entirely to fees. Thus we aren't going to
            // explore any more UTXOs to avoid burning money like that.
            if (curr_waste <= best_waste) {
                best_selection = curr_selection;
                best_selection.resize(utxo_pool.size());
                best_waste = curr_waste;
            }
            curr_waste -= (curr_value - actual_target); // Remove the excess value as we will be selecting different coins now
            backtrack = true;
        }

        // Backtracking, moving backwards
        if (backtrack) {
            // Walk backwards to find the last included UTXO that still needs to have its omission branch traversed.
            while (!curr_selection.empty() && !curr_selection.back()) {
                curr_selection.pop_back();
                curr_available_value += utxo_pool.at(curr_selection.size()).effective_value;
            }

            if (curr_selection.empty()) { // We have walked back to the first utxo and no branch is untraversed. All solutions searched
                break;
            }

            // Output was included on previous iterations, try excluding now.
            curr_selection.back() = false;
            OutputGroup& utxo = utxo_pool.at(curr_selection.size() - 1);
            curr_value -= utxo.effective_value;
            curr_waste -= utxo.fee - utxo.long_term_fee;
        } else { // Moving forwards, continuing down this branch
            OutputGroup& utxo = utxo_pool.at(curr_selection.size());

            // Remove this utxo from the curr_available_value utxo amount
            curr_available_value -= utxo.effective_value;

            // Avoid searching a branch if the previous UTXO has the same value and same waste and was excluded. Since the ratio of fee to
            // long term fee is the same, we only need to check if one of those values match in order to know that the waste is the same.
            if (!curr_selection.empty() && !curr_selection.back() &&
                utxo.effective_value == utxo_pool.at(curr_selection.size() - 1).effective_value &&
                utxo.fee == utxo_pool.at(curr_selection.size() - 1).fee) {
                curr_selection.push_back(false);
            } else {
                // Inclusion branch first (Largest First Exploration)
                curr_selection.push_back(true);
                curr_value += utxo.effective_value;
                curr_waste += utxo.fee - utxo.long_term_fee;
            }
        }
    }

    // Check for solution
    if (best_selection.empty()) {
        return false;
    }

    // Set output set
    value_ret = 0;
    for (size_t i = 0; i < best_selection.size(); ++i) {
        if (best_selection.at(i)) {
            util::insert(out_set, utxo_pool.at(i).m_outputs);
            value_ret += utxo_pool.at(i).m_value;
        }
    }

    return true;
}

static void ApproximateBestSubset(const std::vector<OutputGroup>& groups, const CAmount& nTotalLower, const CAmount& nTargetValue,
                                  std::vector<char>& vfBest, CAmount& nBest, int iterations = 1000)
{
    std::vector<char> vfIncluded;

    vfBest.assign(groups.size(), true);
    nBest = nTotalLower;

    FastRandomContext insecure_rand;

    for (int nRep = 0; nRep < iterations && nBest != nTargetValue; nRep++)
    {
        vfIncluded.assign(groups.size(), false);
        CAmount nTotal = 0;
        bool fReachedTarget = false;
        for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
        {
            for (unsigned int i = 0; i < groups.size(); i++)
            {
                //The solver here uses a randomized algorithm,
                //the randomness serves no real security purpose but is just
                //needed to prevent degenerate behavior and it is important
                //that the rng is fast. We do not use a constant random sequence,
                //because there may be some privacy improvement by making
                //the selection random.
                if (nPass == 0 ? insecure_rand.randbool() : !vfIncluded[i])
                {
                    nTotal += groups[i].m_value;
                    vfIncluded[i] = true;
                    if (nTotal >= nTargetValue)
                    {
                        fReachedTarget = true;
                        if (nTotal < nBest)
                        {
                            nBest = nTotal;
                            vfBest = vfIncluded;
                        }
                        nTotal -= groups[i].m_value;
                        vfIncluded[i] = false;
                    }
                }
            }
        }
    }
}

bool less_then_denom(const CInputCoin& pcoin1, const CInputCoin& pcoin2)
{
    bool found1 = false;
    bool found2 = false;
    for (const auto& d : CPrivateSend::GetStandardDenominations()) // loop through predefined denoms
    {
        if(pcoin1.txout.nValue == d) found1 = true;
        if(pcoin2.txout.nValue == d) found2 = true;
    }
    return (!found1 && found2);
}

bool KnapsackSolver(const CAmount& nTargetValue, std::vector<OutputGroup>& groups, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet)
{
    setCoinsRet.clear();
    nValueRet = 0;

    // List of values less than target
    boost::optional<OutputGroup> lowest_larger;
    std::vector<OutputGroup> applicable_groups;
    CAmount nTotalLower = 0;

    random_shuffle(groups.begin(), groups.end(), GetRandInt);

    for (const OutputGroup& group : groups) {
        if (group.m_value == nTargetValue) {
            util::insert(setCoinsRet, group.m_outputs);
            nValueRet += group.m_value;
            return true;
        } else if (group.m_value < nTargetValue + MIN_CHANGE) {
            applicable_groups.push_back(group);
            nTotalLower += group.m_value;
        } else if (!lowest_larger || group.m_value < lowest_larger->m_value) {
            lowest_larger = group;
        }
    }

    if (nTotalLower == nTargetValue) {
        for (const auto& group : applicable_groups) {
            util::insert(setCoinsRet, group.m_outputs);
            nValueRet += group.m_value;
        }
        return true;
    }

    if (nTotalLower < nTargetValue) {
        if (!lowest_larger) return false;
        util::insert(setCoinsRet, lowest_larger->m_outputs);
        nValueRet += lowest_larger->m_value;
        return true;
    }

    // Solve subset sum by stochastic approximation
    std::sort(applicable_groups.begin(), applicable_groups.end(), descending);
    std::vector<char> vfBest;
    CAmount nBest;

    ApproximateBestSubset(applicable_groups, nTotalLower, nTargetValue, vfBest, nBest);
    if (nBest != nTargetValue && nTotalLower >= nTargetValue + MIN_CHANGE) {
        ApproximateBestSubset(applicable_groups, nTotalLower, nTargetValue + MIN_CHANGE, vfBest, nBest);
    }

    // If we have a bigger coin and (either the stochastic approximation didn't find a good solution,
    //                                   or the next bigger coin is closer), return the bigger coin
    if (lowest_larger &&
        ((nBest != nTargetValue && nBest < nTargetValue + MIN_CHANGE) || lowest_larger->m_value <= nBest)) {
        util::insert(setCoinsRet, lowest_larger->m_outputs);
        nValueRet += lowest_larger->m_value;
    } else {
        for (unsigned int i = 0; i < applicable_groups.size(); i++) {
            if (vfBest[i]) {
                util::insert(setCoinsRet, applicable_groups[i].m_outputs);
                nValueRet += applicable_groups[i].m_value;
            }
        }

        if (LogAcceptCategory(BCLog::SELECTCOINS)) {
            LogPrint(BCLog::SELECTCOINS, "SelectCoins() best subset: "); /* Continued */
            for (unsigned int i = 0; i < applicable_groups.size(); i++) {
                if (vfBest[i]) {
                    LogPrint(BCLog::SELECTCOINS, "%s ", FormatMoney(applicable_groups[i].m_value)); /* Continued */
                }
            }
            LogPrint(BCLog::SELECTCOINS, "total %s\n", FormatMoney(nBest));
        }
    }

    return true;
}

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

 OutputGroup

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

void OutputGroup::Insert(const CInputCoin& output, int depth, bool from_me, size_t ancestors, size_t descendants) {
    m_outputs.push_back(output);
    m_from_me &= from_me;
    m_value += output.effective_value;
    m_depth = std::min(m_depth, depth);
    // ancestors here express the number of ancestors the new coin will end up having, which is
    // the sum, rather than the max; this will overestimate in the cases where multiple inputs
    // have common ancestors
    m_ancestors += ancestors;
    // descendants is the count as seen from the top ancestor, not the descendants as seen from the
    // coin itself; thus, this value is counted as the max, not the sum
    m_descendants = std::max(m_descendants, descendants);
    effective_value = m_value;
}

std::vector<CInputCoin>::iterator OutputGroup::Discard(const CInputCoin& output) {
    auto it = m_outputs.begin();
    while (it != m_outputs.end() && it->outpoint != output.outpoint) ++it;
    if (it == m_outputs.end()) return it;
    m_value -= output.effective_value;
    effective_value -= output.effective_value;
    return m_outputs.erase(it);
}

bool OutputGroup::EligibleForSpending(const CoinEligibilityFilter& eligibility_filter) const
{
    return m_depth >= (m_from_me ? eligibility_filter.conf_mine : eligibility_filter.conf_theirs)
        && m_ancestors <= eligibility_filter.max_ancestors
        && m_descendants <= eligibility_filter.max_descendants;
}
<|endoftext|>


<commit_before>/*******************************************************************************
* Copyright 2017-2018 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/

#include <string>
#include <typeindex>
#include <typeinfo>
#include <unordered_set>

#include "ngraph/node.hpp"
#include "ngraph/ops/add.hpp"
#include "ngraph/ops/avg_pool.hpp"
#include "ngraph/ops/batch_norm.hpp"
#include "ngraph/ops/convolution.hpp"
#include "ngraph/ops/max_pool.hpp"
#include "ngraph/ops/relu.hpp"
#include "ngraph/runtime/cpu/cpu_layout_descriptor.hpp"
#include "ngraph/runtime/cpu/cpu_op_annotations.hpp"
#include "ngraph/runtime/cpu/ops/conv_bias.hpp"
#include "ngraph/types/element_type.hpp"

#include "mkldnn_utils.hpp"

using namespace mkldnn;
using namespace ngraph;
using namespace std;

#define TI(x) std::type_index(typeid(x))

static const std::unordered_set<std::type_index> s_op_registry{
    TI(ngraph::op::Add),
    TI(ngraph::op::AvgPool),
    TI(ngraph::op::AvgPoolBackprop),
    TI(ngraph::op::BatchNorm),
    TI(ngraph::op::BatchNormBackprop),
    TI(ngraph::op::Convolution),
    TI(ngraph::op::ConvolutionBackpropData),
    TI(ngraph::op::ConvolutionBackpropFilters),
	TI(ngraph::op::ConvolutionBias),
    TI(ngraph::op::ConvolutionBiasBackpropFiltersBias),
    TI(ngraph::op::MaxPool),
    TI(ngraph::op::MaxPoolBackprop),
    TI(ngraph::op::Relu),
    TI(ngraph::op::ReluBackprop)};

// Mapping from POD types to MKLDNN data types
static const std::map<element::Type, const mkldnn::memory::data_type> s_mkldnn_data_type_map{
    {element::boolean, mkldnn::memory::data_type::s8},
    {element::f32, mkldnn::memory::data_type::f32},
    {element::f64, mkldnn::memory::data_type::data_undef},
    {element::i8, mkldnn::memory::data_type::s8},
    {element::i16, mkldnn::memory::data_type::s16},
    {element::i32, mkldnn::memory::data_type::s32},
    {element::i64, mkldnn::memory::data_type::data_undef},
    {element::u8, mkldnn::memory::data_type::u8},
    {element::u16, mkldnn::memory::data_type::data_undef},
    {element::u32, mkldnn::memory::data_type::data_undef},
    {element::u64, mkldnn::memory::data_type::data_undef}};

static const std::map<element::Type, const std::string> s_mkldnn_data_type_string_map{
    {element::boolean, "mkldnn::memory::data_type::s8"},
    {element::f32, "mkldnn::memory::data_type::f32"},
    {element::f64, "mkldnn::memory::data_type::data_undef"},
    {element::i8, "mkldnn::memory::data_type::s8"},
    {element::i16, "mkldnn::memory::data_type::s16"},
    {element::i32, "mkldnn::memory::data_type::s32"},
    {element::i64, "mkldnn::memory::data_type::data_undef"},
    {element::u8, "mkldnn::memory::data_type::u8"},
    {element::u16, "mkldnn::memory::data_type::data_undef"},
    {element::u32, "mkldnn::memory::data_type::data_undef"},
    {element::u64, "mkldnn::memory::data_type::data_undef"}};

// TODO (jbobba): Add the rest of memory formats to this map as well
static const std::map<memory::format, const std::string> s_mkldnn_format_string_map{
    {memory::format::format_undef, "memory::format::format_undef"},
    {memory::format::any, "memory::format::any"},
    {memory::format::blocked, "memory::format::blocked"},
    {memory::format::x, "memory::format::x"},
    {memory::format::nc, "memory::format::nc"},
    {memory::format::nchw, "memory::format::nchw"},
    {memory::format::nhwc, "memory::format::nhwc"},
    {memory::format::chwn, "memory::format::chwn"},
    {memory::format::nChw8c, "memory::format::nChw8c"},
    {memory::format::nChw16c, "memory::format::nChw16c"},
    {memory::format::oi, "memory::format::oi"},
    {memory::format::io, "memory::format::io"},
    {memory::format::oihw, "memory::format::oihw"},
    {memory::format::ihwo, "memory::format::ihwo"},
    {memory::format::hwio, "memory::format::hwio"},
    {memory::format::oIhw8i, "memory::format::oIhw8i"},
    {memory::format::oIhw16i, "memory::format::oIhw16i"},
    {memory::format::OIhw8i8o, "memory::format::OIhw8i8o"},
    {memory::format::OIhw16i16o, "memory::format::OIhw16i16o"},
    {memory::format::IOhw16o16i, "memory::format::IOhw16o16i"},
    {memory::format::OIhw8o8i, "memory::format::OIhw8o8i"},
    {memory::format::OIhw16o16i, "memory::format::OIhw16o16i"},
    {memory::format::Oihw8o, "memory::format::Oihw8o"},
    {memory::format::Oihw16o, "memory::format::Oihw16o"},
    {memory::format::Ohwi8o, "memory::format::Ohwi8o"},
    {memory::format::Ohwi16o, "memory::format::Ohwi16o"},
    {memory::format::OhIw16o4i, "memory::format::OhIw16o4i"},
};

bool runtime::cpu::mkldnn_utils::IsMKLDNNOp(ngraph::Node& op)
{
    return (s_op_registry.find(TI(op)) != s_op_registry.end());
}

mkldnn::memory::format runtime::cpu::mkldnn_utils::CreateNativeDataFormat(
    const ngraph::runtime::cpu::LayoutDescriptor& layout)
{
    switch (layout.get_shape().size())
    {
    case 1: return mkldnn::memory::format::x;
    case 2: return mkldnn::memory::format::nc;
    case 4: return mkldnn::memory::format::nchw;
    default: return mkldnn::memory::format::format_undef;
    }
}

const std::string&
    runtime::cpu::mkldnn_utils::get_mkldnn_data_type_string(const ngraph::element::Type& type)
{
    auto it = s_mkldnn_data_type_string_map.find(type);
    if (it == s_mkldnn_data_type_string_map.end() || it->second.empty())
        throw ngraph_error("No MKLDNN data type exists for the given element type");
    return it->second;
}

mkldnn::memory::data_type
    runtime::cpu::mkldnn_utils::get_mkldnn_data_type(const ngraph::element::Type& type)
{
    auto it = s_mkldnn_data_type_map.find(type);
    if (it == s_mkldnn_data_type_map.end() || it->second == memory::data_type::data_undef)
    {
        throw ngraph_error("No MKLDNN data type exists for the given element type");
    }
    return it->second;
}

const std::string& runtime::cpu::mkldnn_utils::get_mkldnn_format_string(memory::format fmt)
{
    auto it = s_mkldnn_format_string_map.find(fmt);
    if (it == s_mkldnn_format_string_map.end())
        throw ngraph_error("No MKLDNN format exists for the given format type " +
                           std::to_string(fmt));
    return it->second;
}

mkldnn::memory::format runtime::cpu::mkldnn_utils::get_input_mkldnn_format(const Node* node,
                                                                           int index)
{
    auto tvl = node->get_inputs()[index].get_output().get_tensor_view()->get_tensor_view_layout();
    return dynamic_cast<runtime::cpu::LayoutDescriptor&>(*tvl).get_mkldnn_format();
}

mkldnn::memory::format runtime::cpu::mkldnn_utils::get_output_mkldnn_format(const Node* node,
                                                                            int index)
{
    auto tvl = node->get_output_tensor_view(index)->get_tensor_view_layout();
    return dynamic_cast<runtime::cpu::LayoutDescriptor&>(*tvl).get_mkldnn_format();
}

bool runtime::cpu::mkldnn_utils::use_mkldnn_kernel(const ngraph::Node* node)
{
    auto op_annotations = static_cast<const ngraph::op::Op*>(node)->get_op_annotations();
    return (op_annotations &&
            static_pointer_cast<ngraph::runtime::cpu::CPUOpAnnotations>(op_annotations)
                ->is_mkldnn_op());
}

bool runtime::cpu::mkldnn_utils::compare_mkldnn_formats(mkldnn::memory::format fmt1,
                                                        mkldnn::memory::format fmt2)
{
    set<mkldnn::memory::format> similar_4d_formats{mkldnn::memory::format::nchw,
                                                   mkldnn::memory::format::oihw};
    if ((fmt1 == fmt2) || (similar_4d_formats.find(fmt1) != similar_4d_formats.end() &&
                           similar_4d_formats.find(fmt2) != similar_4d_formats.end()))
    {
        return true;
    }
    return false;
}
<commit_msg>Update mkldnn_utils.cpp<commit_after>/*******************************************************************************
* Copyright 2017-2018 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/

#include <string>
#include <typeindex>
#include <typeinfo>
#include <unordered_set>

#include "ngraph/node.hpp"
#include "ngraph/ops/add.hpp"
#include "ngraph/ops/avg_pool.hpp"
#include "ngraph/ops/batch_norm.hpp"
#include "ngraph/ops/convolution.hpp"
#include "ngraph/ops/max_pool.hpp"
#include "ngraph/ops/relu.hpp"
#include "ngraph/runtime/cpu/cpu_layout_descriptor.hpp"
#include "ngraph/runtime/cpu/cpu_op_annotations.hpp"
#include "ngraph/runtime/cpu/ops/conv_bias.hpp"
#include "ngraph/types/element_type.hpp"

#include "mkldnn_utils.hpp"

using namespace mkldnn;
using namespace ngraph;
using namespace std;

#define TI(x) std::type_index(typeid(x))

static const std::unordered_set<std::type_index> s_op_registry{
    TI(ngraph::op::Add),
    TI(ngraph::op::AvgPool),
    TI(ngraph::op::AvgPoolBackprop),
    TI(ngraph::op::BatchNorm),
    TI(ngraph::op::BatchNormBackprop),
    TI(ngraph::op::Convolution),
    TI(ngraph::op::ConvolutionBackpropData),
    TI(ngraph::op::ConvolutionBackpropFilters),
    TI(ngraph::op::ConvolutionBias),
    TI(ngraph::op::ConvolutionBiasBackpropFiltersBias),
    TI(ngraph::op::MaxPool),
    TI(ngraph::op::MaxPoolBackprop),
    TI(ngraph::op::Relu),
    TI(ngraph::op::ReluBackprop)};

// Mapping from POD types to MKLDNN data types
static const std::map<element::Type, const mkldnn::memory::data_type> s_mkldnn_data_type_map{
    {element::boolean, mkldnn::memory::data_type::s8},
    {element::f32, mkldnn::memory::data_type::f32},
    {element::f64, mkldnn::memory::data_type::data_undef},
    {element::i8, mkldnn::memory::data_type::s8},
    {element::i16, mkldnn::memory::data_type::s16},
    {element::i32, mkldnn::memory::data_type::s32},
    {element::i64, mkldnn::memory::data_type::data_undef},
    {element::u8, mkldnn::memory::data_type::u8},
    {element::u16, mkldnn::memory::data_type::data_undef},
    {element::u32, mkldnn::memory::data_type::data_undef},
    {element::u64, mkldnn::memory::data_type::data_undef}};

static const std::map<element::Type, const std::string> s_mkldnn_data_type_string_map{
    {element::boolean, "mkldnn::memory::data_type::s8"},
    {element::f32, "mkldnn::memory::data_type::f32"},
    {element::f64, "mkldnn::memory::data_type::data_undef"},
    {element::i8, "mkldnn::memory::data_type::s8"},
    {element::i16, "mkldnn::memory::data_type::s16"},
    {element::i32, "mkldnn::memory::data_type::s32"},
    {element::i64, "mkldnn::memory::data_type::data_undef"},
    {element::u8, "mkldnn::memory::data_type::u8"},
    {element::u16, "mkldnn::memory::data_type::data_undef"},
    {element::u32, "mkldnn::memory::data_type::data_undef"},
    {element::u64, "mkldnn::memory::data_type::data_undef"}};

// TODO (jbobba): Add the rest of memory formats to this map as well
static const std::map<memory::format, const std::string> s_mkldnn_format_string_map{
    {memory::format::format_undef, "memory::format::format_undef"},
    {memory::format::any, "memory::format::any"},
    {memory::format::blocked, "memory::format::blocked"},
    {memory::format::x, "memory::format::x"},
    {memory::format::nc, "memory::format::nc"},
    {memory::format::nchw, "memory::format::nchw"},
    {memory::format::nhwc, "memory::format::nhwc"},
    {memory::format::chwn, "memory::format::chwn"},
    {memory::format::nChw8c, "memory::format::nChw8c"},
    {memory::format::nChw16c, "memory::format::nChw16c"},
    {memory::format::oi, "memory::format::oi"},
    {memory::format::io, "memory::format::io"},
    {memory::format::oihw, "memory::format::oihw"},
    {memory::format::ihwo, "memory::format::ihwo"},
    {memory::format::hwio, "memory::format::hwio"},
    {memory::format::oIhw8i, "memory::format::oIhw8i"},
    {memory::format::oIhw16i, "memory::format::oIhw16i"},
    {memory::format::OIhw8i8o, "memory::format::OIhw8i8o"},
    {memory::format::OIhw16i16o, "memory::format::OIhw16i16o"},
    {memory::format::IOhw16o16i, "memory::format::IOhw16o16i"},
    {memory::format::OIhw8o8i, "memory::format::OIhw8o8i"},
    {memory::format::OIhw16o16i, "memory::format::OIhw16o16i"},
    {memory::format::Oihw8o, "memory::format::Oihw8o"},
    {memory::format::Oihw16o, "memory::format::Oihw16o"},
    {memory::format::Ohwi8o, "memory::format::Ohwi8o"},
    {memory::format::Ohwi16o, "memory::format::Ohwi16o"},
    {memory::format::OhIw16o4i, "memory::format::OhIw16o4i"},
};

bool runtime::cpu::mkldnn_utils::IsMKLDNNOp(ngraph::Node& op)
{
    return (s_op_registry.find(TI(op)) != s_op_registry.end());
}

mkldnn::memory::format runtime::cpu::mkldnn_utils::CreateNativeDataFormat(
    const ngraph::runtime::cpu::LayoutDescriptor& layout)
{
    switch (layout.get_shape().size())
    {
    case 1: return mkldnn::memory::format::x;
    case 2: return mkldnn::memory::format::nc;
    case 4: return mkldnn::memory::format::nchw;
    default: return mkldnn::memory::format::format_undef;
    }
}

const std::string&
    runtime::cpu::mkldnn_utils::get_mkldnn_data_type_string(const ngraph::element::Type& type)
{
    auto it = s_mkldnn_data_type_string_map.find(type);
    if (it == s_mkldnn_data_type_string_map.end() || it->second.empty())
        throw ngraph_error("No MKLDNN data type exists for the given element type");
    return it->second;
}

mkldnn::memory::data_type
    runtime::cpu::mkldnn_utils::get_mkldnn_data_type(const ngraph::element::Type& type)
{
    auto it = s_mkldnn_data_type_map.find(type);
    if (it == s_mkldnn_data_type_map.end() || it->second == memory::data_type::data_undef)
    {
        throw ngraph_error("No MKLDNN data type exists for the given element type");
    }
    return it->second;
}

const std::string& runtime::cpu::mkldnn_utils::get_mkldnn_format_string(memory::format fmt)
{
    auto it = s_mkldnn_format_string_map.find(fmt);
    if (it == s_mkldnn_format_string_map.end())
        throw ngraph_error("No MKLDNN format exists for the given format type " +
                           std::to_string(fmt));
    return it->second;
}

mkldnn::memory::format runtime::cpu::mkldnn_utils::get_input_mkldnn_format(const Node* node,
                                                                           int index)
{
    auto tvl = node->get_inputs()[index].get_output().get_tensor_view()->get_tensor_view_layout();
    return dynamic_cast<runtime::cpu::LayoutDescriptor&>(*tvl).get_mkldnn_format();
}

mkldnn::memory::format runtime::cpu::mkldnn_utils::get_output_mkldnn_format(const Node* node,
                                                                            int index)
{
    auto tvl = node->get_output_tensor_view(index)->get_tensor_view_layout();
    return dynamic_cast<runtime::cpu::LayoutDescriptor&>(*tvl).get_mkldnn_format();
}

bool runtime::cpu::mkldnn_utils::use_mkldnn_kernel(const ngraph::Node* node)
{
    auto op_annotations = static_cast<const ngraph::op::Op*>(node)->get_op_annotations();
    return (op_annotations &&
            static_pointer_cast<ngraph::runtime::cpu::CPUOpAnnotations>(op_annotations)
                ->is_mkldnn_op());
}

bool runtime::cpu::mkldnn_utils::compare_mkldnn_formats(mkldnn::memory::format fmt1,
                                                        mkldnn::memory::format fmt2)
{
    set<mkldnn::memory::format> similar_4d_formats{mkldnn::memory::format::nchw,
                                                   mkldnn::memory::format::oihw};
    if ((fmt1 == fmt2) || (similar_4d_formats.find(fmt1) != similar_4d_formats.end() &&
                           similar_4d_formats.find(fmt2) != similar_4d_formats.end()))
    {
        return true;
    }
    return false;
}
<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                         Peloton
//
// catalog.cpp
//
// Identification: src/wire/libevent_server.cpp
//
// Copyright (c) 2015-16, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//
#include <fstream>
#include "wire/libevent_server.h"
#include "common/logger.h"
#include "common/macros.h"
#include "common/init.h"

namespace peloton {
namespace wire {

std::vector<SocketManager<PktBuf>*> Server::socket_manager_vector_ = { };
unsigned int Server::socket_manager_id = 0;

void Signal_Callback(UNUSED_ATTRIBUTE evutil_socket_t fd, UNUSED_ATTRIBUTE short what, void *arg) {
  struct event_base *base = (event_base*) arg;
  LOG_INFO("stop");
  event_base_loopexit(base, NULL);
}

void SetTCPNoDelay(evutil_socket_t fd) {
  int one = 1;
  setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof one);
}

/**
 * Set a socket to non-blocking mode.
 */
bool SetNonBlocking(int fd) {
  int status = fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
  if (status == -1) {
    return false;
  } else {
    return true;
  }
}

void ManageRead(SocketManager<PktBuf>** socket_manager) {
	if((*socket_manager)->first_packet == false) {
		if(!(*socket_manager)->socket_pkt_manager->ManageFirstPacket()) {
			close((*socket_manager)->GetSocketFD());
			event_del((*socket_manager)->ev_read);
			(*socket_manager)->execution_mutex.unlock();
			return;
		}
		(*socket_manager)->first_packet = true;
	}
	else {
		if(!(*socket_manager)->socket_pkt_manager->ManagePacket()) {
			close((*socket_manager)->GetSocketFD());
			event_del((*socket_manager)->ev_read);
			(*socket_manager)->execution_mutex.unlock();
			return;
		}
	}
	(*socket_manager)->execution_mutex.unlock();
}

void ReadCallback(UNUSED_ATTRIBUTE int fd, UNUSED_ATTRIBUTE short ev, void *arg) {
  // Threads
  if(((SocketManager<PktBuf>*)arg)->execution_mutex.try_lock()) {
	((SocketManager<PktBuf>*)arg)->self = (SocketManager<PktBuf>*)arg;
    thread_pool.SubmitTask(ManageRead, &((SocketManager<PktBuf>*)arg)->self);
  }

	// No threads
//	SocketManager<PktBuf>* socket_manager = (SocketManager<PktBuf>*)arg;
//    ManageRead(&socket_manager);
}

/**
 * This function will be called by libevent when there is a connection
 * ready to be accepted.
 */
void AcceptCallback(struct evconnlistener *listener,
	    evutil_socket_t client_fd, UNUSED_ATTRIBUTE struct sockaddr *address, UNUSED_ATTRIBUTE int socklen,
		UNUSED_ATTRIBUTE void *ctx) {
	LOG_INFO("New connection on fd %d", int(client_fd));
	// Get the event base
	struct event_base *base = evconnlistener_get_base(listener);

	// Set the client socket to non-blocking mode.
	if (!SetNonBlocking(client_fd))
		LOG_INFO("failed to set client socket non-blocking");

	SetTCPNoDelay(client_fd);
	/* We've accepted a new client, allocate a socket manager to
	   maintain the state of this client. */
	SocketManager<PktBuf>* socket_manager = new SocketManager<PktBuf>(client_fd, ++Server::socket_manager_id);
	socket_manager->socket_pkt_manager.reset(new PacketManager(socket_manager));

	Server::AddSocketManager(socket_manager);

	/* Setup the read event, libevent will call ReadCallback whenever
	 * the clients socket becomes read ready.  Make the
	 * read event persistent so we don't have to re-add after each
	 * read. */
	socket_manager->ev_read = event_new(base, client_fd, EV_READ|EV_PERSIST, ReadCallback, socket_manager);

	/* Setting up the event does not activate, add the event so it
	   becomes active. */
	event_add(socket_manager->ev_read, NULL);

}

Server::Server() {
  struct event_base *base;
  struct evconnlistener *listener;
  struct event *evstop;
  socket_manager_id = 0;
  port_ = FLAGS_port;
  max_connections_ = FLAGS_max_connections;

  // For logging purposes
  //  event_enable_debug_mode();
  //  event_set_log_callback(LogCallback);

  // Commented because it's not in the libevent version we're using
  // When we upgrade this should be uncommented
  //  event_enable_debug_logging(EVENT_DBG_ALL);

  // Ignore the broken pipe signal
  // We don't want to exit on write
  // when the client disconnects
  signal(SIGPIPE, SIG_IGN);

  // Create our event base
  base = event_base_new();
  if (!base) {
    LOG_INFO("Couldn't open event base");
    exit(EXIT_FAILURE);
  }
  evstop = evsignal_new(base, SIGHUP, Signal_Callback, base);
  evsignal_add(evstop, NULL);

  if (FLAGS_socket_family == "AF_INET") {
    struct sockaddr_in sin;
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = INADDR_ANY;
    sin.sin_port = htons(port_);
    listener = evconnlistener_new_bind(
        base, AcceptCallback, NULL, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
        -1, (struct sockaddr *)&sin, sizeof(sin));
    if (!listener) {
      LOG_INFO("Couldn't create listener");
      exit(EXIT_FAILURE);
    }

    event_base_dispatch(base);

    evconnlistener_free(listener);
    event_free(evstop);
    event_base_free(base);
  }
  // This socket family code is not implemented yet
  else if (FLAGS_socket_family == "AF_UNIX") {
    LOG_INFO("The AF_UNIX socket family is not implemented");
    exit(EXIT_FAILURE);
  }
}

void Server::LogCallback(int severity, UNUSED_ATTRIBUTE const char *msg) {
  UNUSED_ATTRIBUTE const char *s;
  switch (severity) {
    case _EVENT_LOG_DEBUG:
      s = "debug";
      break;
    case _EVENT_LOG_MSG:
      s = "msg";
      break;
    case _EVENT_LOG_WARN:
      s = "warn";
      break;
    case _EVENT_LOG_ERR:
      s = "error";
      break;
    default:
      s = "?";
      break; /* Should not get this far */
  }
  LOG_INFO("[%s] %s\n", s, msg);
}
}
}
<commit_msg>Added support for AF_UNIX<commit_after>//===----------------------------------------------------------------------===//
//
//                         Peloton
//
// catalog.cpp
//
// Identification: src/wire/libevent_server.cpp
//
// Copyright (c) 2015-16, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//
#include <fstream>
#include "wire/libevent_server.h"
#include "common/logger.h"
#include "common/macros.h"
#include "common/init.h"

namespace peloton {
namespace wire {

std::vector<SocketManager<PktBuf>*> Server::socket_manager_vector_ = { };
unsigned int Server::socket_manager_id = 0;

void Signal_Callback(UNUSED_ATTRIBUTE evutil_socket_t fd, UNUSED_ATTRIBUTE short what, void *arg) {
  struct event_base *base = (event_base*) arg;
  LOG_INFO("stop");
  event_base_loopexit(base, NULL);
}

void SetTCPNoDelay(evutil_socket_t fd) {
  int one = 1;
  setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof one);
}

/**
 * Set a socket to non-blocking mode.
 */
bool SetNonBlocking(int fd) {
  int status = fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
  if (status == -1) {
    return false;
  } else {
    return true;
  }
}

void ManageRead(SocketManager<PktBuf>** socket_manager) {
	if((*socket_manager)->first_packet == false) {
		if(!(*socket_manager)->socket_pkt_manager->ManageFirstPacket()) {
			close((*socket_manager)->GetSocketFD());
			event_del((*socket_manager)->ev_read);
			(*socket_manager)->execution_mutex.unlock();
			return;
		}
		(*socket_manager)->first_packet = true;
	}
	else {
		if(!(*socket_manager)->socket_pkt_manager->ManagePacket()) {
			close((*socket_manager)->GetSocketFD());
			event_del((*socket_manager)->ev_read);
			(*socket_manager)->execution_mutex.unlock();
			return;
		}
	}
	(*socket_manager)->execution_mutex.unlock();
}

void ReadCallback(UNUSED_ATTRIBUTE int fd, UNUSED_ATTRIBUTE short ev, void *arg) {
  // Threads
  if(((SocketManager<PktBuf>*)arg)->execution_mutex.try_lock()) {
	((SocketManager<PktBuf>*)arg)->self = (SocketManager<PktBuf>*)arg;
    thread_pool.SubmitTask(ManageRead, &((SocketManager<PktBuf>*)arg)->self);
  }

	// No threads
//	SocketManager<PktBuf>* socket_manager = (SocketManager<PktBuf>*)arg;
//    ManageRead(&socket_manager);
}

/**
 * This function will be called by libevent when there is a connection
 * ready to be accepted.
 */
void AcceptCallback(struct evconnlistener *listener,
	    evutil_socket_t client_fd, UNUSED_ATTRIBUTE struct sockaddr *address, UNUSED_ATTRIBUTE int socklen,
		UNUSED_ATTRIBUTE void *ctx) {
	LOG_INFO("New connection on fd %d", int(client_fd));
	// Get the event base
	struct event_base *base = evconnlistener_get_base(listener);

	// Set the client socket to non-blocking mode.
	if (!SetNonBlocking(client_fd))
		LOG_INFO("failed to set client socket non-blocking");

	SetTCPNoDelay(client_fd);
	/* We've accepted a new client, allocate a socket manager to
	   maintain the state of this client. */
	SocketManager<PktBuf>* socket_manager = new SocketManager<PktBuf>(client_fd, ++Server::socket_manager_id);
	socket_manager->socket_pkt_manager.reset(new PacketManager(socket_manager));

	Server::AddSocketManager(socket_manager);

	/* Setup the read event, libevent will call ReadCallback whenever
	 * the clients socket becomes read ready.  Make the
	 * read event persistent so we don't have to re-add after each
	 * read. */
	socket_manager->ev_read = event_new(base, client_fd, EV_READ|EV_PERSIST, ReadCallback, socket_manager);

	/* Setting up the event does not activate, add the event so it
	   becomes active. */
	event_add(socket_manager->ev_read, NULL);

}

Server::Server() {
  struct event_base *base;
  struct evconnlistener *listener;
  struct event *evstop;
  socket_manager_id = 0;
  port_ = FLAGS_port;
  max_connections_ = FLAGS_max_connections;

  // For logging purposes
  //  event_enable_debug_mode();
  //  event_set_log_callback(LogCallback);

  // Commented because it's not in the libevent version we're using
  // When we upgrade this should be uncommented
  //  event_enable_debug_logging(EVENT_DBG_ALL);

  // Ignore the broken pipe signal
  // We don't want to exit on write
  // when the client disconnects
  signal(SIGPIPE, SIG_IGN);

  // Create our event base
  base = event_base_new();
  if (!base) {
    LOG_INFO("Couldn't open event base");
    exit(EXIT_FAILURE);
  }
  evstop = evsignal_new(base, SIGHUP, Signal_Callback, base);
  evsignal_add(evstop, NULL);

  if (FLAGS_socket_family == "AF_INET") {
    struct sockaddr_in sin;
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = INADDR_ANY;
    sin.sin_port = htons(port_);
    listener = evconnlistener_new_bind(
        base, AcceptCallback, NULL, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
        -1, (struct sockaddr *)&sin, sizeof(sin));
    if (!listener) {
      LOG_INFO("Couldn't create listener");
      exit(EXIT_FAILURE);
    }

    event_base_dispatch(base);

    evconnlistener_free(listener);
    event_free(evstop);
    event_base_free(base);
  }
  // This socket family code is not implemented yet
  else if (FLAGS_socket_family == "AF_UNIX") {
	struct sockaddr_un serv_addr;
	int len;

	std::string SOCKET_PATH = "/tmp/.s.PGSQL." + std::to_string(port_);
	memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sun_family = AF_UNIX;
    strncpy(serv_addr.sun_path, SOCKET_PATH.c_str(),
            sizeof(serv_addr.sun_path) - 1);
    unlink(serv_addr.sun_path);
    len = strlen(serv_addr.sun_path) + sizeof(serv_addr.sun_family);

    listener = evconnlistener_new_bind(
        base, AcceptCallback, NULL, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
        -1, (struct sockaddr *)&serv_addr, len);
    if (!listener) {
      LOG_INFO("Couldn't create listener");
      exit(EXIT_FAILURE);
    }

    event_base_dispatch(base);

    evconnlistener_free(listener);
    event_free(evstop);
    event_base_free(base);

  }
  else {
	  LOG_ERROR("Socket family %s not supported", FLAGS_socket_family.c_str());
	  exit(EXIT_FAILURE);
  }
}

void Server::LogCallback(int severity, UNUSED_ATTRIBUTE const char *msg) {
  UNUSED_ATTRIBUTE const char *s;
  switch (severity) {
    case _EVENT_LOG_DEBUG:
      s = "debug";
      break;
    case _EVENT_LOG_MSG:
      s = "msg";
      break;
    case _EVENT_LOG_WARN:
      s = "warn";
      break;
    case _EVENT_LOG_ERR:
      s = "error";
      break;
    default:
      s = "?";
      break; /* Should not get this far */
  }
  LOG_INFO("[%s] %s\n", s, msg);
}
}
}
<|endoftext|>


<commit_before>#ifndef CONST_H
#define CONST_H

using namespace std;

const int WORD_SIZE = 8;
const int ADDR_SIZE = 4;
const int RAM_SIZE = ADDR_SIZE*ADDR_SIZE-1;

// Miliseconds between cycles (if automatic)
const int FQ = 300;

const int NUM_OF_INSTRUCTIONS = 8;

#endif<commit_msg>changed RAM_SIZE initialization from ADDR_SIZE*ADDR_SIZE-1 to 15 for clarity<commit_after>#ifndef CONST_H
#define CONST_H

using namespace std;

const int WORD_SIZE = 8;
const int ADDR_SIZE = 4;
const int RAM_SIZE = 15;

// Miliseconds between cycles (if automatic)
const int FQ = 300;

const int NUM_OF_INSTRUCTIONS = 8;

#endif<|endoftext|>


<commit_before>#include "crash.hpp"

// Needed for automatic name demangling, but not all that portable
#include <cxxabi.h>
#include <execinfo.h>
// Needed to hack contexts for signal traces
#ifndef _XOPEN_SOURCE
    #define _XOPEN_SOURCE
    #include <ucontext.h>
    #undef _XOPEN_SOURCE
#else
    #include <ucontext.h>
#endif
// Needed to generate stacktraces ourselves
#include <dlfcn.h>

#include <cstdlib>
#include <string>
#include <iostream>

namespace vg {

// Demangle the name in thsi stack trace frame if we can find the API to do so.
string demangle_frame(string mangled) {
    // Demangle the name in a stack trace line as seen at
    // <http://panthema.net/2008/0901-stacktrace-demangled/>

    // Name is module(function+offset) [address] in standard format.
    // For example:
    // ../createIndex/createIndex(_Z12make_tempdirv+0x1a4) [0x46e8f4]
    // We need to find the start and end of the function part. Sometimes
    // the parens can just be empty, so we need to handle that too.

    // Where is the close paren, reading from the right?
    size_t closeParen = 0;
    // Where is the plus, reading from the right? If there is no plus in
    // the parens, set to 0.
    size_t plus = 0;
    // Where is the open paren, reading from right to left?
    size_t openParen = 0;

    for(size_t j = mangled.size() - 1; j != (size_t) -1; j--) {
        // Scan from right to left.

        if(closeParen == 0 && mangled[j] == ')') {
            // We found the rightmost close paren
            closeParen = j;
        } else if(j < closeParen && plus == 0 && mangled[j] == '+') {
            // We found the + to the left of the close paren.
            plus = j;
        } else if(j < closeParen && openParen == 0 && mangled[j] == '(') {
            // We found the open paren to the left of the close paren.
            openParen = j;

            // We're done parsing.
            break;
        }
    }

    if(openParen == 0 || closeParen == 0 || plus == 0) {
        // We couldn't pull out a name and address. Either we have a
        // nonstandard format or we have empty parens.

        // Just use the default trace message
        return mangled;
    } else {
        // We did parse out stuff!

        // Take everything before the open paren.
        string demangled = mangled.substr(0, openParen + 1);

        // Grab the function name
        string functionName = mangled.substr(openParen + 1, plus - (openParen + 1));

        // Make a place for the demangling function to save its status
        int status;

        // Do the demangling
        char* demangledName = abi::__cxa_demangle(functionName.c_str(), NULL, NULL, &status);

        if(status != 0) {
            // If we couldn't demangle the name, just use the mangled name.
            return mangled;
        }

        // Add the (probably) demangled name, a "+", and the rest of the
        // message.
        demangled += string(demangledName) + "+" + mangled.substr(plus + 1);

        if(status == 0) {
            // We got a demangled name we need to clean up.
            free(demangledName);
        }

        return demangled;
    }
}

void stacktrace_with_backtrace_and_exit(int signalNumber) {
    // How many frames can we handle?
    const size_t MAX_FRAMES = 100;

    // This holds the stack frames
    void *frames[MAX_FRAMES];

    // And this holds how many there actually are, which comes out of the
    // function that gets the frames.
    size_t framesUsed = backtrace(frames, MAX_FRAMES);

    cerr << "Stack trace from backtrace() for signal " << signalNumber << ":" << endl;

    char** traceMessages = backtrace_symbols(frames, framesUsed);

    for(size_t i = 0; i < framesUsed; i++) {
        // Print a demangled version of every frame
        cerr << demangle_frame(traceMessages[i]) << endl;
        // Separate frames because damangled can be long.
        cerr << "=================" << endl;
    }

    // Free our stacktrace memory.
    free(traceMessages);

    exit(signalNumber + 128);
}

void emit_stacktrace(int signalNumber, siginfo_t *signalInfo, void *signalContext) {
    // This holds the context that the signal came from, including registers and stuff
    ucontext_t* context = (ucontext_t*) signalContext;

    cerr << "Got signal " << signalNumber << endl;

    cerr << "Manual stack trace:" << endl;

    #ifdef __APPLE__
        // On OS X we need to do our own stack tracing since backtrace() doesn't seem to work

        // Now we compute our own stack trace, because backtrace() isn't so good on OS X.
        // We operate on the same principles as <https://stackoverflow.com/a/5426269>

        // TODO: This assumes x86
        // Fetch out the registers
        // We model IP as a pointer to void (i.e. into code)
        void* ip;
        // We model BP as an array of two things: previous BP, and previous IP.
        void** bp;

        // OS X 64 bit does it this way
        ip = (void*)context->uc_mcontext->__ss.__rip;
        bp = (void**)context->uc_mcontext->__ss.__rbp;

        // If this were Linux it would be (void*)context->uc_mcontext.gregs[REG_RIP] or REG_RBP

        // Allocate a place to keep the dynamic library info for the address the stack is executing at
        Dl_info address_library;

        cerr << endl;
        cerr << "Next ip: " << ip << " Next bp: " << bp << endl;
        while (true) {
            // Work out where the ip is.
            if (!dladdr(ip, &address_library)) {
                // This address doesn't belong to anything!
                cerr << "Stack leaves code at ip=" << ip << endl;
                break;
            }

            if (address_library.dli_sname != nullptr) {
                // Make a place for the demangling function to save its status
                int status;

                // Do the demangling
                char* demangledName = abi::__cxa_demangle(address_library.dli_sname, NULL, NULL, &status);

                if(status == 0) {
                    // Successfully demangled
                    cerr << "Address " << ip << " in demangled symbol " << demangledName
                        << " at offset " << (void*)((size_t)ip - ((size_t)address_library.dli_saddr))
                        << ", in library " << address_library.dli_fname
                        << " at offset " << (void*)((size_t)ip - ((size_t)address_library.dli_fbase)) << endl;
                    free(demangledName);
                } else {
                    // Leave mangled
                    cerr << "Address " << ip << " in mangled symbol " << address_library.dli_sname
                        << " at offset " << (void*)((size_t)ip - ((size_t)address_library.dli_saddr))
                        << ", in library " << address_library.dli_fname
                        << " at offset " << (void*)((size_t)ip - ((size_t)address_library.dli_fbase)) << endl;
                }

                #ifdef VG_DO_ATOS
                    // Try running atos to print a line number. This can be slow so we don't do it by default.
                    stringstream command;

                    command << "atos -o " << address_library.dli_fname << " -l " << address_library.dli_fbase << " " << ip;
                    cerr << "Running " << command.str() << "..." << endl;
                    system(command.str().c_str());
                #endif

            } else {
                cerr << "Address " << ip << " out of symbol in library " << address_library.dli_fname << endl;
            }

            if(address_library.dli_sname != nullptr && !strcmp(address_library.dli_sname, "main")) {
                cerr << "Stack hit main" << endl;
                break;
            }

            if (bp != nullptr) {
                // Simulate a return
                ip = bp[1];
                bp = (void**) bp[0];
            } else {
                break;
            }

            cerr << endl;
            cerr << "Next ip: " << ip << " Next bp: " << bp << endl;
        }

        cerr << "Stack trace complete" << endl;
        cerr << endl;

        // Make sure to exit with the right code
        exit(signalNumber + 128);

    #else
        // On Linux we should just use Backtrace
        stacktrace_with_backtrace_and_exit(signalNumber);
    #endif

}

}
<commit_msg>Add some includes that Mac Travis wants<commit_after>#include "crash.hpp"

// Needed for automatic name demangling, but not all that portable
#include <cxxabi.h>
#include <execinfo.h>
// Needed to hack contexts for signal traces
#ifndef _XOPEN_SOURCE
    #define _XOPEN_SOURCE
    #include <ucontext.h>
    #undef _XOPEN_SOURCE
#else
    #include <ucontext.h>
#endif
// Needed to generate stacktraces ourselves
#include <dlfcn.h>

// iostream wants this on Travis on Mac
#include <pthread.h>

// We need strcmp
#include <cstring>

#include <cstdlib>
#include <string>
#include <iostream>

namespace vg {

// Demangle the name in thsi stack trace frame if we can find the API to do so.
string demangle_frame(string mangled) {
    // Demangle the name in a stack trace line as seen at
    // <http://panthema.net/2008/0901-stacktrace-demangled/>

    // Name is module(function+offset) [address] in standard format.
    // For example:
    // ../createIndex/createIndex(_Z12make_tempdirv+0x1a4) [0x46e8f4]
    // We need to find the start and end of the function part. Sometimes
    // the parens can just be empty, so we need to handle that too.

    // Where is the close paren, reading from the right?
    size_t closeParen = 0;
    // Where is the plus, reading from the right? If there is no plus in
    // the parens, set to 0.
    size_t plus = 0;
    // Where is the open paren, reading from right to left?
    size_t openParen = 0;

    for(size_t j = mangled.size() - 1; j != (size_t) -1; j--) {
        // Scan from right to left.

        if(closeParen == 0 && mangled[j] == ')') {
            // We found the rightmost close paren
            closeParen = j;
        } else if(j < closeParen && plus == 0 && mangled[j] == '+') {
            // We found the + to the left of the close paren.
            plus = j;
        } else if(j < closeParen && openParen == 0 && mangled[j] == '(') {
            // We found the open paren to the left of the close paren.
            openParen = j;

            // We're done parsing.
            break;
        }
    }

    if(openParen == 0 || closeParen == 0 || plus == 0) {
        // We couldn't pull out a name and address. Either we have a
        // nonstandard format or we have empty parens.

        // Just use the default trace message
        return mangled;
    } else {
        // We did parse out stuff!

        // Take everything before the open paren.
        string demangled = mangled.substr(0, openParen + 1);

        // Grab the function name
        string functionName = mangled.substr(openParen + 1, plus - (openParen + 1));

        // Make a place for the demangling function to save its status
        int status;

        // Do the demangling
        char* demangledName = abi::__cxa_demangle(functionName.c_str(), NULL, NULL, &status);

        if(status != 0) {
            // If we couldn't demangle the name, just use the mangled name.
            return mangled;
        }

        // Add the (probably) demangled name, a "+", and the rest of the
        // message.
        demangled += string(demangledName) + "+" + mangled.substr(plus + 1);

        if(status == 0) {
            // We got a demangled name we need to clean up.
            free(demangledName);
        }

        return demangled;
    }
}

void stacktrace_with_backtrace_and_exit(int signalNumber) {
    // How many frames can we handle?
    const size_t MAX_FRAMES = 100;

    // This holds the stack frames
    void *frames[MAX_FRAMES];

    // And this holds how many there actually are, which comes out of the
    // function that gets the frames.
    size_t framesUsed = backtrace(frames, MAX_FRAMES);

    cerr << "Stack trace from backtrace() for signal " << signalNumber << ":" << endl;

    char** traceMessages = backtrace_symbols(frames, framesUsed);

    for(size_t i = 0; i < framesUsed; i++) {
        // Print a demangled version of every frame
        cerr << demangle_frame(traceMessages[i]) << endl;
        // Separate frames because damangled can be long.
        cerr << "=================" << endl;
    }

    // Free our stacktrace memory.
    free(traceMessages);

    exit(signalNumber + 128);
}

void emit_stacktrace(int signalNumber, siginfo_t *signalInfo, void *signalContext) {
    // This holds the context that the signal came from, including registers and stuff
    ucontext_t* context = (ucontext_t*) signalContext;

    cerr << "Got signal " << signalNumber << endl;

    cerr << "Manual stack trace:" << endl;

    #ifdef __APPLE__
        // On OS X we need to do our own stack tracing since backtrace() doesn't seem to work

        // Now we compute our own stack trace, because backtrace() isn't so good on OS X.
        // We operate on the same principles as <https://stackoverflow.com/a/5426269>

        // TODO: This assumes x86
        // Fetch out the registers
        // We model IP as a pointer to void (i.e. into code)
        void* ip;
        // We model BP as an array of two things: previous BP, and previous IP.
        void** bp;

        // OS X 64 bit does it this way
        ip = (void*)context->uc_mcontext->__ss.__rip;
        bp = (void**)context->uc_mcontext->__ss.__rbp;

        // If this were Linux it would be (void*)context->uc_mcontext.gregs[REG_RIP] or REG_RBP

        // Allocate a place to keep the dynamic library info for the address the stack is executing at
        Dl_info address_library;

        cerr << endl;
        cerr << "Next ip: " << ip << " Next bp: " << bp << endl;
        while (true) {
            // Work out where the ip is.
            if (!dladdr(ip, &address_library)) {
                // This address doesn't belong to anything!
                cerr << "Stack leaves code at ip=" << ip << endl;
                break;
            }

            if (address_library.dli_sname != nullptr) {
                // Make a place for the demangling function to save its status
                int status;

                // Do the demangling
                char* demangledName = abi::__cxa_demangle(address_library.dli_sname, NULL, NULL, &status);

                if(status == 0) {
                    // Successfully demangled
                    cerr << "Address " << ip << " in demangled symbol " << demangledName
                        << " at offset " << (void*)((size_t)ip - ((size_t)address_library.dli_saddr))
                        << ", in library " << address_library.dli_fname
                        << " at offset " << (void*)((size_t)ip - ((size_t)address_library.dli_fbase)) << endl;
                    free(demangledName);
                } else {
                    // Leave mangled
                    cerr << "Address " << ip << " in mangled symbol " << address_library.dli_sname
                        << " at offset " << (void*)((size_t)ip - ((size_t)address_library.dli_saddr))
                        << ", in library " << address_library.dli_fname
                        << " at offset " << (void*)((size_t)ip - ((size_t)address_library.dli_fbase)) << endl;
                }

                #ifdef VG_DO_ATOS
                    // Try running atos to print a line number. This can be slow so we don't do it by default.
                    stringstream command;

                    command << "atos -o " << address_library.dli_fname << " -l " << address_library.dli_fbase << " " << ip;
                    cerr << "Running " << command.str() << "..." << endl;
                    system(command.str().c_str());
                #endif

            } else {
                cerr << "Address " << ip << " out of symbol in library " << address_library.dli_fname << endl;
            }

            if(address_library.dli_sname != nullptr && !strcmp(address_library.dli_sname, "main")) {
                cerr << "Stack hit main" << endl;
                break;
            }

            if (bp != nullptr) {
                // Simulate a return
                ip = bp[1];
                bp = (void**) bp[0];
            } else {
                break;
            }

            cerr << endl;
            cerr << "Next ip: " << ip << " Next bp: " << bp << endl;
        }

        cerr << "Stack trace complete" << endl;
        cerr << endl;

        // Make sure to exit with the right code
        exit(signalNumber + 128);

    #else
        // On Linux we should just use Backtrace
        stacktrace_with_backtrace_and_exit(signalNumber);
    #endif

}

}
<|endoftext|>