<commit_before>#ifndef GNR_FORWARDER_HPP
# define GNR_FORWARDER_HPP
# pragma once

#include <cassert>

// std::size_t
#include <cstddef>

#include <cstring>

#include <functional>

#include <type_traits>

#include <utility>

namespace gnr
{

namespace
{

constexpr auto const default_noexcept =
#if defined(__cpp_exceptions) && __cpp_exceptions
false;
#else
true;
#endif // __cpp_exceptions

constexpr auto const default_size = 4 * sizeof(void*);

}

template <typename F,
  std::size_t N = default_size,
  bool NE = default_noexcept
>
class forwarder;

template <typename R, typename ...A, std::size_t N, bool NE>
class forwarder<R (A...), N, NE>
{
  R (*stub_)(void*, A&&...) noexcept(NE) {};

  std::aligned_storage_t<N> store_;

  template<typename T, typename ...U, std::size_t M>
  friend bool operator==(forwarder<T (U...), M> const&,
    std::nullptr_t) noexcept;
  template<typename T, typename ...U, std::size_t M>
  friend bool operator==(std::nullptr_t,
    forwarder<T (U...), M> const&) noexcept;

  template<typename T, typename ...U, std::size_t M>
  friend bool operator!=(forwarder<T (U...), M> const&,
    std::nullptr_t) noexcept;
  template<typename T, typename ...U, std::size_t M>
  friend bool operator!=(std::nullptr_t,
    forwarder<T (U...), M> const&) noexcept;

public:
  using result_type = R;

  enum : std::size_t { size = N };

public:
  forwarder() = default;

  forwarder(forwarder const&) = default;

  forwarder(forwarder&&) = default;

  template <typename F, typename =
    std::enable_if_t<!std::is_same<std::decay_t<F>, forwarder>{}>
  >
  forwarder(F&& f) noexcept
  {
    assign(std::forward<F>(f));
  }

  forwarder& operator=(forwarder const&) = default;

  forwarder& operator=(forwarder&&) = default;

  template <typename F, typename =
    std::enable_if_t<!std::is_same<std::decay_t<F>, forwarder>{}>
  >
  forwarder& operator=(F&& f) noexcept
  {
    assign(std::forward<F>(f));

    return *this;
  }

  explicit operator bool() const noexcept { return stub_; }

  R operator()(A... args) const
    noexcept(
        noexcept(stub_(const_cast<void*>(static_cast<void const*>(&store_)),
          std::forward<A>(args)...
        )
      )
    )
  {
    //assert(stub_);
    return stub_(const_cast<void*>(static_cast<void const*>(&store_)),
      std::forward<A>(args)...
    );
  }

  void assign(std::nullptr_t) noexcept
  {
    reset();
  }

  template <typename F>
  void assign(F&& f) noexcept
  {
    using functor_type = std::decay_t<F>;

    static_assert(sizeof(functor_type) <= sizeof(store_),
      "functor too large");
    static_assert(std::is_trivially_copyable<functor_type>{},
      "functor not trivially copyable");

    ::new (static_cast<void*>(&store_)) functor_type(std::forward<F>(f));

    stub_ = [](void* const ptr, A&&... args) noexcept(
        noexcept(
        (
#if __cplusplus <= 201402L
          (*static_cast<functor_type*>(ptr))(
            std::forward<A>(args)...)
#else
          std::invoke(*static_cast<functor_type*>(ptr),
            std::forward<A>(args)...)
#endif // __cplusplus
        )
      )
    ) -> R
    {
#if __cplusplus <= 201402L
      return (*static_cast<functor_type*>(ptr))(
        std::forward<A>(args)...);
#else
      return std::invoke(*static_cast<functor_type*>(ptr),
        std::forward<A>(args)...);
#endif // __cplusplus
    };
  }

  void reset() noexcept { stub_ = nullptr; }

  void swap(forwarder& other) noexcept { std::swap(*this, other); }

  template <typename T>
  auto target() noexcept
  {
    return reinterpret_cast<T*>(&store_);
  }

  template <typename T>
  auto target() const noexcept
  {
    return reinterpret_cast<T const*>(&store_);
  }
};

template<typename R, typename ...A, std::size_t N>
bool operator==(forwarder<R (A...), N> const& f,
  std::nullptr_t const) noexcept
{
  return nullptr == f.stub_ ;
}

template<typename R, typename ...A, std::size_t N>
bool operator==(std::nullptr_t const,
  forwarder<R (A...), N> const& f) noexcept
{
  return nullptr == f.stub_;
}

template<typename R, typename ...A, std::size_t N>
bool operator!=(forwarder<R (A...), N> const& f,
  std::nullptr_t const) noexcept
{
  return !operator==(nullptr, f);
}

template<typename R, typename ...A, std::size_t N>
bool operator!=(std::nullptr_t const,
  forwarder<R (A...), N> const& f) noexcept
{
  return !operator==(nullptr, f);
}

}

#endif // GNR_FORWARDER_HPP
<commit_msg>some fixes<commit_after>#ifndef GNR_FORWARDER_HPP
# define GNR_FORWARDER_HPP
# pragma once

#include <cassert>

// std::size_t
#include <cstddef>

#include <cstring>

#include <functional>

#include <type_traits>

#include <utility>

namespace gnr
{

namespace
{

constexpr auto const default_noexcept =
#if defined(__cpp_exceptions) && __cpp_exceptions
false;
#else
true;
#endif // __cpp_exceptions

constexpr auto const default_size = 4 * sizeof(void*);

}

template <typename F,
  std::size_t N = default_size,
  bool NE = default_noexcept
>
class forwarder;

template <typename R, typename ...A, std::size_t N, bool NE>
class forwarder<R (A...), N, NE>
{
  R (*stub_)(void*, A&&...) noexcept(NE) {};

  std::aligned_storage_t<N> store_;

  template<typename T, typename ...U, std::size_t M>
  friend bool operator==(forwarder<T (U...), M> const&,
    std::nullptr_t) noexcept;
  template<typename T, typename ...U, std::size_t M>
  friend bool operator==(std::nullptr_t,
    forwarder<T (U...), M> const&) noexcept;

  template<typename T, typename ...U, std::size_t M>
  friend bool operator!=(forwarder<T (U...), M> const&,
    std::nullptr_t) noexcept;
  template<typename T, typename ...U, std::size_t M>
  friend bool operator!=(std::nullptr_t,
    forwarder<T (U...), M> const&) noexcept;

public:
  using result_type = R;

  enum : std::size_t { size = N };

public:
  forwarder() = default;

  forwarder(forwarder const&) = default;

  forwarder(forwarder&&) = default;

  template <typename F, typename =
    std::enable_if_t<!std::is_same<std::decay_t<F>, forwarder>{}>
  >
  forwarder(F&& f) noexcept
  {
    assign(std::forward<F>(f));
  }

  forwarder& operator=(forwarder const&) = default;

  forwarder& operator=(forwarder&&) = default;

  template <typename F, typename =
    std::enable_if_t<!std::is_same<std::decay_t<F>, forwarder>{}>
  >
  forwarder& operator=(F&& f) noexcept
  {
    assign(std::forward<F>(f));

    return *this;
  }

  explicit operator bool() const noexcept { return stub_; }

  R operator()(A... args) const
    noexcept(
        noexcept(stub_(const_cast<void*>(static_cast<void const*>(&store_)),
          std::forward<A>(args)...
        )
      )
    )
  {
    //assert(stub_);
    return stub_(const_cast<void*>(static_cast<void const*>(&store_)),
      std::forward<A>(args)...
    );
  }

  void assign(std::nullptr_t) noexcept
  {
    reset();
  }

  template <typename F>
  void assign(F&& f) noexcept
  {
    using functor_type = std::decay_t<F>;

    static_assert(sizeof(functor_type) <= sizeof(store_),
      "functor too large");
    static_assert(std::is_trivially_copyable<functor_type>{},
      "functor not trivially copyable");

    ::new (static_cast<void*>(&store_)) functor_type(std::forward<F>(f));

    stub_ = [](void* const ptr, A&&... args) noexcept(
        noexcept(
        (
#if __cplusplus <= 201402L
          (*static_cast<functor_type*>(ptr))(
            std::forward<A>(args)...)
#else
          std::invoke(*static_cast<functor_type*>(ptr),
            std::forward<A>(args)...)
#endif // __cplusplus
        )
      )
    ) -> R
    {
#if __cplusplus <= 201402L
      return (*static_cast<functor_type*>(ptr))(
        std::forward<A>(args)...);
#else
      return std::invoke(*static_cast<functor_type*>(ptr),
        std::forward<A>(args)...);
#endif // __cplusplus
    };
  }

  void reset() noexcept { stub_ = nullptr; }

  void swap(forwarder& other) noexcept
  {
    std::swap(*this, other);
  }

  void swap(forwarder&& other) noexcept
  {
    std::swap(*this, std::move(other));
  }

  template <typename T>
  auto target() noexcept
  {
    return reinterpret_cast<T*>(&store_);
  }

  template <typename T>
  auto target() const noexcept
  {
    return reinterpret_cast<T const*>(&store_);
  }
};

template<typename R, typename ...A, std::size_t N>
bool operator==(forwarder<R (A...), N> const& f,
  std::nullptr_t const) noexcept
{
  return nullptr == f.stub_ ;
}

template<typename R, typename ...A, std::size_t N>
bool operator==(std::nullptr_t const,
  forwarder<R (A...), N> const& f) noexcept
{
  return nullptr == f.stub_;
}

template<typename R, typename ...A, std::size_t N>
bool operator!=(forwarder<R (A...), N> const& f,
  std::nullptr_t const) noexcept
{
  return !operator==(nullptr, f);
}

template<typename R, typename ...A, std::size_t N>
bool operator!=(std::nullptr_t const,
  forwarder<R (A...), N> const& f) noexcept
{
  return !operator==(nullptr, f);
}

}

#endif // GNR_FORWARDER_HPP
<|endoftext|>


<commit_before>/****************************************************************************
 * Copyright (c) 2012-2018 by the DataTransferKit authors                   *
 * All rights reserved.                                                     *
 *                                                                          *
 * This file is part of the DataTransferKit library. DataTransferKit is     *
 * distributed under a BSD 3-clause license. For the licensing terms see    *
 * the LICENSE file in the top-level directory.                             *
 *                                                                          *
 * SPDX-License-Identifier: BSD-3-Clause                                    *
 ****************************************************************************/
/*!
 * \file DTK_View.hpp
 * \brief Flat view wrapper for Kokkos::View objects.
 */
//---------------------------------------------------------------------------//

#ifndef DTK_VIEW_HPP
#define DTK_VIEW_HPP

#include <Kokkos_Core.hpp>
#include <Kokkos_DynRankView.hpp>

#include <cassert>
#include <type_traits>

namespace DataTransferKit
{

//---------------------------------------------------------------------------//
/*!
 * \class View
 *
 * \brief Basic unmanaged wrapper around Kokkos::View data designed for
 * handling user input in function callbacks.
 *
 * The View exposes the raw pointer under any Kokkos::View so it may be
 * treated as a flat array and so it can be accessed directly by the
 * application in any manner on and off device. If the Kokkos::View lives on
 * the device, the DTK view will provide a raw pointer to that device data and
 * the length of the view under that pointer.
 *
 * The view is copyable to device and provides a device-accessible element
 * accessor to facilitate user implementation.
 *
 * The view is intended only to be used during the local scope of a
 * function. It does not track the lifetime of the Kokkos::View it is wrapping
 * nor does it manage the memory of that Kokkos:View.
 *
 * In C++ the view data can be accessed directly via the [] operator. The raw
 * pointer to the view is provided for accessing view data in C and Fortran.
 */
template <class SC>
class View
{
  public:
    //@{
    //! Type aliases.
    using Scalar = SC;
    //@}

    // Empty constructor.
    KOKKOS_INLINE_FUNCTION
    View()
        : _size( 0 )
        , _data( nullptr )
    { /* ... */
    }

    // Kokkos::View constructor.
    template <class KokkosViewType>
    KOKKOS_INLINE_FUNCTION
    View( KokkosViewType kokkos_view,
          typename std::enable_if<
              Kokkos::is_view<KokkosViewType>::value ||
                  Kokkos::Experimental::is_dyn_rank_view<KokkosViewType>::value,
              void *>::type = nullptr )
        : _size( kokkos_view.size() )
        , _data( kokkos_view.data() )
    {
        // Make sure the Kokkos view value type and the DTK view scalar type is
        // the same.
        static_assert(
            std::is_same<typename KokkosViewType::value_type, SC>::value,
            "Kokkos View value type and DTK View Scalar type do not match" );

        // Make sure the Kokkos view is left layout. The assures that for
        // multi-dimensional views that the data will be column-major.
        static_assert( std::is_same<typename KokkosViewType::array_layout,
                                    Kokkos::LayoutLeft>::value,
                       "Kokkos View layout must be LayoutLeft" );

#ifdef KOKKOS_ENABLE_CUDA
        static_assert( std::is_same<typename KokkosViewType::memory_space,
                                    Kokkos::CudaSpace>::value == false,
                       "DTK for CUDA currently does not support CudaSpace "
                       "memory. Please use CudaUVM memory space instead." );
#endif
    }

