<commit_before>
#pragma once

#include "ksp_plugin/part.hpp"

#include <list>
#include <string>

#include "base/array.hpp"
#include "base/hexadecimal.hpp"
#include "base/not_null.hpp"

namespace principia {
namespace ksp_plugin {
namespace internal_part {

using base::Array;
using base::HexadecimalEncode;
using base::make_not_null_unique;
using base::UniqueBytes;

Part::Part(
    PartId const part_id,
    std::string const& name,
    Mass const& mass,
    DegreesOfFreedom<Barycentric> const& degrees_of_freedom,
    std::function<void()> deletion_callback)
    : part_id_(part_id),
      name_(name),
      mass_(mass),
      degrees_of_freedom_(degrees_of_freedom),
      tail_(make_not_null_unique<DiscreteTrajectory<Barycentric>>()),
      subset_node_(make_not_null_unique<Subset<Part>::Node>()),
      deletion_callback_(std::move(deletion_callback)) {}

Part::~Part() {
  LOG(INFO) << "Destroying part " << ShortDebugString();
  CHECK(!is_piled_up());
  if (deletion_callback_ != nullptr) {
    deletion_callback_();
  }
}

PartId Part::part_id() const {
  return part_id_;
}

void Part::set_mass(Mass const& mass) {
  mass_ = mass;
}

Mass const& Part::mass() const {
  return mass_;
}

void Part::clear_intrinsic_force() {
  intrinsic_force_ = Vector<Force, Barycentric>{};
}

void Part::increment_intrinsic_force(
    Vector<Force, Barycentric> const& intrinsic_force) {
  intrinsic_force_ += intrinsic_force;
}

Vector<Force, Barycentric> const& Part::intrinsic_force() const {
  return intrinsic_force_;
}

void Part::set_degrees_of_freedom(
    DegreesOfFreedom<Barycentric> const& degrees_of_freedom) {
  degrees_of_freedom_ = degrees_of_freedom;
}

DegreesOfFreedom<Barycentric> const&
Part::degrees_of_freedom() const {
  return degrees_of_freedom_;
}

DiscreteTrajectory<Barycentric>& Part::tail() {
  return *tail_;
}

DiscreteTrajectory<Barycentric> const& Part::tail() const {
  return *tail_;
}

bool Part::tail_is_authoritative() const {
  return tail_is_authoritative_;
}

void Part::set_tail_is_authoritative(bool const tail_is_authoritative) {
  tail_is_authoritative_ = tail_is_authoritative;
}

void Part::set_containing_pile_up(IteratorOn<std::list<PileUp>> const pile_up) {
  CHECK(!is_piled_up());
  LOG(INFO) << "Adding part " << ShortDebugString() << " to the pile up at "
            << &*pile_up.iterator();
  containing_pile_up_ = pile_up;
}

std::experimental::optional<IteratorOn<std::list<PileUp>>>
Part::containing_pile_up() const {
  return containing_pile_up_;
}

bool Part::is_piled_up() const {
  // TODO(egg): |has_value()| once we have a standard |optional|.
  return static_cast<bool>(containing_pile_up_);
}

void Part::clear_pile_up() {
  if (is_piled_up()) {
    IteratorOn<std::list<PileUp>> pile_up = *containing_pile_up_;
    for (not_null<Part*> const part : pile_up.iterator()->parts()) {
      LOG(INFO) << "Removing part " << part->ShortDebugString()
                << " from its pile up at " << &*pile_up.iterator();
      part->containing_pile_up_ = std::experimental::nullopt;
    }
    CHECK(!is_piled_up());
    pile_up.Erase();
  }
}

void Part::WriteToMessage(not_null<serialization::Part*> const message) const {
  message->set_part_id(part_id_);
  message->set_name(name_);
  mass_.WriteToMessage(message->mutable_mass());
  intrinsic_force_.WriteToMessage(message->mutable_intrinsic_force());
  if (containing_pile_up_) {
    message->set_containing_pile_up(containing_pile_up_->distance_from_begin());
  }
  degrees_of_freedom_.WriteToMessage(message->mutable_degrees_of_freedom());
  tail_->WriteToMessage(message->mutable_tail(), /*forks=*/{});
  message->set_tail_is_authoritative(tail_is_authoritative_);
}

not_null<std::unique_ptr<Part>> Part::ReadFromMessage(
    serialization::Part const& message,
    std::function<void()> deletion_callback) {
  not_null<std::unique_ptr<Part>> part =
      make_not_null_unique<Part>(message.part_id(),
                                 message.name(),
                                 Mass::ReadFromMessage(message.mass()),
                                 DegreesOfFreedom<Barycentric>::ReadFromMessage(
                                     message.degrees_of_freedom()),
                                 std::move(deletion_callback));
  part->increment_intrinsic_force(
      Vector<Force, Barycentric>::ReadFromMessage(message.intrinsic_force()));
  part->tail_ = DiscreteTrajectory<Barycentric>::ReadFromMessage(message.tail(),
                                                                 /*forks=*/{});
  part->set_tail_is_authoritative(message.tail_is_authoritative());
  return part;
}

void Part::FillContainingPileUpFromMessage(
    serialization::Part const& message,
    not_null<std::list<PileUp>*> const pile_ups) {
  if (message.has_containing_pile_up()) {
    auto it = pile_ups->begin();
    std::advance(it, message.containing_pile_up());
    containing_pile_up_ = IteratorOn<std::list<PileUp>>(pile_ups, it);
  }
}

std::string Part::ShortDebugString() const {
  UniqueBytes hex_id(sizeof(part_id_) * 2 + 1);
  Array<std::uint8_t const> id_bytes(
      reinterpret_cast<std::uint8_t const*>(&part_id_), sizeof(part_id_));
  HexadecimalEncode(id_bytes, hex_id.get());
  hex_id.data[sizeof(part_id_) * 2] = '\0';
  return name_ + " (" + reinterpret_cast<char const*>(hex_id.data.get()) + ")";
}

std::ostream& operator<<(std::ostream& out, Part const& part) {
  return out << "{"
             << part.part_id() << ", "
             << part.mass() << "}";
}

}  // namespace internal_part
}  // namespace ksp_plugin
}  // namespace principia
<commit_msg>to the nearest tonne, how much does this Kerbal weigh?<commit_after>
#pragma once

#include "ksp_plugin/part.hpp"

#include <list>
#include <string>

#include "base/array.hpp"
#include "base/hexadecimal.hpp"
#include "base/not_null.hpp"

namespace principia {
namespace ksp_plugin {
namespace internal_part {

using base::Array;
using base::HexadecimalEncode;
using base::make_not_null_unique;
using base::UniqueBytes;

Part::Part(
    PartId const part_id,
    std::string const& name,
    Mass const& mass,
    DegreesOfFreedom<Barycentric> const& degrees_of_freedom,
    std::function<void()> deletion_callback)
    : part_id_(part_id),
      name_(name),
      mass_(mass),
      degrees_of_freedom_(degrees_of_freedom),
      tail_(make_not_null_unique<DiscreteTrajectory<Barycentric>>()),
      subset_node_(make_not_null_unique<Subset<Part>::Node>()),
      deletion_callback_(std::move(deletion_callback)) {
  CHECK_GT(mass_, Mass{}) << ShortDebugString();
}

Part::~Part() {
  LOG(INFO) << "Destroying part " << ShortDebugString();
  CHECK(!is_piled_up());
  if (deletion_callback_ != nullptr) {
    deletion_callback_();
  }
}

PartId Part::part_id() const {
  return part_id_;
}

void Part::set_mass(Mass const& mass) {
  CHECK_GT(mass, Mass{}) << ShortDebugString();
  mass_ = mass;
}

Mass const& Part::mass() const {
  return mass_;
}

void Part::clear_intrinsic_force() {
  intrinsic_force_ = Vector<Force, Barycentric>{};
}

void Part::increment_intrinsic_force(
    Vector<Force, Barycentric> const& intrinsic_force) {
  intrinsic_force_ += intrinsic_force;
}

Vector<Force, Barycentric> const& Part::intrinsic_force() const {
  return intrinsic_force_;
}

void Part::set_degrees_of_freedom(
    DegreesOfFreedom<Barycentric> const& degrees_of_freedom) {
  degrees_of_freedom_ = degrees_of_freedom;
}

DegreesOfFreedom<Barycentric> const&
Part::degrees_of_freedom() const {
  return degrees_of_freedom_;
}

DiscreteTrajectory<Barycentric>& Part::tail() {
  return *tail_;
}

DiscreteTrajectory<Barycentric> const& Part::tail() const {
  return *tail_;
}

bool Part::tail_is_authoritative() const {
  return tail_is_authoritative_;
}

void Part::set_tail_is_authoritative(bool const tail_is_authoritative) {
  tail_is_authoritative_ = tail_is_authoritative;
}

void Part::set_containing_pile_up(IteratorOn<std::list<PileUp>> const pile_up) {
  CHECK(!is_piled_up());
  LOG(INFO) << "Adding part " << ShortDebugString() << " to the pile up at "
            << &*pile_up.iterator();
  containing_pile_up_ = pile_up;
}

std::experimental::optional<IteratorOn<std::list<PileUp>>>
Part::containing_pile_up() const {
  return containing_pile_up_;
}

bool Part::is_piled_up() const {
  // TODO(egg): |has_value()| once we have a standard |optional|.
  return static_cast<bool>(containing_pile_up_);
}

void Part::clear_pile_up() {
  if (is_piled_up()) {
    IteratorOn<std::list<PileUp>> pile_up = *containing_pile_up_;
    for (not_null<Part*> const part : pile_up.iterator()->parts()) {
      LOG(INFO) << "Removing part " << part->ShortDebugString()
                << " from its pile up at " << &*pile_up.iterator();
      part->containing_pile_up_ = std::experimental::nullopt;
    }
    CHECK(!is_piled_up());
    pile_up.Erase();
  }
}

void Part::WriteToMessage(not_null<serialization::Part*> const message) const {
  message->set_part_id(part_id_);
  message->set_name(name_);
  mass_.WriteToMessage(message->mutable_mass());
  intrinsic_force_.WriteToMessage(message->mutable_intrinsic_force());
  if (containing_pile_up_) {
    message->set_containing_pile_up(containing_pile_up_->distance_from_begin());
  }
  degrees_of_freedom_.WriteToMessage(message->mutable_degrees_of_freedom());
  tail_->WriteToMessage(message->mutable_tail(), /*forks=*/{});
  message->set_tail_is_authoritative(tail_is_authoritative_);
}

not_null<std::unique_ptr<Part>> Part::ReadFromMessage(
    serialization::Part const& message,
    std::function<void()> deletion_callback) {
  not_null<std::unique_ptr<Part>> part =
      make_not_null_unique<Part>(message.part_id(),
                                 message.name(),
                                 Mass::ReadFromMessage(message.mass()),
                                 DegreesOfFreedom<Barycentric>::ReadFromMessage(
                                     message.degrees_of_freedom()),
                                 std::move(deletion_callback));
  part->increment_intrinsic_force(
      Vector<Force, Barycentric>::ReadFromMessage(message.intrinsic_force()));
  part->tail_ = DiscreteTrajectory<Barycentric>::ReadFromMessage(message.tail(),
                                                                 /*forks=*/{});
  part->set_tail_is_authoritative(message.tail_is_authoritative());
  return part;
}

void Part::FillContainingPileUpFromMessage(
    serialization::Part const& message,
    not_null<std::list<PileUp>*> const pile_ups) {
  if (message.has_containing_pile_up()) {
    auto it = pile_ups->begin();
    std::advance(it, message.containing_pile_up());
    containing_pile_up_ = IteratorOn<std::list<PileUp>>(pile_ups, it);
  }
}

std::string Part::ShortDebugString() const {
  UniqueBytes hex_id(sizeof(part_id_) * 2 + 1);
  Array<std::uint8_t const> id_bytes(
      reinterpret_cast<std::uint8_t const*>(&part_id_), sizeof(part_id_));
  HexadecimalEncode(id_bytes, hex_id.get());
  hex_id.data[sizeof(part_id_) * 2] = '\0';
  return name_ + " (" + reinterpret_cast<char const*>(hex_id.data.get()) + ")";
}

std::ostream& operator<<(std::ostream& out, Part const& part) {
  return out << "{"
             << part.part_id() << ", "
             << part.mass() << "}";
}

}  // namespace internal_part
}  // namespace ksp_plugin
}  // namespace principia
<|endoftext|>


