<commit_before>/* The Next Great Finite Element Library. */
/* Copyright (C) 2003  Benjamin S. Kirk */

/* This library is free software; you can redistribute it and/or */
/* modify it under the terms of the GNU Lesser General Public */
/* License as published by the Free Software Foundation; either */
/* version 2.1 of the License, or (at your option) any later version. */

/* This library 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 for more details. */

/* You should have received a copy of the GNU Lesser General Public */
/* License along with this library; if not, write to the Free Software */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#include "getpot.h"

#include "laplace_system.h"

#include "boundary_info.h"
#include "dof_map.h"
#include "fe_base.h"
#include "fe_interface.h"
#include "fem_context.h"
#include "mesh.h"
#include "quadrature.h"
#include "string_to_enum.h"

// Bring in everything from the libMesh namespace
using namespace libMesh;

LaplaceSystem::LaplaceSystem( EquationSystems& es,
			      const std::string& name,
			      const unsigned int number)
  : FEMSystem(es, name, number)
{
  return;
}

void LaplaceSystem::init_data ()
{
  // Check the input file for Reynolds number, application type,
  // approximation type
  GetPot infile("laplace.in");

  // Add the solution variable
  u_var = this->add_variable ("u", SECOND, LAGRANGE_VEC);

  this->time_evolving(u_var);

  // Useful debugging options
  // Set verify_analytic_jacobians to 1e-6 to use
  this->verify_analytic_jacobians = infile("verify_analytic_jacobians", 0.);
  this->print_jacobians = infile("print_jacobians", false);
  this->print_element_jacobians = infile("print_element_jacobians", false);

  this->init_dirichlet_bcs();

  // Do the parent's initialization after variables and boundary constraints are defined
  FEMSystem::init_data();
}

void LaplaceSystem::init_dirichlet_bcs()
{
  const boundary_id_type all_ids[6] = {0,1,2,3,4,5};
  std::set<boundary_id_type> boundary_ids( all_ids, all_ids+6 );

  std::vector<unsigned int> vars;
  vars.push_back( u_var );

  BoundaryFunction func( u_var );

  this->get_dof_map().add_dirichlet_boundary( libMesh::DirichletBoundary( boundary_ids, vars, &func ) );
  return;
}

void LaplaceSystem::init_context(DiffContext &context)
{
  FEMContext &c = libmesh_cast_ref<FEMContext&>(context);

  // Get finite element object
  FEGenericBase<RealGradient>* fe;
  c.get_element_fe<RealGradient>( u_var, fe );

  // We should prerequest all the data
  // we will need to build the linear system.
  fe->get_JxW();
  fe->get_phi();
  fe->get_dphi();
  fe->get_xyz();

  FEGenericBase<RealGradient>* side_fe;
  c.get_side_fe<RealGradient>( u_var, side_fe );

  side_fe->get_JxW();
  side_fe->get_phi();
}

bool LaplaceSystem::element_time_derivative (bool request_jacobian,
                                            DiffContext &context)
{
  FEMContext &c = libmesh_cast_ref<FEMContext&>(context);

  // Get finite element object
  FEGenericBase<RealGradient>* fe = NULL;
  c.get_element_fe<RealGradient>( u_var, fe );

  // First we get some references to cell-specific data that
  // will be used to assemble the linear system.

  // Element Jacobian * quadrature weights for interior integration
  const std::vector<Real> &JxW = fe->get_JxW();

  // The velocity shape functions at interior quadrature points.
  const std::vector<std::vector<RealGradient> >& phi = fe->get_phi();

  // The velocity shape function gradients at interior
  // quadrature points.
  const std::vector<std::vector<RealTensor> >& grad_phi = fe->get_dphi();

  const std::vector<Point>& qpoint = fe->get_xyz();

  // The number of local degrees of freedom in each variable
  const unsigned int n_u_dofs = c.dof_indices_var[u_var].size();

  DenseSubMatrix<Number> &Kuu = *c.elem_subjacobians[u_var][u_var];

  DenseSubVector<Number> &Fu = *c.elem_subresiduals[u_var];

  // Now we will build the element Jacobian and residual.
  // Constructing the residual requires the solution and its
  // gradient from the previous timestep.  This must be
  // calculated at each quadrature point by summing the
  // solution degree-of-freedom values by the appropriate
  // weight functions.
  const unsigned int n_qpoints = (c.get_element_qrule())->n_points();

  for (unsigned int qp=0; qp != n_qpoints; qp++)
    {
      RealTensor grad_u;

      c.interior_gradient<RealGradient>( u_var, qp, grad_u );

      // Value of the forcing function at this quadrature point
      RealGradient f = this->forcing(qpoint[qp]);

      // First, an i-loop over the velocity degrees of freedom.
      // We know that n_u_dofs == n_v_dofs so we can compute contributions
      // for both at the same time.
      for (unsigned int i=0; i != n_u_dofs; i++)
        {
          Fu(i) += ( grad_u.contract(grad_phi[i][qp]) - f*phi[i][qp] )*JxW[qp];

          if (request_jacobian)
            {
              // Matrix contributions for the uu and vv couplings.
              for (unsigned int j=0; j != n_u_dofs; j++)
                {
                  Kuu(i,j) += grad_phi[j][qp].contract(grad_phi[i][qp])*JxW[qp];

		}
	    }
        }
    } // end of the quadrature point qp-loop

  return request_jacobian;
}

/*
bool LaplaceSystem::side_constraint (bool request_jacobian,
				     DiffContext &context)
{
  FEMContext &c = libmesh_cast_ref<FEMContext&>(context);

  // Get finite element object
  FEGenericBase<RealGradient>* side_fe = NULL;
  c.get_side_fe<RealGradient>( u_var, side_fe );

  // First we get some references to cell-specific data that
  // will be used to assemble the linear system.

  // Element Jacobian * quadrature weights for interior integration
  const std::vector<Real> &JxW = side_fe->get_JxW();

  // The velocity shape functions at interior quadrature points.
  const std::vector<std::vector<RealGradient> >& phi = side_fe->get_phi();

  // The number of local degrees of freedom in each variable
  const unsigned int n_u_dofs = c.dof_indices_var[u_var].size();

  const std::vector<Point>& qpoint = side_fe->get_xyz();

  // The penalty value.  \frac{1}{\epsilon}
  // in the discussion above.
  const Real penalty = 1.e10;

  DenseSubMatrix<Number> &Kuu = *c.elem_subjacobians[u_var][u_var];
  DenseSubVector<Number> &Fu = *c.elem_subresiduals[u_var];

  const unsigned int n_qpoints = (c.get_side_qrule())->n_points();

  for (unsigned int qp=0; qp != n_qpoints; qp++)
    {
      RealGradient u;
      c.side_value<RealGradient>( u_var, qp, u );

      RealGradient u_exact( this->exact_solution( 0, qpoint[qp](0), qpoint[qp](1) ),
			    this->exact_solution( 1, qpoint[qp](0), qpoint[qp](1) ));

      for (unsigned int i=0; i != n_u_dofs; i++)
	{
	  Fu(i) += penalty*(u - u_exact)*phi[i][qp]*JxW[qp];

	  if (request_jacobian)
	    {
	      for (unsigned int j=0; j != n_u_dofs; j++)
		Kuu(i,j) += penalty*phi[j][qp]*phi[i][qp]*JxW[qp];
	    }
	}
    }

  return request_jacobian;
}
*/

RealGradient LaplaceSystem::forcing( const Point& p )
{
  Real x = p(0); Real y = p(1); Real z = p(2);

  const Real eps = 1.e-3;

  const Real fx = -(exact_solution(0,x,y,z-eps) +
		    exact_solution(0,x,y,z+eps) +
		    exact_solution(0,x,y-eps,z) +
		    exact_solution(0,x,y+eps,z) +
		    exact_solution(0,x-eps,y,z) +
		    exact_solution(0,x+eps,y,z) -
		    6.*exact_solution(0,x,y,z))/eps/eps;

  const Real fy = -(exact_solution(1,x,y,z-eps) +
		    exact_solution(1,x,y,z+eps) +
		    exact_solution(1,x,y-eps,z) +
		    exact_solution(1,x,y+eps,z) +
		    exact_solution(1,x-eps,y,z) +
		    exact_solution(1,x+eps,y,z) -
		    6.*exact_solution(1,x,y,z))/eps/eps;

  const Real fz = -(exact_solution(2,x,y,z-eps) +
		    exact_solution(2,x,y,z+eps) +
		    exact_solution(2,x,y-eps,z) +
		    exact_solution(2,x,y+eps,z) +
		    exact_solution(2,x-eps,y,z) +
		    exact_solution(2,x+eps,y,z) -
		    6.*exact_solution(2,x,y,z))/eps/eps;

  return RealGradient( fx, fy, fz );
}
<commit_msg>Fix for --enable-complex<commit_after>/* The Next Great Finite Element Library. */
/* Copyright (C) 2003  Benjamin S. Kirk */

/* This library is free software; you can redistribute it and/or */
/* modify it under the terms of the GNU Lesser General Public */
/* License as published by the Free Software Foundation; either */
/* version 2.1 of the License, or (at your option) any later version. */

/* This library 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 for more details. */

/* You should have received a copy of the GNU Lesser General Public */
/* License along with this library; if not, write to the Free Software */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#include "getpot.h"

#include "laplace_system.h"

#include "boundary_info.h"
#include "dof_map.h"
#include "fe_base.h"
#include "fe_interface.h"
#include "fem_context.h"
#include "mesh.h"
#include "quadrature.h"
#include "string_to_enum.h"

// Bring in everything from the libMesh namespace
using namespace libMesh;

LaplaceSystem::LaplaceSystem( EquationSystems& es,
			      const std::string& name,
			      const unsigned int number)
  : FEMSystem(es, name, number)
{
  return;
}

void LaplaceSystem::init_data ()
{
  // Check the input file for Reynolds number, application type,
  // approximation type
  GetPot infile("laplace.in");

  // Add the solution variable
  u_var = this->add_variable ("u", SECOND, LAGRANGE_VEC);

  this->time_evolving(u_var);

  // Useful debugging options
  // Set verify_analytic_jacobians to 1e-6 to use
  this->verify_analytic_jacobians = infile("verify_analytic_jacobians", 0.);
  this->print_jacobians = infile("print_jacobians", false);
  this->print_element_jacobians = infile("print_element_jacobians", false);

  this->init_dirichlet_bcs();

  // Do the parent's initialization after variables and boundary constraints are defined
  FEMSystem::init_data();
}

void LaplaceSystem::init_dirichlet_bcs()
{
  const boundary_id_type all_ids[6] = {0,1,2,3,4,5};
  std::set<boundary_id_type> boundary_ids( all_ids, all_ids+6 );

  std::vector<unsigned int> vars;
  vars.push_back( u_var );

  BoundaryFunction func( u_var );

  this->get_dof_map().add_dirichlet_boundary( libMesh::DirichletBoundary( boundary_ids, vars, &func ) );
  return;
}

void LaplaceSystem::init_context(DiffContext &context)
{
  FEMContext &c = libmesh_cast_ref<FEMContext&>(context);

  // Get finite element object
  FEGenericBase<RealGradient>* fe;
  c.get_element_fe<RealGradient>( u_var, fe );

  // We should prerequest all the data
  // we will need to build the linear system.
  fe->get_JxW();
  fe->get_phi();
  fe->get_dphi();
  fe->get_xyz();

  FEGenericBase<RealGradient>* side_fe;
  c.get_side_fe<RealGradient>( u_var, side_fe );

  side_fe->get_JxW();
  side_fe->get_phi();
}