    // Get size of the view.
    KOKKOS_INLINE_FUNCTION
    size_t size() const { return _size; }

    // Get the raw pointer to the view data.
    KOKKOS_INLINE_FUNCTION
    Scalar *data() { return _data; }

    // Get the const raw pointer to the view data.
    KOKKOS_INLINE_FUNCTION
    const Scalar *data() const { return _data; }

    // Access an element in the view.
    KOKKOS_FORCEINLINE_FUNCTION
    Scalar &operator[]( const size_t i )
    {
        assert( _data );
        assert( i < _size );
        return _data[i];
    }

    // Access a const element in the view.
    KOKKOS_FORCEINLINE_FUNCTION
    Scalar &operator[]( const size_t i ) const
    {
        assert( _data );
        assert( i < _size );
        return _data[i];
    }

  private:
    // Size of the view.
    // Note: The use of size_t matches the return type of
    // Kokkos::View<>::size().
    size_t _size;

    // View raw pointer.
    Scalar *_data;
};

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

} // namespace DataTransferKit

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

#endif // end DTK_VIEW_HPP

//---------------------------------------------------------------------------//
// end DTK_View.hpp
//---------------------------------------------------------------------------//
<commit_msg>Kokkos::Experimental::is_dyn_rank_view<T> -> Kokkos::is_dyn_rank_view<T><commit_after>/****************************************************************************
 * Copyright (c) 2012-2018 by the DataTransferKit authors                   *
 * All rights reserved.                                                     *
 *                                                                          *
 * This file is part of the DataTransferKit library. DataTransferKit is     *
 * distributed under a BSD 3-clause license. For the licensing terms see    *
 * the LICENSE file in the top-level directory.                             *
 *                                                                          *
 * SPDX-License-Identifier: BSD-3-Clause                                    *
 ****************************************************************************/
/*!
 * \file DTK_View.hpp
 * \brief Flat view wrapper for Kokkos::View objects.
 */
//---------------------------------------------------------------------------//

#ifndef DTK_VIEW_HPP
#define DTK_VIEW_HPP

#include <Kokkos_Core.hpp>
#include <Kokkos_DynRankView.hpp>

#include <cassert>
#include <type_traits>

namespace DataTransferKit
{

//---------------------------------------------------------------------------//
/*!
 * \class View
 *
 * \brief Basic unmanaged wrapper around Kokkos::View data designed for
 * handling user input in function callbacks.
 *
 * The View exposes the raw pointer under any Kokkos::View so it may be
 * treated as a flat array and so it can be accessed directly by the
 * application in any manner on and off device. If the Kokkos::View lives on
 * the device, the DTK view will provide a raw pointer to that device data and
 * the length of the view under that pointer.
 *
 * The view is copyable to device and provides a device-accessible element
 * accessor to facilitate user implementation.
 *
 * The view is intended only to be used during the local scope of a
 * function. It does not track the lifetime of the Kokkos::View it is wrapping
 * nor does it manage the memory of that Kokkos:View.
 *
 * In C++ the view data can be accessed directly via the [] operator. The raw
 * pointer to the view is provided for accessing view data in C and Fortran.
 */
template <class SC>
class View
{
  public:
    //@{
    //! Type aliases.
    using Scalar = SC;
    //@}

    // Empty constructor.
    KOKKOS_INLINE_FUNCTION
    View()
        : _size( 0 )
        , _data( nullptr )
    { /* ... */
    }

    // Kokkos::View constructor.
    template <class KokkosViewType>
    KOKKOS_INLINE_FUNCTION
    View( KokkosViewType kokkos_view,
          typename std::enable_if<
              Kokkos::is_view<KokkosViewType>::value ||
                  Kokkos::is_dyn_rank_view<KokkosViewType>::value,
              void *>::type = nullptr )
        : _size( kokkos_view.size() )
        , _data( kokkos_view.data() )
    {
        // Make sure the Kokkos view value type and the DTK view scalar type is
        // the same.
        static_assert(
            std::is_same<typename KokkosViewType::value_type, SC>::value,
            "Kokkos View value type and DTK View Scalar type do not match" );

        // Make sure the Kokkos view is left layout. The assures that for
        // multi-dimensional views that the data will be column-major.
        static_assert( std::is_same<typename KokkosViewType::array_layout,
                                    Kokkos::LayoutLeft>::value,
                       "Kokkos View layout must be LayoutLeft" );

#ifdef KOKKOS_ENABLE_CUDA
        static_assert( std::is_same<typename KokkosViewType::memory_space,
                                    Kokkos::CudaSpace>::value == false,
                       "DTK for CUDA currently does not support CudaSpace "
                       "memory. Please use CudaUVM memory space instead." );
#endif
    }

    // Get size of the view.
    KOKKOS_INLINE_FUNCTION
    size_t size() const { return _size; }

    // Get the raw pointer to the view data.
    KOKKOS_INLINE_FUNCTION
    Scalar *data() { return _data; }

    // Get the const raw pointer to the view data.
    KOKKOS_INLINE_FUNCTION
    const Scalar *data() const { return _data; }

    // Access an element in the view.
    KOKKOS_FORCEINLINE_FUNCTION
    Scalar &operator[]( const size_t i )
    {
        assert( _data );
        assert( i < _size );
        return _data[i];
    }

    // Access a const element in the view.
    KOKKOS_FORCEINLINE_FUNCTION
    Scalar &operator[]( const size_t i ) const
    {
        assert( _data );
        assert( i < _size );
        return _data[i];
    }

  private:
    // Size of the view.
    // Note: The use of size_t matches the return type of
    // Kokkos::View<>::size().
    size_t _size;

    // View raw pointer.
    Scalar *_data;
};

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

} // namespace DataTransferKit

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

#endif // end DTK_VIEW_HPP

//---------------------------------------------------------------------------//
// end DTK_View.hpp
//---------------------------------------------------------------------------//
<|endoftext|>


<commit_before>#include "server/server.h"

#include <chrono>
#include <csignal>
#include <functional>
#include <gflags/gflags.h>

#include "log/frontend.h"
#include "server/proxy.h"
#include "monitoring/gcm/exporter.h"
#include "log/log_lookup.h"
#include "log/log_verifier.h"
#include "server/metrics.h"
#include "log/cluster_state_controller.h"
#include "log/etcd_consistent_store.h"
#include "monitoring/monitoring.h"
#include "server/handler.h"
#include "util/thread_pool.h"
#include "util/uuid.h"

using std::bind;

DEFINE_int32(node_state_refresh_seconds, 10,
             "How often to refresh the ClusterNodeState entry for this node.");
DEFINE_int32(watchdog_seconds, 120,
             "How many seconds without successfully refreshing this node's "
             "before firing the watchdog timer.");
DEFINE_bool(watchdog_timeout_is_fatal, true,
            "Exit if the watchdog timer fires.");

namespace cert_trans {

Gauge<>* latest_local_tree_size_gauge() {
  static Gauge<>* const gauge(Gauge<>::New("latest_local_tree_size", "Size of latest locally generated STH."));

  return gauge;
}

namespace {

void RefreshNodeState(ClusterStateController<LoggedEntry>* controller,
                      util::Task* task) {
  CHECK_NOTNULL(task);
  const std::chrono::steady_clock::duration period(
      (std::chrono::seconds(FLAGS_node_state_refresh_seconds)));
  std::chrono::steady_clock::time_point target_run_time(
      std::chrono::steady_clock::now());

  while (true) {
    if (task->CancelRequested()) {
      task->Return(util::Status::CANCELLED);
      alarm(0);
    }
    // If we haven't managed to refresh our state file in a timely fashion,
    // then send us a SIGALRM:
    alarm(FLAGS_watchdog_seconds);

    controller->RefreshNodeState();

    const std::chrono::steady_clock::time_point now(
        std::chrono::steady_clock::now());
    while (target_run_time <= now) {
      target_run_time += period;
    }
    std::this_thread::sleep_for(target_run_time - now);
  }
}

void WatchdogTimeout(int) {
  if (FLAGS_watchdog_timeout_is_fatal) {
    LOG(FATAL) << "Watchdog timed out, killing process.";
  } else {
    LOG(INFO) << "Watchdog timeout out, ignoring.";
  }
}

std::string GetNodeId(Database* db) {
  std::string node_id;
  if (db->NodeId(&node_id) != Database::LOOKUP_OK) {
    node_id = cert_trans::UUID4();
    LOG(INFO) << "Initializing Node DB with UUID: " << node_id;
    db->InitializeNode(node_id);
  } else {
    LOG(INFO) << "Found DB with Node UUID: " << node_id;
  }
  return node_id;
}

}  // namespace

// static
void Server::StaticInit() {
  CHECK_NE(SIG_ERR, std::signal(SIGALRM, &WatchdogTimeout));
}

Server::Server(const Options& opts,
               const std::shared_ptr<libevent::Base>& event_base,
               ThreadPool* internal_pool, ThreadPool* http_pool, Database* db,
               EtcdClient* etcd_client, UrlFetcher* url_fetcher,
               const LogVerifier* log_verifier)
    : options_(opts),
      event_base_(event_base),
      event_pump_(new libevent::EventPumpThread(event_base_)),
      http_server_(*event_base_),
      db_(CHECK_NOTNULL(db)),
      log_verifier_(CHECK_NOTNULL(log_verifier)),
      node_id_(GetNodeId(db_)),
      url_fetcher_(CHECK_NOTNULL(url_fetcher)),
      etcd_client_(CHECK_NOTNULL(etcd_client)),
      election_(event_base_, etcd_client_, options_.etcd_root + "/election",
                node_id_),
      internal_pool_(CHECK_NOTNULL(internal_pool)),
      server_task_(internal_pool_),
      consistent_store_(&election_,
                        new EtcdConsistentStore<LoggedEntry>(
                            event_base_.get(), internal_pool_, etcd_client_,
                            &election_, options_.etcd_root, node_id_)),
      http_pool_(CHECK_NOTNULL(http_pool)) {
  CHECK_LT(0, options_.port);
  CHECK_LT(0, options_.num_http_server_threads);

  if (FLAGS_monitoring == kPrometheus) {
    http_server_.AddHandler("/metrics",
                            bind(&cert_trans::ExportPrometheusMetrics,
                                 std::placeholders::_1));
  } else if (FLAGS_monitoring == kGcm) {
    gcm_exporter_.reset(
        new GCMExporter(options_.server, url_fetcher_, internal_pool_));
  } else {
    LOG(FATAL) << "Please set --monitoring to one of the supported values.";
  }

  http_server_.Bind(nullptr, options_.port);
  election_.StartElection();
}

Server::~Server() {
  server_task_.Cancel();
  node_refresh_thread_->join();
  server_task_.Wait();
}

void Server::RegisterHandler(HttpHandler* handler) {
  CHECK_NOTNULL(handler);
  // Configure the handler to use our JSON output and proxy instances:
  handler->SetProxy(proxy_.get());
  handler->Add(&http_server_);
}

bool Server::IsMaster() const {
  return election_.IsMaster();
}

MasterElection* Server::election() {
  return &election_;
}

ConsistentStore<LoggedEntry>* Server::consistent_store() {
  return &consistent_store_;
}

ClusterStateController<LoggedEntry>* Server::cluster_state_controller() {
  return cluster_controller_.get();
}

LogLookup* Server::log_lookup() {
  return log_lookup_.get();
}

ContinuousFetcher* Server::continuous_fetcher() {
  return fetcher_.get();
}

void Server::WaitForReplication() const {
  // If we're joining an existing cluster, this node needs to get its database
  // up-to-date with the serving_sth before we can do anything, so we'll wait
  // here for that:
  util::StatusOr<ct::SignedTreeHead> serving_sth(
      consistent_store_.GetServingSTH());
  if (serving_sth.ok()) {
    while (db_->TreeSize() < serving_sth.ValueOrDie().tree_size()) {
      LOG(WARNING) << "Waiting for local database to catch up to serving_sth ("
                   << db_->TreeSize() << " of "
                   << serving_sth.ValueOrDie().tree_size() << ")";
      sleep(1);
    }
  }
}

void Server::Initialise(bool is_mirror) {
  fetcher_.reset(ContinuousFetcher::New(event_base_.get(), internal_pool_, db_,
                                        log_verifier_, !is_mirror)
                     .release());

  log_lookup_.reset(new LogLookup(db_));

  cluster_controller_.reset(new ClusterStateController<LoggedEntry>(
      internal_pool_, event_base_, url_fetcher_, db_, &consistent_store_,
      &election_, fetcher_.get()));

  // Publish this node's hostname:port info
  cluster_controller_->SetNodeHostPort(options_.server, options_.port);
  {
    ct::SignedTreeHead db_sth;
    if (db_->LatestTreeHead(&db_sth) == Database::LOOKUP_OK) {
      const LogVerifier::VerifyResult sth_verify_result(
          log_verifier_->VerifySignedTreeHead(db_sth));
      if (sth_verify_result != LogVerifier::VERIFY_OK) {
        LOG(FATAL) << "STH retrieved from DB did not verify: "
                   << LogVerifier::VerifyResultString(sth_verify_result);
      }
      cluster_controller_->NewTreeHead(db_sth);
    }
  }

  node_refresh_thread_.reset(new std::thread(&RefreshNodeState,
                                             cluster_controller_.get(),
                                             server_task_.task()));

  proxy_.reset(
      new Proxy(event_base_.get(),
                bind(&ClusterStateController<LoggedEntry>::GetFreshNodes,
                     cluster_controller_.get()),
                url_fetcher_, http_pool_));
}

void Server::Run() {
  // Ding the temporary event pump because we're about to enter the event loop
  event_pump_.reset();
  event_base_->Dispatch();
}

}  // namespace cert_trans
<commit_msg>Add some "using" statements to server.cc.<commit_after>#include "server/server.h"