<commit_before>/**
 *  Copyright (C) 2011
 *  University of Rochester Department of Computer Science
 *    and
 *  Lehigh University Department of Computer Science and Engineering
 *
 * License: Modified BSD
 *          Please see the file LICENSE.RSTM for licensing information
 */

#include "common/platform.hpp"   // NORETURN, FASTCALL, etc
#include "stm/lib_globals.hpp"   // AbortHandler
#include "stm/macros.hpp"        // barrier signatures
#include "stm/txthread.hpp"      // TxThread stuff
#include "policies/policies.hpp" // curr_policy
#include "algs/algs.hpp"         // stms
#include "algs/tml_inline.hpp"

using stm::UNRECOVERABLE;
using stm::TxThread;
using stm::AbortHandler;
using stm::stms;
using stm::curr_policy;
using stm::CGL;

namespace {
  /**
   *  The abort handler is set during sys_init. We overwrite it with
   *  abort_irrevocable when a transaction becomes irrevocable, and we save the
   *  old one here so we can restore it during commit.
   */
  AbortHandler old_abort_handler = NULL;

  /**
   *  Handler for abort attempts while irrevocable. Useful for trapping problems
   *  early.
   */
  NORETURN void abort_irrevocable(TxThread* tx)
  {
      UNRECOVERABLE("Irrevocable thread attempted to abort.");
  }

  /**
   *  Handler for rollback attempts while irrevocable. Useful for trapping
   *  problems early.
   *
   *  NB: For whatever reason a 'using stm::scope_t' triggers an ICE in Mac OS
   *      X's default gcc-4.2.1. It's fine if we use the fully qualified
   *      namespace here.
   */
  stm::scope_t* rollback_irrevocable(STM_ROLLBACK_SIG(,,))
  {
      UNRECOVERABLE("Irrevocable thread attempted to rollback.");
      return NULL;
  }

  /**
   *  Resets all of the barriers to be the curr_policy bariers, except for
   *  tmabort which reverts to the one we saved, and tmbegin which should be
   *  done manually in the caller.
   */
  inline void unset_irrevocable_barriers(TxThread& tx)
  {
      tx.tmread           = stms[curr_policy.ALG_ID].read;
      tx.tmwrite          = stms[curr_policy.ALG_ID].write;
      tx.tmcommit         = stms[curr_policy.ALG_ID].commit;
      tx.tmrollback       = stms[curr_policy.ALG_ID].rollback;
      TxThread::tmirrevoc = stms[curr_policy.ALG_ID].irrevoc;
      tx.tmabort          = old_abort_handler;
  }

  /**
   *  custom commit for irrevocable transactions
   */
  TM_FASTCALL void commit_irrevocable(TxThread* tx)
  {
      // make self non-irrevocable, and unset local r/w/c barriers
      tx->irrevocable = false;
      unset_irrevocable_barriers(*tx);
      // now allow other transactions to run
      CFENCE;
      TxThread::tmbegin = stms[curr_policy.ALG_ID].begin;
      // finally, call the standard commit cleanup routine
      OnReadOnlyCommit(tx);
  }

  /**
   *  Sets all of the barriers to be irrevocable, except tmbegin.
   */
  inline void set_irrevocable_barriers(TxThread& tx)
  {
      tx.tmread           = stms[CGL].read;
      tx.tmwrite          = stms[CGL].write;
      tx.tmcommit         = commit_irrevocable;
      tx.tmrollback       = rollback_irrevocable;
      TxThread::tmirrevoc = stms[CGL].irrevoc;
      old_abort_handler   = tx.tmabort;
      tx.tmabort          = abort_irrevocable;
  }
}

namespace stm
{
  /**
   *  The 'Serial' algorithm requires a custom override for irrevocability,
   *  which we implement here.
   */
  void serial_irrevoc_override(TxThread* tx);

  /**
   *  Try to become irrevocable, inflight. This happens via mode
   *  switching. If the inflight irrevocability fails, we fall-back to an
   *  abort-and-restart-as-irrevocable scheme, based on the understanding
   *  that the begin_blocker tmbegin barrier will configure us as irrevocable
   *  and let us through if we have our irrevocable flag set. In addition to
   *  letting us through, it will set our barrier pointers to be the
   *  irrevocable barriers---it has to be done here because the rollback that
   *  the abort triggers will reset anything we try and set here.
   */
  void become_irrevoc()
  {
      TxThread* tx = Self;
      // special code for degenerate STM implementations
      //
      // NB: stm::is_irrevoc relies on how this works, so if it changes then
      //     please update that code as well.
      if (TxThread::tmirrevoc == stms[CGL].irrevoc)
          return;

      if ((curr_policy.ALG_ID == MCS) || (curr_policy.ALG_ID == Ticket))
          return;

      if (curr_policy.ALG_ID == Serial) {
          serial_irrevoc_override(tx);
          return;
      }

      if (curr_policy.ALG_ID == TML) {
          if (!tx->tmlHasLock)
              beforewrite_TML(tx);
          return;
      }

      // prevent new txns from starting.  If this fails, it means one of
      // three things:
      //
      //  - Someone else became irrevoc
      //  - Thread creation is in progress
      //  - Adaptivity is in progress
      //
      //  The first of these cases requires us to abort, because the irrevoc
      //  thread is running the 'wait for everyone' code that immediately
      //  follows this CAS.  Since we can't distinguish the three cases,
      //  we'll just abort all the time.  The impact should be minimal.
      if (!bcasptr(&TxThread::tmbegin, stms[curr_policy.ALG_ID].begin,
                   &begin_blocker))
          tx->tmabort(tx);

      // wait for everyone to be out of a transaction (scope == NULL)
      for (unsigned i = 0; i < threadcount.val; ++i)
          while ((i != (tx->id-1)) && (threads[i]->scope))
              spin64();

      // try to become irrevocable inflight
      tx->irrevocable = TxThread::tmirrevoc(tx);

      // If inflight succeeded, switch our barriers and return true.
      if (tx->irrevocable) {
          set_irrevocable_barriers(*tx);
          return;
      }

      // Otherwise we tmabort (but mark ourselves as irrevocable so that we get
      // through the begin_blocker after the abort). We don't switch the barriers
      // here because a) one of the barriers that we'd like to switch is
      // rollback, which is used by tmabort and b) rollback is designed to reset
      // our barriers to the default read-only barriers for the algorithm which
      // will just overwrite what we do here
      //
      // begin_blocker sets our barriers to be irrevocable if we have our
      // irrevocable flag set.
      tx->irrevocable = true;
      tx->tmabort(tx);
  }

  /**
   * True if the current algorithm is irrevocable.
   */
  bool is_irrevoc(const TxThread& tx)
  {
      if (tx.irrevocable || TxThread::tmirrevoc == stms[CGL].irrevoc)
          return true;
      if ((curr_policy.ALG_ID == MCS) || (curr_policy.ALG_ID  == Ticket))
          return true;
      if ((curr_policy.ALG_ID == TML) && (tx.tmlHasLock))
          return true;
      if (curr_policy.ALG_ID == Serial)
          return true;
      return false;
  }

  /**
   *  Custom begin method that blocks the starting thread, in order to get
   *  rendezvous correct during mode switching and GRL irrevocability. It
   *  doubles as an irrevocability mechanism for implementations where we don't
   *  have (or can't write) an in-flight irrevocability mechanism.
   */
  bool begin_blocker(TxThread* tx)
  {
      // if the caller is trying to restart as irrevocable, let them
      if (tx->irrevocable) {
          set_irrevocable_barriers(*tx);
          return true;
      }

      // adapt without longjmp
      while (true) {
          // first, clear the outer scope, because it's our 'tx/nontx' flag
          scope_t* b = tx->scope;
          tx->scope = 0;
          // next, wait for the begin_blocker to be uninstalled
          while (TxThread::tmbegin == begin_blocker)
              spin64();
          CFENCE;
          // now re-install the scope
#ifdef STM_CPU_SPARC
          tx->scope = b; WBR;
#else
          casptr((volatile uintptr_t*)&tx->scope, (uintptr_t)0, (uintptr_t)b);
#endif
          // read the begin function pointer AFTER setting the scope
          bool TM_FASTCALL (*beginner)(TxThread*) = TxThread::tmbegin;
          // if begin_blocker is no longer installed, we can call the pointer
          // to start a transaction, and then return.  Otherwise, we missed our
          // window, so we need to go back to the top of the loop.
          if (beginner != begin_blocker)
              return beginner(tx);
      }
  }
}

<commit_msg>Fixed the allocation logic for irrevocable transactions. Becoming irrevocable used to mess up the allocator's counter logic, which meant that we'd hit malloc and free from transactional contexts. Not sure how anything irrevocable ever worked... always concerning. :-|<commit_after>/**
 *  Copyright (C) 2011
 *  University of Rochester Department of Computer Science
 *    and
 *  Lehigh University Department of Computer Science and Engineering
 *
 * License: Modified BSD
 *          Please see the file LICENSE.RSTM for licensing information
 */

#include "profiling.hpp"         // Trigger
#include "common/platform.hpp"   // NORETURN, FASTCALL, etc
#include "stm/lib_globals.hpp"   // AbortHandler
#include "stm/macros.hpp"        // barrier signatures
#include "stm/txthread.hpp"      // TxThread stuff
#include "policies/policies.hpp" // curr_policy
#include "algs/algs.hpp"         // stms
#include "algs/tml_inline.hpp"