bool LaplaceSystem::element_time_derivative (bool request_jacobian,
                                            DiffContext &context)
{
  FEMContext &c = libmesh_cast_ref<FEMContext&>(context);

  // Get finite element object
  FEGenericBase<RealGradient>* fe = NULL;
  c.get_element_fe<RealGradient>( u_var, fe );

  // First we get some references to cell-specific data that
  // will be used to assemble the linear system.

  // Element Jacobian * quadrature weights for interior integration
  const std::vector<Real> &JxW = fe->get_JxW();

  // The velocity shape functions at interior quadrature points.
  const std::vector<std::vector<RealGradient> >& phi = fe->get_phi();

  // The velocity shape function gradients at interior
  // quadrature points.
  const std::vector<std::vector<RealTensor> >& grad_phi = fe->get_dphi();

  const std::vector<Point>& qpoint = fe->get_xyz();

  // The number of local degrees of freedom in each variable
  const unsigned int n_u_dofs = c.dof_indices_var[u_var].size();

  DenseSubMatrix<Number> &Kuu = *c.elem_subjacobians[u_var][u_var];

  DenseSubVector<Number> &Fu = *c.elem_subresiduals[u_var];

  // Now we will build the element Jacobian and residual.
  // Constructing the residual requires the solution and its
  // gradient from the previous timestep.  This must be
  // calculated at each quadrature point by summing the
  // solution degree-of-freedom values by the appropriate
  // weight functions.
  const unsigned int n_qpoints = (c.get_element_qrule())->n_points();

  for (unsigned int qp=0; qp != n_qpoints; qp++)
    {
      Tensor grad_u;

      c.interior_gradient<RealGradient>( u_var, qp, grad_u );

      // Value of the forcing function at this quadrature point
      RealGradient f = this->forcing(qpoint[qp]);

      // First, an i-loop over the velocity degrees of freedom.
      // We know that n_u_dofs == n_v_dofs so we can compute contributions
      // for both at the same time.
      for (unsigned int i=0; i != n_u_dofs; i++)
        {
          Fu(i) += ( grad_u.contract(grad_phi[i][qp]) - f*phi[i][qp] )*JxW[qp];

          if (request_jacobian)
            {
              // Matrix contributions for the uu and vv couplings.
              for (unsigned int j=0; j != n_u_dofs; j++)
                {
                  Kuu(i,j) += grad_phi[j][qp].contract(grad_phi[i][qp])*JxW[qp];

		}
	    }
        }
    } // end of the quadrature point qp-loop

  return request_jacobian;
}

/*
bool LaplaceSystem::side_constraint (bool request_jacobian,
				     DiffContext &context)
{
  FEMContext &c = libmesh_cast_ref<FEMContext&>(context);

  // Get finite element object
  FEGenericBase<RealGradient>* side_fe = NULL;
  c.get_side_fe<RealGradient>( u_var, side_fe );

  // First we get some references to cell-specific data that
  // will be used to assemble the linear system.

  // Element Jacobian * quadrature weights for interior integration
  const std::vector<Real> &JxW = side_fe->get_JxW();

  // The velocity shape functions at interior quadrature points.
  const std::vector<std::vector<RealGradient> >& phi = side_fe->get_phi();

  // The number of local degrees of freedom in each variable
  const unsigned int n_u_dofs = c.dof_indices_var[u_var].size();

  const std::vector<Point>& qpoint = side_fe->get_xyz();

  // The penalty value.  \frac{1}{\epsilon}
  // in the discussion above.
  const Real penalty = 1.e10;

  DenseSubMatrix<Number> &Kuu = *c.elem_subjacobians[u_var][u_var];
  DenseSubVector<Number> &Fu = *c.elem_subresiduals[u_var];

  const unsigned int n_qpoints = (c.get_side_qrule())->n_points();

  for (unsigned int qp=0; qp != n_qpoints; qp++)
    {
      RealGradient u;
      c.side_value<RealGradient>( u_var, qp, u );

      RealGradient u_exact( this->exact_solution( 0, qpoint[qp](0), qpoint[qp](1) ),
			    this->exact_solution( 1, qpoint[qp](0), qpoint[qp](1) ));

      for (unsigned int i=0; i != n_u_dofs; i++)
	{
	  Fu(i) += penalty*(u - u_exact)*phi[i][qp]*JxW[qp];

	  if (request_jacobian)
	    {
	      for (unsigned int j=0; j != n_u_dofs; j++)
		Kuu(i,j) += penalty*phi[j][qp]*phi[i][qp]*JxW[qp];
	    }
	}
    }

  return request_jacobian;
}
*/

RealGradient LaplaceSystem::forcing( const Point& p )
{
  Real x = p(0); Real y = p(1); Real z = p(2);

  const Real eps = 1.e-3;

  const Real fx = -(exact_solution(0,x,y,z-eps) +
		    exact_solution(0,x,y,z+eps) +
		    exact_solution(0,x,y-eps,z) +
		    exact_solution(0,x,y+eps,z) +
		    exact_solution(0,x-eps,y,z) +
		    exact_solution(0,x+eps,y,z) -
		    6.*exact_solution(0,x,y,z))/eps/eps;

  const Real fy = -(exact_solution(1,x,y,z-eps) +
		    exact_solution(1,x,y,z+eps) +
		    exact_solution(1,x,y-eps,z) +
		    exact_solution(1,x,y+eps,z) +
		    exact_solution(1,x-eps,y,z) +
		    exact_solution(1,x+eps,y,z) -
		    6.*exact_solution(1,x,y,z))/eps/eps;

  const Real fz = -(exact_solution(2,x,y,z-eps) +
		    exact_solution(2,x,y,z+eps) +
		    exact_solution(2,x,y-eps,z) +
		    exact_solution(2,x,y+eps,z) +
		    exact_solution(2,x-eps,y,z) +
		    exact_solution(2,x+eps,y,z) -
		    6.*exact_solution(2,x,y,z))/eps/eps;

  return RealGradient( fx, fy, fz );
}
<|endoftext|>


<commit_before>/*
	This file is part of cpp-ethereum.

	cpp-ethereum 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 3 of the License, or
	(at your option) any later version.

	cpp-ethereum 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 cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file net.cpp
 * @author Alex Leverington <nessence@gmail.com>
 * @date 2014
 */

#include <boost/test/unit_test.hpp>

#include <libdevcore/Worker.h>
#include <libdevcore/Assertions.h>
#include <libdevcrypto/Common.h>
#include <libp2p/UDP.h>
#include <libp2p/NodeTable.h>
using namespace std;
using namespace dev;
using namespace dev::p2p;
namespace ba = boost::asio;
namespace bi = ba::ip;

struct NetFixture
{
	NetFixture() { dev::p2p::NodeIPEndpoint::test_allowLocal = true;; }
	~NetFixture() { dev::p2p::NodeIPEndpoint::test_allowLocal = false; }
};

BOOST_FIXTURE_TEST_SUITE(net, NetFixture)

/**
 * Only used for testing. Not useful beyond tests.
 */
class TestHost: public Worker
{
public:
	TestHost(): Worker("test",0), m_io() {};
	virtual ~TestHost() { m_io.stop(); stopWorking(); }
	void start() { startWorking(); }
	void doWork() { m_io.run(); }
	void doneWorking() { m_io.reset(); m_io.poll(); m_io.reset(); }

protected:
	ba::io_service m_io;
};

struct TestNodeTable: public NodeTable
{
	/// Constructor
	TestNodeTable(ba::io_service& _io, KeyPair _alias, bi::address const& _addr, uint16_t _port = 30300): NodeTable(_io, _alias, NodeIPEndpoint(_addr, _port, _port)) {}

	static std::vector<std::pair<KeyPair,unsigned>> createTestNodes(unsigned _count)
	{
		std::vector<std::pair<KeyPair,unsigned>> ret;
		asserts(_count < 1000);
		static uint16_t s_basePort = 30500;

		ret.clear();
		for (unsigned i = 0; i < _count; i++)
		{
			KeyPair k = KeyPair::create();
			ret.push_back(make_pair(k,s_basePort+i));
		}

		return std::move(ret);
	}

	void pingTestNodes(std::vector<std::pair<KeyPair,unsigned>> const& _testNodes)
	{
		bi::address ourIp = bi::address::from_string("127.0.0.1");
		for (auto& n: _testNodes)
		{
			ping(bi::udp::endpoint(ourIp, n.second));
			this_thread::sleep_for(chrono::milliseconds(2));
		}
	}

	void populateTestNodes(std::vector<std::pair<KeyPair,unsigned>> const& _testNodes, size_t _count = 0)
	{
		if (!_count)
			_count = _testNodes.size();

		bi::address ourIp = bi::address::from_string("127.0.0.1");
		for (auto& n: _testNodes)
			if (_count--)
			{
				// manually add node for test
				{
					Guard ln(x_nodes);
					shared_ptr<NodeEntry> node(new NodeEntry(m_node, n.first.pub(), NodeIPEndpoint(ourIp, n.second, n.second)));
					node->pending = false;
					m_nodes[node->id] = node;
				}
				noteActiveNode(n.first.pub(), bi::udp::endpoint(ourIp, n.second));
			}
			else
				break;
	}

	void reset()
	{
		Guard l(x_state);
		for (auto& n: m_state) n.nodes.clear();
	}
};

/**
 * Only used for testing. Not useful beyond tests.
 */
struct TestNodeTableHost: public TestHost
{
	TestNodeTableHost(unsigned _count = 8): m_alias(KeyPair::create()), nodeTable(new TestNodeTable(m_io, m_alias, bi::address::from_string("127.0.0.1"))), testNodes(TestNodeTable::createTestNodes(_count)) {};
	~TestNodeTableHost() { m_io.stop(); stopWorking(); }

	void setup() { for (auto n: testNodes) nodeTables.push_back(make_shared<TestNodeTable>(m_io,n.first, bi::address::from_string("127.0.0.1"),n.second)); }

	void pingAll() { for (auto& t: nodeTables) t->pingTestNodes(testNodes); }

	void populateAll(size_t _count = 0) { for (auto& t: nodeTables) t->populateTestNodes(testNodes, _count); }

	void populate(size_t _count = 0) { nodeTable->populateTestNodes(testNodes, _count); }

	KeyPair m_alias;
	shared_ptr<TestNodeTable> nodeTable;
	std::vector<std::pair<KeyPair,unsigned>> testNodes; // keypair and port
	std::vector<shared_ptr<TestNodeTable>> nodeTables;
};

class TestUDPSocket: UDPSocketEvents, public TestHost
{
public:
	TestUDPSocket(): m_socket(new UDPSocket<TestUDPSocket, 1024>(m_io, *this, 30300)) {}

	void onDisconnected(UDPSocketFace*) {};
	void onReceived(UDPSocketFace*, bi::udp::endpoint const&, bytesConstRef _packet) { if (_packet.toString() == "AAAA") success = true; }

	shared_ptr<UDPSocket<TestUDPSocket, 1024>> m_socket;

	bool success = false;
};

BOOST_AUTO_TEST_CASE(requestTimeout)
{
	using TimePoint = std::chrono::steady_clock::time_point;
	using RequestTimeout = std::pair<NodeId, TimePoint>;

	std::chrono::milliseconds timeout(300);
	std::list<RequestTimeout> timeouts;

	NodeId nodeA(sha3("a"));
	NodeId nodeB(sha3("b"));
	timeouts.push_back(make_pair(nodeA, chrono::steady_clock::now()));
	this_thread::sleep_for(std::chrono::milliseconds(100));
	timeouts.push_back(make_pair(nodeB, chrono::steady_clock::now()));
	this_thread::sleep_for(std::chrono::milliseconds(210));

	bool nodeAtriggered = false;
	bool nodeBtriggered = false;
	timeouts.remove_if([&](RequestTimeout const& t)
	{
		auto now = chrono::steady_clock::now();
		auto diff = now - t.second;
		if (t.first == nodeA && diff < timeout)
			nodeAtriggered = true;
		if (t.first == nodeB && diff < timeout)
			nodeBtriggered = true;
		return (t.first == nodeA || t.first == nodeB);
	});

	BOOST_REQUIRE(nodeAtriggered == false);
	BOOST_REQUIRE(nodeBtriggered == true);
	BOOST_REQUIRE(timeouts.size() == 0);
}

BOOST_AUTO_TEST_CASE(isIPAddressType)
{
	string wildcard = "0.0.0.0";
	BOOST_REQUIRE(bi::address::from_string(wildcard).is_unspecified());

	string empty = "";
	BOOST_REQUIRE_THROW(bi::address::from_string(empty).is_unspecified(), std::exception);

	string publicAddress192 = "192.169.0.0";
	BOOST_REQUIRE(isPublicAddress(publicAddress192));
	BOOST_REQUIRE(!isPrivateAddress(publicAddress192));
	BOOST_REQUIRE(!isLocalHostAddress(publicAddress192));

	string publicAddress172 = "172.32.0.0";
	BOOST_REQUIRE(isPublicAddress(publicAddress172));
	BOOST_REQUIRE(!isPrivateAddress(publicAddress172));
	BOOST_REQUIRE(!isLocalHostAddress(publicAddress172));

	string privateAddress192 = "192.168.1.0";
	BOOST_REQUIRE(isPrivateAddress(privateAddress192));
	BOOST_REQUIRE(!isPublicAddress(privateAddress192));
	BOOST_REQUIRE(!isLocalHostAddress(privateAddress192));

	string privateAddress172 = "172.16.0.0";
	BOOST_REQUIRE(isPrivateAddress(privateAddress172));
	BOOST_REQUIRE(!isPublicAddress(privateAddress172));
	BOOST_REQUIRE(!isLocalHostAddress(privateAddress172));

	string privateAddress10 = "10.0.0.0";
	BOOST_REQUIRE(isPrivateAddress(privateAddress10));
	BOOST_REQUIRE(!isPublicAddress(privateAddress10));
	BOOST_REQUIRE(!isLocalHostAddress(privateAddress10));
}