#include <chrono>
#include <csignal>
#include <functional>
#include <gflags/gflags.h>

#include "log/frontend.h"
#include "server/proxy.h"
#include "monitoring/gcm/exporter.h"
#include "log/log_lookup.h"
#include "log/log_verifier.h"
#include "server/metrics.h"
#include "log/cluster_state_controller.h"
#include "log/etcd_consistent_store.h"
#include "monitoring/monitoring.h"
#include "server/handler.h"
#include "util/thread_pool.h"
#include "util/uuid.h"

using std::bind;
using std::chrono::seconds;
using std::chrono::steady_clock;
using std::placeholders::_1;
using std::shared_ptr;
using std::signal;
using std::string;
using std::this_thread::sleep_for;
using std::thread;

DEFINE_int32(node_state_refresh_seconds, 10,
             "How often to refresh the ClusterNodeState entry for this node.");
DEFINE_int32(watchdog_seconds, 120,
             "How many seconds without successfully refreshing this node's "
             "before firing the watchdog timer.");
DEFINE_bool(watchdog_timeout_is_fatal, true,
            "Exit if the watchdog timer fires.");

namespace cert_trans {

Gauge<>* latest_local_tree_size_gauge() {
  static Gauge<>* const gauge(Gauge<>::New("latest_local_tree_size", "Size of latest locally generated STH."));

  return gauge;
}

namespace {

void RefreshNodeState(ClusterStateController<LoggedEntry>* controller,
                      util::Task* task) {
  CHECK_NOTNULL(task);
  const steady_clock::duration period(
      (seconds(FLAGS_node_state_refresh_seconds)));
  steady_clock::time_point target_run_time(steady_clock::now());

  while (true) {
    if (task->CancelRequested()) {
      task->Return(util::Status::CANCELLED);
      alarm(0);
    }
    // If we haven't managed to refresh our state file in a timely fashion,
    // then send us a SIGALRM:
    alarm(FLAGS_watchdog_seconds);

    controller->RefreshNodeState();

    const steady_clock::time_point now(steady_clock::now());
    while (target_run_time <= now) {
      target_run_time += period;
    }
    sleep_for(target_run_time - now);
  }
}

void WatchdogTimeout(int) {
  if (FLAGS_watchdog_timeout_is_fatal) {
    LOG(FATAL) << "Watchdog timed out, killing process.";
  } else {
    LOG(INFO) << "Watchdog timeout out, ignoring.";
  }
}

string GetNodeId(Database* db) {
  string node_id;
  if (db->NodeId(&node_id) != Database::LOOKUP_OK) {
    node_id = UUID4();
    LOG(INFO) << "Initializing Node DB with UUID: " << node_id;
    db->InitializeNode(node_id);
  } else {
    LOG(INFO) << "Found DB with Node UUID: " << node_id;
  }
  return node_id;
}

}  // namespace

// static
void Server::StaticInit() {
  CHECK_NE(SIG_ERR, signal(SIGALRM, &WatchdogTimeout));
}

Server::Server(const Options& opts,
               const shared_ptr<libevent::Base>& event_base,
               ThreadPool* internal_pool, ThreadPool* http_pool, Database* db,
               EtcdClient* etcd_client, UrlFetcher* url_fetcher,
               const LogVerifier* log_verifier)
    : options_(opts),
      event_base_(event_base),
      event_pump_(new libevent::EventPumpThread(event_base_)),
      http_server_(*event_base_),
      db_(CHECK_NOTNULL(db)),
      log_verifier_(CHECK_NOTNULL(log_verifier)),
      node_id_(GetNodeId(db_)),
      url_fetcher_(CHECK_NOTNULL(url_fetcher)),
      etcd_client_(CHECK_NOTNULL(etcd_client)),
      election_(event_base_, etcd_client_, options_.etcd_root + "/election",
                node_id_),
      internal_pool_(CHECK_NOTNULL(internal_pool)),
      server_task_(internal_pool_),
      consistent_store_(&election_,
                        new EtcdConsistentStore<LoggedEntry>(
                            event_base_.get(), internal_pool_, etcd_client_,
                            &election_, options_.etcd_root, node_id_)),
      http_pool_(CHECK_NOTNULL(http_pool)) {
  CHECK_LT(0, options_.port);
  CHECK_LT(0, options_.num_http_server_threads);

  if (FLAGS_monitoring == kPrometheus) {
    http_server_.AddHandler("/metrics", bind(&ExportPrometheusMetrics, _1));
  } else if (FLAGS_monitoring == kGcm) {
    gcm_exporter_.reset(
        new GCMExporter(options_.server, url_fetcher_, internal_pool_));
  } else {
    LOG(FATAL) << "Please set --monitoring to one of the supported values.";
  }

  http_server_.Bind(nullptr, options_.port);
  election_.StartElection();
}

Server::~Server() {
  server_task_.Cancel();
  node_refresh_thread_->join();
  server_task_.Wait();
}

void Server::RegisterHandler(HttpHandler* handler) {
  CHECK_NOTNULL(handler);
  // Configure the handler to use our JSON output and proxy instances:
  handler->SetProxy(proxy_.get());
  handler->Add(&http_server_);
}

bool Server::IsMaster() const {
  return election_.IsMaster();
}

MasterElection* Server::election() {
  return &election_;
}

ConsistentStore<LoggedEntry>* Server::consistent_store() {
  return &consistent_store_;
}

ClusterStateController<LoggedEntry>* Server::cluster_state_controller() {
  return cluster_controller_.get();
}

LogLookup* Server::log_lookup() {
  return log_lookup_.get();
}

ContinuousFetcher* Server::continuous_fetcher() {
  return fetcher_.get();
}

void Server::WaitForReplication() const {
  // If we're joining an existing cluster, this node needs to get its database
  // up-to-date with the serving_sth before we can do anything, so we'll wait
  // here for that:
  util::StatusOr<ct::SignedTreeHead> serving_sth(
      consistent_store_.GetServingSTH());
  if (serving_sth.ok()) {
    while (db_->TreeSize() < serving_sth.ValueOrDie().tree_size()) {
      LOG(WARNING) << "Waiting for local database to catch up to serving_sth ("
                   << db_->TreeSize() << " of "
                   << serving_sth.ValueOrDie().tree_size() << ")";
      sleep(1);
    }
  }
}

void Server::Initialise(bool is_mirror) {
  fetcher_.reset(ContinuousFetcher::New(event_base_.get(), internal_pool_, db_,
                                        log_verifier_, !is_mirror)
                     .release());

  log_lookup_.reset(new LogLookup(db_));

  cluster_controller_.reset(new ClusterStateController<LoggedEntry>(
      internal_pool_, event_base_, url_fetcher_, db_, &consistent_store_,
      &election_, fetcher_.get()));

  // Publish this node's hostname:port info
  cluster_controller_->SetNodeHostPort(options_.server, options_.port);
  {
    ct::SignedTreeHead db_sth;
    if (db_->LatestTreeHead(&db_sth) == Database::LOOKUP_OK) {
      const LogVerifier::VerifyResult sth_verify_result(
          log_verifier_->VerifySignedTreeHead(db_sth));
      if (sth_verify_result != LogVerifier::VERIFY_OK) {
        LOG(FATAL) << "STH retrieved from DB did not verify: "
                   << LogVerifier::VerifyResultString(sth_verify_result);
      }
      cluster_controller_->NewTreeHead(db_sth);
    }
  }

  node_refresh_thread_.reset(new thread(&RefreshNodeState,
                                        cluster_controller_.get(),
                                        server_task_.task()));

  proxy_.reset(
      new Proxy(event_base_.get(),
                bind(&ClusterStateController<LoggedEntry>::GetFreshNodes,
                     cluster_controller_.get()),
                url_fetcher_, http_pool_));
}

void Server::Run() {
  // Ding the temporary event pump because we're about to enter the event loop
  event_pump_.reset();
  event_base_->Dispatch();
}

}  // namespace cert_trans
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_bridges.hxx"

#if defined OS2
#define INCL_DOS
#define INCL_DOSMISC
#endif

#include "bridges/cpp_uno/shared/vtablefactory.hxx"

#include "guardedarray.hxx"

#include "bridges/cpp_uno/shared/vtables.hxx"

#include "osl/thread.h"
#include "osl/security.hxx"
#include "osl/file.hxx"
#include "osl/diagnose.h"
#include "osl/mutex.hxx"
#include "rtl/alloc.h"
#include "rtl/ustring.hxx"
#include "sal/types.h"
#include "typelib/typedescription.hxx"

#include <hash_map>
#include <new>
#include <vector>

#if defined SAL_UNX
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#elif defined SAL_W32
#define WIN32_LEAN_AND_MEAN
#ifdef _MSC_VER
#pragma warning(push,1) // disable warnings within system headers
#endif
#include <windows.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#elif defined SAL_OS2
#define INCL_DOS
#define INCL_DOSMISC
#include <os2.h>
#else
#error Unsupported platform
#endif

using bridges::cpp_uno::shared::VtableFactory;

namespace {

extern "C" void * SAL_CALL allocExec(rtl_arena_type *, sal_Size * size) {
    sal_Size pagesize;
#if defined SAL_UNX
#if defined FREEBSD || defined NETBSD
    pagesize = getpagesize();
#else
    pagesize = sysconf(_SC_PAGESIZE);
#endif
#elif defined SAL_W32
    SYSTEM_INFO info;
    GetSystemInfo(&info);
    pagesize = info.dwPageSize;
#elif defined(SAL_OS2)
    ULONG ulPageSize;
    DosQuerySysInfo(QSV_PAGE_SIZE, QSV_PAGE_SIZE, &ulPageSize, sizeof(ULONG));
    pagesize = (sal_Size)ulPageSize;
#else
#error Unsupported platform
#endif
    sal_Size n = (*size + (pagesize - 1)) & ~(pagesize - 1);
    void * p;
#if defined SAL_UNX
    p = mmap(
        0, n, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1,
        0);
    if (p == MAP_FAILED) {
        p = 0;
    }
    else if (mprotect (static_cast<char*>(p), n, PROT_READ | PROT_WRITE | PROT_EXEC) == -1)
    {
        munmap (static_cast<char*>(p), n);
        p = 0;
    }
#elif defined SAL_W32
    p = VirtualAlloc(0, n, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
#elif defined(SAL_OS2)
    p = 0;
    DosAllocMem( &p, n, PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_ANY);
#endif
    if (p != 0) {
        *size = n;
    }
    return p;
}

extern "C" void SAL_CALL freeExec(
    rtl_arena_type *, void * address, sal_Size size)
{
#if defined SAL_UNX
    munmap(static_cast< char * >(address), size);
#elif defined SAL_W32
    (void) size; // unused
    VirtualFree(address, 0, MEM_RELEASE);
#elif defined(SAL_OS2)
    (void) DosFreeMem( address);
#endif
}

}

class VtableFactory::GuardedBlocks: public std::vector< Block > {
public:
    GuardedBlocks(VtableFactory const & factory):
        m_factory(factory), m_guarded(true) {}