using stm::UNRECOVERABLE;
using stm::TxThread;
using stm::AbortHandler;
using stm::stms;
using stm::curr_policy;
using stm::CGL;
using stm::Trigger;

namespace {
  /**
   *  The abort handler is set during sys_init. We overwrite it with
   *  abort_irrevocable when a transaction becomes irrevocable, and we save the
   *  old one here so we can restore it during commit.
   */
  AbortHandler old_abort_handler = NULL;

  /**
   *  Handler for abort attempts while irrevocable. Useful for trapping problems
   *  early.
   */
  NORETURN void abort_irrevocable(TxThread* tx)
  {
      UNRECOVERABLE("Irrevocable thread attempted to abort.");
  }

  /**
   *  Handler for rollback attempts while irrevocable. Useful for trapping
   *  problems early.
   *
   *  NB: For whatever reason a 'using stm::scope_t' triggers an ICE in Mac OS
   *      X's default gcc-4.2.1. It's fine if we use the fully qualified
   *      namespace here.
   */
  stm::scope_t* rollback_irrevocable(STM_ROLLBACK_SIG(,,))
  {
      UNRECOVERABLE("Irrevocable thread attempted to rollback.");
      return NULL;
  }

  /**
   *  Resets all of the barriers to be the curr_policy bariers, except for
   *  tmabort which reverts to the one we saved, and tmbegin which should be
   *  done manually in the caller.
   */
  inline void unset_irrevocable_barriers(TxThread& tx)
  {
      tx.tmread           = stms[curr_policy.ALG_ID].read;
      tx.tmwrite          = stms[curr_policy.ALG_ID].write;
      tx.tmcommit         = stms[curr_policy.ALG_ID].commit;
      tx.tmrollback       = stms[curr_policy.ALG_ID].rollback;
      TxThread::tmirrevoc = stms[curr_policy.ALG_ID].irrevoc;
      tx.tmabort          = old_abort_handler;
  }

  /**
   *  custom commit for irrevocable transactions
   */
  TM_FASTCALL void commit_irrevocable(TxThread* tx)
  {
      // make self non-irrevocable, and unset local r/w/c barriers
      tx->irrevocable = false;
      unset_irrevocable_barriers(*tx);
      // now allow other transactions to run
      CFENCE;
      TxThread::tmbegin = stms[curr_policy.ALG_ID].begin;
      // finally, call the standard commit cleanup routine
      // OnReadOnlyCommit(tx);
      // NB: We need custom commit logic here, in particular, we don't want to
      //     notify the allocator of anything because irrevocable transactions
      //     don't buffer allocations.
      tx->abort_hist.onCommit(tx->consec_aborts);
      tx->consec_aborts = 0;
      ++tx->num_commits;
      Trigger::onCommitSTM(tx);
  }

  /**
   *  Sets all of the barriers to be irrevocable, except tmbegin.
   */
  inline void set_irrevocable_barriers(TxThread& tx)
  {
      tx.tmread           = stms[CGL].read;
      tx.tmwrite          = stms[CGL].write;
      tx.tmcommit         = commit_irrevocable;
      tx.tmrollback       = rollback_irrevocable;
      TxThread::tmirrevoc = stms[CGL].irrevoc;
      old_abort_handler   = tx.tmabort;
      tx.tmabort          = abort_irrevocable;
  }
}

namespace stm
{
  /**
   *  The 'Serial' algorithm requires a custom override for irrevocability,
   *  which we implement here.
   */
  void serial_irrevoc_override(TxThread* tx);

  /**
   *  Try to become irrevocable, inflight. This happens via mode
   *  switching. If the inflight irrevocability fails, we fall-back to an
   *  abort-and-restart-as-irrevocable scheme, based on the understanding
   *  that the begin_blocker tmbegin barrier will configure us as irrevocable
   *  and let us through if we have our irrevocable flag set. In addition to
   *  letting us through, it will set our barrier pointers to be the
   *  irrevocable barriers---it has to be done here because the rollback that
   *  the abort triggers will reset anything we try and set here.
   */
  void become_irrevoc()
  {
      TxThread* tx = Self;
      // special code for degenerate STM implementations
      //
      // NB: stm::is_irrevoc relies on how this works, so if it changes then
      //     please update that code as well.
      if (TxThread::tmirrevoc == stms[CGL].irrevoc)
          return;

      if ((curr_policy.ALG_ID == MCS) || (curr_policy.ALG_ID == Ticket))
          return;

      if (curr_policy.ALG_ID == Serial) {
          serial_irrevoc_override(tx);
          return;
      }

      if (curr_policy.ALG_ID == TML) {
          if (!tx->tmlHasLock)
              beforewrite_TML(tx);
          return;
      }

      // prevent new txns from starting.  If this fails, it means one of
      // three things:
      //
      //  - Someone else became irrevoc
      //  - Thread creation is in progress
      //  - Adaptivity is in progress
      //
      //  The first of these cases requires us to abort, because the irrevoc
      //  thread is running the 'wait for everyone' code that immediately
      //  follows this CAS.  Since we can't distinguish the three cases,
      //  we'll just abort all the time.  The impact should be minimal.
      if (!bcasptr(&TxThread::tmbegin, stms[curr_policy.ALG_ID].begin,
                   &begin_blocker))
          tx->tmabort(tx);

      // wait for everyone to be out of a transaction (scope == NULL)
      for (unsigned i = 0; i < threadcount.val; ++i)
          while ((i != (tx->id-1)) && (threads[i]->scope))
              spin64();

      // try to become irrevocable inflight
      tx->irrevocable = TxThread::tmirrevoc(tx);

      // If inflight succeeded, switch our barriers and return true.
      if (tx->irrevocable) {
          tx->allocator.onTxCommit();    // tell the allocator do cleanup
          set_irrevocable_barriers(*tx);
          return;
      }

      // Otherwise we tmabort (but mark ourselves as irrevocable so that we get
      // through the begin_blocker after the abort). We don't switch the barriers
      // here because a) one of the barriers that we'd like to switch is
      // rollback, which is used by tmabort and b) rollback is designed to reset
      // our barriers to the default read-only barriers for the algorithm which
      // will just overwrite what we do here
      //
      // begin_blocker sets our barriers to be irrevocable if we have our
      // irrevocable flag set.
      tx->irrevocable = true;
      tx->tmabort(tx);
  }

  /**
   * True if the current algorithm is irrevocable.
   */
  bool is_irrevoc(const TxThread& tx)
  {
      if (tx.irrevocable || TxThread::tmirrevoc == stms[CGL].irrevoc)
          return true;
      if ((curr_policy.ALG_ID == MCS) || (curr_policy.ALG_ID  == Ticket))
          return true;
      if ((curr_policy.ALG_ID == TML) && (tx.tmlHasLock))
          return true;
      if (curr_policy.ALG_ID == Serial)
          return true;
      return false;
  }

  /**
   *  Custom begin method that blocks the starting thread, in order to get
   *  rendezvous correct during mode switching and GRL irrevocability. It
   *  doubles as an irrevocability mechanism for implementations where we don't
   *  have (or can't write) an in-flight irrevocability mechanism.
   */
  bool begin_blocker(TxThread* tx)
  {
      // if the caller is trying to restart as irrevocable, let them
      // NB: do not notify allocator of anything because irrevocable
      //     transactions don't buffer allocation.
      if (tx->irrevocable) {
          set_irrevocable_barriers(*tx);
          return true;
      }

      // adapt without longjmp
      while (true) {
          // first, clear the outer scope, because it's our 'tx/nontx' flag
          scope_t* b = tx->scope;
          tx->scope = 0;
          // next, wait for the begin_blocker to be uninstalled
          while (TxThread::tmbegin == begin_blocker)
              spin64();
          CFENCE;
          // now re-install the scope
#ifdef STM_CPU_SPARC
          tx->scope = b; WBR;
#else
          casptr((volatile uintptr_t*)&tx->scope, (uintptr_t)0, (uintptr_t)b);
#endif
          // read the begin function pointer AFTER setting the scope
          bool TM_FASTCALL (*beginner)(TxThread*) = TxThread::tmbegin;
          // if begin_blocker is no longer installed, we can call the pointer
          // to start a transaction, and then return.  Otherwise, we missed our
          // window, so we need to go back to the top of the loop.
          if (beginner != begin_blocker)
              return beginner(tx);
      }
  }
}

<|endoftext|>


<commit_before>#include "Arduino.h"
#include "DFR_Key.h"

static int DEFAULT_KEY_PIN = 0;
static int DEFAULT_THRESHOLD = 5;

/*
	To use any alternate set of values you will need to enable it by a define.
	The define should NOT be done in code or it will impact all users. Visual
	Studio users can set 'DF_ROBOT_V1' in the Preprocessor definitions of the
	project, or add '-DDF_ROBOT_V1' under advanced options.

	Users of the standard Arduino IDE should create the file 'platform.local.txt'
	under <arduino_install>/hardware.arduino/avr and add the following line but
	be aware that when you upgrade your IDE this file may need to be re-created:

	compiler.cpp.extra_flags=-DDF_ROBOT_V1

	If further values are added in the future then of course adjust the name
	of the define that you specify accordingly.
*/
#ifdef DF_ROBOT_V1
	static int RIGHTKEY_ARV = 0;
	static int DOWNKEY_ARV	= 98;  //that's read "analogue read value"
	static int UPKEY_ARV	= 254;
	static int LEFTKEY_ARV	= 407;
	static int SELKEY_ARV	= 638;
	static int NOKEY_ARV	= 1023;
#else
	static int UPKEY_ARV	= 144; //that's read "analogue read value"
	static int DOWNKEY_ARV	= 329;
	static int LEFTKEY_ARV	= 505;
	static int RIGHTKEY_ARV = 0;
	static int SELKEY_ARV	= 742;
	static int NOKEY_ARV	= 1023;
#endif // ALT_VALUES

DFR_Key::DFR_Key()
{
  _refreshRate = 10;
  _keyPin = DEFAULT_KEY_PIN;
  _threshold = DEFAULT_THRESHOLD;
  _keyIn = NO_KEY;
  _curInput = NO_KEY;
  _curKey = NO_KEY;
  _prevInput = NO_KEY;
  _prevKey = NO_KEY;
  _oldTime = 0;
}