BOOST_AUTO_TEST_CASE(v2PingNodePacket)
{
	// test old versino of pingNode packet w/new
	RLPStream s;
	s.appendList(3); s << "1.1.1.1" << 30303 << std::chrono::duration_cast<std::chrono::seconds>((std::chrono::system_clock::now() + chrono::seconds(60)).time_since_epoch()).count();

	PingNode p((bi::udp::endpoint()));
	BOOST_REQUIRE_NO_THROW(p = PingNode::fromBytesConstRef(bi::udp::endpoint(), bytesConstRef(&s.out())));
	BOOST_REQUIRE(p.version == 2);
}

BOOST_AUTO_TEST_CASE(neighboursPacketLength)
{
	KeyPair k = KeyPair::create();
	std::vector<std::pair<KeyPair,unsigned>> testNodes(TestNodeTable::createTestNodes(16));
	bi::udp::endpoint to(boost::asio::ip::address::from_string("127.0.0.1"), 30000);

	// hash(32), signature(65), overhead: packet(2), type(1), nodeList(2), ts(9),
	static unsigned const nlimit = (1280 - 111) / 87;
	for (unsigned offset = 0; offset < testNodes.size(); offset += nlimit)
	{
		Neighbours out(to);

		auto limit = nlimit ? std::min(testNodes.size(), (size_t)(offset + nlimit)) : testNodes.size();
		for (auto i = offset; i < limit; i++)
		{
			Neighbours::Node node;
			node.ipAddress = boost::asio::ip::address::from_string("200.200.200.200").to_string();
			node.port = testNodes[i].second;
			node.node = testNodes[i].first.pub();
			out.nodes.push_back(node);
		}

		out.sign(k.sec());
		BOOST_REQUIRE_LE(out.data.size(), 1280);
	}
}

BOOST_AUTO_TEST_CASE(test_neighbours_packet)
{
	KeyPair k = KeyPair::create();
	std::vector<std::pair<KeyPair,unsigned>> testNodes(TestNodeTable::createTestNodes(16));
	bi::udp::endpoint to(boost::asio::ip::address::from_string("127.0.0.1"), 30000);

	Neighbours out(to);
	for (auto n: testNodes)
	{
		Neighbours::Node node;
		node.ipAddress = boost::asio::ip::address::from_string("127.0.0.1").to_string();
		node.udpPort = n.second;
		node.node = n.first.pub();
		out.nodes.push_back(node);
	}
	out.sign(k.sec());

	bytesConstRef packet(out.data.data(), out.data.size());
	bytesConstRef rlpBytes(packet.cropped(h256::size + Signature::size + 1));
	Neighbours in = Neighbours::fromBytesConstRef(to, rlpBytes);
	int count = 0;
	for (auto n: in.nodes)
	{
		BOOST_REQUIRE_EQUAL(testNodes[count].second, n.udpPort);
		BOOST_REQUIRE_EQUAL(testNodes[count].first.pub(), n.node);
		BOOST_REQUIRE_EQUAL(sha3(testNodes[count].first.pub()), sha3(n.node));
		count++;
	}
}

BOOST_AUTO_TEST_CASE(test_findnode_neighbours)
{
	// Executing findNode should result in a list which is serialized
	// into Neighbours packet. Neighbours packet should then be deserialized
	// into the same list of nearest nodes.
}

BOOST_AUTO_TEST_CASE(test_windows_template)
{
	bi::udp::endpoint ep;
	PingNode p(ep);
}

BOOST_AUTO_TEST_CASE(kademlia)
{
	// Not yet a 'real' test.
	TestNodeTableHost node(8);
	node.start();
	node.nodeTable->discover(); // ideally, joining with empty node table logs warning we can check for
	node.setup();
	node.populate();
	clog << "NodeTable:\n" << *node.nodeTable.get() << endl;

	node.populateAll();
	clog << "NodeTable:\n" << *node.nodeTable.get() << endl;

	auto nodes = node.nodeTable->nodes();
	nodes.sort();

	node.nodeTable->reset();
	clog << "NodeTable:\n" << *node.nodeTable.get() << endl;

	node.populate(1);
	clog << "NodeTable:\n" << *node.nodeTable.get() << endl;

	node.nodeTable->discover();
	this_thread::sleep_for(chrono::milliseconds(2000));
	clog << "NodeTable:\n" << *node.nodeTable.get() << endl;

	BOOST_REQUIRE_EQUAL(node.nodeTable->count(), 8);

	auto netNodes = node.nodeTable->nodes();
	netNodes.sort();

}

BOOST_AUTO_TEST_CASE(test_udp_once)
{
	UDPDatagram d(bi::udp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 30300), bytes({65,65,65,65}));
	TestUDPSocket a; a.m_socket->connect(); a.start();
	a.m_socket->send(d);
	this_thread::sleep_for(chrono::seconds(1));
	BOOST_REQUIRE_EQUAL(true, a.success);
}

BOOST_AUTO_TEST_SUITE_END()

<commit_msg>update test<commit_after>/*
	This file is part of cpp-ethereum.

	cpp-ethereum 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 3 of the License, or
	(at your option) any later version.

	cpp-ethereum 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 cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file net.cpp
 * @author Alex Leverington <nessence@gmail.com>
 * @date 2014
 */

#include <boost/test/unit_test.hpp>

#include <libdevcore/Worker.h>
#include <libdevcore/Assertions.h>
#include <libdevcrypto/Common.h>
#include <libp2p/UDP.h>
#include <libp2p/NodeTable.h>
using namespace std;
using namespace dev;
using namespace dev::p2p;
namespace ba = boost::asio;
namespace bi = ba::ip;

struct NetFixture
{
	NetFixture() { dev::p2p::NodeIPEndpoint::test_allowLocal = true;; }
	~NetFixture() { dev::p2p::NodeIPEndpoint::test_allowLocal = false; }
};

BOOST_FIXTURE_TEST_SUITE(net, NetFixture)

/**
 * Only used for testing. Not useful beyond tests.
 */
class TestHost: public Worker
{
public:
	TestHost(): Worker("test",0), m_io() {};
	virtual ~TestHost() { m_io.stop(); stopWorking(); }
	void start() { startWorking(); }
	void doWork() { m_io.run(); }
	void doneWorking() { m_io.reset(); m_io.poll(); m_io.reset(); }

protected:
	ba::io_service m_io;
};

struct TestNodeTable: public NodeTable
{
	/// Constructor
	TestNodeTable(ba::io_service& _io, KeyPair _alias, bi::address const& _addr, uint16_t _port = 30300): NodeTable(_io, _alias, NodeIPEndpoint(_addr, _port, _port)) {}

	static std::vector<std::pair<KeyPair,unsigned>> createTestNodes(unsigned _count)
	{
		std::vector<std::pair<KeyPair,unsigned>> ret;
		asserts(_count < 1000);
		static uint16_t s_basePort = 30500;

		ret.clear();
		for (unsigned i = 0; i < _count; i++)
		{
			KeyPair k = KeyPair::create();
			ret.push_back(make_pair(k,s_basePort+i));
		}

		return std::move(ret);
	}

	void pingTestNodes(std::vector<std::pair<KeyPair,unsigned>> const& _testNodes)
	{
		bi::address ourIp = bi::address::from_string("127.0.0.1");
		for (auto& n: _testNodes)
		{
			ping(bi::udp::endpoint(ourIp, n.second));
			this_thread::sleep_for(chrono::milliseconds(2));
		}
	}

	void populateTestNodes(std::vector<std::pair<KeyPair,unsigned>> const& _testNodes, size_t _count = 0)
	{
		if (!_count)
			_count = _testNodes.size();

		bi::address ourIp = bi::address::from_string("127.0.0.1");
		for (auto& n: _testNodes)
			if (_count--)
			{
				// manually add node for test
				{
					Guard ln(x_nodes);
					shared_ptr<NodeEntry> node(new NodeEntry(m_node, n.first.pub(), NodeIPEndpoint(ourIp, n.second, n.second)));
					node->pending = false;
					m_nodes[node->id] = node;
				}
				noteActiveNode(n.first.pub(), bi::udp::endpoint(ourIp, n.second));
			}
			else
				break;
	}

	void reset()
	{
		Guard l(x_state);
		for (auto& n: m_state) n.nodes.clear();
	}
};

/**
 * Only used for testing. Not useful beyond tests.
 */
struct TestNodeTableHost: public TestHost
{
	TestNodeTableHost(unsigned _count = 8): m_alias(KeyPair::create()), nodeTable(new TestNodeTable(m_io, m_alias, bi::address::from_string("127.0.0.1"))), testNodes(TestNodeTable::createTestNodes(_count)) {};
	~TestNodeTableHost() { m_io.stop(); stopWorking(); }

	void setup() { for (auto n: testNodes) nodeTables.push_back(make_shared<TestNodeTable>(m_io,n.first, bi::address::from_string("127.0.0.1"),n.second)); }

	void pingAll() { for (auto& t: nodeTables) t->pingTestNodes(testNodes); }

	void populateAll(size_t _count = 0) { for (auto& t: nodeTables) t->populateTestNodes(testNodes, _count); }

	void populate(size_t _count = 0) { nodeTable->populateTestNodes(testNodes, _count); }

	KeyPair m_alias;
	shared_ptr<TestNodeTable> nodeTable;
	std::vector<std::pair<KeyPair,unsigned>> testNodes; // keypair and port
	std::vector<shared_ptr<TestNodeTable>> nodeTables;
};

class TestUDPSocket: UDPSocketEvents, public TestHost
{
public:
	TestUDPSocket(): m_socket(new UDPSocket<TestUDPSocket, 1024>(m_io, *this, 30300)) {}

	void onDisconnected(UDPSocketFace*) {};
	void onReceived(UDPSocketFace*, bi::udp::endpoint const&, bytesConstRef _packet) { if (_packet.toString() == "AAAA") success = true; }

	shared_ptr<UDPSocket<TestUDPSocket, 1024>> m_socket;

	bool success = false;
};

BOOST_AUTO_TEST_CASE(requestTimeout)
{
	using TimePoint = std::chrono::steady_clock::time_point;
	using RequestTimeout = std::pair<NodeId, TimePoint>;

	std::chrono::milliseconds timeout(300);
	std::list<RequestTimeout> timeouts;

	NodeId nodeA(sha3("a"));
	NodeId nodeB(sha3("b"));
	timeouts.push_back(make_pair(nodeA, chrono::steady_clock::now()));
	this_thread::sleep_for(std::chrono::milliseconds(100));
	timeouts.push_back(make_pair(nodeB, chrono::steady_clock::now()));
	this_thread::sleep_for(std::chrono::milliseconds(210));

	bool nodeAtriggered = false;
	bool nodeBtriggered = false;
	timeouts.remove_if([&](RequestTimeout const& t)
	{
		auto now = chrono::steady_clock::now();
		auto diff = now - t.second;
		if (t.first == nodeA && diff < timeout)
			nodeAtriggered = true;
		if (t.first == nodeB && diff < timeout)
			nodeBtriggered = true;
		return (t.first == nodeA || t.first == nodeB);
	});

	BOOST_REQUIRE(nodeAtriggered == false);
	BOOST_REQUIRE(nodeBtriggered == true);
	BOOST_REQUIRE(timeouts.size() == 0);
}

BOOST_AUTO_TEST_CASE(isIPAddressType)
{
	string wildcard = "0.0.0.0";
	BOOST_REQUIRE(bi::address::from_string(wildcard).is_unspecified());

	string empty = "";
	BOOST_REQUIRE_THROW(bi::address::from_string(empty).is_unspecified(), std::exception);

	string publicAddress192 = "192.169.0.0";
	BOOST_REQUIRE(isPublicAddress(publicAddress192));
	BOOST_REQUIRE(!isPrivateAddress(publicAddress192));
	BOOST_REQUIRE(!isLocalHostAddress(publicAddress192));

	string publicAddress172 = "172.32.0.0";
	BOOST_REQUIRE(isPublicAddress(publicAddress172));
	BOOST_REQUIRE(!isPrivateAddress(publicAddress172));
	BOOST_REQUIRE(!isLocalHostAddress(publicAddress172));

	string privateAddress192 = "192.168.1.0";
	BOOST_REQUIRE(isPrivateAddress(privateAddress192));
	BOOST_REQUIRE(!isPublicAddress(privateAddress192));
	BOOST_REQUIRE(!isLocalHostAddress(privateAddress192));

	string privateAddress172 = "172.16.0.0";
	BOOST_REQUIRE(isPrivateAddress(privateAddress172));
	BOOST_REQUIRE(!isPublicAddress(privateAddress172));
	BOOST_REQUIRE(!isLocalHostAddress(privateAddress172));

	string privateAddress10 = "10.0.0.0";
	BOOST_REQUIRE(isPrivateAddress(privateAddress10));
	BOOST_REQUIRE(!isPublicAddress(privateAddress10));
	BOOST_REQUIRE(!isLocalHostAddress(privateAddress10));
}