    ~GuardedBlocks();

    void unguard() { m_guarded = false; }

private:
    GuardedBlocks(GuardedBlocks &); // not implemented
    void operator =(GuardedBlocks); // not implemented

    VtableFactory const & m_factory;
    bool m_guarded;
};

VtableFactory::GuardedBlocks::~GuardedBlocks() {
    if (m_guarded) {
        for (iterator i(begin()); i != end(); ++i) {
            m_factory.freeBlock(*i);
        }
    }
}

class VtableFactory::BaseOffset {
public:
    BaseOffset(typelib_InterfaceTypeDescription * type) { calculate(type, 0); }

    sal_Int32 getFunctionOffset(rtl::OUString const & name) const
    { return m_map.find(name)->second; }

private:
    sal_Int32 calculate(
        typelib_InterfaceTypeDescription * type, sal_Int32 offset);

    typedef std::hash_map< rtl::OUString, sal_Int32, rtl::OUStringHash > Map;

    Map m_map;
};

sal_Int32 VtableFactory::BaseOffset::calculate(
    typelib_InterfaceTypeDescription * type, sal_Int32 offset)
{
    rtl::OUString name(type->aBase.pTypeName);
    if (m_map.find(name) == m_map.end()) {
        for (sal_Int32 i = 0; i < type->nBaseTypes; ++i) {
            offset = calculate(type->ppBaseTypes[i], offset);
        }
        m_map.insert(Map::value_type(name, offset));
        typelib_typedescription_complete(
            reinterpret_cast< typelib_TypeDescription ** >(&type));
        offset += bridges::cpp_uno::shared::getLocalFunctions(type);
    }
    return offset;
}

VtableFactory::VtableFactory(): m_arena(
    rtl_arena_create(
        "bridges::cpp_uno::shared::VtableFactory",
        sizeof (void *), // to satisfy alignment requirements
        0, reinterpret_cast< rtl_arena_type * >(-1), allocExec, freeExec, 0))
{
    if (m_arena == 0) {
        throw std::bad_alloc();
    }
}

VtableFactory::~VtableFactory() {
    {
        osl::MutexGuard guard(m_mutex);
        for (Map::iterator i(m_map.begin()); i != m_map.end(); ++i) {
            for (sal_Int32 j = 0; j < i->second.count; ++j) {
                freeBlock(i->second.blocks[j]);
            }
            delete[] i->second.blocks;
        }
    }
    rtl_arena_destroy(m_arena);
}

VtableFactory::Vtables VtableFactory::getVtables(
    typelib_InterfaceTypeDescription * type)
{
    rtl::OUString name(type->aBase.pTypeName);
    osl::MutexGuard guard(m_mutex);
    Map::iterator i(m_map.find(name));
    if (i == m_map.end()) {
        GuardedBlocks blocks(*this);
        createVtables(blocks, BaseOffset(type), type, true);
        Vtables vtables;
        OSL_ASSERT(blocks.size() <= SAL_MAX_INT32);
        vtables.count = static_cast< sal_Int32 >(blocks.size());
        bridges::cpp_uno::shared::GuardedArray< Block > guardedBlocks(
            new Block[vtables.count]);
        vtables.blocks = guardedBlocks.get();
        for (sal_Int32 j = 0; j < vtables.count; ++j) {
            vtables.blocks[j] = blocks[j];
        }
        i = m_map.insert(Map::value_type(name, vtables)).first;
        guardedBlocks.release();
        blocks.unguard();
    }
    return i->second;
}

#ifdef USE_DOUBLE_MMAP
bool VtableFactory::createBlock(Block &block, sal_Int32 slotCount) const
{
    sal_Size size = getBlockSize(slotCount);
    sal_Size pagesize = sysconf(_SC_PAGESIZE);
    block.size = (size + (pagesize - 1)) & ~(pagesize - 1);
    block.start = block.exec = NULL;
    block.fd = -1;

    osl::Security aSecurity;
    rtl::OUString strDirectory;
    rtl::OUString strURLDirectory;
    if (aSecurity.getHomeDir(strURLDirectory))
        osl::File::getSystemPathFromFileURL(strURLDirectory, strDirectory);

    for (int i = strDirectory.getLength() == 0 ? 1 : 0; i < 2; ++i)
    {
        if (!strDirectory.getLength())
            strDirectory = rtl::OUString::createFromAscii("/tmp");

        strDirectory += rtl::OUString::createFromAscii("/.execoooXXXXXX");
        rtl::OString aTmpName = rtl::OUStringToOString(strDirectory, osl_getThreadTextEncoding());
        char *tmpfname = new char[aTmpName.getLength()+1];
        strncpy(tmpfname, aTmpName.getStr(), aTmpName.getLength()+1);
        if ((block.fd = mkstemp(tmpfname)) == -1)
            perror("creation of executable memory area failed");
        if (block.fd == -1)
        {
            delete[] tmpfname;
            break;
        }
        unlink(tmpfname);
        delete[] tmpfname;
        if (ftruncate(block.fd, block.size) == -1)
        {
            perror("truncation of executable memory area failed");
            close(block.fd);
            block.fd = -1;
            break;
        }
        block.start = mmap(NULL, block.size, PROT_READ | PROT_WRITE, MAP_SHARED, block.fd, 0);
        if (block.start== MAP_FAILED) {
            block.start = 0;
        }
        block.exec = mmap(NULL, block.size, PROT_READ | PROT_EXEC, MAP_SHARED, block.fd, 0);
        if (block.exec == MAP_FAILED) {
           block.exec = 0;
        }

        //All good
        if (block.start && block.exec && block.fd != -1)
            break;

        freeBlock(block);

        strDirectory = rtl::OUString();
    }
    if (!block.start || !block.exec || block.fd == -1)
    {
       //Fall back to non-doublemmaped allocation
       block.fd = -1;
       block.start = block.exec = rtl_arena_alloc(m_arena, &block.size);
    }
    return (block.start != 0 && block.exec != 0);
}

void VtableFactory::freeBlock(Block const & block) const {
    //if the double-map failed we were allocated on the arena
    if (block.fd == -1 && block.start == block.exec && block.start != NULL)
        rtl_arena_free(m_arena, block.start, block.size);
    else
    {
        if (block.start) munmap(block.start, block.size);
        if (block.exec) munmap(block.exec, block.size);
        if (block.fd != -1) close(block.fd);
    }
}
#else
bool VtableFactory::createBlock(Block &block, sal_Int32 slotCount) const
{
    block.size = getBlockSize(slotCount);
    block.start = rtl_arena_alloc(m_arena, &block.size);
    return block.start != 0;
}

void VtableFactory::freeBlock(Block const & block) const {
    rtl_arena_free(m_arena, block.start, block.size);
}
#endif

void VtableFactory::createVtables(
    GuardedBlocks & blocks, BaseOffset const & baseOffset,
    typelib_InterfaceTypeDescription * type, bool includePrimary) const
{
    if (includePrimary) {
        sal_Int32 slotCount
            = bridges::cpp_uno::shared::getPrimaryFunctions(type);
        Block block;
        if (!createBlock(block, slotCount)) {
            throw std::bad_alloc();
        }
        try {
            Slot * slots = initializeBlock(block.start, slotCount);
            unsigned char * codeBegin =
                reinterpret_cast< unsigned char * >(slots);
            unsigned char * code = codeBegin;
            sal_Int32 vtableOffset = blocks.size() * sizeof (Slot *);
            for (typelib_InterfaceTypeDescription const * type2 = type;
                 type2 != 0; type2 = type2->pBaseTypeDescription)
            {
                code = addLocalFunctions(
                    &slots, code,
#ifdef USE_DOUBLE_MMAP
                    sal_IntPtr(block.exec) - sal_IntPtr(block.start),
#endif
                    type2,
                    baseOffset.getFunctionOffset(type2->aBase.pTypeName),
                    bridges::cpp_uno::shared::getLocalFunctions(type2),
                    vtableOffset);
            }
            flushCode(codeBegin, code);
#ifdef USE_DOUBLE_MMAP
        //Finished generating block, swap writable pointer with executable
        //pointer
            ::std::swap(block.start, block.exec);
#endif
            blocks.push_back(block);
        } catch (...) {
            freeBlock(block);
            throw;
        }
    }
    for (sal_Int32 i = 0; i < type->nBaseTypes; ++i) {
        createVtables(blocks, baseOffset, type->ppBaseTypes[i], i != 0);
    }
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>use getpagesize() on OpenBSD<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_bridges.hxx"

#if defined OS2
#define INCL_DOS
#define INCL_DOSMISC
#endif

#include "bridges/cpp_uno/shared/vtablefactory.hxx"

#include "guardedarray.hxx"

#include "bridges/cpp_uno/shared/vtables.hxx"

#include "osl/thread.h"
#include "osl/security.hxx"
#include "osl/file.hxx"
#include "osl/diagnose.h"
#include "osl/mutex.hxx"
#include "rtl/alloc.h"
#include "rtl/ustring.hxx"
#include "sal/types.h"
#include "typelib/typedescription.hxx"

#include <hash_map>
#include <new>
#include <vector>

#if defined SAL_UNX
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#elif defined SAL_W32
#define WIN32_LEAN_AND_MEAN
#ifdef _MSC_VER
#pragma warning(push,1) // disable warnings within system headers
#endif
#include <windows.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#elif defined SAL_OS2
#define INCL_DOS
#define INCL_DOSMISC
#include <os2.h>
#else
#error Unsupported platform
#endif

using bridges::cpp_uno::shared::VtableFactory;

namespace {

extern "C" void * SAL_CALL allocExec(rtl_arena_type *, sal_Size * size) {
    sal_Size pagesize;
#if defined SAL_UNX
#if defined FREEBSD || defined NETBSD || defined OPENBSD
    pagesize = getpagesize();
#else
    pagesize = sysconf(_SC_PAGESIZE);
#endif
#elif defined SAL_W32
    SYSTEM_INFO info;
    GetSystemInfo(&info);
    pagesize = info.dwPageSize;
#elif defined(SAL_OS2)
    ULONG ulPageSize;
    DosQuerySysInfo(QSV_PAGE_SIZE, QSV_PAGE_SIZE, &ulPageSize, sizeof(ULONG));
    pagesize = (sal_Size)ulPageSize;
#else
#error Unsupported platform
#endif
    sal_Size n = (*size + (pagesize - 1)) & ~(pagesize - 1);
    void * p;
#if defined SAL_UNX
    p = mmap(
        0, n, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1,
        0);
    if (p == MAP_FAILED) {
        p = 0;
    }
    else if (mprotect (static_cast<char*>(p), n, PROT_READ | PROT_WRITE | PROT_EXEC) == -1)
    {
        munmap (static_cast<char*>(p), n);
        p = 0;
    }
#elif defined SAL_W32
    p = VirtualAlloc(0, n, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
#elif defined(SAL_OS2)
    p = 0;
    DosAllocMem( &p, n, PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_ANY);
#endif
    if (p != 0) {
        *size = n;
    }
    return p;
}

extern "C" void SAL_CALL freeExec(
    rtl_arena_type *, void * address, sal_Size size)
{
#if defined SAL_UNX
    munmap(static_cast< char * >(address), size);
#elif defined SAL_W32
    (void) size; // unused
    VirtualFree(address, 0, MEM_RELEASE);
#elif defined(SAL_OS2)
    (void) DosFreeMem( address);
#endif
}

}

class VtableFactory::GuardedBlocks: public std::vector< Block > {
public:
    GuardedBlocks(VtableFactory const & factory):
        m_factory(factory), m_guarded(true) {}

    ~GuardedBlocks();

    void unguard() { m_guarded = false; }

private:
    GuardedBlocks(GuardedBlocks &); // not implemented
    void operator =(GuardedBlocks); // not implemented

    VtableFactory const & m_factory;
    bool m_guarded;
};

VtableFactory::GuardedBlocks::~GuardedBlocks() {
    if (m_guarded) {
        for (iterator i(begin()); i != end(); ++i) {
            m_factory.freeBlock(*i);
        }
    }
}

class VtableFactory::BaseOffset {
public:
    BaseOffset(typelib_InterfaceTypeDescription * type) { calculate(type, 0); }

    sal_Int32 getFunctionOffset(rtl::OUString const & name) const
    { return m_map.find(name)->second; }

private:
    sal_Int32 calculate(
        typelib_InterfaceTypeDescription * type, sal_Int32 offset);

    typedef std::hash_map< rtl::OUString, sal_Int32, rtl::OUStringHash > Map;

    Map m_map;
};

sal_Int32 VtableFactory::BaseOffset::calculate(
    typelib_InterfaceTypeDescription * type, sal_Int32 offset)
{
    rtl::OUString name(type->aBase.pTypeName);
    if (m_map.find(name) == m_map.end()) {
        for (sal_Int32 i = 0; i < type->nBaseTypes; ++i) {
            offset = calculate(type->ppBaseTypes[i], offset);
        }
        m_map.insert(Map::value_type(name, offset));
        typelib_typedescription_complete(
            reinterpret_cast< typelib_TypeDescription ** >(&type));
        offset += bridges::cpp_uno::shared::getLocalFunctions(type);
    }
    return offset;
}

VtableFactory::VtableFactory(): m_arena(
    rtl_arena_create(
        "bridges::cpp_uno::shared::VtableFactory",
        sizeof (void *), // to satisfy alignment requirements
        0, reinterpret_cast< rtl_arena_type * >(-1), allocExec, freeExec, 0))
{
    if (m_arena == 0) {
        throw std::bad_alloc();
    }
}

VtableFactory::~VtableFactory() {
    {
        osl::MutexGuard guard(m_mutex);
        for (Map::iterator i(m_map.begin()); i != m_map.end(); ++i) {
            for (sal_Int32 j = 0; j < i->second.count; ++j) {
                freeBlock(i->second.blocks[j]);
            }
            delete[] i->second.blocks;
        }
    }
    rtl_arena_destroy(m_arena);
}

VtableFactory::Vtables VtableFactory::getVtables(
    typelib_InterfaceTypeDescription * type)
{
    rtl::OUString name(type->aBase.pTypeName);
    osl::MutexGuard guard(m_mutex);
    Map::iterator i(m_map.find(name));
    if (i == m_map.end()) {
        GuardedBlocks blocks(*this);
        createVtables(blocks, BaseOffset(type), type, true);
        Vtables vtables;
        OSL_ASSERT(blocks.size() <= SAL_MAX_INT32);
        vtables.count = static_cast< sal_Int32 >(blocks.size());
        bridges::cpp_uno::shared::GuardedArray< Block > guardedBlocks(
            new Block[vtables.count]);
        vtables.blocks = guardedBlocks.get();
        for (sal_Int32 j = 0; j < vtables.count; ++j) {
            vtables.blocks[j] = blocks[j];
        }
        i = m_map.insert(Map::value_type(name, vtables)).first;
        guardedBlocks.release();
        blocks.unguard();
    }
    return i->second;
}

#ifdef USE_DOUBLE_MMAP
bool VtableFactory::createBlock(Block &block, sal_Int32 slotCount) const
{
    sal_Size size = getBlockSize(slotCount);
    sal_Size pagesize = sysconf(_SC_PAGESIZE);
    block.size = (size + (pagesize - 1)) & ~(pagesize - 1);
    block.start = block.exec = NULL;
    block.fd = -1;

    osl::Security aSecurity;
    rtl::OUString strDirectory;
    rtl::OUString strURLDirectory;
    if (aSecurity.getHomeDir(strURLDirectory))
        osl::File::getSystemPathFromFileURL(strURLDirectory, strDirectory);

    for (int i = strDirectory.getLength() == 0 ? 1 : 0; i < 2; ++i)
    {
        if (!strDirectory.getLength())
            strDirectory = rtl::OUString::createFromAscii("/tmp");

        strDirectory += rtl::OUString::createFromAscii("/.execoooXXXXXX");
        rtl::OString aTmpName = rtl::OUStringToOString(strDirectory, osl_getThreadTextEncoding());
        char *tmpfname = new char[aTmpName.getLength()+1];
        strncpy(tmpfname, aTmpName.getStr(), aTmpName.getLength()+1);
        if ((block.fd = mkstemp(tmpfname)) == -1)
            perror("creation of executable memory area failed");
        if (block.fd == -1)
        {
            delete[] tmpfname;
            break;
        }
        unlink(tmpfname);
        delete[] tmpfname;
        if (ftruncate(block.fd, block.size) == -1)
        {
            perror("truncation of executable memory area failed");
            close(block.fd);
            block.fd = -1;
            break;
        }
        block.start = mmap(NULL, block.size, PROT_READ | PROT_WRITE, MAP_SHARED, block.fd, 0);
        if (block.start== MAP_FAILED) {
            block.start = 0;
        }
        block.exec = mmap(NULL, block.size, PROT_READ | PROT_EXEC, MAP_SHARED, block.fd, 0);
        if (block.exec == MAP_FAILED) {
           block.exec = 0;
        }

        //All good
        if (block.start && block.exec && block.fd != -1)
            break;

        freeBlock(block);

        strDirectory = rtl::OUString();
    }
    if (!block.start || !block.exec || block.fd == -1)
    {
       //Fall back to non-doublemmaped allocation
       block.fd = -1;
       block.start = block.exec = rtl_arena_alloc(m_arena, &block.size);
    }
    return (block.start != 0 && block.exec != 0);
}

void VtableFactory::freeBlock(Block const & block) const {
    //if the double-map failed we were allocated on the arena
    if (block.fd == -1 && block.start == block.exec && block.start != NULL)
        rtl_arena_free(m_arena, block.start, block.size);
    else
    {
        if (block.start) munmap(block.start, block.size);
        if (block.exec) munmap(block.exec, block.size);
        if (block.fd != -1) close(block.fd);
    }
}
#else
bool VtableFactory::createBlock(Block &block, sal_Int32 slotCount) const
{
    block.size = getBlockSize(slotCount);
    block.start = rtl_arena_alloc(m_arena, &block.size);
    return block.start != 0;
}

void VtableFactory::freeBlock(Block const & block) const {
    rtl_arena_free(m_arena, block.start, block.size);
}
#endif

void VtableFactory::createVtables(
    GuardedBlocks & blocks, BaseOffset const & baseOffset,
    typelib_InterfaceTypeDescription * type, bool includePrimary) const
{
    if (includePrimary) {
        sal_Int32 slotCount
            = bridges::cpp_uno::shared::getPrimaryFunctions(type);
        Block block;
        if (!createBlock(block, slotCount)) {
            throw std::bad_alloc();
        }
        try {
            Slot * slots = initializeBlock(block.start, slotCount);
            unsigned char * codeBegin =
                reinterpret_cast< unsigned char * >(slots);
            unsigned char * code = codeBegin;
            sal_Int32 vtableOffset = blocks.size() * sizeof (Slot *);
            for (typelib_InterfaceTypeDescription const * type2 = type;
                 type2 != 0; type2 = type2->pBaseTypeDescription)
            {
                code = addLocalFunctions(
                    &slots, code,
#ifdef USE_DOUBLE_MMAP
                    sal_IntPtr(block.exec) - sal_IntPtr(block.start),
#endif
                    type2,
                    baseOffset.getFunctionOffset(type2->aBase.pTypeName),
                    bridges::cpp_uno::shared::getLocalFunctions(type2),
                    vtableOffset);
            }
            flushCode(codeBegin, code);
#ifdef USE_DOUBLE_MMAP
        //Finished generating block, swap writable pointer with executable
        //pointer
            ::std::swap(block.start, block.exec);
#endif
            blocks.push_back(block);
        } catch (...) {
            freeBlock(block);
            throw;
        }
    }
    for (sal_Int32 i = 0; i < type->nBaseTypes; ++i) {
        createVtables(blocks, baseOffset, type->ppBaseTypes[i], i != 0);
    }
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>//
// PHP-compatible unserializer for C++
//
// Copyright (C) 2012-2013 Kisli    http://www.kisli.com
//
//    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.
//

#define BOOST_TEST_MODULE pherialize_unserialize test
#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>

#include "pherialize/unserialize.hpp"

using namespace pherialize;

BOOST_AUTO_TEST_CASE(unserializeNull) {

	shared_ptr <Mixed> m = unserialize("");

	BOOST_CHECK(m == NULL);
}

BOOST_AUTO_TEST_CASE(unserializeString) {

	shared_ptr <Mixed> m = unserialize("s:11:\"test string\";");

	BOOST_CHECK(m->type() == Mixed::TYPE_STRING);
	BOOST_CHECK(m->stringValue() == "test string");
}

BOOST_AUTO_TEST_CASE(unserializeInteger) {

	shared_ptr <Mixed> m = unserialize("i:4242;");

	BOOST_CHECK(m->type() == Mixed::TYPE_INT);
	BOOST_CHECK(m->intValue() == 4242);
}

BOOST_AUTO_TEST_CASE(unserializeBool) {

	shared_ptr <Mixed> m1 = unserialize("b:1;");

	BOOST_CHECK(m1->type() == Mixed::TYPE_BOOL);
	BOOST_CHECK(m1->boolValue() == true);

	shared_ptr <Mixed> m2 = unserialize("b:0;");

	BOOST_CHECK(m2->type() == Mixed::TYPE_BOOL);
	BOOST_CHECK(m2->boolValue() == false);
}

BOOST_AUTO_TEST_CASE(unserializeDouble) {

	shared_ptr <Mixed> m = unserialize("d:44.83834308566653;");

	BOOST_CHECK(m->type() == Mixed::TYPE_DOUBLE);
	BOOST_CHECK_CLOSE(m->doubleValue(), 44.83834308566653, 0.000001);

	shared_ptr <Mixed> m2 = unserialize("d:-0.05;");

	BOOST_CHECK(m2->type() == Mixed::TYPE_DOUBLE);
	BOOST_CHECK_CLOSE(m2->doubleValue(), -0.05, 0.000001);
}

const Mixed &readMap(const std::map <Mixed, Mixed> &map, const Mixed &key) {
	const std::map <Mixed, Mixed>::const_iterator it = map.find(key);
	if (it == map.end()) {
		throw std::out_of_range("Key not found");
	}
	return (*it).second;
}

BOOST_AUTO_TEST_CASE(unserializeMap) {

	shared_ptr <Mixed> m1 = unserialize("a:2:{s:2:\"ab\";s:2:\"cd\";s:2:\"ef\";s:2:\"gh\";}");

	BOOST_CHECK(m1->type() == Mixed::TYPE_ARRAY);

	const MixedArray &marr1 = m1->arrayValue();

	BOOST_CHECK(marr1.type() == MixedArray::TYPE_MAP);
	BOOST_CHECK(marr1.mapValue().size() == 2);
	BOOST_CHECK(readMap(marr1.mapValue(), "ab") == "cd");
	BOOST_CHECK(readMap(marr1.mapValue(), "ef") == "gh");
}

BOOST_AUTO_TEST_CASE(unserializeVector) {

	// Vector with 2 elements
	shared_ptr <Mixed> m1 = unserialize("a:2:{i:0;s:2:\"ab\";i:1;s:2:\"cd\";}");

	BOOST_CHECK(m1->type() == Mixed::TYPE_ARRAY);

	const MixedArray &marr1 = m1->arrayValue();

	BOOST_CHECK(marr1.type() == MixedArray::TYPE_VECTOR);
	BOOST_CHECK(marr1.vectorValue().size() == 2);
	BOOST_CHECK(marr1.vectorValue()[0] == "ab");
	BOOST_CHECK(marr1.vectorValue()[1] == "cd");

	// Empty vector
	shared_ptr <Mixed> m2 = unserialize("a:0:{}");

	BOOST_CHECK(m2->type() == Mixed::TYPE_ARRAY);

	const MixedArray &marr2 = m2->arrayValue();

	BOOST_CHECK(marr2.type() == MixedArray::TYPE_VECTOR);
	BOOST_CHECK(marr2.vectorValue().size() == 0);

	// Vector in vector
	shared_ptr <Mixed> m3 = unserialize("a:1:{i:0;a:1:{i:0;i:42;}}");

	BOOST_CHECK(m3->type() == Mixed::TYPE_ARRAY);

	const MixedArray &marr3_1 = m3->arrayValue();

	BOOST_CHECK(marr3_1.type() == MixedArray::TYPE_VECTOR);
	BOOST_CHECK(marr3_1.vectorValue().size() == 1);
	BOOST_CHECK(marr3_1.vectorValue()[0].type() == Mixed::TYPE_ARRAY);

	const MixedArray &marr3_2 = marr3_1.vectorValue()[0].arrayValue();

	BOOST_CHECK(marr3_2.type() == MixedArray::TYPE_VECTOR);
	BOOST_CHECK(marr3_2.vectorValue().size() == 1);
	BOOST_CHECK(marr3_2.vectorValue()[0].type() == Mixed::TYPE_INT);
	BOOST_CHECK(marr3_2.vectorValue()[0].intValue() == 42);
}

BOOST_AUTO_TEST_CASE(unserializeInvalid) {

	// Incorrect string length
	BOOST_CHECK_THROW(
		unserialize("s:3:\"ab\";"),
		std::runtime_error
	);

	// Too much input data
	BOOST_CHECK_THROW(
		unserialize("i:42:1234;"),
		std::runtime_error
	);
}
<commit_msg>Use BOOST_CHECK_EQUAL for easier debugging.<commit_after>//
// PHP-compatible unserializer for C++
//
// Copyright (C) 2012-2013 Kisli    http://www.kisli.com
//
//    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.
//

#define BOOST_TEST_MODULE pherialize_unserialize test
#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>

#include "pherialize/unserialize.hpp"

using namespace pherialize;

BOOST_AUTO_TEST_CASE(unserializeNull) {

	shared_ptr <Mixed> m = unserialize("");

	BOOST_CHECK(m == NULL);
}

BOOST_AUTO_TEST_CASE(unserializeString) {

	shared_ptr <Mixed> m = unserialize("s:11:\"test string\";");

	BOOST_CHECK_EQUAL(Mixed::TYPE_STRING, m->type());
	BOOST_CHECK_EQUAL("test string", m->stringValue());
}

BOOST_AUTO_TEST_CASE(unserializeInteger) {

	shared_ptr <Mixed> m = unserialize("i:4242;");

	BOOST_CHECK_EQUAL(Mixed::TYPE_INT, m->type());
	BOOST_CHECK_EQUAL(4242, m->intValue());
}

BOOST_AUTO_TEST_CASE(unserializeBool) {

	shared_ptr <Mixed> m1 = unserialize("b:1;");

	BOOST_CHECK_EQUAL(Mixed::TYPE_BOOL, m1->type());
	BOOST_CHECK_EQUAL(true, m1->boolValue());

	shared_ptr <Mixed> m2 = unserialize("b:0;");

	BOOST_CHECK_EQUAL(Mixed::TYPE_BOOL, m2->type());
	BOOST_CHECK_EQUAL(false, m2->boolValue());
}

BOOST_AUTO_TEST_CASE(unserializeDouble) {

	shared_ptr <Mixed> m = unserialize("d:44.83834308566653;");

	BOOST_CHECK_EQUAL(Mixed::TYPE_DOUBLE, m->type());
	BOOST_CHECK_CLOSE(m->doubleValue(), 44.83834308566653, 0.000001);

	shared_ptr <Mixed> m2 = unserialize("d:-0.05;");

	BOOST_CHECK_EQUAL(Mixed::TYPE_DOUBLE, m2->type());
	BOOST_CHECK_CLOSE(m2->doubleValue(), -0.05, 0.000001);
}

const Mixed &readMap(const std::map <Mixed, Mixed> &map, const Mixed &key) {
	const std::map <Mixed, Mixed>::const_iterator it = map.find(key);
	if (it == map.end()) {
		throw std::out_of_range("Key not found");
	}
	return (*it).second;
}

BOOST_AUTO_TEST_CASE(unserializeMap) {

	shared_ptr <Mixed> m1 = unserialize("a:2:{s:2:\"ab\";s:2:\"cd\";s:2:\"ef\";s:2:\"gh\";}");

	BOOST_CHECK_EQUAL(Mixed::TYPE_ARRAY, m1->type());

	const MixedArray &marr1 = m1->arrayValue();

	BOOST_CHECK_EQUAL(MixedArray::TYPE_MAP, marr1.type());
	BOOST_CHECK_EQUAL(2, marr1.mapValue().size());
	BOOST_CHECK_EQUAL("cd", readMap(marr1.mapValue(), "ab").stringValue());
	BOOST_CHECK_EQUAL("gh", readMap(marr1.mapValue(), "ef").stringValue());
}

BOOST_AUTO_TEST_CASE(unserializeVector) {

	// Vector with 2 elements
	shared_ptr <Mixed> m1 = unserialize("a:2:{i:0;s:2:\"ab\";i:1;s:2:\"cd\";}");

	BOOST_CHECK_EQUAL(Mixed::TYPE_ARRAY, m1->type());

	const MixedArray &marr1 = m1->arrayValue();

	BOOST_CHECK_EQUAL(MixedArray::TYPE_VECTOR, marr1.type());
	BOOST_CHECK_EQUAL(2, marr1.vectorValue().size());
	BOOST_CHECK_EQUAL("ab", marr1.vectorValue()[0].stringValue());
	BOOST_CHECK_EQUAL("cd", marr1.vectorValue()[1].stringValue());

	// Empty vector
	shared_ptr <Mixed> m2 = unserialize("a:0:{}");

	BOOST_CHECK_EQUAL(Mixed::TYPE_ARRAY, m2->type());

	const MixedArray &marr2 = m2->arrayValue();

	BOOST_CHECK_EQUAL(MixedArray::TYPE_VECTOR, marr2.type());
	BOOST_CHECK_EQUAL(0, marr2.vectorValue().size());

	// Vector in vector
	shared_ptr <Mixed> m3 = unserialize("a:1:{i:0;a:1:{i:0;i:42;}}");

	BOOST_CHECK_EQUAL(Mixed::TYPE_ARRAY, m3->type());

	const MixedArray &marr3_1 = m3->arrayValue();

	BOOST_CHECK_EQUAL(MixedArray::TYPE_VECTOR, marr3_1.type());
	BOOST_CHECK_EQUAL(1, marr3_1.vectorValue().size());
	BOOST_CHECK_EQUAL(Mixed::TYPE_ARRAY, marr3_1.vectorValue()[0].type());

	const MixedArray &marr3_2 = marr3_1.vectorValue()[0].arrayValue();

	BOOST_CHECK_EQUAL(MixedArray::TYPE_VECTOR, marr3_2.type());
	BOOST_CHECK_EQUAL(1, marr3_2.vectorValue().size());
	BOOST_CHECK_EQUAL(Mixed::TYPE_INT, marr3_2.vectorValue()[0].type());
	BOOST_CHECK_EQUAL(42, marr3_2.vectorValue()[0].intValue());
}

BOOST_AUTO_TEST_CASE(unserializeInvalid) {

	// Incorrect string length
	BOOST_CHECK_THROW(
		unserialize("s:3:\"ab\";"),
		std::runtime_error
	);

	// Too much input data
	BOOST_CHECK_THROW(
		unserialize("i:42:1234;"),
		std::runtime_error
	);
}

<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/* $Id$ */

// Generator using Herwig as an external generator
// The main Herwig options are accessable for the user through this interface.
// Uses the THerwig implementation of TGenerator.

#include "AliGenHerwig.h"
#include "AliHerwigRndm.h"
#include "AliRun.h"

#include <TParticle.h>
#include "THerwig6.h"

#include "Riostream.h"
#include "AliMC.h"

ClassImp(AliGenHerwig)

  AliGenHerwig::AliGenHerwig() :
    AliGenMC(),
    fAutPDF("GRV"),
    fModPDF(5),
    fStrucFunc(kGRVHO),
    fKeep(0),
    fDecaysOff(1),
    fTrigger(0),
    fSelectAll(0),
    fFlavor(0),
    fEnergyCMS(14000),
    fMomentum1(7000),
    fMomentum2(7000),
    fKineBias(1),
    fTrials(0),
    fXsection(0),
    fHerwig(0x0),
    fProcess(0),
    fPtHardMin(0),
    fPtRMS(0),
    fMaxPr(10),
    fMaxErrors(1000),
    fEnSoft(1)
{
// Constructor
}

AliGenHerwig::AliGenHerwig(Int_t npart)
    :AliGenMC(npart)
{
    SetBeamMomenta();
    SetTarget();
    SetProjectile();
    SetStrucFunc(kGRVLO98);
    fKeep=0;
    fTrigger=0;
    fDecaysOff=1;
    fSelectAll=0;
    fFlavor=0;
    fPtHardMin=0.;
    fPtRMS=0.0;
    fEnSoft=1.0;
    fMaxPr=10;
    fMaxErrors=1000;
    // Set random number generator
    AliHerwigRndm::SetHerwigRandom(GetRandom());
}

AliGenHerwig::AliGenHerwig(const AliGenHerwig & Herwig)
    :AliGenMC(Herwig)
{
// Copy constructor
    Herwig.Copy(*this);
}

AliGenHerwig::~AliGenHerwig()
{
// Destructor
}

void AliGenHerwig::Init()
{
// Initialisation
  fTarget.Resize(8);
  fProjectile.Resize(8);
  SetMC(new THerwig6());
  fHerwig=(THerwig6*) fMCEvGen;
  // initialize common blocks
  fHerwig->Initialize(fProjectile, fTarget, fMomentum1, fMomentum2, fProcess);
  // reset parameters according to user needs
  InitPDF();
  fHerwig->SetPTMIN(fPtHardMin);
  fHerwig->SetPTRMS(fPtRMS);
  fHerwig->SetMAXPR(fMaxPr);
  fHerwig->SetMAXER(fMaxErrors);
  fHerwig->SetENSOF(fEnSoft);
  // compute parameter dependent constants
  fHerwig->PrepareRun();
}

void AliGenHerwig::InitPDF()
{
  switch(fStrucFunc)
    {
    case kGRVLO:
      fModPDF=5;
      fAutPDF="GRV";
      break;
    case kGRVHO:
      fModPDF=6;
      fAutPDF="GRV";
      break;
    case kGRVLO98:
      fModPDF=12;
      fAutPDF="GRV";
      break;
    case kMRSDminus:
      fModPDF=31;
      fAutPDF="MRS";
      break;
    case kMRSD0:
      fModPDF=30;
      fAutPDF="MRS";
      break;
    case kMRSG:
      fModPDF=41;
      fAutPDF="MRS";
      break;
    case kMRSTcgLO:
      fModPDF=72;
      fAutPDF="MRS";
      break;
    case kCTEQ4M:
      fModPDF=34;
      fAutPDF="CTEQ";
      break;
    case kCTEQ5L:
      fModPDF=46;
      fAutPDF="CTEQ";
      break;
    default:
      cerr << "This structure function is not inplemented " << fStrucFunc << endl;
      break;
    }
  fAutPDF.Resize(20);
  fHerwig->SetMODPDF(1,fModPDF);
  fHerwig->SetMODPDF(2,fModPDF);
  fHerwig->SetAUTPDF(1,fAutPDF);
  fHerwig->SetAUTPDF(2,fAutPDF);
}

void AliGenHerwig::Generate()
{
  // Generate one event

  Float_t polar[3] =   {0,0,0};
  Float_t origin[3]=   {0,0,0};
  Float_t origin0[3]=  {0,0,0};
  Float_t p[4], random[6];

  static TClonesArray *particles;
  //  converts from mm/c to s
  const Float_t kconv=0.001/2.999792458e8;
  //
  Int_t nt=0;
  Int_t jev=0;
  Int_t j, kf, ks, imo;
  kf=0;

  if(!particles) particles=new TClonesArray("TParticle",10000);

  fTrials=0;
  for (j=0;j<3;j++) origin0[j]=fOrigin[j];
  if(fVertexSmear==kPerEvent) {
    Rndm(random,6);
    for (j=0;j<3;j++) {
      origin0[j]+=fOsigma[j]*TMath::Cos(2*random[2*j]*TMath::Pi())*
	TMath::Sqrt(-2*TMath::Log(random[2*j+1]));
    }
  }

  while(1)
    {
	fHerwig->GenerateEvent();
	fTrials++;
	fHerwig->ImportParticles(particles,"All");
	Int_t np = particles->GetEntriesFast()-1;
	printf("Particles from Herwig %d \n", np);

	if (np == 0 ) continue;

	Int_t nc=0;

	Int_t * newPos = new Int_t[np];
	for (Int_t i = 0; i<np; i++) *(newPos+i)=-1;

	for (Int_t i = 0; i<np; i++) {
	    TParticle *  iparticle       = (TParticle *) particles->At(i);
	    imo = iparticle->GetFirstMother();
	    kf        = iparticle->GetPdgCode();
	    ks        = iparticle->GetStatusCode();
	    if (ks != 3 &&
		KinematicSelection(iparticle,0))
	    {
		nc++;
		p[0]=iparticle->Px();
		p[1]=iparticle->Py();
		p[2]=iparticle->Pz();
		p[3]=iparticle->Energy();
		origin[0]=origin0[0]+iparticle->Vx()/10;
		origin[1]=origin0[1]+iparticle->Vy()/10;
		origin[2]=origin0[2]+iparticle->Vz()/10;
		Float_t tof = kconv*iparticle->T();
		Int_t   iparent = (imo > -1) ? newPos[imo] : -1;
		Int_t   trackIt = (ks == 1) && fTrackIt;
		PushTrack(trackIt, iparent, kf,
			  p[0], p[1], p[2], p[3],
			  origin[0], origin[1], origin[2],
			  tof,
			  polar[0], polar[1], polar[2],
			  kPPrimary, nt, 1., ks);
		KeepTrack(nt);
		newPos[i]=nt;
	    } // end of if: selection of particle
	} // end of for: particle loop
	if (newPos) delete[] newPos;
	printf("\n I've put %i particles on the stack \n",nc);
	//      MakeHeader();
	printf("nc: %d %d\n", nc, fNpart);

	if (nc > 0) {
	    jev+=nc;
	    if (jev >= fNpart || fNpart == -1) {
		fKineBias=Float_t(fNpart)/Float_t(fTrials);
		printf("\n Trials: %i %i %i\n",fTrials, fNpart, jev);
		break;
	    }
	}
    }
  SetHighWaterMark(nt);
//  adjust weight due to kinematic selection
  AdjustWeights();
//  get cross-section
  fXsection=fHerwig->GetAVWGT();
}

void AliGenHerwig::AdjustWeights()
{
// Adjust the weights after generation of all events
    TParticle *part;
    Int_t ntrack=gAlice->GetMCApp()->GetNtrack();
    for (Int_t i=0; i<ntrack; i++) {
        part= gAlice->GetMCApp()->Particle(i);
        part->SetWeight(part->GetWeight()*fKineBias);
    }
}

void AliGenHerwig::KeepFullEvent()
{
    fKeep=1;
}

Bool_t AliGenHerwig::DaughtersSelection(TParticle* iparticle, TClonesArray* particles)
{
//
// Looks recursively if one of the daughters has been selected
//
//    printf("\n Consider daughters %d:",iparticle->GetPdgCode());
    Int_t imin=-1;
    Int_t imax=-1;
    Int_t i;
    Bool_t hasDaughters= (iparticle->GetFirstDaughter() >=0);
    Bool_t selected=kFALSE;
    if (hasDaughters) {
	imin=iparticle->GetFirstDaughter();
	imax=iparticle->GetLastDaughter();
	for (i=imin; i<= imax; i++){
	    TParticle *  jparticle       = (TParticle *) particles->At(i);
	    Int_t ip=jparticle->GetPdgCode();
	    if (KinematicSelection(jparticle,0)&&SelectFlavor(ip)) {
		selected=kTRUE; break;
	    }
	    if (DaughtersSelection(jparticle, particles)) {selected=kTRUE; break; }
	}
    } else {
	return kFALSE;
    }

    return selected;
}

Bool_t AliGenHerwig::SelectFlavor(Int_t pid)
{
// Select flavor of particle
// 0: all
// 4: charm and beauty
// 5: beauty
    if (fFlavor == 0) return kTRUE;

    Int_t ifl=TMath::Abs(pid/100);
    if (ifl > 10) ifl/=10;
    return (fFlavor == ifl);
}

Bool_t AliGenHerwig::Stable(TParticle*  particle)
{
// Return true for a stable particle
//
    Int_t kf = TMath::Abs(particle->GetPdgCode());

    if ( (particle->GetFirstDaughter() < 0 ) || (kf == 1000*fFlavor+122))

    {
	return kTRUE;
    } else {
	return kFALSE;
    }
}

void AliGenHerwig::FinishRun()
{
  fHerwig->Hwefin();
}

AliGenHerwig& AliGenHerwig::operator=(const  AliGenHerwig& rhs)
{
// Assignment operator
    rhs.Copy(*this);
    return (*this);
}

<commit_msg>Obsolete printf's removed.<commit_after>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/* $Id$ */

// Generator using Herwig as an external generator
// The main Herwig options are accessable for the user through this interface.
// Uses the THerwig implementation of TGenerator.

#include "AliGenHerwig.h"
#include "AliHerwigRndm.h"
#include "AliRun.h"

#include <TParticle.h>
#include "THerwig6.h"

#include "Riostream.h"
#include "AliMC.h"

ClassImp(AliGenHerwig)

  AliGenHerwig::AliGenHerwig() :
    AliGenMC(),
    fAutPDF("GRV"),
    fModPDF(5),
    fStrucFunc(kGRVHO),
    fKeep(0),
    fDecaysOff(1),
    fTrigger(0),
    fSelectAll(0),
    fFlavor(0),
    fEnergyCMS(14000),
    fMomentum1(7000),
    fMomentum2(7000),
    fKineBias(1),
    fTrials(0),
    fXsection(0),
    fHerwig(0x0),
    fProcess(0),
    fPtHardMin(0),
    fPtRMS(0),
    fMaxPr(10),
    fMaxErrors(1000),
    fEnSoft(1)
{
// Constructor
}

AliGenHerwig::AliGenHerwig(Int_t npart)
    :AliGenMC(npart)
{
    SetBeamMomenta();
    SetTarget();
    SetProjectile();
    SetStrucFunc(kGRVLO98);
    fKeep=0;
    fTrigger=0;
    fDecaysOff=1;
    fSelectAll=0;
    fFlavor=0;
    fPtHardMin=0.;
    fPtRMS=0.0;
    fEnSoft=1.0;
    fMaxPr=10;
    fMaxErrors=1000;
    // Set random number generator
    AliHerwigRndm::SetHerwigRandom(GetRandom());
}

AliGenHerwig::AliGenHerwig(const AliGenHerwig & Herwig)
    :AliGenMC(Herwig)
{
// Copy constructor
    Herwig.Copy(*this);
}

AliGenHerwig::~AliGenHerwig()
{
// Destructor
}

void AliGenHerwig::Init()
{
// Initialisation
  fTarget.Resize(8);
  fProjectile.Resize(8);
  SetMC(new THerwig6());
  fHerwig=(THerwig6*) fMCEvGen;
  // initialize common blocks
  fHerwig->Initialize(fProjectile, fTarget, fMomentum1, fMomentum2, fProcess);
  // reset parameters according to user needs
  InitPDF();
  fHerwig->SetPTMIN(fPtHardMin);
  fHerwig->SetPTRMS(fPtRMS);
  fHerwig->SetMAXPR(fMaxPr);
  fHerwig->SetMAXER(fMaxErrors);
  fHerwig->SetENSOF(fEnSoft);
  // compute parameter dependent constants
  fHerwig->PrepareRun();
}

void AliGenHerwig::InitPDF()
{
  switch(fStrucFunc)
    {
    case kGRVLO:
      fModPDF=5;
      fAutPDF="GRV";
      break;
    case kGRVHO:
      fModPDF=6;
      fAutPDF="GRV";
      break;
    case kGRVLO98:
      fModPDF=12;
      fAutPDF="GRV";
      break;
    case kMRSDminus:
      fModPDF=31;
      fAutPDF="MRS";
      break;
    case kMRSD0:
      fModPDF=30;
      fAutPDF="MRS";
      break;
    case kMRSG:
      fModPDF=41;
      fAutPDF="MRS";
      break;
    case kMRSTcgLO:
      fModPDF=72;
      fAutPDF="MRS";
      break;
    case kCTEQ4M:
      fModPDF=34;
      fAutPDF="CTEQ";
      break;
    case kCTEQ5L:
      fModPDF=46;
      fAutPDF="CTEQ";
      break;
    default:
      cerr << "This structure function is not inplemented " << fStrucFunc << endl;
      break;
    }
  fAutPDF.Resize(20);
  fHerwig->SetMODPDF(1,fModPDF);
  fHerwig->SetMODPDF(2,fModPDF);
  fHerwig->SetAUTPDF(1,fAutPDF);
  fHerwig->SetAUTPDF(2,fAutPDF);
}

void AliGenHerwig::Generate()
{
  // Generate one event

  Float_t polar[3] =   {0,0,0};
  Float_t origin[3]=   {0,0,0};
  Float_t origin0[3]=  {0,0,0};
  Float_t p[4], random[6];

  static TClonesArray *particles;
  //  converts from mm/c to s
  const Float_t kconv=0.001/2.999792458e8;
  //
  Int_t nt=0;
  Int_t jev=0;
  Int_t j, kf, ks, imo;
  kf=0;

  if(!particles) particles=new TClonesArray("TParticle",10000);

  fTrials=0;
  for (j=0;j<3;j++) origin0[j]=fOrigin[j];
  if(fVertexSmear==kPerEvent) {
    Rndm(random,6);
    for (j=0;j<3;j++) {
      origin0[j]+=fOsigma[j]*TMath::Cos(2*random[2*j]*TMath::Pi())*
	TMath::Sqrt(-2*TMath::Log(random[2*j+1]));
    }
  }

  while(1)
    {
	fHerwig->GenerateEvent();
	fTrials++;
	fHerwig->ImportParticles(particles,"All");
	Int_t np = particles->GetEntriesFast()-1;
	if (np == 0 ) continue;

	Int_t nc=0;

	Int_t * newPos = new Int_t[np];
	for (Int_t i = 0; i<np; i++) *(newPos+i)=-1;

	for (Int_t i = 0; i<np; i++) {
	    TParticle *  iparticle       = (TParticle *) particles->At(i);
	    imo = iparticle->GetFirstMother();
	    kf        = iparticle->GetPdgCode();
	    ks        = iparticle->GetStatusCode();
	    if (ks != 3 &&
		KinematicSelection(iparticle,0))
	    {
		nc++;
		p[0]=iparticle->Px();
		p[1]=iparticle->Py();
		p[2]=iparticle->Pz();
		p[3]=iparticle->Energy();
		origin[0]=origin0[0]+iparticle->Vx()/10;
		origin[1]=origin0[1]+iparticle->Vy()/10;
		origin[2]=origin0[2]+iparticle->Vz()/10;
		Float_t tof = kconv*iparticle->T();
		Int_t   iparent = (imo > -1) ? newPos[imo] : -1;
		Int_t   trackIt = (ks == 1) && fTrackIt;
		PushTrack(trackIt, iparent, kf,
			  p[0], p[1], p[2], p[3],
			  origin[0], origin[1], origin[2],
			  tof,
			  polar[0], polar[1], polar[2],
			  kPPrimary, nt, 1., ks);
		KeepTrack(nt);
		newPos[i]=nt;
	    } // end of if: selection of particle
	} // end of for: particle loop
	if (newPos) delete[] newPos;
	//      MakeHeader();
	if (nc > 0) {
	    jev+=nc;
	    if (jev >= fNpart || fNpart == -1) {
		fKineBias=Float_t(fNpart)/Float_t(fTrials);
		break;
	    }
	}
    }
  SetHighWaterMark(nt);
//  adjust weight due to kinematic selection
  AdjustWeights();
//  get cross-section
  fXsection=fHerwig->GetAVWGT();
}

void AliGenHerwig::AdjustWeights()
{
// Adjust the weights after generation of all events
    TParticle *part;
    Int_t ntrack=gAlice->GetMCApp()->GetNtrack();
    for (Int_t i=0; i<ntrack; i++) {
        part= gAlice->GetMCApp()->Particle(i);
        part->SetWeight(part->GetWeight()*fKineBias);
    }
}

void AliGenHerwig::KeepFullEvent()
{
    fKeep=1;
}

Bool_t AliGenHerwig::DaughtersSelection(TParticle* iparticle, TClonesArray* particles)
{
//
// Looks recursively if one of the daughters has been selected
//
//    printf("\n Consider daughters %d:",iparticle->GetPdgCode());
    Int_t imin=-1;
    Int_t imax=-1;
    Int_t i;
    Bool_t hasDaughters= (iparticle->GetFirstDaughter() >=0);
    Bool_t selected=kFALSE;
    if (hasDaughters) {
	imin=iparticle->GetFirstDaughter();
	imax=iparticle->GetLastDaughter();
	for (i=imin; i<= imax; i++){
	    TParticle *  jparticle       = (TParticle *) particles->At(i);
	    Int_t ip=jparticle->GetPdgCode();
	    if (KinematicSelection(jparticle,0)&&SelectFlavor(ip)) {
		selected=kTRUE; break;
	    }
	    if (DaughtersSelection(jparticle, particles)) {selected=kTRUE; break; }
	}
    } else {
	return kFALSE;
    }

    return selected;
}

Bool_t AliGenHerwig::SelectFlavor(Int_t pid)
{
// Select flavor of particle
// 0: all
// 4: charm and beauty
// 5: beauty
    if (fFlavor == 0) return kTRUE;

    Int_t ifl=TMath::Abs(pid/100);
    if (ifl > 10) ifl/=10;
    return (fFlavor == ifl);
}

Bool_t AliGenHerwig::Stable(TParticle*  particle)
{
// Return true for a stable particle
//
    Int_t kf = TMath::Abs(particle->GetPdgCode());

    if ( (particle->GetFirstDaughter() < 0 ) || (kf == 1000*fFlavor+122))

    {
	return kTRUE;
    } else {
	return kFALSE;
    }
}

void AliGenHerwig::FinishRun()
{
  fHerwig->Hwefin();
}

AliGenHerwig& AliGenHerwig::operator=(const  AliGenHerwig& rhs)
{
// Assignment operator
    rhs.Copy(*this);
    return (*this);
}

<|endoftext|>


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

  Library   : Image Registration Toolkit (IRTK)
  Module    : $Id$
  Copyright : Imperial College, Department of Computing
              Visual Information Processing (VIP), 2008 onwards
  Date      : $Date$
  Version   : $Revision$
  Changes   : $Author$

=========================================================================*/

#include <irtkRegistration.h>

char *dof1_name = NULL;
char *dof2_name = NULL;
char *dof3_name = NULL;

void usage()
{
  cerr << "Usage: dofcombine [input doffile 1] [input doffile 2] [output doffile] [-invert1] [-invert2]" << endl;
  exit(1);
}

int main(int argc, char **argv)
{
  int ok, invert1, invert2;
  irtkMatrix m1, m2, m3;
  irtkAffineTransformation transformation1, transformation2, transformation3;

  // Check arguments
  if (argc < 4) usage();

  // Parse arguments
  dof1_name = argv[1];
  argc--;
  argv++;
  dof2_name = argv[1];
  argc--;
  argv++;
  dof3_name = argv[1];
  argc--;
  argv++;

  // Default
  invert1 = false;
  invert2 = false;

  while (argc > 1) {
    ok = false;
    if ((ok == false) && (strcmp(argv[1], "-invert1") == 0)) {
      argc--;
      argv++;
      invert1 = true;
      ok = true;
    }
    if ((ok == false) && (strcmp(argv[1], "-invert2") == 0)) {
      argc--;
      argv++;
      invert2 = true;
      ok = true;
    }
    if (ok == false) {
      cerr << "Can not parse argument " << argv[1] << endl;
      usage();
    }
  }

  // Read transformations
  transformation1.irtkTransformation::Read(dof1_name);
  m1 = transformation1.GetMatrix();
  transformation2.irtkTransformation::Read(dof2_name);
  m2 = transformation2.GetMatrix();

  // Invert if necessary
  if (invert1 == true) m1.Invert();
  if (invert2 == true) m2.Invert();

  // Combine
  m3 = m1 * m2;
  transformation3.PutMatrix(m3);
  transformation3.UpdateParameter();

  // Write transformation
  transformation3.irtkTransformation::Write(dof3_name);
  transformation3.Print();
}
<commit_msg>Added comments to dofcombine.cc<commit_after>/*=========================================================================

  Library   : Image Registration Toolkit (IRTK)
  Module    : $Id$
  Copyright : Imperial College, Department of Computing
              Visual Information Processing (VIP), 2008 onwards
  Date      : $Date$
  Version   : $Revision$
  Changes   : $Author$

=========================================================================*/

#include <irtkRegistration.h>

char *dof1_name = NULL;
char *dof2_name = NULL;
char *dof3_name = NULL;

void usage()
{
  cerr << "Usage: dofcombine [input doffile 1] [input doffile 2] [output doffile] [-invert1] [-invert2]" << endl;
  cerr << endl;
  cerr << "dofcombine composes two affine transformations T_1 and T_2 so that T_out = T1 o T2." << endl;
  cerr << "It performs the multiplication of two affine transformation matrices."
  exit(1);
}

int main(int argc, char **argv)
{
  int ok, invert1, invert2;
  irtkMatrix m1, m2, m3;
  irtkAffineTransformation transformation1, transformation2, transformation3;

  // Check arguments
  if (argc < 4) usage();

  // Parse arguments
  dof1_name = argv[1];
  argc--;
  argv++;
  dof2_name = argv[1];
  argc--;
  argv++;
  dof3_name = argv[1];
  argc--;
  argv++;

  // Default
  invert1 = false;
  invert2 = false;

  while (argc > 1) {
    ok = false;
    if ((ok == false) && (strcmp(argv[1], "-invert1") == 0)) {
      argc--;
      argv++;
      invert1 = true;
      ok = true;
    }
    if ((ok == false) && (strcmp(argv[1], "-invert2") == 0)) {
      argc--;
      argv++;
      invert2 = true;
      ok = true;
    }
    if (ok == false) {
      cerr << "Can not parse argument " << argv[1] << endl;
      usage();
    }
  }

  // Read transformations
  transformation1.irtkTransformation::Read(dof1_name);
  m1 = transformation1.GetMatrix();
  transformation2.irtkTransformation::Read(dof2_name);
  m2 = transformation2.GetMatrix();

  // Invert if necessary
  if (invert1 == true) m1.Invert();
  if (invert2 == true) m2.Invert();

  // Combine
  m3 = m1 * m2;
  transformation3.PutMatrix(m3);
  transformation3.UpdateParameter();

  // Write transformation
  transformation3.irtkTransformation::Write(dof3_name);
  transformation3.Print();
}
<|endoftext|>


<commit_before><commit_msg>`Universe::screenshot`: depth and stencil buffer to rendering.<commit_after><|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (C) 2005 - 2007 by                                          *
 *      Last.fm Ltd <client@last.fm>                                       *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Steet, Fifth Floor, Boston, MA  02110-1301, USA.          *
 ***************************************************************************/

#include "BreakPad.h"

#ifndef NBREAKPAD

#include "Debug.h"
#include "Unicode.h"
#include "FindFile.h"

#ifndef WIN32
#include <unistd.h>

// defined in main.cpp
extern void teeStdoutQuit();

static bool
LaunchUploader( const char* dump_dir,
               const char* minidump_id,
               void* that,
               bool succeeded )
{
    // DON'T USE THE HEAP!!!
    // So that indeed means, no QStrings, no qDebug(), no QAnything, seriously!

	printf("CrashHandler called, minidump_id: %s\n", minidump_id);

    if (!succeeded)
        return false;

	// NOTE: If we would want to add any further information to be added to the crash report,
	// like local variables or so, we could just write them with printf() at this point. This
	// is save. The process which writes to stdout is not affected by the crash!
	// Anyway, accessing any ingame variables could be insafe, so we should avoid any access
	// here which could lead to a crash.
	// A better/safer way would be to analyse the minidump and read some variables
	// directly from there.

	// Save it because we will quit the teeStdout and this will reset the logfilename.
	char logfile[2048]; logfile[0] = 0;
	strncpy(logfile, GetLogFilename(), sizeof(logfile));

	// Close the logfile, we don't want the crashreport debug info in there (too much spam right now from breakpad).
	// This should be save.
	teeStdoutQuit();

    pid_t pid = fork();

    if (pid == -1) // fork failed
        return false;
    if (pid == 0) { // we are the fork

        execl( GetBinaryFilename(),
               GetBinaryFilename(),
			   "-crashreport",
               dump_dir,
               minidump_id,
			   logfile,
               (char*) 0 );

        // execl replaces this process, so no more code will be executed
        // unless it failed. If it failed, then we should return false.

		// Return anyway true because otherwise, the process will not die.
		printf("ERROR: Cannot start %s\n", GetBinaryFilename());
		return true;
	}

    // we called fork()
    return true;
}

#else
static bool
LaunchUploader( const wchar_t* dump_dir,
               const wchar_t* minidump_id,
               void* that,
               EXCEPTION_POINTERS *exinfo,
               MDRawAssertionInfo *assertion,
               bool succeeded )
{
    if (!succeeded)
        return false;

    // DON'T USE THE HEAP!!!
    // So that indeed means, no QStrings, no qDebug(), no QAnything, seriously!

    const char* m_product_name = static_cast<BreakPad*>(that)->productName();

    // convert m_product_name to widechars, which sadly means the product name must be Latin1
    wchar_t product_name[ 256 ];
    char* out = (char*)product_name;
    const char* in = m_product_name - 1;
    do {
        *out++ = *++in; //latin1 chars fit in first byte of each wchar
        *out++ = '\0';  //every second byte is NULL
    }
    while (*in);

    wchar_t command[MAX_PATH * 3 + 6];
    wcscpy( command, GetBinaryFilename() );
	wcscat( command, L" -crashreport \"" );
    wcscat( command, dump_dir );
    wcscat( command, L"\" \"" );
    wcscat( command, minidump_id );
    wcscat( command, L"\" \"" );
    wcscat( command, GetLogFilename() );
    wcscat( command, L"\"" );

    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    ZeroMemory( &si, sizeof(si) );
    si.cb = sizeof(si);
    si.dwFlags = STARTF_USESHOWWINDOW;
    si.wShowWindow = SW_SHOWNORMAL;
    ZeroMemory( &pi, sizeof(pi) );

    if (CreateProcess( NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
    {
        CloseHandle( pi.hProcess );
        CloseHandle( pi.hThread );
        TerminateProcess( GetCurrentProcess(), 1 );
    }

    return false;
}

#endif // WIN32

BreakPad::BreakPad( const std::string& path )
: google_breakpad::ExceptionHandler( Utf8ToSystemNative(path),
									0,
									LaunchUploader,
									this,
									true )
{}

BreakPad::~BreakPad()
{}

#endif // NBREAKPAD
<commit_msg>more fixes to windows (unicode related)<commit_after>/***************************************************************************
 *   Copyright (C) 2005 - 2007 by                                          *
 *      Last.fm Ltd <client@last.fm>                                       *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Steet, Fifth Floor, Boston, MA  02110-1301, USA.          *
 ***************************************************************************/

#include "BreakPad.h"

#ifndef NBREAKPAD

#include "Debug.h"
#include "Unicode.h"
#include "FindFile.h"

#ifndef WIN32
#include <unistd.h>

// defined in main.cpp
extern void teeStdoutQuit();

static bool
LaunchUploader( const char* dump_dir,
               const char* minidump_id,
               void* that,
               bool succeeded )
{
    // DON'T USE THE HEAP!!!
    // So that indeed means, no QStrings, no qDebug(), no QAnything, seriously!

	printf("CrashHandler called, minidump_id: %s\n", minidump_id);

    if (!succeeded)
        return false;

	// NOTE: If we would want to add any further information to be added to the crash report,
	// like local variables or so, we could just write them with printf() at this point. This
	// is save. The process which writes to stdout is not affected by the crash!
	// Anyway, accessing any ingame variables could be insafe, so we should avoid any access
	// here which could lead to a crash.
	// A better/safer way would be to analyse the minidump and read some variables
	// directly from there.

	// Save it because we will quit the teeStdout and this will reset the logfilename.
	char logfile[2048]; logfile[0] = 0;
	strncpy(logfile, GetLogFilename(), sizeof(logfile));

	// Close the logfile, we don't want the crashreport debug info in there (too much spam right now from breakpad).
	// This should be save.
	teeStdoutQuit();

    pid_t pid = fork();

    if (pid == -1) // fork failed
        return false;
    if (pid == 0) { // we are the fork

        execl( GetBinaryFilename(),
               GetBinaryFilename(),
			   "-crashreport",
               dump_dir,
               minidump_id,
			   logfile,
               (char*) 0 );

        // execl replaces this process, so no more code will be executed
        // unless it failed. If it failed, then we should return false.

		// Return anyway true because otherwise, the process will not die.
		printf("ERROR: Cannot start %s\n", GetBinaryFilename());
		return true;
	}

    // we called fork()
    return true;
}

#else
static bool
LaunchUploader( const char* dump_dir,
               const char* minidump_id,
               void* that,
               EXCEPTION_POINTERS *exinfo,
               MDRawAssertionInfo *assertion,
               bool succeeded )
{
    if (!succeeded)
        return false;

    // DON'T USE THE HEAP!!!
    // So that indeed means, no QStrings, no qDebug(), no QAnything, seriously!

    char command[MAX_PATH * 3 + 6];
    strcpy( command, GetBinaryFilename() );
	strcat( command, " -crashreport \"" );
    strcat( command, dump_dir );
    strcat( command, "\" \"" );
    strcat( command, minidump_id );
    strcat( command, "\" \"" );
    strcat( command, GetLogFilename() );
    strcat( command, "\"" );

    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    ZeroMemory( &si, sizeof(si) );
    si.cb = sizeof(si);
    si.dwFlags = STARTF_USESHOWWINDOW;
    si.wShowWindow = SW_SHOWNORMAL;
    ZeroMemory( &pi, sizeof(pi) );

    if (CreateProcess( NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
    {
        CloseHandle( pi.hProcess );
        CloseHandle( pi.hThread );
        TerminateProcess( GetCurrentProcess(), 1 );
    }

    return false;
}

#endif // WIN32

BreakPad::BreakPad( const std::string& path )
: google_breakpad::ExceptionHandler( Utf8ToSystemNative(path),
									0,
									LaunchUploader,
									this,
									true )
{}

BreakPad::~BreakPad()
{}

#endif // NBREAKPAD
<|endoftext|>