int DFR_Key::getKey()
{
 if (millis() > _oldTime + _refreshRate)
 {
    _prevInput = _curInput;
    _curInput = analogRead(_keyPin);

    if (_curInput == _prevInput)
    {
      _change = false;
      _curKey = _prevKey;
    }
    else
    {
      _change = true;
      _prevKey = _curKey;

      if (_curInput > UPKEY_ARV - _threshold && _curInput < UPKEY_ARV + _threshold ) _curKey = UP_KEY;
      else if (_curInput > DOWNKEY_ARV - _threshold && _curInput < DOWNKEY_ARV + _threshold ) _curKey = DOWN_KEY;
      else if (_curInput > RIGHTKEY_ARV - _threshold && _curInput < RIGHTKEY_ARV + _threshold ) _curKey = RIGHT_KEY;
      else if (_curInput > LEFTKEY_ARV - _threshold && _curInput < LEFTKEY_ARV + _threshold ) _curKey = LEFT_KEY;
      else if (_curInput > SELKEY_ARV - _threshold && _curInput < SELKEY_ARV + _threshold ) _curKey = SELECT_KEY;
      else _curKey = NO_KEY;
   }

   if (_change) return _curKey; else return SAMPLE_WAIT;
   _oldTime = millis();
 }
}

void DFR_Key::setRate(int rate)
{
  _refreshRate = rate;
}<commit_msg>Modified order of keypad defines for SwainSmart v1.1<commit_after>#include "Arduino.h"
#include "DFR_Key.h"

static int DEFAULT_KEY_PIN = 0;
static int DEFAULT_THRESHOLD = 5;

/*
	To use any alternate set of values you will need to enable it by a define.
	The define should NOT be done in code or it will impact all users. Visual
	Studio users can set 'DF_ROBOT_V1' in the Preprocessor definitions of the
	project, or add '-DDF_ROBOT_V1' under advanced options.

	Users of the standard Arduino IDE should create the file 'platform.local.txt'
	under <arduino_install>/hardware.arduino/avr and add the following line but
	be aware that when you upgrade your IDE this file may need to be re-created:

	compiler.cpp.extra_flags=-DDF_ROBOT_V1

	If further values are added in the future then of course adjust the name
	of the define that you specify accordingly.
*/
#ifdef DF_ROBOT_V1
	static int RIGHTKEY_ARV = 0;	//that's read "analogue read value"
	static int DOWNKEY_ARV	= 98;
	static int UPKEY_ARV	= 254;
	static int LEFTKEY_ARV	= 407;
	static int SELKEY_ARV	= 638;
	static int NOKEY_ARV	= 1023;
#else
	static int RIGHTKEY_ARV = 0;
	static int UPKEY_ARV	= 144;
	static int DOWNKEY_ARV	= 329;
	static int LEFTKEY_ARV	= 505;
	static int SELKEY_ARV	= 742;
	static int NOKEY_ARV	= 1023;
#endif

DFR_Key::DFR_Key()
{
  _refreshRate = 10;
  _keyPin = DEFAULT_KEY_PIN;
  _threshold = DEFAULT_THRESHOLD;
  _keyIn = NO_KEY;
  _curInput = NO_KEY;
  _curKey = NO_KEY;
  _prevInput = NO_KEY;
  _prevKey = NO_KEY;
  _oldTime = 0;
}

int DFR_Key::getKey()
{
 if (millis() > _oldTime + _refreshRate)
 {
    _prevInput = _curInput;
    _curInput = analogRead(_keyPin);

    if (_curInput == _prevInput)
    {
      _change = false;
      _curKey = _prevKey;
    }
    else
    {
      _change = true;
      _prevKey = _curKey;

      if (_curInput > UPKEY_ARV - _threshold && _curInput < UPKEY_ARV + _threshold ) _curKey = UP_KEY;
      else if (_curInput > DOWNKEY_ARV - _threshold && _curInput < DOWNKEY_ARV + _threshold ) _curKey = DOWN_KEY;
      else if (_curInput > RIGHTKEY_ARV - _threshold && _curInput < RIGHTKEY_ARV + _threshold ) _curKey = RIGHT_KEY;
      else if (_curInput > LEFTKEY_ARV - _threshold && _curInput < LEFTKEY_ARV + _threshold ) _curKey = LEFT_KEY;
      else if (_curInput > SELKEY_ARV - _threshold && _curInput < SELKEY_ARV + _threshold ) _curKey = SELECT_KEY;
      else _curKey = NO_KEY;
   }

   if (_change) return _curKey; else return SAMPLE_WAIT;
   _oldTime = millis();
 }
}

void DFR_Key::setRate(int rate)
{
  _refreshRate = rate;
}<|endoftext|>


<commit_before>#include <maya/MFnMesh.h>
#include <maya/MFnMeshData.h>
#include <maya/MEulerRotation.h>
#include <maya/MQuaternion.h>
#include <maya/MFnArrayAttrsData.h>

#include "Asset.h"
#include "AssetNode.h"
#include "AssetNodeOptions.h"
#include "OutputInstancerObject.h"
#include "hapiutil.h"
#include "util.h"

OutputInstancerObject::OutputInstancerObject(
        HAPI_NodeId nodeId
        ) :
    OutputObject(
            nodeId
          ),
    myGeoInfo(HAPI_GeoInfo_Create()),
    myLastSopCookCount(0)
{
}

OutputInstancerObject::~OutputInstancerObject() {}

OutputObject::ObjectType
OutputInstancerObject::type()
{
    return OutputObject::OBJECT_TYPE_INSTANCER;
}

void
OutputInstancerObject::update()
{
    HAPI_Result hapiResult;

    hapiResult = HAPI_GetNodeInfo(
            Util::theHAPISession.get(),
            myNodeId, &myNodeInfo
            );
    CHECK_HAPI(hapiResult);

    hapiResult = HAPI_GetObjectInfo(
            Util::theHAPISession.get(),
            myNodeId, &myObjectInfo
            );
    CHECK_HAPI(hapiResult);

    // Get the SOP nodes
    int geoCount;
    hapiResult = HAPI_ComposeChildNodeList(
            Util::theHAPISession.get(),
            myNodeId,
            HAPI_NODETYPE_SOP,
            HAPI_NODEFLAGS_DISPLAY,
            false,
            &geoCount
            );
    CHECK_HAPI(hapiResult);

    std::vector<HAPI_NodeId> geoNodeIds(geoCount);
    if(geoCount > 0)
    {
        hapiResult = HAPI_GetComposedChildNodeList(
                Util::theHAPISession.get(),
                myNodeId,
                &geoNodeIds.front(),
                geoCount
                );
        CHECK_HAPI(hapiResult);

        hapiResult = HAPI_GetNodeInfo(
                Util::theHAPISession.get(),
                geoNodeIds[0],
                &mySopNodeInfo
                );
        CHECK_HAPI(hapiResult);

        hapiResult = HAPI_GetGeoInfo(
                Util::theHAPISession.get(),
                geoNodeIds[0],
                &myGeoInfo
                );
        CHECK_HAPI(hapiResult);
    }

    if(mySopNodeInfo.totalCookCount > myLastSopCookCount)
    {
        // clear the arrays
        myInstancedObjectNames.clear();
        myInstancedObjectIndices.clear();
        myUniqueInstObjNames.clear();
        myHoudiniInstanceAttribute.clear();
        myHoudiniNameAttribute.clear();

        hapiResult = HAPI_GetPartInfo(
                Util::theHAPISession.get(),
                mySopNodeInfo.id, 0,
                &myPartInfo
                );
        CHECK_HAPI(hapiResult);

        if(myObjectInfo.objectToInstanceId >= 0)
        {
            myInstancedObjectIndices = MIntArray(myPartInfo.pointCount, 0);
            return;
        }

        // fill array of size pointCount of instanced names
        HAPI_AttributeInfo attrInfo;
        MStringArray instanceAttrs;
        hapiGetPointAttribute(mySopNodeInfo.id, 0, "instance", attrInfo, instanceAttrs);
        for(unsigned int i=0; i<instanceAttrs.length(); i++)
        {
            MStringArray splitObjName;
            instanceAttrs[i].split('/', splitObjName);
            myInstancedObjectNames.append(splitObjName[splitObjName.length()-1]);
            myHoudiniInstanceAttribute.append(instanceAttrs[i]);
        }

        MStringArray nameAttrs;
        hapiGetPointAttribute(mySopNodeInfo.id, 0, "name", attrInfo, nameAttrs);
        for(unsigned int ii = 0; ii < nameAttrs.length(); ii++)
        {
            myHoudiniNameAttribute.append(nameAttrs[ii]);
        }

        // get a list of unique instanced names, and compute the object indices that would
        // be passed to Maya instancer
        for(unsigned int i = 0; i< myInstancedObjectNames.length(); ++i)
        {
            bool duplicate = false;
            unsigned int j = 0;
            for(; j< myUniqueInstObjNames.length(); ++j)
            {
                if(myUniqueInstObjNames[j] == myInstancedObjectNames[i])
                {
                    duplicate = true;
                    break;
                }
            }
            if(!duplicate)
                myUniqueInstObjNames.append(myInstancedObjectNames[i]);
            myInstancedObjectIndices.append((int) j);
        }

        // Workaround a crash where we can't determine the object to instance.
        if(!myInstancedObjectNames.length())
        {
            myInstancedObjectIndices = MIntArray(myPartInfo.pointCount, -1);
        }
    }
}

MIntArray
OutputInstancerObject::getInstancedObjIds()
{
    MIntArray ret;
    if(myObjectInfo.objectToInstanceId >= 0)
        ret.append(myObjectInfo.objectToInstanceId);
    return ret;
}

MStringArray
OutputInstancerObject::getUniqueInstObjNames()
{
    return myUniqueInstObjNames;
}