BOOST_AUTO_TEST_CASE(v2PingNodePacket)
{
	// test old versino of pingNode packet w/new
	RLPStream s;
	s.appendList(3); s << "1.1.1.1" << 30303 << std::chrono::duration_cast<std::chrono::seconds>((std::chrono::system_clock::now() + chrono::seconds(60)).time_since_epoch()).count();

	PingNode p((bi::udp::endpoint()));
	BOOST_REQUIRE_NO_THROW(p = PingNode::fromBytesConstRef(bi::udp::endpoint(), bytesConstRef(&s.out())));
	BOOST_REQUIRE(p.version == 2);
}

BOOST_AUTO_TEST_CASE(neighboursPacketLength)
{
	KeyPair k = KeyPair::create();
	std::vector<std::pair<KeyPair,unsigned>> testNodes(TestNodeTable::createTestNodes(16));
	bi::udp::endpoint to(boost::asio::ip::address::from_string("127.0.0.1"), 30000);

	// hash(32), signature(65), overhead: packet(2), type(1), nodeList(2), ts(9),
	static unsigned const nlimit = (1280 - 111) / 87;
	for (unsigned offset = 0; offset < testNodes.size(); offset += nlimit)
	{
		Neighbours out(to);

		auto limit = nlimit ? std::min(testNodes.size(), (size_t)(offset + nlimit)) : testNodes.size();
		for (auto i = offset; i < limit; i++)
		{
			Neighbours::Node node;
			node.ipAddress = boost::asio::ip::address::from_string("200.200.200.200").to_string();
			node.udpPort = testNodes[i].second;
			node.node = testNodes[i].first.pub();
			out.nodes.push_back(node);
		}

		out.sign(k.sec());
		BOOST_REQUIRE_LE(out.data.size(), 1280);
	}
}

BOOST_AUTO_TEST_CASE(test_neighbours_packet)
{
	KeyPair k = KeyPair::create();
	std::vector<std::pair<KeyPair,unsigned>> testNodes(TestNodeTable::createTestNodes(16));
	bi::udp::endpoint to(boost::asio::ip::address::from_string("127.0.0.1"), 30000);

	Neighbours out(to);
	for (auto n: testNodes)
	{
		Neighbours::Node node;
		node.ipAddress = boost::asio::ip::address::from_string("127.0.0.1").to_string();
		node.udpPort = n.second;
		node.node = n.first.pub();
		out.nodes.push_back(node);
	}
	out.sign(k.sec());

	bytesConstRef packet(out.data.data(), out.data.size());
	bytesConstRef rlpBytes(packet.cropped(h256::size + Signature::size + 1));
	Neighbours in = Neighbours::fromBytesConstRef(to, rlpBytes);
	int count = 0;
	for (auto n: in.nodes)
	{
		BOOST_REQUIRE_EQUAL(testNodes[count].second, n.udpPort);
		BOOST_REQUIRE_EQUAL(testNodes[count].first.pub(), n.node);
		BOOST_REQUIRE_EQUAL(sha3(testNodes[count].first.pub()), sha3(n.node));
		count++;
	}
}

BOOST_AUTO_TEST_CASE(test_findnode_neighbours)
{
	// Executing findNode should result in a list which is serialized
	// into Neighbours packet. Neighbours packet should then be deserialized
	// into the same list of nearest nodes.
}

BOOST_AUTO_TEST_CASE(test_windows_template)
{
	bi::udp::endpoint ep;
	PingNode p(ep);
}

BOOST_AUTO_TEST_CASE(kademlia)
{
	// Not yet a 'real' test.
	TestNodeTableHost node(8);
	node.start();
	node.nodeTable->discover(); // ideally, joining with empty node table logs warning we can check for
	node.setup();
	node.populate();
	clog << "NodeTable:\n" << *node.nodeTable.get() << endl;

	node.populateAll();
	clog << "NodeTable:\n" << *node.nodeTable.get() << endl;

	auto nodes = node.nodeTable->nodes();
	nodes.sort();

	node.nodeTable->reset();
	clog << "NodeTable:\n" << *node.nodeTable.get() << endl;

	node.populate(1);
	clog << "NodeTable:\n" << *node.nodeTable.get() << endl;

	node.nodeTable->discover();
	this_thread::sleep_for(chrono::milliseconds(2000));
	clog << "NodeTable:\n" << *node.nodeTable.get() << endl;

	BOOST_REQUIRE_EQUAL(node.nodeTable->count(), 8);

	auto netNodes = node.nodeTable->nodes();
	netNodes.sort();

}

BOOST_AUTO_TEST_CASE(test_udp_once)
{
	UDPDatagram d(bi::udp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 30300), bytes({65,65,65,65}));
	TestUDPSocket a; a.m_socket->connect(); a.start();
	a.m_socket->send(d);
	this_thread::sleep_for(chrono::seconds(1));
	BOOST_REQUIRE_EQUAL(true, a.success);
}

BOOST_AUTO_TEST_SUITE_END()

<|endoftext|>


<commit_before>#include <iostream>
#include <limits>

#include "src/parser.h"

int main()
{
	std::string inputTerm;

	std::cin >> inputTerm;

	try {
		typedef std::numeric_limits<double> dbl;
		std::cout.precision(dbl::digits10);

		std::cout << SimpleParser::calculate(inputTerm) << std::endl;
	}
	catch ( std::exception &e )
	{
		std::cerr << e.what() << std::endl;
		return 1;
	}

	return 0;
}
<commit_msg>Added simple input loop to clc<commit_after>#include <iostream>
#include <limits>

#include "src/parser.h"

typedef std::numeric_limits<double> dbl;