MStatus
OutputInstancerObject::compute(
        const MTime &time,
        const MPlug &plug,
        MDataBlock& data,
        MDataHandle& handle,
        AssetNodeOptions::AccessorDataBlock &options,
        bool &needToSyncOutputs,
        const bool needToRecomputeOutputData
        )
{
    update();

    if(myGeoInfo.partCount <= 0)
        return MS::kFailure;

    if((mySopNodeInfo.totalCookCount > myLastSopCookCount) || needToRecomputeOutputData)
    {
        MDataHandle instancerDataHandle = handle.child(AssetNode::outputInstancerData);
        MArrayDataHandle instancedObjectNamesHandle = handle.child(AssetNode::outputInstancedObjectNames);
        MArrayDataHandle houdiniInstanceAttributeHandle = handle.child(AssetNode::outputHoudiniInstanceAttribute);
        MArrayDataHandle houdiniNameAttributeHandle = handle.child(AssetNode::outputHoudiniNameAttribute);
        MArrayDataHandle instanceTransformHandle = handle.child(AssetNode::outputInstanceTransform);

        MObject arrayDataObj = instancerDataHandle.data();
        MFnArrayAttrsData arrayDataFn(arrayDataObj);
        if(arrayDataObj.isNull())
        {
            arrayDataObj = arrayDataFn.create();
            instancerDataHandle.set(arrayDataObj);

            arrayDataObj = instancerDataHandle.data();
            arrayDataFn.setObject(arrayDataObj);
        }

        MVectorArray positions = arrayDataFn.vectorArray("position");
        MVectorArray rotations = arrayDataFn.vectorArray("rotation");
        MVectorArray scales = arrayDataFn.vectorArray("scale");
        MIntArray objectIndices = arrayDataFn.intArray("objectIndex");

        unsigned int size = myPartInfo.pointCount;
        HAPI_Transform * instTransforms = new HAPI_Transform[size];
        CHECK_HAPI(HAPI_GetInstanceTransformsOnPart(
                Util::theHAPISession.get(),
		0,
                mySopNodeInfo.id,
                HAPI_SRT,
                instTransforms,
                0, size
                ));

        Util::resizeArrayDataHandle(houdiniInstanceAttributeHandle, size);
        Util::resizeArrayDataHandle(houdiniNameAttributeHandle, size);
        Util::resizeArrayDataHandle(instanceTransformHandle, size);

        if(positions.length() != size && !options.useInstancerNode())
        {
            needToSyncOutputs = true;
        }

        positions.setLength(size);
        rotations.setLength(size);
        scales.setLength(size);
        objectIndices.setLength(size);

        for(unsigned int j=0; j<size; j++)
        {
            HAPI_Transform it = instTransforms[j];
            MVector p(it.position[0], it.position[1], it.position[2]);
            MVector r = MQuaternion(it.rotationQuaternion[0],
                    it.rotationQuaternion[1], it.rotationQuaternion[2],
                    it.rotationQuaternion[3]).asEulerRotation().asVector();
            MVector s(it.scale[0], it.scale[1], it.scale[2]);

            int objIndex = myInstancedObjectIndices[j];

            if (options.preserveScale())
                p *= 100.0;

            positions[j] = p;
            rotations[j] = r;
            scales[j] = s;
            objectIndices[j] = objIndex;

            CHECK_MSTATUS(houdiniInstanceAttributeHandle.jumpToArrayElement(j));
            MDataHandle intanceAttributeHandle = houdiniInstanceAttributeHandle.outputValue();
            intanceAttributeHandle .set(myHoudiniInstanceAttribute[j]);

            CHECK_MSTATUS(houdiniNameAttributeHandle.jumpToArrayElement(j));
            MDataHandle nameAttributeHandle = houdiniNameAttributeHandle.outputValue();
            nameAttributeHandle.set(myHoudiniNameAttribute[j]);

            CHECK_MSTATUS(instanceTransformHandle.jumpToArrayElement(j));
            MDataHandle transformHandle  = instanceTransformHandle.outputValue();

            MDataHandle translateHandle = transformHandle.child(AssetNode::outputInstanceTranslate);
            MDataHandle rotateHandle = transformHandle.child(AssetNode::outputInstanceRotate);
            MDataHandle scaleHandle = transformHandle.child(AssetNode::outputInstanceScale);

            MDataHandle txHandle = translateHandle.child(AssetNode::outputInstanceTranslateX);
            txHandle.set(p.x);
            MDataHandle tyHandle = translateHandle.child(AssetNode::outputInstanceTranslateY);
            tyHandle.set(p.y);
            MDataHandle tzHandle = translateHandle.child(AssetNode::outputInstanceTranslateZ);
            tzHandle.set(p.z);

            MDataHandle rxHandle = rotateHandle.child(AssetNode::outputInstanceRotateX);
            rxHandle.set(r.x);
            MDataHandle ryHandle = rotateHandle.child(AssetNode::outputInstanceRotateY);
            ryHandle.set(r.y);
            MDataHandle rzHandle = rotateHandle.child(AssetNode::outputInstanceRotateZ);
            rzHandle.set(r.z);

            MDataHandle sxHandle = scaleHandle.child(AssetNode::outputInstanceScaleX);
            sxHandle.set(s.x);
            MDataHandle syHandle = scaleHandle.child(AssetNode::outputInstanceScaleY);
            syHandle.set(s.y);
            MDataHandle szHandle = scaleHandle.child(AssetNode::outputInstanceScaleZ);
            szHandle.set(s.z);
        }

        houdiniInstanceAttributeHandle.setAllClean();
        houdiniNameAttributeHandle.setAllClean();
        instanceTransformHandle.setAllClean();

        delete[] instTransforms;

        if(myObjectInfo.objectToInstanceId >= 0)
        {
            // instancing a single object
            Util::resizeArrayDataHandle(instancedObjectNamesHandle, 1);

            HAPI_ObjectInfo instanceObjectInfo;
            CHECK_HAPI(HAPI_GetObjectInfo(
                    Util::theHAPISession.get(),
                    myObjectInfo.objectToInstanceId,
                    &instanceObjectInfo
                    ));
            MString name = Util::HAPIString(instanceObjectInfo.nameSH);

            CHECK_MSTATUS(instancedObjectNamesHandle.jumpToArrayElement(0));
            MDataHandle h = instancedObjectNamesHandle.outputValue();
            h.set(name);
        } else
        {
            // instancing multiple objects
            Util::resizeArrayDataHandle(instancedObjectNamesHandle,
                    myUniqueInstObjNames.length());

            for(unsigned int i=0; i< myUniqueInstObjNames.length(); i++)
            {
                CHECK_MSTATUS(instancedObjectNamesHandle.jumpToArrayElement(i));
                MDataHandle h = instancedObjectNamesHandle.outputValue();
                h.set(myUniqueInstObjNames[i]);
            }
        }
        instancedObjectNamesHandle.setAllClean();

        myLastSopCookCount = mySopNodeInfo.totalCookCount;
    }

    return MS::kSuccess;
}
<commit_msg>fix typo that caused instance transforms to sometimes not be computed in the maya plugin.<commit_after>#include <maya/MFnMesh.h>
#include <maya/MFnMeshData.h>
#include <maya/MEulerRotation.h>
#include <maya/MQuaternion.h>
#include <maya/MFnArrayAttrsData.h>

#include "Asset.h"
#include "AssetNode.h"
#include "AssetNodeOptions.h"
#include "OutputInstancerObject.h"
#include "hapiutil.h"
#include "util.h"

OutputInstancerObject::OutputInstancerObject(
        HAPI_NodeId nodeId
        ) :
    OutputObject(
            nodeId
          ),
    myGeoInfo(HAPI_GeoInfo_Create()),
    myLastSopCookCount(0)
{
}

OutputInstancerObject::~OutputInstancerObject() {}

OutputObject::ObjectType
OutputInstancerObject::type()
{
    return OutputObject::OBJECT_TYPE_INSTANCER;
}

void
OutputInstancerObject::update()
{
    HAPI_Result hapiResult;

    hapiResult = HAPI_GetNodeInfo(
            Util::theHAPISession.get(),
            myNodeId, &myNodeInfo
            );
    CHECK_HAPI(hapiResult);

    hapiResult = HAPI_GetObjectInfo(
            Util::theHAPISession.get(),
            myNodeId, &myObjectInfo
            );
    CHECK_HAPI(hapiResult);

    // Get the SOP nodes
    int geoCount;
    hapiResult = HAPI_ComposeChildNodeList(
            Util::theHAPISession.get(),
            myNodeId,
            HAPI_NODETYPE_SOP,
            HAPI_NODEFLAGS_DISPLAY,
            false,
            &geoCount
            );
    CHECK_HAPI(hapiResult);

    std::vector<HAPI_NodeId> geoNodeIds(geoCount);
    if(geoCount > 0)
    {
        hapiResult = HAPI_GetComposedChildNodeList(
                Util::theHAPISession.get(),
                myNodeId,
                &geoNodeIds.front(),
                geoCount
                );
        CHECK_HAPI(hapiResult);

        hapiResult = HAPI_GetNodeInfo(
                Util::theHAPISession.get(),
                geoNodeIds[0],
                &mySopNodeInfo
                );
        CHECK_HAPI(hapiResult);

        hapiResult = HAPI_GetGeoInfo(
                Util::theHAPISession.get(),
                geoNodeIds[0],
                &myGeoInfo
                );
        CHECK_HAPI(hapiResult);
    }

    if(mySopNodeInfo.totalCookCount > myLastSopCookCount)
    {
        // clear the arrays
        myInstancedObjectNames.clear();
        myInstancedObjectIndices.clear();
        myUniqueInstObjNames.clear();
        myHoudiniInstanceAttribute.clear();
        myHoudiniNameAttribute.clear();

        hapiResult = HAPI_GetPartInfo(
                Util::theHAPISession.get(),
                mySopNodeInfo.id, 0,
                &myPartInfo
                );
        CHECK_HAPI(hapiResult);

        if(myObjectInfo.objectToInstanceId >= 0)
        {
            myInstancedObjectIndices = MIntArray(myPartInfo.pointCount, 0);
            return;
        }

        // fill array of size pointCount of instanced names
        HAPI_AttributeInfo attrInfo;
        MStringArray instanceAttrs;
        hapiGetPointAttribute(mySopNodeInfo.id, 0, "instance", attrInfo, instanceAttrs);
        for(unsigned int i=0; i<instanceAttrs.length(); i++)
        {
            MStringArray splitObjName;
            instanceAttrs[i].split('/', splitObjName);
            myInstancedObjectNames.append(splitObjName[splitObjName.length()-1]);
            myHoudiniInstanceAttribute.append(instanceAttrs[i]);
        }

        MStringArray nameAttrs;
        hapiGetPointAttribute(mySopNodeInfo.id, 0, "name", attrInfo, nameAttrs);
        for(unsigned int ii = 0; ii < nameAttrs.length(); ii++)
        {
            myHoudiniNameAttribute.append(nameAttrs[ii]);
        }

        // get a list of unique instanced names, and compute the object indices that would
        // be passed to Maya instancer
        for(unsigned int i = 0; i< myInstancedObjectNames.length(); ++i)
        {
            bool duplicate = false;
            unsigned int j = 0;
            for(; j< myUniqueInstObjNames.length(); ++j)
            {
                if(myUniqueInstObjNames[j] == myInstancedObjectNames[i])
                {
                    duplicate = true;
                    break;
                }
            }
            if(!duplicate)
                myUniqueInstObjNames.append(myInstancedObjectNames[i]);
            myInstancedObjectIndices.append((int) j);
        }

        // Workaround a crash where we can't determine the object to instance.
        if(!myInstancedObjectNames.length())
        {
            myInstancedObjectIndices = MIntArray(myPartInfo.pointCount, -1);
        }
    }
}

MIntArray
OutputInstancerObject::getInstancedObjIds()
{
    MIntArray ret;
    if(myObjectInfo.objectToInstanceId >= 0)
        ret.append(myObjectInfo.objectToInstanceId);
    return ret;
}

MStringArray
OutputInstancerObject::getUniqueInstObjNames()
{
    return myUniqueInstObjNames;
}