int main() {
	std::string inputTerm;
	std::cout.precision(dbl::digits10);

	while ( std::cin >> inputTerm ) {
		try {
			std::cout << SimpleParser::calculate(inputTerm) << std::endl;
		}
		catch ( std::exception &e ) {
			std::cerr << e.what() << std::endl;
		}
	}

	return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2011, Cornell University
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of HyperDex nor the names of its contributors may be
//       used to endorse or promote products derived from this software without
//       specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#define __STDC_LIMIT_MACROS

// POSIX
#include <errno.h>

// STL
#include <string>
#include <tr1/memory>
#include <vector>

// po6
#include <po6/net/ipaddr.h>
#include <po6/threads/barrier.h>
#include <po6/threads/thread.h>

// e
#include <e/convert.h>
#include <e/locking_fifo.h>
#include <e/timer.h>

// HyperDex
#include <hyperclient/client.h>
#include <hyperclient/returncode.h>

static e::locking_fifo<std::string> lines;
static po6::threads::mutex unblock_lock;
static po6::threads::cond unblock(&unblock_lock);
static po6::net::ipaddr ip;
static uint16_t port;
static std::string space;
static uint16_t num_threads;

static int
usage();

static void
worker(po6::threads::barrier*);

int
main(int argc, char* argv[])
{
    if (argc != 5)
    {
        return usage();
    }

    space = argv[3];

    try
    {
        ip = argv[1];
    }
    catch (std::invalid_argument& e)
    {
        std::cerr << "The IP address must be an IPv4 or IPv6 address." << std::endl;
        return EXIT_FAILURE;
    }

    try
    {
        port = e::convert::to_uint16_t(argv[2]);
    }
    catch (std::domain_error& e)
    {
        std::cerr << "The port number must be an integer." << std::endl;
        return EXIT_FAILURE;
    }
    catch (std::out_of_range& e)
    {
        std::cerr << "The port number must be suitably small." << std::endl;
        return EXIT_FAILURE;
    }

    try
    {
        num_threads = e::convert::to_uint16_t(argv[4]);
    }
    catch (std::domain_error& e)
    {
        std::cerr << "The number of threads must be an integer." << std::endl;
        return EXIT_FAILURE;
    }
    catch (std::out_of_range& e)
    {
        std::cerr << "The number of threads must be suitably small." << std::endl;
        return EXIT_FAILURE;
    }

    po6::threads::barrier bar(num_threads + 1);

    try
    {
        std::vector<std::tr1::shared_ptr<po6::threads::thread> > threads;

        for (size_t i = 0; i < num_threads; ++i)
        {
            std::tr1::shared_ptr<po6::threads::thread> t(new po6::threads::thread(std::tr1::bind(worker, &bar)));
            t->start();
            threads.push_back(t);
        }

        e::stopwatch stopwatch;
        bar.wait();
        stopwatch.start();
        std::string line;
        size_t i = 0;

        while (std::getline(std::cin, line))
        {
            lines.push(line);

            if (lines.size() > 10000)
            {
                e::sleep_ms(0, 1);
            }

            ++i;
        }

        lines.shutdown();
        bar.wait();

        uint64_t nanosecs = stopwatch.peek();
        std::cerr << "test took " << nanosecs << " nanoseconds." << std::endl;

        for (std::vector<std::tr1::shared_ptr<po6::threads::thread> >::iterator t = threads.begin();
                t != threads.end(); ++t)
        {
            (*t)->join();
        }
    }
    catch (po6::error& e)
    {
        std::cerr << "There was a system error:  " << e.what();
        return EXIT_FAILURE;
    }
    catch (std::runtime_error& e)
    {
        std::cerr << "There was a runtime error:  " << e.what();
        return EXIT_FAILURE;
    }
    catch (std::bad_alloc& e)
    {
        std::cerr << "There was a memory allocation error:  " << e.what();
        return EXIT_FAILURE;
    }
    catch (std::exception& e)
    {
        std::cerr << "There was a generic error:  " << e.what();
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

int
usage()
{
    std::cerr << "Usage:  hyperdex-cli <coordinator ip> <coordinator port> <space name> <threads>"
              << std::endl;
    return EXIT_FAILURE;
}

void
handle_get(hyperclient::returncode ret, const std::vector<e::buffer>& value)
{
    if (ret == hyperclient::SUCCESS)
    {
        for (size_t i = 0; i < value.size(); ++i)
        {
            std::cout << "\t" << value[i].hex();
        }

        std::cout << std::endl;
    }
    else
    {
        std::cerr << "Get returned " << ret << "." << std::endl;
    }
}

void
handle_put(hyperclient::returncode ret)
{
    std::cerr << "Put returned " << ret << "." << std::endl;
}

void
handle_del(hyperclient::returncode ret)
{
    std::cerr << "Del returned " << ret << "." << std::endl;
}

void
handle_search(hyperclient::returncode ret, const e::buffer& key, const std::vector<e::buffer>& value)
{
    if (ret == hyperclient::SUCCESS)
    {
        std::cout << "\t" << key.hex() << " =";

        for (size_t i = 0; i < value.size(); ++i)
        {
            std::cout << "\t" << value[i].hex();
        }

        std::cout << std::endl;
    }
    else
    {
        std::cerr << "Search returned " << ret << "." << std::endl;
    }
}

void
handle_update(hyperclient::returncode ret)
{
    std::cerr << "Update returned " << ret << "." << std::endl;
}

void
worker(po6::threads::barrier* bar)
{
    hyperclient::client cl(po6::net::location(ip, port));
    cl.connect();
    std::string line;

    bar->wait();

    while (lines.pop(&line))
    {
        std::istringstream istr(line);
        std::string command = "";
        std::getline(istr, command, '\t');

        if (command == "GET")
        {
            std::string tmp;

            if (!std::getline(istr, tmp, '\t'))
            {
                std::cerr << "Could not read key for " << line << std::endl;
            }

            e::buffer key(tmp.c_str(), tmp.size());
            cl.get(space, key, handle_get);
            cl.flush(-1);
        }
        else if (command == "PUT")
        {
            std::string tmp;

            if (!std::getline(istr, tmp, '\t'))
            {
                std::cerr << "Could not read key for " << line << std::endl;
            }

            e::buffer key(tmp.c_str(), tmp.size());
            std::vector<e::buffer> value;

            while (std::getline(istr, tmp, '\t'))
            {
                e::buffer val(tmp.c_str(), tmp.size());
                value.push_back(e::buffer());
                value.back().swap(val);
            }

            cl.put(space, key, value, handle_put);
            cl.flush(-1);
        }
        else if (command == "DEL")
        {
            std::string tmp;

            if (!std::getline(istr, tmp, '\t'))
            {
                std::cerr << "Could not read key for " << line << std::endl;
            }

            e::buffer key(tmp.c_str(), tmp.size());
            cl.del(space, key, handle_del);
            cl.flush(-1);
        }
        else if (command == "QUERY")
        {
            std::string attr;
            std::string val;
            bool wellformed = true;
            std::map<std::string, e::buffer> search;

            while (std::getline(istr, attr, '\t'))
            {
                if (!std::getline(istr, val, '\t'))
                {
                    wellformed = false;
                }

                search.insert(std::make_pair(attr, e::buffer(val.c_str(), val.size())));
            }

            if (wellformed)
            {
                cl.search(space, search, handle_search, UINT16_MAX);
                cl.flush(-1);
            }
            else
            {
                std::cerr << "Search line malformed." << std::endl;
            }
        }
        else if (command == "UPDATE")
        {
            std::string tmp;
            std::string attr;
            std::string val;

            if (!std::getline(istr, tmp, '\t'))
            {
                std::cerr << "Could not read key for " << line << std::endl;
            }

            e::buffer key(tmp.c_str(), tmp.size());
            bool wellformed = true;
            std::map<std::string, e::buffer> update;

            while (std::getline(istr, attr, '\t'))
            {
                if (!std::getline(istr, val, '\t'))
                {
                    wellformed = false;
                }

                update.insert(std::make_pair(attr, e::buffer(val.c_str(), val.size())));
            }

            if (wellformed)
            {
                cl.update(space, key, update, handle_update);
                cl.flush(-1);
            }
            else
            {
                std::cerr << "Update line malformed." << std::endl;
            }
        }
        else
        {
            std::cerr << "Unknown commands cannot be acted upon." << std::endl;
        }
    }

    bar->wait();
}
<commit_msg>Add range queries to the cli.<commit_after>// Copyright (c) 2011, Cornell University
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of HyperDex nor the names of its contributors may be
//       used to endorse or promote products derived from this software without
//       specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#define __STDC_LIMIT_MACROS

// POSIX
#include <errno.h>

// STL
#include <string>
#include <tr1/memory>
#include <vector>

// po6
#include <po6/net/ipaddr.h>
#include <po6/threads/barrier.h>
#include <po6/threads/thread.h>

// e
#include <e/convert.h>
#include <e/locking_fifo.h>
#include <e/timer.h>

// HyperDex
#include <hyperclient/client.h>
#include <hyperclient/returncode.h>

static e::locking_fifo<std::string> lines;
static po6::threads::mutex unblock_lock;
static po6::threads::cond unblock(&unblock_lock);
static po6::net::ipaddr ip;
static uint16_t port;
static std::string space;
static uint16_t num_threads;

static int
usage();

static void
worker(po6::threads::barrier*);

int
main(int argc, char* argv[])
{
    if (argc != 5)
    {
        return usage();
    }

    space = argv[3];

    try
    {
        ip = argv[1];
    }
    catch (std::invalid_argument& e)
    {
        std::cerr << "The IP address must be an IPv4 or IPv6 address." << std::endl;
        return EXIT_FAILURE;
    }

    try
    {
        port = e::convert::to_uint16_t(argv[2]);
    }
    catch (std::domain_error& e)
    {
        std::cerr << "The port number must be an integer." << std::endl;
        return EXIT_FAILURE;
    }
    catch (std::out_of_range& e)
    {
        std::cerr << "The port number must be suitably small." << std::endl;
        return EXIT_FAILURE;
    }

    try
    {
        num_threads = e::convert::to_uint16_t(argv[4]);
    }
    catch (std::domain_error& e)
    {
        std::cerr << "The number of threads must be an integer." << std::endl;
        return EXIT_FAILURE;
    }
    catch (std::out_of_range& e)
    {
        std::cerr << "The number of threads must be suitably small." << std::endl;
        return EXIT_FAILURE;
    }

    po6::threads::barrier bar(num_threads + 1);

    try
    {
        std::vector<std::tr1::shared_ptr<po6::threads::thread> > threads;

        for (size_t i = 0; i < num_threads; ++i)
        {
            std::tr1::shared_ptr<po6::threads::thread> t(new po6::threads::thread(std::tr1::bind(worker, &bar)));
            t->start();
            threads.push_back(t);
        }

        e::stopwatch stopwatch;
        bar.wait();
        stopwatch.start();
        std::string line;
        size_t i = 0;

        while (std::getline(std::cin, line))
        {
            lines.push(line);

            if (lines.size() > 10000)
            {
                e::sleep_ms(0, 1);
            }

            ++i;
        }

        lines.shutdown();
        bar.wait();

        uint64_t nanosecs = stopwatch.peek();
        std::cerr << "test took " << nanosecs << " nanoseconds." << std::endl;

        for (std::vector<std::tr1::shared_ptr<po6::threads::thread> >::iterator t = threads.begin();
                t != threads.end(); ++t)
        {
            (*t)->join();
        }
    }
    catch (po6::error& e)
    {
        std::cerr << "There was a system error:  " << e.what();
        return EXIT_FAILURE;
    }
    catch (std::runtime_error& e)
    {
        std::cerr << "There was a runtime error:  " << e.what();
        return EXIT_FAILURE;
    }
    catch (std::bad_alloc& e)
    {
        std::cerr << "There was a memory allocation error:  " << e.what();
        return EXIT_FAILURE;
    }
    catch (std::exception& e)
    {
        std::cerr << "There was a generic error:  " << e.what();
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

int
usage()
{
    std::cerr << "Usage:  hyperdex-cli <coordinator ip> <coordinator port> <space name> <threads>"
              << std::endl;
    return EXIT_FAILURE;
}

void
handle_get(hyperclient::returncode ret, const std::vector<e::buffer>& value)
{
    if (ret == hyperclient::SUCCESS)
    {
        for (size_t i = 0; i < value.size(); ++i)
        {
            std::cout << "\t" << value[i].hex();
        }

        std::cout << std::endl;
    }
    else
    {
        std::cerr << "Get returned " << ret << "." << std::endl;
    }
}

void
handle_put(hyperclient::returncode ret)
{
    std::cerr << "Put returned " << ret << "." << std::endl;
}

void
handle_del(hyperclient::returncode ret)
{
    std::cerr << "Del returned " << ret << "." << std::endl;
}

void
handle_search(hyperclient::returncode ret, const e::buffer& key, const std::vector<e::buffer>& value)
{
    if (ret == hyperclient::SUCCESS)
    {
        std::cout << "\t" << key.hex() << " =";

        for (size_t i = 0; i < value.size(); ++i)
        {
            std::cout << "\t" << value[i].hex();
        }

        std::cout << std::endl;
    }
    else
    {
        std::cerr << "Search returned " << ret << "." << std::endl;
    }
}

void
handle_update(hyperclient::returncode ret)
{
    std::cerr << "Update returned " << ret << "." << std::endl;
}

void
worker(po6::threads::barrier* bar)
{
    hyperclient::client cl(po6::net::location(ip, port));
    cl.connect();
    std::string line;

    bar->wait();

    while (lines.pop(&line))
    {
        std::istringstream istr(line);
        std::string command = "";
        std::getline(istr, command, '\t');

        if (command == "GET")
        {
            std::string tmp;

            if (!std::getline(istr, tmp, '\t'))
            {
                std::cerr << "Could not read key for " << line << std::endl;
            }

            e::buffer key(tmp.c_str(), tmp.size());
            cl.get(space, key, handle_get);
            cl.flush(-1);
        }
        else if (command == "PUT")
        {
            std::string tmp;

            if (!std::getline(istr, tmp, '\t'))
            {
                std::cerr << "Could not read key for " << line << std::endl;
            }

            e::buffer key(tmp.c_str(), tmp.size());
            std::vector<e::buffer> value;

            while (std::getline(istr, tmp, '\t'))
            {
                e::buffer val(tmp.c_str(), tmp.size());
                value.push_back(e::buffer());
                value.back().swap(val);
            }

            cl.put(space, key, value, handle_put);
            cl.flush(-1);
        }
        else if (command == "DEL")
        {
            std::string tmp;

            if (!std::getline(istr, tmp, '\t'))
            {
                std::cerr << "Could not read key for " << line << std::endl;
            }

            e::buffer key(tmp.c_str(), tmp.size());
            cl.del(space, key, handle_del);
            cl.flush(-1);
        }
        else if (command == "EQUALITY")
        {
            std::string attr;
            std::string val;
            bool wellformed = true;
            std::map<std::string, e::buffer> search;

            while (std::getline(istr, attr, '\t'))
            {
                if (!std::getline(istr, val, '\t'))
                {
                    wellformed = false;
                }

                search.insert(std::make_pair(attr, e::buffer(val.c_str(), val.size())));
            }

            if (wellformed)
            {
                cl.search(space, search, handle_search);
                cl.flush(-1);
            }
            else
            {
                std::cerr << "Search line malformed." << std::endl;
            }
        }
        else if (command == "RANGE")
        {
            std::string attr;
            std::string lower_str;
            std::string upper_str;
            bool wellformed = true;
            std::map<std::string, std::pair<uint64_t, uint64_t> > search;

            while (std::getline(istr, attr, '\t'))
            {
                if (!std::getline(istr, lower_str, '\t'))
                {
                    wellformed = false;
                }

                if (!std::getline(istr, upper_str, '\t'))
                {
                    wellformed = false;
                }

                // XXX Be safer with this.
                uint64_t lower = atoi(lower_str.c_str());
                uint64_t upper = atoi(upper_str.c_str());
                search.insert(std::make_pair(attr, std::make_pair(lower, upper)));
            }

            if (wellformed)
            {
                cl.search(space, search, handle_search);
                cl.flush(-1);
            }
            else
            {
                std::cerr << "Search line malformed." << std::endl;
            }
        }
        else if (command == "UPDATE")
        {
            std::string tmp;
            std::string attr;
            std::string val;

            if (!std::getline(istr, tmp, '\t'))
            {
                std::cerr << "Could not read key for " << line << std::endl;
            }

            e::buffer key(tmp.c_str(), tmp.size());
            bool wellformed = true;
            std::map<std::string, e::buffer> update;

            while (std::getline(istr, attr, '\t'))
            {
                if (!std::getline(istr, val, '\t'))
                {
                    wellformed = false;
                }

                update.insert(std::make_pair(attr, e::buffer(val.c_str(), val.size())));
            }

            if (wellformed)
            {
                cl.update(space, key, update, handle_update);
                cl.flush(-1);
            }
            else
            {
                std::cerr << "Update line malformed." << std::endl;
            }
        }
        else
        {
            std::cerr << "Unknown commands cannot be acted upon." << std::endl;
        }
    }

    bar->wait();
}
<|endoftext|>


<commit_before>#include "fb.h"
#include "string.h"
#include "types.h"
#include "mm.h"
#include "arch/platform.h"
#include "memcopy.h"

static volatile ptr_val_t __fb_mutex = 0;

FB::FB()
{
	m_current = NULL;
	m_buffer = NULL;
	m_backbuffer = NULL;
	m_double_buffer = true;
	m_direct = false;
	m_configured = false;
	m.assign(&__fb_mutex);
}

FB::~FB()
{
	freeBuffers();
}

void FB::setSingleBuffer()
{
	m.lock();

	m_double_buffer = false;
	if (m_buffer!=NULL) {
		MM::instance()->free(m_buffer);
	}
	m_buffer = NULL;

	m.unlock();
}

void FB::setDirect()
{
	m.lock();

	m_direct = true;
	if (m_backbuffer!=NULL) {
		MM::instance()->free(m_backbuffer);
	}
	if (m_buffer!=NULL) {
		MM::instance()->free(m_buffer);
	}
	m_backbuffer = m_current->base;
	m_buffer = m_current->base;

	m.unlock();
}

void FB::allocBuffers()
{
	if (m_direct) return;
	m.lock();

	m_size = m_current->bytes_per_line*(m_current->height);
	//m_backbuffer = (unsigned char*)MM::instance()->alloc(m_size, MM::AllocClear);
	m_backbuffer = (unsigned char*)MM::instance()->alloc(m_size);
	if (m_backbuffer!=NULL) {
		m_backbuffer[0] = 0xfe;
		m_backbuffer[m_size/2] = 0xed;
		m_backbuffer[m_size-1] = 0xdc;
		if (m_backbuffer==NULL || m_backbuffer[0] != 0xfe || m_backbuffer[m_size/2] != 0xed || m_backbuffer[m_size-1] != 0xdc) {
			m_direct = true;
			MM::instance()->free(m_backbuffer);
			m_backbuffer = m_current->base;
			//Platform::video()->printf("direct\n");
		} else {
			m_backbuffer[0] = 0;
			m_backbuffer[m_size/2] = 0;
			m_backbuffer[m_size-1] = 0;
			m_buffer = (unsigned char*)MM::instance()->alloc(m_size, MM::AllocClear);
			m_buffer[0] = 0xef;
			m_buffer[m_size/2] = 0xde;
			m_buffer[m_size-1] = 0xec;
			if (m_buffer==NULL || m_buffer[0] != 0xef || m_buffer[m_size/2] != 0xde || m_buffer[m_size-1] != 0xec) {
				m_double_buffer = false;
				MM::instance()->free(m_buffer);
				m_buffer = NULL;
				//m_buffer = m_backbuffer;
				//Platform::video()->printf("singlebuffer\n");
			} else {
				m_buffer[0] = 0;
				m_buffer[m_size/2] = 0;
				m_buffer[m_size-1] = 0;
			}
		}
	}
#if 0
	for (uint32_t i=0; i<m_size; i++) {
		if (buffer!=NULL) buffer[i] = 0;
		if (backbuffer!=NULL) backbuffer[i] = 0;
	}
#endif
	//Platform::video()->printf("Allocbuffers: %x %x %x sizes: %d\n",m_current->base,m_buffer,m_backbuffer,m_current->bytes_per_line*(m_current->height));
	m.unlock();
}

void FB::freeBuffers()
{
	m.lock();
	if (m_buffer!=NULL) {
		MM::instance()->free(m_buffer);
		m_buffer = NULL;
	}
	if (m_backbuffer!=NULL) {
		MM::instance()->free(m_backbuffer);
		m_backbuffer = NULL;
	}
	m.unlock();
}

bool FB::configure(ModeConfig *mode)
{
	if (mode==NULL) return false;

	m_current = mode;

	allocBuffers();

	m_configured = true;
	return true;
}

unsigned char *FB::data()
{
	if (m_buffer == NULL) return NULL;
	return m_buffer;
}

void FB::swap()
{
	if (m_buffer == NULL) return;
	if (m_backbuffer == NULL) return;
	if (m_direct) return;
	if (!m_double_buffer) {
		m_buffer = m_backbuffer;
		return;
	}

	m.lock();
	if (m_buffer!=NULL && !m_direct) {
		memcpy_opt(m_buffer, m_backbuffer, m_size);
		//Mem::copy(m_buffer, m_backbuffer, m_size);
	}
	m.unlock();
}

#if 0
void printD(uint32_t d)
{
	char aa[5];
	while (d>0) {
		uint32_t i = d%10;
		d/=10;
		aa[0] = '0'+i;
		aa[1] = 0;
		Video::get()->printf(aa);
	}
	Video::get()->printf("\n");
}
#endif

void FB::putPixel(int x, int y, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
{
	if (m_backbuffer==NULL) return;
	if (m_current==NULL) return;

/*
	x %= m_current->width;
	y %= m_current->height;
*/
	if (x>m_current->width) x = m_current->width;
	if (y>m_current->height) y = m_current->height;

	switch (m_current->depth) {
		case 16:
			{
			unsigned short *pos = (unsigned short*)(m_backbuffer+(y*m_current->bytes_per_line + x*2));
			unsigned short color = 0;
			color += (r & 0x7C) << 8;
			color += (g & 0x7E) << 2;
			color += (b & 0x7C) >> 3;
			*pos = color;
			}
			break;
		/*case 24:
			{
			unsigned char *pos = (unsigned char*)(backbuffer+(y*current->bytes_per_line + x*4));
			*pos++ = r;
			*pos++ = g;
			*pos++ = b;
			}
			break;*/
		case 24:
			{
			unsigned char *pos = (unsigned char*)(m_backbuffer+(y*m_current->bytes_per_line + x*3));
			*pos++ = r;
			*pos++ = g;
			*pos = b;
			}
			break;
		case 32:
			{
			uint32_t *pos = (uint32_t*)(m_backbuffer+(y*m_current->bytes_per_line + x*4));
			uint32_t color = (a<<24)+(r<<16)+(g<<8)+b;
			*pos = color;
			}
			break;
		default:
			//Platform::video()->printf("Unsupported depth: %d\n",m_current->depth);
			// Unsupported
			break;
	}
}

void FB::putPixel(int x, int y, unsigned int color)
{
	if (m_backbuffer!=NULL && m_current!=NULL && m_current->depth==32) {
		x %= m_current->width;
		y %= m_current->height;
		uint32_t *pos = (uint32_t*)(m_backbuffer+(y*m_current->bytes_per_line + x*4));
		*pos = color;
	} else {
		unsigned char b = color & 0xff;
		unsigned char g = (color>>8) & 0xff;
		unsigned char r = (color>>16) & 0xff;
		unsigned char a = (color>>24) & 0xff;
		putPixel(x, y, r,g,b,a);
	}
}

void FB::clear()
{
	m.lock();
	if (m_backbuffer!=NULL) Mem::set(m_backbuffer, 0, m_size);
	if (m_buffer!=NULL) Mem::set(m_buffer, 0, m_size);
	m.unlock();
	//swap();
#if 0
	unsigned char *dest = backbuffer+(current->height*current->bytes_per_line);
	unsigned char *ptr = backbuffer;
	while (ptr<dest) {
		*ptr++ = 0;
	}
#endif
}
<commit_msg>Clear memory<commit_after>#include "fb.h"
#include "string.h"
#include "types.h"
#include "mm.h"
#include "arch/platform.h"
#include "memcopy.h"

static volatile ptr_val_t __fb_mutex = 0;

FB::FB()
{
	m_current = NULL;
	m_buffer = NULL;
	m_backbuffer = NULL;
	m_double_buffer = true;
	m_direct = false;
	m_configured = false;
	m.assign(&__fb_mutex);
}

FB::~FB()
{
	freeBuffers();
}

void FB::setSingleBuffer()
{
	m.lock();

	m_double_buffer = false;
	if (m_buffer!=NULL) {
		MM::instance()->free(m_buffer);
	}
	m_buffer = NULL;

	m.unlock();
}

void FB::setDirect()
{
	m.lock();

	m_direct = true;
	if (m_backbuffer!=NULL) {
		MM::instance()->free(m_backbuffer);
	}
	if (m_buffer!=NULL) {
		MM::instance()->free(m_buffer);
	}
	m_backbuffer = m_current->base;
	m_buffer = m_current->base;

	m.unlock();
}

void FB::allocBuffers()
{
	if (m_direct) return;
	m.lock();

	m_size = m_current->bytes_per_line*(m_current->height);
	m_backbuffer = (unsigned char*)MM::instance()->alloc(m_size, MM::AllocClear);
	//m_backbuffer = (unsigned char*)MM::instance()->alloc(m_size);
	if (m_backbuffer!=NULL) {
		m_backbuffer[0] = 0xfe;
		m_backbuffer[m_size/2] = 0xed;
		m_backbuffer[m_size-1] = 0xdc;
		if (m_backbuffer==NULL || m_backbuffer[0] != 0xfe || m_backbuffer[m_size/2] != 0xed || m_backbuffer[m_size-1] != 0xdc) {
			m_direct = true;
			MM::instance()->free(m_backbuffer);
			m_backbuffer = m_current->base;
			//Platform::video()->printf("direct\n");
		} else {
			m_backbuffer[0] = 0;
			m_backbuffer[m_size/2] = 0;
			m_backbuffer[m_size-1] = 0;
			m_buffer = (unsigned char*)MM::instance()->alloc(m_size, MM::AllocClear);
			m_buffer[0] = 0xef;
			m_buffer[m_size/2] = 0xde;
			m_buffer[m_size-1] = 0xec;
			if (m_buffer==NULL || m_buffer[0] != 0xef || m_buffer[m_size/2] != 0xde || m_buffer[m_size-1] != 0xec) {
				m_double_buffer = false;
				MM::instance()->free(m_buffer);
				m_buffer = NULL;
				//m_buffer = m_backbuffer;
				//Platform::video()->printf("singlebuffer\n");
			} else {
				m_buffer[0] = 0;
				m_buffer[m_size/2] = 0;
				m_buffer[m_size-1] = 0;
			}
		}
	}
#if 0
	for (uint32_t i=0; i<m_size; i++) {
		if (buffer!=NULL) buffer[i] = 0;
		if (backbuffer!=NULL) backbuffer[i] = 0;
	}
#endif
	//Platform::video()->printf("Allocbuffers: %x %x %x sizes: %d\n",m_current->base,m_buffer,m_backbuffer,m_current->bytes_per_line*(m_current->height));
	m.unlock();
}

void FB::freeBuffers()
{
	m.lock();
	if (m_buffer!=NULL) {
		MM::instance()->free(m_buffer);
		m_buffer = NULL;
	}
	if (m_backbuffer!=NULL) {
		MM::instance()->free(m_backbuffer);
		m_backbuffer = NULL;
	}
	m.unlock();
}

bool FB::configure(ModeConfig *mode)
{
	if (mode==NULL) return false;

	m_current = mode;

	allocBuffers();

	m_configured = true;
	return true;
}

unsigned char *FB::data()
{
	if (m_buffer == NULL) return NULL;
	return m_buffer;
}

void FB::swap()
{
	if (m_buffer == NULL) return;
	if (m_backbuffer == NULL) return;
	if (m_direct) return;
	if (!m_double_buffer) {
		m_buffer = m_backbuffer;
		return;
	}

	m.lock();
	if (m_buffer!=NULL && !m_direct) {
		memcpy_opt(m_buffer, m_backbuffer, m_size);
		//Mem::copy(m_buffer, m_backbuffer, m_size);
	}
	m.unlock();
}

#if 0
void printD(uint32_t d)
{
	char aa[5];
	while (d>0) {
		uint32_t i = d%10;
		d/=10;
		aa[0] = '0'+i;
		aa[1] = 0;
		Video::get()->printf(aa);
	}
	Video::get()->printf("\n");
}
#endif

void FB::putPixel(int x, int y, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
{
	if (m_backbuffer==NULL) return;
	if (m_current==NULL) return;

/*
	x %= m_current->width;
	y %= m_current->height;
*/
	if (x>m_current->width) x = m_current->width;
	if (y>m_current->height) y = m_current->height;

	switch (m_current->depth) {
		case 16:
			{
			unsigned short *pos = (unsigned short*)(m_backbuffer+(y*m_current->bytes_per_line + x*2));
			unsigned short color = 0;
			color += (r & 0x7C) << 8;
			color += (g & 0x7E) << 2;
			color += (b & 0x7C) >> 3;
			*pos = color;
			}
			break;
		/*case 24:
			{
			unsigned char *pos = (unsigned char*)(backbuffer+(y*current->bytes_per_line + x*4));
			*pos++ = r;
			*pos++ = g;
			*pos++ = b;
			}
			break;*/
		case 24:
			{
			unsigned char *pos = (unsigned char*)(m_backbuffer+(y*m_current->bytes_per_line + x*3));
			*pos++ = r;
			*pos++ = g;
			*pos = b;
			}
			break;
		case 32:
			{
			uint32_t *pos = (uint32_t*)(m_backbuffer+(y*m_current->bytes_per_line + x*4));
			uint32_t color = (a<<24)+(r<<16)+(g<<8)+b;
			*pos = color;
			}
			break;
		default:
			//Platform::video()->printf("Unsupported depth: %d\n",m_current->depth);
			// Unsupported
			break;
	}
}

void FB::putPixel(int x, int y, unsigned int color)
{
	if (m_backbuffer!=NULL && m_current!=NULL && m_current->depth==32) {
		x %= m_current->width;
		y %= m_current->height;
		uint32_t *pos = (uint32_t*)(m_backbuffer+(y*m_current->bytes_per_line + x*4));
		*pos = color;
	} else {
		unsigned char b = color & 0xff;
		unsigned char g = (color>>8) & 0xff;
		unsigned char r = (color>>16) & 0xff;
		unsigned char a = (color>>24) & 0xff;
		putPixel(x, y, r,g,b,a);
	}
}

void FB::clear()
{
	m.lock();
	if (m_backbuffer!=NULL) Mem::set(m_backbuffer, 0, m_size);
	if (m_buffer!=NULL) Mem::set(m_buffer, 0, m_size);
	m.unlock();
	//swap();
#if 0
	unsigned char *dest = backbuffer+(current->height*current->bytes_per_line);
	unsigned char *ptr = backbuffer;
	while (ptr<dest) {
		*ptr++ = 0;
	}
#endif
}
<|endoftext|>


<commit_before>#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkCommand.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkProperty.h>
#include <vtkAxesActor.h>
#include <vtkNamedColors.h>

class vtkTimerCallback2 : public vtkCommand
{
public:
 static vtkTimerCallback2 *New()
 {
  vtkTimerCallback2 *cb = new vtkTimerCallback2;
  return cb;
 }

 virtual void Execute(vtkObject *caller, unsigned long eventId, void * vtkNotUsed(callData))
 {
  actor->RotateZ(5);
  vtkRenderWindowInteractor *iren = dynamic_cast<vtkRenderWindowInteractor*>(caller);
  iren->GetRenderWindow()->Render();
 }
private:
 int TimerCount;
public:
 vtkActor* actor;
};

int main(int, char*[])
{
 vtkSmartPointer<vtkNamedColors> colors = vtkSmartPointer<vtkNamedColors>::New();

 // Create a sphere
 vtkSmartPointer<vtkSphereSource> sphereSource = vtkSmartPointer<vtkSphereSource>::New();
 sphereSource->SetCenter(0.0, 0.0, 0.0);
 sphereSource->SetRadius(1.0);
 sphereSource->SetThetaResolution(15);
 sphereSource->SetPhiResolution(15);
 sphereSource->Update();

 // Create a mapper and actor
 vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
 mapper->SetInputConnection(sphereSource->GetOutputPort());
 vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
 actor->SetMapper(mapper);
 actor->RotateX(90);
 actor->GetProperty()->SetRepresentationToWireframe();

 // Create a renderer, render window, and interactor
 vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
 vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
 renderWindow->AddRenderer(renderer);

 vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
 renderWindowInteractor->SetRenderWindow(renderWindow);

 // Add the actor to the scene
 renderer->AddActor(actor);

 renderer->SetBackground(colors->GetColor3d("Seashell").GetData()); // Background color white
 // Render and interact
 renderWindow->Render();

 // Initialize must be called prior to creating timer events.
 renderWindowInteractor->Initialize();

 // Sign up to receive TimerEvent
 vtkSmartPointer<vtkTimerCallback2> cb = vtkSmartPointer<vtkTimerCallback2>::New();
 cb->actor = actor;
 renderWindowInteractor->AddObserver(vtkCommand::TimerEvent, cb);

 int timerId = renderWindowInteractor->CreateRepeatingTimer(100);

 // Start the interaction and timer
 renderWindowInteractor->Start();

 return EXIT_SUCCESS;
}
<commit_msg>Update RotatingSphere.cxx<commit_after>#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkProperty.h>
#include <vtkNamedColors.h>
#include <vtkAnimationScene.h>

class vtkTimerCallback2 : public vtkCommand
{
public:

	int timerId;
	static vtkTimerCallback2 *New()
	{
		vtkTimerCallback2 *cb = new vtkTimerCallback2;
		cb->TimerCount = 0;
		return cb;
	}

	virtual void Execute(vtkObject *caller, unsigned long eventId, void * vtkNotUsed(callData))
	{
		vtkRenderWindowInteractor *iren = dynamic_cast<vtkRenderWindowInteractor*>(caller);
		if (vtkCommand::TimerEvent == eventId)
		{
			++this->TimerCount;
		}
		if (TimerCount <36)
		{
			actor->RotateZ(5);

			iren->GetRenderWindow()->Render();
		}
		else
		{
			iren->DestroyTimer();
		}

	}
private:
	int TimerCount;

public:
	vtkActor* actor;
};

int main(int, char*[])
{
	vtkSmartPointer<vtkNamedColors> colors = vtkSmartPointer<vtkNamedColors>::New();

	// Create a sphere
	vtkSmartPointer<vtkSphereSource> sphereSource = vtkSmartPointer<vtkSphereSource>::New();
	sphereSource->SetCenter(0.0, 0.0, 0.0);
	sphereSource->SetRadius(1.0);
	sphereSource->SetThetaResolution(15);
	sphereSource->SetPhiResolution(15);
	sphereSource->Update();

	// Create a mapper and actor
	vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
	mapper->SetInputConnection(sphereSource->GetOutputPort());
	vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
	actor->SetMapper(mapper);
	actor->RotateX(90);
	actor->GetProperty()->SetRepresentationToWireframe();

	// Create a renderer, render window, and interactor
	vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
	vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
	renderWindow->AddRenderer(renderer);
	renderWindow->SetSize(640, 480);

	vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
	renderWindowInteractor->SetRenderWindow(renderWindow);

	// Add the actor to the scene
	renderer->AddActor(actor);

	renderer->SetBackground(colors->GetColor3d("Seashell").GetData());
	// Render and interact
	renderWindow->Render();

	// Initialize must be called prior to creating timer events.
	renderWindowInteractor->Initialize();

	// Sign up to receive TimerEvent
	vtkSmartPointer<vtkTimerCallback2> cb = vtkSmartPointer<vtkTimerCallback2>::New();
	cb->actor = actor;

	renderWindowInteractor->AddObserver(vtkCommand::TimerEvent, cb);

	int timerId = renderWindowInteractor->CreateRepeatingTimer(100);
	cb->timerId = timerId;

	// Start the interaction and timer
	renderWindowInteractor->Start();

	return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>#include "arguments.hpp"
#include "call_frame.hpp"
#include "on_stack.hpp"
#include "memory.hpp"
#include "metrics.hpp"
#include "raise_reason.hpp"
#include "thread_phase.hpp"

#include "builtin/array.hpp"
#include "builtin/class.hpp"
#include "builtin/exception.hpp"
#include "builtin/fiber.hpp"
#include "builtin/lookup_table.hpp"
#include "builtin/native_method.hpp"
#include "builtin/object.hpp"
#include "builtin/thread.hpp"

#include "memory/gc.hpp"

#include "dtrace/dtrace.h"

#include "logger.hpp"

#include "missing/gettid.h"

#include <ostream>
#include <regex>
#include <string>

namespace rubinius {
  std::atomic<uint32_t> Fiber::fiber_ids_;

  void Fiber::bootstrap(STATE) {
    GO(fiber).set(state->memory()->new_class<Class, Fiber>(state, "Fiber"));

    fiber_ids_.store(0);
  }

  bool Fiber::root_p() {
    return vm()->fiber()->vm() == vm()->thread()->vm();
  }

  void Fiber::unpack_arguments(STATE, Arguments& args) {
    switch(args.total()) {
      case 0:
        value(state, cNil);
        break;
      case 1:
        value(state, args.get_argument(0));
        break;
      default:
        value(state,  args.as_array(state));
        break;
    }
  }

  void Fiber::start(STATE, Arguments& args) {
    arguments(state, args.as_array(state));

    pthread_attr_t attrs;
    pthread_attr_init(&attrs);
    pthread_attr_setstacksize(&attrs, stack_size()->to_native());
    pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED);

    pthread_create(&vm()->os_thread(), &attrs,
        Fiber::run, (void*)vm());

    pthread_attr_destroy(&attrs);

    // Wait for Fiber thread to start up and pause.
    while(!vm()->wait_flag());
  }

  void Fiber::restart(STATE) {
    std::lock_guard<std::mutex> guard(state->vm()->thread()->fiber_mutex());

    state->vm()->thread()->vm()->set_current_fiber(vm());

    while(vm()->wait_flag()) {
      std::lock_guard<std::mutex> guard(vm()->wait_mutex());
      vm()->wait_condition().notify_one();
    }
  }

  void Fiber::suspend(STATE) {
    {
      std::unique_lock<std::mutex> lk(vm()->wait_mutex());
      vm()->set_wait_flag(true);

      {
        UnmanagedPhase unmanaged(state);
        vm()->wait_condition().wait(lk);
      }

      vm()->set_wait_flag(false);
    }

    std::lock_guard<std::mutex> guard(state->vm()->thread()->fiber_mutex());
  }

  Object* Fiber::return_value(STATE) {
    if(vm()->thread_state()->raise_reason() == cNone) {
      return value();
    } else {
      invoke_context()->thread_state()->set_state(vm()->thread_state());
      return NULL;
    }
  }

  void* Fiber::run(void* ptr) {
    VM* vm = reinterpret_cast<VM*>(ptr);
    State state_obj(vm), *state = &state_obj;

    vm->set_stack_bounds(vm->fiber()->stack_size()->to_native());
    vm->set_current_thread();
    vm->set_start_time();

    RUBINIUS_THREAD_START(
        const_cast<RBX_DTRACE_CHAR_P>(
          vm->name().c_str()), vm->fiber()->fiber_id()->to_native(), 0);

    vm->fiber()->pid(state, Fixnum::from(gettid()));

    if(state->shared().config.machine_thread_log_lifetime.value) {
      logger::write("fiber: run: %s, %d, %#x",
          vm->name().c_str(), vm->fiber()->pid()->to_native(),
          (intptr_t)pthread_self());
    }

    NativeMethod::init_thread(state);

    vm->fiber()->suspend(state);

    Object* value = vm->fiber()->block()->send(state, G(sym_call),
        vm->fiber()->arguments(), vm->fiber()->block());
    vm->set_call_frame(NULL);

    value = vm->fiber()->return_value(state);

    vm->fiber()->invoke_context()->fiber()->restart(state);

    vm->fiber()->status(eDead);
    vm->fiber()->vm()->set_wait_flag(true);

    vm->unmanaged_phase();

    state->shared().report_profile(state);

    NativeMethod::cleanup_thread(state);

    if(state->shared().config.machine_fiber_log_lifetime.value) {
      logger::write("fiber: exit: %s %fs", vm->name().c_str(), vm->run_time());
    }

    vm->set_zombie(state);

    RUBINIUS_THREAD_STOP(
        const_cast<RBX_DTRACE_CHAR_P>(
          vm->name().c_str()), vm->fiber()->fiber_id()->to_native(), 0);

    return 0;
  }

  Fiber* Fiber::current(STATE) {
    return state->vm()->fiber();
  }

  /* This creates the pseudo-Fiber for the Thread. This provides a uniform
   * means of expressing things like Fiber.current.
   */
  Fiber* Fiber::create(STATE, VM* vm) {
    Fiber* fiber = state->memory()->new_object<Fiber>(state, G(fiber));

    vm->set_fiber(fiber);
    fiber->vm(vm);

    fiber->pid(vm->thread()->pid());
    fiber->stack_size(vm->thread()->stack_size());
    fiber->thread_name(state, String::create(state, vm->name().c_str()));
    fiber->fiber_id(Fixnum::from(0));
    fiber->status(eRunning);
    fiber->invoke_context(vm);

    return fiber;
  }

  Fiber* Fiber::create(STATE, Object* self, Object* stack_size, Object* block) {
    Fiber* fiber = state->memory()->new_object<Fiber>(state, as<Class>(self));
    fiber->block(state, block);

    std::ostringstream name;
    name << "fiber." << fiber->fiber_id()->to_native();

    fiber->vm(state->vm()->thread_nexus()->new_vm(&state->shared(), name.str().c_str()));

    if(Fixnum* size = try_as<Fixnum>(stack_size)) {
      fiber->vm()->validate_stack_size(state, size->to_native());
      fiber->stack_size(state, size);
    }

    fiber->vm()->set_thread(state->vm()->thread());
    fiber->vm()->set_fiber(fiber);

    state->memory()->native_finalizer(state, fiber,
        (memory::FinalizerFunction)&Fiber::finalize);

    if(state->shared().config.machine_fiber_log_lifetime.value) {
      const std::regex& filter = state->shared().config.machine_fiber_log_filter();

      if(CallFrame* call_frame = state->vm()->get_filtered_frame(state, filter)) {
        std::ostringstream source;

        source << call_frame->file(state)->cpp_str(state).c_str()
          << ":" << call_frame->line(state);

        logger::write("fiber: new: %s, %d, %s",
            fiber->thread_name()->c_str(state),
            fiber->fiber_id()->to_native(), source.str().c_str());

        fiber->source(state, String::create(state, source.str().c_str()));
      } else {
        logger::write("fiber: new: %s, %d",
            fiber->thread_name()->c_str(state), fiber->fiber_id()->to_native());
      }
    }

    state->vm()->metrics().system.fibers_created++;

    return fiber;
  }

  String* Fiber::status(STATE) {
    switch(status()) {
      case eCreated:
        return String::create(state, "created");
        break;
      case eRunning:
        return String::create(state, "run");
        break;
      case eYielding:
        return String::create(state, "yield");
        break;
      case eTransfer:
        return String::create(state, "transfer");
        break;
      case eDead:
        return String::create(state, "dead");
        break;
    }

    return String::create(state, "unknown");
  }

  Object* Fiber::resume(STATE, Arguments& args) {
    if(status() == eCreated) {
      start(state, args);
    } else if(status() == eTransfer) {
      Exception::raise_fiber_error(state, "attempt to resume transfered fiber");
    } else if(status() == eRunning) {
      Exception::raise_fiber_error(state, "attempt to resume running fiber");
    } else if(status() == eDead) {
      Exception::raise_fiber_error(state, "attempt to resume dead fiber");
    } else if(root_p()) {
      Exception::raise_fiber_error(state, "attempt to resume root fiber");
    }

    status(eRunning);
    unpack_arguments(state, args);
    invoke_context(state->vm());

    // Being cooperative...
    restart(state);

    // Through the worm hole...
    state->vm()->fiber()->suspend(state);

    // We're back...
    return return_value(state);
  }

  Object* Fiber::transfer(STATE, Arguments& args) {
    if(status() == eCreated) {
      start(state, args);
    } else if(state->vm()->fiber() == this) {
      return args.as_array(state);
    } else if(status() == eDead) {
      Exception::raise_fiber_error(state, "attempt to transfer to dead fiber");
    }

    status(eTransfer);
    unpack_arguments(state, args);
    invoke_context(state->vm()->thread()->vm());

    // Being cooperative...
    restart(state);

    // Through the worm hole...
    state->vm()->fiber()->suspend(state);

    // We're back...
    return return_value(state);
  }

  Object* Fiber::s_yield(STATE, Arguments& args) {
    Fiber* fiber = state->vm()->fiber();
    OnStack<1> os(state, fiber);

    if(fiber->root_p()) {
      Exception::raise_fiber_error(state, "can't yield from root fiber");
    } else if(fiber->status() == eTransfer) {
      Exception::raise_fiber_error(state, "can't yield from transferred fiber");
    }

    fiber->unpack_arguments(state, args);
    fiber->status(eYielding);

    // Being cooperative...
    fiber->invoke_context()->fiber()->restart(state);

    // Through the worm hole...
    fiber->suspend(state);

    // We're back...
    return fiber->invoke_context()->fiber()->return_value(state);
  }

  void Fiber::finalize(STATE, Fiber* fib) {
    if(state->shared().config.machine_fiber_log_finalizer.value) {
      logger::write("fiber: finalizer: %s, %d",
          fib->thread_name()->c_str(state), fib->fiber_id()->to_native());
    }
  }
}
<commit_msg>Fixed passing arguments with Fiber.yield, Fiber#resume.<commit_after>#include "arguments.hpp"
#include "call_frame.hpp"
#include "on_stack.hpp"
#include "memory.hpp"
#include "metrics.hpp"
#include "raise_reason.hpp"
#include "thread_phase.hpp"

#include "builtin/array.hpp"
#include "builtin/class.hpp"
#include "builtin/exception.hpp"
#include "builtin/fiber.hpp"
#include "builtin/lookup_table.hpp"
#include "builtin/native_method.hpp"
#include "builtin/object.hpp"
#include "builtin/thread.hpp"

#include "memory/gc.hpp"

#include "dtrace/dtrace.h"

#include "logger.hpp"

#include "missing/gettid.h"

#include <ostream>
#include <regex>
#include <string>

namespace rubinius {
  std::atomic<uint32_t> Fiber::fiber_ids_;

  void Fiber::bootstrap(STATE) {
    GO(fiber).set(state->memory()->new_class<Class, Fiber>(state, "Fiber"));

    fiber_ids_.store(0);
  }

  bool Fiber::root_p() {
    return vm()->fiber()->vm() == vm()->thread()->vm();
  }

  void Fiber::unpack_arguments(STATE, Arguments& args) {
    switch(args.total()) {
      case 0:
        value(state, cNil);
        break;
      case 1:
        value(state, args.get_argument(0));
        break;
      default:
        value(state,  args.as_array(state));
        break;
    }
  }

  void Fiber::start(STATE, Arguments& args) {
    arguments(state, args.as_array(state));

    pthread_attr_t attrs;
    pthread_attr_init(&attrs);
    pthread_attr_setstacksize(&attrs, stack_size()->to_native());
    pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED);

    pthread_create(&vm()->os_thread(), &attrs,
        Fiber::run, (void*)vm());

    pthread_attr_destroy(&attrs);

    // Wait for Fiber thread to start up and pause.
    while(!vm()->wait_flag());
  }

  void Fiber::restart(STATE) {
    std::lock_guard<std::mutex> guard(state->vm()->thread()->fiber_mutex());

    state->vm()->thread()->vm()->set_current_fiber(vm());

    while(vm()->wait_flag()) {
      std::lock_guard<std::mutex> guard(vm()->wait_mutex());
      vm()->wait_condition().notify_one();
    }
  }

  void Fiber::suspend(STATE) {
    {
      std::unique_lock<std::mutex> lk(vm()->wait_mutex());
      vm()->set_wait_flag(true);

      {
        UnmanagedPhase unmanaged(state);
        vm()->wait_condition().wait(lk);
      }

      vm()->set_wait_flag(false);
    }

    std::lock_guard<std::mutex> guard(state->vm()->thread()->fiber_mutex());
  }

  Object* Fiber::return_value(STATE) {
    if(vm()->thread_state()->raise_reason() == cNone) {
      return value();
    } else {
      invoke_context()->thread_state()->set_state(vm()->thread_state());
      return NULL;
    }
  }

  void* Fiber::run(void* ptr) {
    VM* vm = reinterpret_cast<VM*>(ptr);
    State state_obj(vm), *state = &state_obj;

    vm->set_stack_bounds(vm->fiber()->stack_size()->to_native());
    vm->set_current_thread();
    vm->set_start_time();

    RUBINIUS_THREAD_START(
        const_cast<RBX_DTRACE_CHAR_P>(
          vm->name().c_str()), vm->fiber()->fiber_id()->to_native(), 0);

    vm->fiber()->pid(state, Fixnum::from(gettid()));

    if(state->shared().config.machine_thread_log_lifetime.value) {
      logger::write("fiber: run: %s, %d, %#x",
          vm->name().c_str(), vm->fiber()->pid()->to_native(),
          (intptr_t)pthread_self());
    }

    NativeMethod::init_thread(state);

    vm->fiber()->suspend(state);

    Object* value = vm->fiber()->block()->send(state, G(sym_call),
        vm->fiber()->arguments(), vm->fiber()->block());
    vm->set_call_frame(NULL);

    if(value) {
      vm->fiber()->value(state, value);
    } else {
      vm->fiber()->value(state, cNil);
    }

    vm->fiber()->invoke_context()->fiber()->restart(state);

    vm->fiber()->status(eDead);
    vm->fiber()->vm()->set_wait_flag(true);

    vm->unmanaged_phase();

    state->shared().report_profile(state);

    NativeMethod::cleanup_thread(state);

    if(state->shared().config.machine_fiber_log_lifetime.value) {
      logger::write("fiber: exit: %s %fs", vm->name().c_str(), vm->run_time());
    }

    vm->set_zombie(state);

    RUBINIUS_THREAD_STOP(
        const_cast<RBX_DTRACE_CHAR_P>(
          vm->name().c_str()), vm->fiber()->fiber_id()->to_native(), 0);

    return 0;
  }

  Fiber* Fiber::current(STATE) {
    return state->vm()->fiber();
  }

  /* This creates the pseudo-Fiber for the Thread. This provides a uniform
   * means of expressing things like Fiber.current.
   */
  Fiber* Fiber::create(STATE, VM* vm) {
    Fiber* fiber = state->memory()->new_object<Fiber>(state, G(fiber));

    vm->set_fiber(fiber);
    fiber->vm(vm);

    fiber->pid(vm->thread()->pid());
    fiber->stack_size(vm->thread()->stack_size());
    fiber->thread_name(state, String::create(state, vm->name().c_str()));
    fiber->fiber_id(Fixnum::from(0));
    fiber->status(eRunning);
    fiber->invoke_context(vm);

    return fiber;
  }

  Fiber* Fiber::create(STATE, Object* self, Object* stack_size, Object* block) {
    Fiber* fiber = state->memory()->new_object<Fiber>(state, as<Class>(self));
    fiber->block(state, block);

    std::ostringstream name;
    name << "fiber." << fiber->fiber_id()->to_native();

    fiber->vm(state->vm()->thread_nexus()->new_vm(&state->shared(), name.str().c_str()));

    if(Fixnum* size = try_as<Fixnum>(stack_size)) {
      fiber->vm()->validate_stack_size(state, size->to_native());
      fiber->stack_size(state, size);
    }

    fiber->vm()->set_thread(state->vm()->thread());
    fiber->vm()->set_fiber(fiber);

    state->memory()->native_finalizer(state, fiber,
        (memory::FinalizerFunction)&Fiber::finalize);

    if(state->shared().config.machine_fiber_log_lifetime.value) {
      const std::regex& filter = state->shared().config.machine_fiber_log_filter();

      if(CallFrame* call_frame = state->vm()->get_filtered_frame(state, filter)) {
        std::ostringstream source;

        source << call_frame->file(state)->cpp_str(state).c_str()
          << ":" << call_frame->line(state);

        logger::write("fiber: new: %s, %d, %s",
            fiber->thread_name()->c_str(state),
            fiber->fiber_id()->to_native(), source.str().c_str());

        fiber->source(state, String::create(state, source.str().c_str()));
      } else {
        logger::write("fiber: new: %s, %d",
            fiber->thread_name()->c_str(state), fiber->fiber_id()->to_native());
      }
    }

    state->vm()->metrics().system.fibers_created++;

    return fiber;
  }

  String* Fiber::status(STATE) {
    switch(status()) {
      case eCreated:
        return String::create(state, "created");
        break;
      case eRunning:
        return String::create(state, "run");
        break;
      case eYielding:
        return String::create(state, "yield");
        break;
      case eTransfer:
        return String::create(state, "transfer");
        break;
      case eDead:
        return String::create(state, "dead");
        break;
    }

    return String::create(state, "unknown");
  }

  Object* Fiber::resume(STATE, Arguments& args) {
    if(status() == eCreated) {
      start(state, args);
    } else if(status() == eTransfer) {
      Exception::raise_fiber_error(state, "attempt to resume transfered fiber");
    } else if(status() == eRunning) {
      Exception::raise_fiber_error(state, "attempt to resume running fiber");
    } else if(status() == eDead) {
      Exception::raise_fiber_error(state, "attempt to resume dead fiber");
    } else if(root_p()) {
      Exception::raise_fiber_error(state, "attempt to resume root fiber");
    }

    status(eRunning);
    unpack_arguments(state, args);
    invoke_context(state->vm());

    // Being cooperative...
    restart(state);

    // Through the worm hole...
    state->vm()->fiber()->suspend(state);

    // We're back...
    return return_value(state);
  }

  Object* Fiber::transfer(STATE, Arguments& args) {
    if(status() == eCreated) {
      start(state, args);
    } else if(state->vm()->fiber() == this) {
      return args.as_array(state);
    } else if(status() == eDead) {
      Exception::raise_fiber_error(state, "attempt to transfer to dead fiber");
    }

    status(eTransfer);
    unpack_arguments(state, args);
    invoke_context(state->vm()->thread()->vm());

    // Being cooperative...
    restart(state);

    // Through the worm hole...
    state->vm()->fiber()->suspend(state);

    // We're back...
    return return_value(state);
  }

  Object* Fiber::s_yield(STATE, Arguments& args) {
    Fiber* fiber = state->vm()->fiber();
    OnStack<1> os(state, fiber);

    if(fiber->root_p()) {
      Exception::raise_fiber_error(state, "can't yield from root fiber");
    } else if(fiber->status() == eTransfer) {
      Exception::raise_fiber_error(state, "can't yield from transferred fiber");
    }

    fiber->unpack_arguments(state, args);
    fiber->status(eYielding);

    // Being cooperative...
    fiber->invoke_context()->fiber()->restart(state);

    // Through the worm hole...
    fiber->suspend(state);

    // We're back...
    return fiber->return_value(state);
  }

  void Fiber::finalize(STATE, Fiber* fib) {
    if(state->shared().config.machine_fiber_log_finalizer.value) {
      logger::write("fiber: finalizer: %s, %d",
          fib->thread_name()->c_str(state), fib->fiber_id()->to_native());
    }
  }
}
<|endoftext|>