MStatus
OutputInstancerObject::compute(
        const MTime &time,
        const MPlug &plug,
        MDataBlock& data,
        MDataHandle& handle,
        AssetNodeOptions::AccessorDataBlock &options,
        bool &needToSyncOutputs,
        const bool needToRecomputeOutputData
        )
{
    update();

    if(myGeoInfo.partCount <= 0)
        return MS::kFailure;

    if((mySopNodeInfo.totalCookCount > myLastSopCookCount) || needToRecomputeOutputData)
    {
        MDataHandle instancerDataHandle = handle.child(AssetNode::outputInstancerData);
        MArrayDataHandle instancedObjectNamesHandle = handle.child(AssetNode::outputInstancedObjectNames);
        MArrayDataHandle houdiniInstanceAttributeHandle = handle.child(AssetNode::outputHoudiniInstanceAttribute);
        MArrayDataHandle houdiniNameAttributeHandle = handle.child(AssetNode::outputHoudiniNameAttribute);
        MArrayDataHandle instanceTransformHandle = handle.child(AssetNode::outputInstanceTransform);

        MObject arrayDataObj = instancerDataHandle.data();
        MFnArrayAttrsData arrayDataFn(arrayDataObj);
        if(arrayDataObj.isNull())
        {
            arrayDataObj = arrayDataFn.create();
            instancerDataHandle.set(arrayDataObj);

            arrayDataObj = instancerDataHandle.data();
            arrayDataFn.setObject(arrayDataObj);
        }

        MVectorArray positions = arrayDataFn.vectorArray("position");
        MVectorArray rotations = arrayDataFn.vectorArray("rotation");
        MVectorArray scales = arrayDataFn.vectorArray("scale");
        MIntArray objectIndices = arrayDataFn.intArray("objectIndex");

        unsigned int size = myPartInfo.pointCount;
        HAPI_Transform * instTransforms = new HAPI_Transform[size];
        CHECK_HAPI(HAPI_GetInstanceTransformsOnPart(
                Util::theHAPISession.get(),
                mySopNodeInfo.id,
		0,
                HAPI_SRT,
                instTransforms,
                0, size
                ));

        Util::resizeArrayDataHandle(houdiniInstanceAttributeHandle, size);
        Util::resizeArrayDataHandle(houdiniNameAttributeHandle, size);
        Util::resizeArrayDataHandle(instanceTransformHandle, size);

        if(positions.length() != size && !options.useInstancerNode())
        {
            needToSyncOutputs = true;
        }

        positions.setLength(size);
        rotations.setLength(size);
        scales.setLength(size);
        objectIndices.setLength(size);

        for(unsigned int j=0; j<size; j++)
        {
            HAPI_Transform it = instTransforms[j];
            MVector p(it.position[0], it.position[1], it.position[2]);
            MVector r = MQuaternion(it.rotationQuaternion[0],
                    it.rotationQuaternion[1], it.rotationQuaternion[2],
                    it.rotationQuaternion[3]).asEulerRotation().asVector();
            MVector s(it.scale[0], it.scale[1], it.scale[2]);

            int objIndex = myInstancedObjectIndices[j];

            if (options.preserveScale())
                p *= 100.0;

            positions[j] = p;
            rotations[j] = r;
            scales[j] = s;
            objectIndices[j] = objIndex;

            CHECK_MSTATUS(houdiniInstanceAttributeHandle.jumpToArrayElement(j));
            MDataHandle intanceAttributeHandle = houdiniInstanceAttributeHandle.outputValue();
            intanceAttributeHandle .set(myHoudiniInstanceAttribute[j]);

            CHECK_MSTATUS(houdiniNameAttributeHandle.jumpToArrayElement(j));
            MDataHandle nameAttributeHandle = houdiniNameAttributeHandle.outputValue();
            nameAttributeHandle.set(myHoudiniNameAttribute[j]);

            CHECK_MSTATUS(instanceTransformHandle.jumpToArrayElement(j));
            MDataHandle transformHandle  = instanceTransformHandle.outputValue();

            MDataHandle translateHandle = transformHandle.child(AssetNode::outputInstanceTranslate);
            MDataHandle rotateHandle = transformHandle.child(AssetNode::outputInstanceRotate);
            MDataHandle scaleHandle = transformHandle.child(AssetNode::outputInstanceScale);

            MDataHandle txHandle = translateHandle.child(AssetNode::outputInstanceTranslateX);
            txHandle.set(p.x);
            MDataHandle tyHandle = translateHandle.child(AssetNode::outputInstanceTranslateY);
            tyHandle.set(p.y);
            MDataHandle tzHandle = translateHandle.child(AssetNode::outputInstanceTranslateZ);
            tzHandle.set(p.z);

            MDataHandle rxHandle = rotateHandle.child(AssetNode::outputInstanceRotateX);
            rxHandle.set(r.x);
            MDataHandle ryHandle = rotateHandle.child(AssetNode::outputInstanceRotateY);
            ryHandle.set(r.y);
            MDataHandle rzHandle = rotateHandle.child(AssetNode::outputInstanceRotateZ);
            rzHandle.set(r.z);

            MDataHandle sxHandle = scaleHandle.child(AssetNode::outputInstanceScaleX);
            sxHandle.set(s.x);
            MDataHandle syHandle = scaleHandle.child(AssetNode::outputInstanceScaleY);
            syHandle.set(s.y);
            MDataHandle szHandle = scaleHandle.child(AssetNode::outputInstanceScaleZ);
            szHandle.set(s.z);
        }

        houdiniInstanceAttributeHandle.setAllClean();
        houdiniNameAttributeHandle.setAllClean();
        instanceTransformHandle.setAllClean();

        delete[] instTransforms;

        if(myObjectInfo.objectToInstanceId >= 0)
        {
            // instancing a single object
            Util::resizeArrayDataHandle(instancedObjectNamesHandle, 1);

            HAPI_ObjectInfo instanceObjectInfo;
            CHECK_HAPI(HAPI_GetObjectInfo(
                    Util::theHAPISession.get(),
                    myObjectInfo.objectToInstanceId,
                    &instanceObjectInfo
                    ));
            MString name = Util::HAPIString(instanceObjectInfo.nameSH);

            CHECK_MSTATUS(instancedObjectNamesHandle.jumpToArrayElement(0));
            MDataHandle h = instancedObjectNamesHandle.outputValue();
            h.set(name);
        } else
        {
            // instancing multiple objects
            Util::resizeArrayDataHandle(instancedObjectNamesHandle,
                    myUniqueInstObjNames.length());

            for(unsigned int i=0; i< myUniqueInstObjNames.length(); i++)
            {
                CHECK_MSTATUS(instancedObjectNamesHandle.jumpToArrayElement(i));
                MDataHandle h = instancedObjectNamesHandle.outputValue();
                h.set(myUniqueInstObjNames[i]);
            }
        }
        instancedObjectNamesHandle.setAllClean();

        myLastSopCookCount = mySopNodeInfo.totalCookCount;
    }

    return MS::kSuccess;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015, Cryptonomex, Inc.
 * All rights reserved.
 *
 * This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
 * the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
 * are permitted until September 8, 2015, provided that the following conditions are met:
 *
 * 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 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 COPYRIGHT HOLDER OR
 * 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.
 */

#include <graphene/chain/database.hpp>
#include <graphene/chain/db_with.hpp>

#include <graphene/chain/asset_object.hpp>
#include <graphene/chain/global_property_object.hpp>
#include <graphene/chain/proposal_object.hpp>
#include <graphene/chain/transaction_object.hpp>
#include <graphene/chain/market_evaluator.hpp>
#include <graphene/chain/withdraw_permission_object.hpp>
#include <graphene/chain/witness_object.hpp>
#include <graphene/chain/protocol/fee_schedule.hpp>

#include <fc/uint128.hpp>

namespace graphene { namespace chain {

void database::update_global_dynamic_data( const signed_block& b )
{
   const dynamic_global_property_object& _dgp =
      dynamic_global_property_id_type(0)(*this);

   uint32_t missed_blocks = get_slot_at_time( b.timestamp );
   assert( missed_blocks != 0 );
   missed_blocks--;
   for( uint32_t i = 0; i < missed_blocks; ++i ) {
      const auto& witness_missed = get_scheduled_witness( i+1 )(*this);
      if(  witness_missed.id != b.witness ) {
         const auto& witness_account = witness_missed.witness_account(*this);
         /*
         if( (fc::time_point::now() - b.timestamp) < fc::seconds(30) )
            wlog( "Witness ${name} missed block ${n} around ${t}", ("name",witness_account.name)("n",b.block_num())("t",b.timestamp) );
            */

         modify( witness_missed, [&]( witness_object& w ) {
           w.total_missed++;
         });
      }
   }

   // dynamic global properties updating
   modify( _dgp, [&]( dynamic_global_property_object& dgp ){
      if( BOOST_UNLIKELY( b.block_num() == 1 ) )
         dgp.recently_missed_count = 0;
         else if( _checkpoints.size() && _checkpoints.rbegin()->first >= b.block_num() )
         dgp.recently_missed_count = 0;
      else if( missed_blocks )
         dgp.recently_missed_count += GRAPHENE_RECENTLY_MISSED_COUNT_INCREMENT*missed_blocks;
      else if( dgp.recently_missed_count > GRAPHENE_RECENTLY_MISSED_COUNT_INCREMENT )
         dgp.recently_missed_count -= GRAPHENE_RECENTLY_MISSED_COUNT_DECREMENT;
      else if( dgp.recently_missed_count > 0 )
         dgp.recently_missed_count--;

      dgp.head_block_number = b.block_num();
      dgp.head_block_id = b.id();
      dgp.time = b.timestamp;
      dgp.current_witness = b.witness;
      dgp.recent_slots_filled = (
           (dgp.recent_slots_filled << 1)
           + 1) << missed_blocks;
      dgp.current_aslot += missed_blocks+1;
   });

   if( !(get_node_properties().skip_flags & skip_undo_history_check) )
   {
      GRAPHENE_ASSERT( _dgp.recently_missed_count < GRAPHENE_MAX_UNDO_HISTORY, undo_database_exception,
                 "The database does not have enough undo history to support a blockchain with so many missed blocks. "
                 "Please add a checkpoint if you would like to continue applying blocks beyond this point.",
                 ("recently_missed",_dgp.recently_missed_count)("max_undo",GRAPHENE_MAX_UNDO_HISTORY) );
   }

   _undo_db.set_max_size( _dgp.recently_missed_count + GRAPHENE_MIN_UNDO_HISTORY );
   _fork_db.set_max_size( _dgp.recently_missed_count + GRAPHENE_MIN_UNDO_HISTORY );
}

void database::update_signing_witness(const witness_object& signing_witness, const signed_block& new_block)
{
   const global_property_object& gpo = get_global_properties();
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();
   uint64_t new_block_aslot = dpo.current_aslot + get_slot_at_time( new_block.timestamp );

   share_type witness_pay = std::min( gpo.parameters.witness_pay_per_block, dpo.witness_budget );

   modify( dpo, [&]( dynamic_global_property_object& _dpo )
   {
      _dpo.witness_budget -= witness_pay;
   } );

   deposit_witness_pay( signing_witness, witness_pay );

   modify( signing_witness, [&]( witness_object& _wit )
   {
      _wit.last_aslot = new_block_aslot;
   } );
}

void database::clear_expired_transactions()
{
   //Look for expired transactions in the deduplication list, and remove them.
   //Transactions must have expired by at least two forking windows in order to be removed.
   auto& transaction_idx = static_cast<transaction_index&>(get_mutable_index(implementation_ids, impl_transaction_object_type));
   const auto& dedupe_index = transaction_idx.indices().get<by_expiration>();
   while( (!dedupe_index.empty()) && (head_block_time() > dedupe_index.rbegin()->trx.expiration) )
      transaction_idx.remove(*dedupe_index.rbegin());
}

void database::clear_expired_proposals()
{
   const auto& proposal_expiration_index = get_index_type<proposal_index>().indices().get<by_expiration>();
   while( !proposal_expiration_index.empty() && proposal_expiration_index.begin()->expiration_time <= head_block_time() )
   {
      const proposal_object& proposal = *proposal_expiration_index.begin();
      processed_transaction result;
      try {
         if( proposal.is_authorized_to_execute(*this) )
         {
            result = push_proposal(proposal);
            //TODO: Do something with result so plugins can process it.
            continue;
         }
      } catch( const fc::exception& e ) {
         elog("Failed to apply proposed transaction on its expiration. Deleting it.\n${proposal}\n${error}",
              ("proposal", proposal)("error", e.to_detail_string()));
      }
      remove(proposal);
   }
}

void database::clear_expired_orders()
{
   detail::with_skip_flags( *this,
      get_node_properties().skip_flags | skip_authority_check, [&](){
         transaction_evaluation_state cancel_context(this);

         //Cancel expired limit orders
         auto& limit_index = get_index_type<limit_order_index>().indices().get<by_expiration>();
         while( !limit_index.empty() && limit_index.begin()->expiration <= head_block_time() )
         {
            limit_order_cancel_operation canceler;
            const limit_order_object& order = *limit_index.begin();
            canceler.fee_paying_account = order.seller;
            canceler.order = order.id;
            apply_operation(cancel_context, canceler);
         }
     });

   //Process expired force settlement orders
   auto& settlement_index = get_index_type<force_settlement_index>().indices().get<by_expiration>();
   if( !settlement_index.empty() )
   {
      asset_id_type current_asset = settlement_index.begin()->settlement_asset_id();
      asset max_settlement_volume;

      auto next_asset = [&current_asset, &settlement_index] {
         auto bound = settlement_index.upper_bound(current_asset);
         if( bound == settlement_index.end() )
            return false;
         current_asset = bound->settlement_asset_id();
         return true;
      };

      // At each iteration, we either consume the current order and remove it, or we move to the next asset
      for( auto itr = settlement_index.lower_bound(current_asset);
           itr != settlement_index.end();
           itr = settlement_index.lower_bound(current_asset) )
      {
         const force_settlement_object& order = *itr;
         auto order_id = order.id;
         current_asset = order.settlement_asset_id();
         const asset_object& mia_object = get(current_asset);
         const asset_bitasset_data_object mia = mia_object.bitasset_data(*this);

         // Has this order not reached its settlement date?
         if( order.settlement_date > head_block_time() )
         {
            if( next_asset() )
               continue;
            break;
         }
         // Can we still settle in this asset?
         if( mia.current_feed.settlement_price.is_null() )
         {
            ilog("Canceling a force settlement in ${asset} because settlement price is null",
                 ("asset", mia_object.symbol));
            cancel_order(order);
            continue;
         }
         if( max_settlement_volume.asset_id != current_asset )
            max_settlement_volume = mia_object.amount(mia.max_force_settlement_volume(mia_object.dynamic_data(*this).current_supply));
         if( mia.force_settled_volume >= max_settlement_volume.amount )
         {
            /*
            ilog("Skipping force settlement in ${asset}; settled ${settled_volume} / ${max_volume}",
                 ("asset", mia_object.symbol)("settlement_price_null",mia.current_feed.settlement_price.is_null())
                 ("settled_volume", mia.force_settled_volume)("max_volume", max_settlement_volume));
                 */
            if( next_asset() )
               continue;
            break;
         }

         auto& pays = order.balance;
         auto receives = (order.balance * mia.current_feed.settlement_price);
         receives.amount = (fc::uint128_t(receives.amount.value) *
                            (GRAPHENE_100_PERCENT - mia.options.force_settlement_offset_percent) / GRAPHENE_100_PERCENT).to_uint64();
         assert(receives <= order.balance * mia.current_feed.settlement_price);

         price settlement_price = pays / receives;

         auto& call_index = get_index_type<call_order_index>().indices().get<by_collateral>();
         asset settled = mia_object.amount(mia.force_settled_volume);
         // Match against the least collateralized short until the settlement is finished or we reach max settlements
         while( settled < max_settlement_volume && find_object(order_id) )
         {
            auto itr = call_index.lower_bound(boost::make_tuple(price::min(mia_object.bitasset_data(*this).options.short_backing_asset,
                                                                           mia_object.get_id())));
            // There should always be a call order, since asset exists!
            assert(itr != call_index.end() && itr->debt_type() == mia_object.get_id());
            asset max_settlement = max_settlement_volume - settled;
            settled += match(*itr, order, settlement_price, max_settlement);
         }
         modify(mia, [settled](asset_bitasset_data_object& b) {
            b.force_settled_volume = settled.amount;
         });
      }
   }
}

void database::update_expired_feeds()
{
   auto& asset_idx = get_index_type<asset_index>().indices();
   for( const asset_object& a : asset_idx )
   {
      if( !a.is_market_issued() )
         continue;

      const asset_bitasset_data_object& b = a.bitasset_data(*this);
      if( b.feed_is_expired(head_block_time()) )
      {
         modify(b, [this](asset_bitasset_data_object& a) {
            a.update_median_feeds(head_block_time());
         });
         check_call_orders(b.current_feed.settlement_price.base.asset_id(*this));
      }
      if( !b.current_feed.core_exchange_rate.is_null() &&
          a.options.core_exchange_rate != b.current_feed.core_exchange_rate )
         modify(a, [&b](asset_object& a) {
            a.options.core_exchange_rate = b.current_feed.core_exchange_rate;
         });
   }
}

void database::update_maintenance_flag( bool new_maintenance_flag )
{
   modify( get_dynamic_global_properties(), [&]( dynamic_global_property_object& dpo )
   {
      auto maintenance_flag = dynamic_global_property_object::maintenance_flag;
      dpo.dynamic_flags =
           (dpo.dynamic_flags & ~maintenance_flag)
         | (new_maintenance_flag ? maintenance_flag : 0);
   } );
   return;
}

void database::update_withdraw_permissions()
{
   auto& permit_index = get_index_type<withdraw_permission_index>().indices().get<by_expiration>();
   while( !permit_index.empty() && permit_index.begin()->expiration <= head_block_time() )
      remove(*permit_index.begin());
}

} }
<commit_msg>db_update.cpp:  Fix compiler warning<commit_after>/*
 * Copyright (c) 2015, Cryptonomex, Inc.
 * All rights reserved.
 *
 * This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
 * the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
 * are permitted until September 8, 2015, provided that the following conditions are met:
 *
 * 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 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 COPYRIGHT HOLDER OR
 * 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.
 */

#include <graphene/chain/database.hpp>
#include <graphene/chain/db_with.hpp>

#include <graphene/chain/asset_object.hpp>
#include <graphene/chain/global_property_object.hpp>
#include <graphene/chain/proposal_object.hpp>
#include <graphene/chain/transaction_object.hpp>
#include <graphene/chain/market_evaluator.hpp>
#include <graphene/chain/withdraw_permission_object.hpp>
#include <graphene/chain/witness_object.hpp>
#include <graphene/chain/protocol/fee_schedule.hpp>

#include <fc/uint128.hpp>

namespace graphene { namespace chain {

void database::update_global_dynamic_data( const signed_block& b )
{
   const dynamic_global_property_object& _dgp =
      dynamic_global_property_id_type(0)(*this);

   uint32_t missed_blocks = get_slot_at_time( b.timestamp );
   assert( missed_blocks != 0 );
   missed_blocks--;
   for( uint32_t i = 0; i < missed_blocks; ++i ) {
      const auto& witness_missed = get_scheduled_witness( i+1 )(*this);
      if(  witness_missed.id != b.witness ) {
         /*
         const auto& witness_account = witness_missed.witness_account(*this);
         if( (fc::time_point::now() - b.timestamp) < fc::seconds(30) )
            wlog( "Witness ${name} missed block ${n} around ${t}", ("name",witness_account.name)("n",b.block_num())("t",b.timestamp) );
            */

         modify( witness_missed, [&]( witness_object& w ) {
           w.total_missed++;
         });
      }
   }

   // dynamic global properties updating
   modify( _dgp, [&]( dynamic_global_property_object& dgp ){
      if( BOOST_UNLIKELY( b.block_num() == 1 ) )
         dgp.recently_missed_count = 0;
         else if( _checkpoints.size() && _checkpoints.rbegin()->first >= b.block_num() )
         dgp.recently_missed_count = 0;
      else if( missed_blocks )
         dgp.recently_missed_count += GRAPHENE_RECENTLY_MISSED_COUNT_INCREMENT*missed_blocks;
      else if( dgp.recently_missed_count > GRAPHENE_RECENTLY_MISSED_COUNT_INCREMENT )
         dgp.recently_missed_count -= GRAPHENE_RECENTLY_MISSED_COUNT_DECREMENT;
      else if( dgp.recently_missed_count > 0 )
         dgp.recently_missed_count--;

      dgp.head_block_number = b.block_num();
      dgp.head_block_id = b.id();
      dgp.time = b.timestamp;
      dgp.current_witness = b.witness;
      dgp.recent_slots_filled = (
           (dgp.recent_slots_filled << 1)
           + 1) << missed_blocks;
      dgp.current_aslot += missed_blocks+1;
   });

   if( !(get_node_properties().skip_flags & skip_undo_history_check) )
   {
      GRAPHENE_ASSERT( _dgp.recently_missed_count < GRAPHENE_MAX_UNDO_HISTORY, undo_database_exception,
                 "The database does not have enough undo history to support a blockchain with so many missed blocks. "
                 "Please add a checkpoint if you would like to continue applying blocks beyond this point.",
                 ("recently_missed",_dgp.recently_missed_count)("max_undo",GRAPHENE_MAX_UNDO_HISTORY) );
   }

   _undo_db.set_max_size( _dgp.recently_missed_count + GRAPHENE_MIN_UNDO_HISTORY );
   _fork_db.set_max_size( _dgp.recently_missed_count + GRAPHENE_MIN_UNDO_HISTORY );
}

void database::update_signing_witness(const witness_object& signing_witness, const signed_block& new_block)
{
   const global_property_object& gpo = get_global_properties();
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();
   uint64_t new_block_aslot = dpo.current_aslot + get_slot_at_time( new_block.timestamp );

   share_type witness_pay = std::min( gpo.parameters.witness_pay_per_block, dpo.witness_budget );

   modify( dpo, [&]( dynamic_global_property_object& _dpo )
   {
      _dpo.witness_budget -= witness_pay;
   } );

   deposit_witness_pay( signing_witness, witness_pay );

   modify( signing_witness, [&]( witness_object& _wit )
   {
      _wit.last_aslot = new_block_aslot;
   } );
}

void database::clear_expired_transactions()
{
   //Look for expired transactions in the deduplication list, and remove them.
   //Transactions must have expired by at least two forking windows in order to be removed.
   auto& transaction_idx = static_cast<transaction_index&>(get_mutable_index(implementation_ids, impl_transaction_object_type));
   const auto& dedupe_index = transaction_idx.indices().get<by_expiration>();
   while( (!dedupe_index.empty()) && (head_block_time() > dedupe_index.rbegin()->trx.expiration) )
      transaction_idx.remove(*dedupe_index.rbegin());
}

void database::clear_expired_proposals()
{
   const auto& proposal_expiration_index = get_index_type<proposal_index>().indices().get<by_expiration>();
   while( !proposal_expiration_index.empty() && proposal_expiration_index.begin()->expiration_time <= head_block_time() )
   {
      const proposal_object& proposal = *proposal_expiration_index.begin();
      processed_transaction result;
      try {
         if( proposal.is_authorized_to_execute(*this) )
         {
            result = push_proposal(proposal);
            //TODO: Do something with result so plugins can process it.
            continue;
         }
      } catch( const fc::exception& e ) {
         elog("Failed to apply proposed transaction on its expiration. Deleting it.\n${proposal}\n${error}",
              ("proposal", proposal)("error", e.to_detail_string()));
      }
      remove(proposal);
   }
}

void database::clear_expired_orders()
{
   detail::with_skip_flags( *this,
      get_node_properties().skip_flags | skip_authority_check, [&](){
         transaction_evaluation_state cancel_context(this);

         //Cancel expired limit orders
         auto& limit_index = get_index_type<limit_order_index>().indices().get<by_expiration>();
         while( !limit_index.empty() && limit_index.begin()->expiration <= head_block_time() )
         {
            limit_order_cancel_operation canceler;
            const limit_order_object& order = *limit_index.begin();
            canceler.fee_paying_account = order.seller;
            canceler.order = order.id;
            apply_operation(cancel_context, canceler);
         }
     });

   //Process expired force settlement orders
   auto& settlement_index = get_index_type<force_settlement_index>().indices().get<by_expiration>();
   if( !settlement_index.empty() )
   {
      asset_id_type current_asset = settlement_index.begin()->settlement_asset_id();
      asset max_settlement_volume;

      auto next_asset = [&current_asset, &settlement_index] {
         auto bound = settlement_index.upper_bound(current_asset);
         if( bound == settlement_index.end() )
            return false;
         current_asset = bound->settlement_asset_id();
         return true;
      };

      // At each iteration, we either consume the current order and remove it, or we move to the next asset
      for( auto itr = settlement_index.lower_bound(current_asset);
           itr != settlement_index.end();
           itr = settlement_index.lower_bound(current_asset) )
      {
         const force_settlement_object& order = *itr;
         auto order_id = order.id;
         current_asset = order.settlement_asset_id();
         const asset_object& mia_object = get(current_asset);
         const asset_bitasset_data_object mia = mia_object.bitasset_data(*this);

         // Has this order not reached its settlement date?
         if( order.settlement_date > head_block_time() )
         {
            if( next_asset() )
               continue;
            break;
         }
         // Can we still settle in this asset?
         if( mia.current_feed.settlement_price.is_null() )
         {
            ilog("Canceling a force settlement in ${asset} because settlement price is null",
                 ("asset", mia_object.symbol));
            cancel_order(order);
            continue;
         }
         if( max_settlement_volume.asset_id != current_asset )
            max_settlement_volume = mia_object.amount(mia.max_force_settlement_volume(mia_object.dynamic_data(*this).current_supply));
         if( mia.force_settled_volume >= max_settlement_volume.amount )
         {
            /*
            ilog("Skipping force settlement in ${asset}; settled ${settled_volume} / ${max_volume}",
                 ("asset", mia_object.symbol)("settlement_price_null",mia.current_feed.settlement_price.is_null())
                 ("settled_volume", mia.force_settled_volume)("max_volume", max_settlement_volume));
                 */
            if( next_asset() )
               continue;
            break;
         }

         auto& pays = order.balance;
         auto receives = (order.balance * mia.current_feed.settlement_price);
         receives.amount = (fc::uint128_t(receives.amount.value) *
                            (GRAPHENE_100_PERCENT - mia.options.force_settlement_offset_percent) / GRAPHENE_100_PERCENT).to_uint64();
         assert(receives <= order.balance * mia.current_feed.settlement_price);

         price settlement_price = pays / receives;

         auto& call_index = get_index_type<call_order_index>().indices().get<by_collateral>();
         asset settled = mia_object.amount(mia.force_settled_volume);
         // Match against the least collateralized short until the settlement is finished or we reach max settlements
         while( settled < max_settlement_volume && find_object(order_id) )
         {
            auto itr = call_index.lower_bound(boost::make_tuple(price::min(mia_object.bitasset_data(*this).options.short_backing_asset,
                                                                           mia_object.get_id())));
            // There should always be a call order, since asset exists!
            assert(itr != call_index.end() && itr->debt_type() == mia_object.get_id());
            asset max_settlement = max_settlement_volume - settled;
            settled += match(*itr, order, settlement_price, max_settlement);
         }
         modify(mia, [settled](asset_bitasset_data_object& b) {
            b.force_settled_volume = settled.amount;
         });
      }
   }
}

void database::update_expired_feeds()
{
   auto& asset_idx = get_index_type<asset_index>().indices();
   for( const asset_object& a : asset_idx )
   {
      if( !a.is_market_issued() )
         continue;

      const asset_bitasset_data_object& b = a.bitasset_data(*this);
      if( b.feed_is_expired(head_block_time()) )
      {
         modify(b, [this](asset_bitasset_data_object& a) {
            a.update_median_feeds(head_block_time());
         });
         check_call_orders(b.current_feed.settlement_price.base.asset_id(*this));
      }
      if( !b.current_feed.core_exchange_rate.is_null() &&
          a.options.core_exchange_rate != b.current_feed.core_exchange_rate )
         modify(a, [&b](asset_object& a) {
            a.options.core_exchange_rate = b.current_feed.core_exchange_rate;
         });
   }
}

void database::update_maintenance_flag( bool new_maintenance_flag )
{
   modify( get_dynamic_global_properties(), [&]( dynamic_global_property_object& dpo )
   {
      auto maintenance_flag = dynamic_global_property_object::maintenance_flag;
      dpo.dynamic_flags =
           (dpo.dynamic_flags & ~maintenance_flag)
         | (new_maintenance_flag ? maintenance_flag : 0);
   } );
   return;
}

void database::update_withdraw_permissions()
{
   auto& permit_index = get_index_type<withdraw_permission_index>().indices().get<by_expiration>();
   while( !permit_index.empty() && permit_index.begin()->expiration <= head_block_time() )
      remove(*permit_index.begin());
}

} }
<|endoftext|>


<commit_before>#include "AliPHOSTracker.h"
#include "AliPHOSClusterizerv1.h"
#include "AliPHOSTrackSegmentMakerv1.h"
#include "AliPHOSTrackSegmentMakerv2.h"
#include "AliPHOSPIDv1.h"
#include "AliRunLoader.h"
#include "AliESD.h"

//-------------------------------------------------------------------------
//                          PHOS tracker.
// Matches ESD tracks with the PHOS and makes the PID.
// Currently, has only one function implemented : PropagateBack(AliESD*)
//-------------------------------------------------------------------------

ClassImp(AliPHOSTracker)

Bool_t AliPHOSTracker::fgDebug = kFALSE ;

Int_t AliPHOSTracker::PropagateBack(AliESD *esd) {
  // Called by AliReconstruction
  // Creates the tracksegments and Recparticles
  // Makes the PID

  Int_t eventNumber = fRunLoader->GetEventNumber() ;

  TString headerFile(fRunLoader->GetFileName()) ;
  TString branchName(fRunLoader->GetEventFolder()->GetName()) ;

  AliPHOSTrackSegmentMakerv1 tsm(headerFile, branchName);
//  AliPHOSTrackSegmentMakerv2 tsm(headerFile, branchName);
  tsm.SetESD(esd) ;
  AliPHOSPIDv1 pid(headerFile, branchName);
  pid.SetESD(esd) ;

  SetDebug() ;

  // do current event; the loop over events is done by AliReconstruction::Run()
  tsm.SetEventRange(eventNumber, eventNumber) ;
  pid.SetEventRange(eventNumber, eventNumber) ;
  if ( Debug() ) {
   tsm.ExecuteTask("deb all") ;
   pid.ExecuteTask("deb all") ;
  }
  else {
    tsm.ExecuteTask("") ;
    pid.ExecuteTask("") ;
  }

  return 0;
}
<commit_msg>Verbose output commented out<commit_after>#include "AliPHOSTracker.h"
#include "AliPHOSClusterizerv1.h"
#include "AliPHOSTrackSegmentMakerv1.h"
#include "AliPHOSTrackSegmentMakerv2.h"
#include "AliPHOSPIDv1.h"
#include "AliRunLoader.h"
#include "AliESD.h"

//-------------------------------------------------------------------------
//                          PHOS tracker.
// Matches ESD tracks with the PHOS and makes the PID.
// Currently, has only one function implemented : PropagateBack(AliESD*)
//-------------------------------------------------------------------------

ClassImp(AliPHOSTracker)

Bool_t AliPHOSTracker::fgDebug = kFALSE ;

Int_t AliPHOSTracker::PropagateBack(AliESD *esd) {
  // Called by AliReconstruction
  // Creates the tracksegments and Recparticles
  // Makes the PID

  Int_t eventNumber = fRunLoader->GetEventNumber() ;

  TString headerFile(fRunLoader->GetFileName()) ;
  TString branchName(fRunLoader->GetEventFolder()->GetName()) ;

  AliPHOSTrackSegmentMakerv1 tsm(headerFile, branchName);
//  AliPHOSTrackSegmentMakerv2 tsm(headerFile, branchName);
  tsm.SetESD(esd) ;
  AliPHOSPIDv1 pid(headerFile, branchName);
  pid.SetESD(esd) ;

  //PH  SetDebug() ;

  // do current event; the loop over events is done by AliReconstruction::Run()
  tsm.SetEventRange(eventNumber, eventNumber) ;
  pid.SetEventRange(eventNumber, eventNumber) ;
  if ( Debug() ) {
   tsm.ExecuteTask("deb all") ;
   pid.ExecuteTask("deb all") ;
  }
  else {
    tsm.ExecuteTask("") ;
    pid.ExecuteTask("") ;
  }

  return 0;
}
<|endoftext|>