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

#include "views/bubble/bubble_frame_view.h"

#include <algorithm>

#include "views/bubble/bubble_border.h"
#include "views/bubble/border_contents_view.h"
#include "views/widget/widget.h"
#include "views/window/client_view.h"

namespace views {

BubbleFrameView::BubbleFrameView(BubbleBorder::ArrowLocation location,
                                 const gfx::Size& client_size,
                                 SkColor color,
                                 bool allow_bubble_offscreen)
    : border_contents_(new BorderContentsView()),
      location_(location),
      allow_bubble_offscreen_(allow_bubble_offscreen) {
  border_contents_->Init();
  bubble_border()->set_arrow_location(location_);
  bubble_border()->set_background_color(color);
  AddChildView(border_contents_);
  gfx::Rect bounds(gfx::Point(), client_size);
  gfx::Rect windows_bounds = GetWindowBoundsForClientBounds(bounds);
  border_contents_->SetBoundsRect(
      gfx::Rect(gfx::Point(), windows_bounds.size()));
  SetBoundsRect(windows_bounds);
}

BubbleFrameView::~BubbleFrameView() {}

gfx::Rect BubbleFrameView::GetBoundsForClientView() const {
  gfx::Insets margin;
  bubble_border()->GetInsets(&margin);
  margin += border_contents_->content_margins();
  return gfx::Rect(margin.left(),
                   margin.top(),
                   std::max(width() - margin.width(), 0),
                   std::max(height() - margin.height(), 0));
}

gfx::Rect BubbleFrameView::GetWindowBoundsForClientBounds(
    const gfx::Rect& client_bounds) const {
  // The |client_bounds| origin is the bubble arrow anchor point.
  gfx::Rect position_relative_to(client_bounds.origin(), gfx::Size());
  // The |client_bounds| size is the bubble client view size.
  gfx::Rect content_bounds;
  gfx::Rect window_bounds;
  border_contents_->SizeAndGetBounds(position_relative_to,
                                     location_,
                                     allow_bubble_offscreen_,
                                     client_bounds.size(),
                                     &content_bounds,
                                     &window_bounds);
  return window_bounds;
}

int BubbleFrameView::NonClientHitTest(const gfx::Point& point) {
  return GetWidget()->client_view()->NonClientHitTest(point);
}

gfx::Size BubbleFrameView::GetPreferredSize() {
  Widget* widget = GetWidget();
  gfx::Rect rect(gfx::Point(), widget->client_view()->GetPreferredSize());
  return widget->non_client_view()->GetWindowBoundsForClientBounds(rect).size();
}

BubbleBorder* BubbleFrameView::bubble_border() const {
  return static_cast<BubbleBorder*>(border_contents_->border());
}

}  // namespace views
<commit_msg>Set FillLayout on BubbleFrameView. Make bubbles' BorderContentsView fill the BubbleFrameView. Fixes a sizing issue with the in-progress bubble conversions.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "views/bubble/bubble_frame_view.h"

#include <algorithm>

#include "views/bubble/bubble_border.h"
#include "views/bubble/border_contents_view.h"
#include "views/layout/fill_layout.h"
#include "views/widget/widget.h"
#include "views/window/client_view.h"

namespace views {

BubbleFrameView::BubbleFrameView(BubbleBorder::ArrowLocation location,
                                 const gfx::Size& client_size,
                                 SkColor color,
                                 bool allow_bubble_offscreen)
    : border_contents_(new BorderContentsView()),
      location_(location),
      allow_bubble_offscreen_(allow_bubble_offscreen) {
  border_contents_->Init();
  bubble_border()->set_arrow_location(location_);
  bubble_border()->set_background_color(color);
  SetLayoutManager(new views::FillLayout());
  AddChildView(border_contents_);
  gfx::Rect bounds(gfx::Point(), client_size);
  gfx::Rect windows_bounds = GetWindowBoundsForClientBounds(bounds);
  border_contents_->SetBoundsRect(
      gfx::Rect(gfx::Point(), windows_bounds.size()));
  SetBoundsRect(windows_bounds);
}

BubbleFrameView::~BubbleFrameView() {}

gfx::Rect BubbleFrameView::GetBoundsForClientView() const {
  gfx::Insets margin;
  bubble_border()->GetInsets(&margin);
  margin += border_contents_->content_margins();
  return gfx::Rect(margin.left(),
                   margin.top(),
                   std::max(width() - margin.width(), 0),
                   std::max(height() - margin.height(), 0));
}

gfx::Rect BubbleFrameView::GetWindowBoundsForClientBounds(
    const gfx::Rect& client_bounds) const {
  // The |client_bounds| origin is the bubble arrow anchor point.
  gfx::Rect position_relative_to(client_bounds.origin(), gfx::Size());
  // The |client_bounds| size is the bubble client view size.
  gfx::Rect content_bounds;
  gfx::Rect window_bounds;
  border_contents_->SizeAndGetBounds(position_relative_to,
                                     location_,
                                     allow_bubble_offscreen_,
                                     client_bounds.size(),
                                     &content_bounds,
                                     &window_bounds);
  return window_bounds;
}

int BubbleFrameView::NonClientHitTest(const gfx::Point& point) {
  return GetWidget()->client_view()->NonClientHitTest(point);
}

gfx::Size BubbleFrameView::GetPreferredSize() {
  Widget* widget = GetWidget();
  gfx::Rect rect(gfx::Point(), widget->client_view()->GetPreferredSize());
  return widget->non_client_view()->GetWindowBoundsForClientBounds(rect).size();
}

BubbleBorder* BubbleFrameView::bubble_border() const {
  return static_cast<BubbleBorder*>(border_contents_->border());
}

}  // namespace views
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko, Jean-Francois Doyon
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
//$Id: mapnik_envelope.cc 27 2005-03-30 21:45:40Z pavlenko $

// boost
#include <boost/python.hpp>

// mapnik
#include <mapnik/box2d.hpp>
#include <mapnik/value_error.hpp>

using mapnik::coord;
using mapnik::box2d;

struct envelope_pickle_suite : boost::python::pickle_suite
{
    static boost::python::tuple
    getinitargs(const box2d<double>& e)
    {
        using namespace boost::python;
        return boost::python::make_tuple(e.minx(),e.miny(),e.maxx(),e.maxy());
    }
};

box2d<double> from_string(std::string const& s)
{
    box2d<double> bbox;
    bool success = bbox.from_string(s);
    if (success)
    {
        return bbox;
    }
    else
    {
        std::stringstream ss;
        ss << "Could not parse bbox from string: '" << s << "'";
        throw mapnik::value_error(ss.str());
    }
}

//define overloads here
void (box2d<double>::*width_p1)(double) = &box2d<double>::width;
double (box2d<double>::*width_p2)() const = &box2d<double>::width;

void (box2d<double>::*height_p1)(double) = &box2d<double>::height;
double (box2d<double>::*height_p2)() const = &box2d<double>::height;

void (box2d<double>::*expand_to_include_p1)(double,double) = &box2d<double>::expand_to_include;
void (box2d<double>::*expand_to_include_p2)(coord<double,2> const& ) = &box2d<double>::expand_to_include;
void (box2d<double>::*expand_to_include_p3)(box2d<double> const& ) = &box2d<double>::expand_to_include;

bool (box2d<double>::*contains_p1)(double,double) const = &box2d<double>::contains;
bool (box2d<double>::*contains_p2)(coord<double,2> const&) const = &box2d<double>::contains;
bool (box2d<double>::*contains_p3)(box2d<double> const&) const = &box2d<double>::contains;

//intersects
bool (box2d<double>::*intersects_p1)(double,double) const = &box2d<double>::intersects;
bool (box2d<double>::*intersects_p2)(coord<double,2> const&) const = &box2d<double>::intersects;
bool (box2d<double>::*intersects_p3)(box2d<double> const&) const = &box2d<double>::intersects;

// intersect
box2d<double> (box2d<double>::*intersect)(box2d<double> const&) const = &box2d<double>::intersect;

// re_center
void (box2d<double>::*re_center_p1)(double,double) = &box2d<double>::re_center;
void (box2d<double>::*re_center_p2)(coord<double,2> const& ) = &box2d<double>::re_center;

// clip
void (box2d<double>::*clip)(box2d<double> const&) = &box2d<double>::clip;

void export_envelope()
{
    using namespace boost::python;
    class_<box2d<double> >("Box2d",
                           // class docstring is in mapnik/__init__.py, class _Coord
                           init<double,double,double,double>(
                               (arg("minx"),arg("miny"),arg("maxx"),arg("maxy")),
                               "Constructs a new envelope from the coordinates\n"
                               "of its lower left and upper right corner points.\n"))
        .def(init<>("Equivalent to Box2d(0, 0, -1, -1).\n"))
        .def(init<const coord<double,2>&, const coord<double,2>&>(
                 (arg("ll"),arg("ur")),
                 "Equivalent to Box2d(ll.x, ll.y, ur.x, ur.y).\n"))
        .def("from_string",from_string)
        .staticmethod("from_string")
        .add_property("minx", &box2d<double>::minx,
                      "X coordinate for the lower left corner")
        .add_property("miny", &box2d<double>::miny,
                      "Y coordinate for the lower left corner")
        .add_property("maxx", &box2d<double>::maxx,
                      "X coordinate for the upper right corner")
        .add_property("maxy", &box2d<double>::maxy,
                      "Y coordinate for the upper right corner")
        .def("center", &box2d<double>::center,
             "Returns the coordinates of the center of the bounding box.\n"
             "\n"
             "Example:\n"
             ">>> e = Box2d(0, 0, 100, 100)\n"
             ">>> e.center()\n"
             "Coord(50, 50)\n")
        .def("center", re_center_p1,
             (arg("x"), arg("y")),
             "Moves the envelope so that the given coordinates become its new center.\n"
             "The width and the height are preserved.\n"
             "\n "
             "Example:\n"
             ">>> e = Box2d(0, 0, 100, 100)\n"
             ">>> e.center(60, 60)\n"
             ">>> e.center()\n"
             "Coord(60.0,60.0)\n"
             ">>> (e.width(), e.height())\n"
             "(100.0, 100.0)\n"
             ">>> e\n"
             "Box2d(10.0, 10.0, 110.0, 110.0)\n"
            )
        .def("center", re_center_p2,
             (arg("Coord")),
             "Moves the envelope so that the given coordinates become its new center.\n"
             "The width and the height are preserved.\n"
             "\n "
             "Example:\n"
             ">>> e = Box2d(0, 0, 100, 100)\n"
             ">>> e.center(Coord60, 60)\n"
             ">>> e.center()\n"
             "Coord(60.0,60.0)\n"
             ">>> (e.width(), e.height())\n"
             "(100.0, 100.0)\n"
             ">>> e\n"
             "Box2d(10.0, 10.0, 110.0, 110.0)\n"
            )
        .def("clip", clip,
             (arg("other")),
             "Clip the envelope based on the bounds of another envelope.\n"
             "\n "
             "Example:\n"
             ">>> e = Box2d(0, 0, 100, 100)\n"
             ">>> e.center(Coord60, 60)\n"
             ">>> e.center()\n"
             "Coord(60.0,60.0)\n"
             ">>> (e.width(), e.height())\n"
             "(100.0, 100.0)\n"
             ">>> e\n"
             "Box2d(10.0, 10.0, 110.0, 110.0)\n"
            )
        .def("width", width_p1,
             (arg("new_width")),
             "Sets the width to new_width of the envelope preserving its center.\n"
             "\n "
             "Example:\n"
             ">>> e = Box2d(0, 0, 100, 100)\n"
             ">>> e.width(120)\n"
             ">>> e.center()\n"
             "Coord(50.0,50.0)\n"
             ">>> e\n"
             "Box2d(-10.0, 0.0, 110.0, 100.0)\n"
            )
        .def("width", width_p2,
             "Returns the width of this envelope.\n"
            )
        .def("height", height_p1,
             (arg("new_height")),
             "Sets the height to new_height of the envelope preserving its center.\n"
             "\n "
             "Example:\n"
             ">>> e = Box2d(0, 0, 100, 100)\n"
             ">>> e.height(120)\n"
             ">>> e.center()\n"
             "Coord(50.0,50.0)\n"
             ">>> e\n"
             "Box2d(0.0, -10.0, 100.0, 110.0)\n"
            )
        .def("height", height_p2,
             "Returns the height of this envelope.\n"
            )
        .def("expand_to_include",expand_to_include_p1,
             (arg("x"),arg("y")),
             "Expands this envelope to include the point given by x and y.\n"
             "\n"
             "Example:\n",
             ">>> e = Box2d(0, 0, 100, 100)\n"
             ">>> e.expand_to_include(110, 110)\n"
             ">>> e\n"
             "Box2d(0.0, 00.0, 110.0, 110.0)\n"
            )
        .def("expand_to_include",expand_to_include_p2,
             (arg("p")),
             "Equivalent to expand_to_include(p.x, p.y)\n"
            )
        .def("expand_to_include",expand_to_include_p3,
             (arg("other")),
             "Equivalent to:\n"
             "  expand_to_include(other.minx, other.miny)\n"
             "  expand_to_include(other.maxx, other.maxy)\n"
            )
        .def("contains",contains_p1,
             (arg("x"),arg("y")),
             "Returns True iff this envelope contains the point\n"
             "given by x and y.\n"
            )
        .def("contains",contains_p2,
             (arg("p")),
             "Equivalent to contains(p.x, p.y)\n"
            )
        .def("contains",contains_p3,
             (arg("other")),
             "Equivalent to:\n"
             "  contains(other.minx, other.miny) and contains(other.maxx, other.maxy)\n"
            )
        .def("intersects",intersects_p1,
             (arg("x"),arg("y")),
             "Returns True iff this envelope intersects the point\n"
             "given by x and y.\n"
             "\n"
             "Note: For points, intersection is equivalent\n"
             "to containment, i.e. the following holds:\n"
             "   e.contains(x, y) == e.intersects(x, y)\n"
            )
        .def("intersects",intersects_p2,
             (arg("p")),
             "Equivalent to contains(p.x, p.y)\n")
        .def("intersects",intersects_p3,
             (arg("other")),
             "Returns True iff this envelope intersects the other envelope,\n"
             "This relationship is symmetric."
             "\n"
             "Example:\n"
             ">>> e1 = Box2d(0, 0, 100, 100)\n"
             ">>> e2 = Box2d(50, 50, 150, 150)\n"
             ">>> e1.intersects(e2)\n"
             "True\n"
             ">>> e1.contains(e2)\n"
             "False\n"
            )
        .def("intersect",intersect,
             (arg("other")),
             "Returns the overlap of this envelope and the other envelope\n"
             "as a new envelope.\n"
             "\n"
             "Example:\n"
             ">>> e1 = Box2d(0, 0, 100, 100)\n"
             ">>> e2 = Box2d(50, 50, 150, 150)\n"
             ">>> e1.intersect(e2)\n"
             "Box2d(50.0, 50.0, 100.0, 100.0)\n"
            )
        .def(self == self) // __eq__
        .def(self + self)  // __add__
        //.def(self - self)  // __sub__
        .def(self * float()) // __mult__
        .def(float() * self)
        .def(self / float()) // __div__
        .def("__getitem__",&box2d<double>::operator[])
        .def_pickle(envelope_pickle_suite())
        ;
}
<commit_msg>+ add __neq__ operator<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko, Jean-Francois Doyon
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
//$Id: mapnik_envelope.cc 27 2005-03-30 21:45:40Z pavlenko $

// boost
#include <boost/python.hpp>

// mapnik
#include <mapnik/box2d.hpp>
#include <mapnik/value_error.hpp>

using mapnik::coord;
using mapnik::box2d;

struct envelope_pickle_suite : boost::python::pickle_suite
{
    static boost::python::tuple
    getinitargs(const box2d<double>& e)
    {
        using namespace boost::python;
        return boost::python::make_tuple(e.minx(),e.miny(),e.maxx(),e.maxy());
    }
};

box2d<double> from_string(std::string const& s)
{
    box2d<double> bbox;
    bool success = bbox.from_string(s);
    if (success)
    {
        return bbox;
    }
    else
    {
        std::stringstream ss;
        ss << "Could not parse bbox from string: '" << s << "'";
        throw mapnik::value_error(ss.str());
    }
}

//define overloads here
void (box2d<double>::*width_p1)(double) = &box2d<double>::width;
double (box2d<double>::*width_p2)() const = &box2d<double>::width;

void (box2d<double>::*height_p1)(double) = &box2d<double>::height;
double (box2d<double>::*height_p2)() const = &box2d<double>::height;

void (box2d<double>::*expand_to_include_p1)(double,double) = &box2d<double>::expand_to_include;
void (box2d<double>::*expand_to_include_p2)(coord<double,2> const& ) = &box2d<double>::expand_to_include;
void (box2d<double>::*expand_to_include_p3)(box2d<double> const& ) = &box2d<double>::expand_to_include;

bool (box2d<double>::*contains_p1)(double,double) const = &box2d<double>::contains;
bool (box2d<double>::*contains_p2)(coord<double,2> const&) const = &box2d<double>::contains;
bool (box2d<double>::*contains_p3)(box2d<double> const&) const = &box2d<double>::contains;

//intersects
bool (box2d<double>::*intersects_p1)(double,double) const = &box2d<double>::intersects;
bool (box2d<double>::*intersects_p2)(coord<double,2> const&) const = &box2d<double>::intersects;
bool (box2d<double>::*intersects_p3)(box2d<double> const&) const = &box2d<double>::intersects;

// intersect
box2d<double> (box2d<double>::*intersect)(box2d<double> const&) const = &box2d<double>::intersect;

// re_center
void (box2d<double>::*re_center_p1)(double,double) = &box2d<double>::re_center;
void (box2d<double>::*re_center_p2)(coord<double,2> const& ) = &box2d<double>::re_center;

// clip
void (box2d<double>::*clip)(box2d<double> const&) = &box2d<double>::clip;

void export_envelope()
{
    using namespace boost::python;
    class_<box2d<double> >("Box2d",
                           // class docstring is in mapnik/__init__.py, class _Coord
                           init<double,double,double,double>(
                               (arg("minx"),arg("miny"),arg("maxx"),arg("maxy")),
                               "Constructs a new envelope from the coordinates\n"
                               "of its lower left and upper right corner points.\n"))
        .def(init<>("Equivalent to Box2d(0, 0, -1, -1).\n"))
        .def(init<const coord<double,2>&, const coord<double,2>&>(
                 (arg("ll"),arg("ur")),
                 "Equivalent to Box2d(ll.x, ll.y, ur.x, ur.y).\n"))
        .def("from_string",from_string)
        .staticmethod("from_string")
        .add_property("minx", &box2d<double>::minx,
                      "X coordinate for the lower left corner")
        .add_property("miny", &box2d<double>::miny,
                      "Y coordinate for the lower left corner")
        .add_property("maxx", &box2d<double>::maxx,
                      "X coordinate for the upper right corner")
        .add_property("maxy", &box2d<double>::maxy,
                      "Y coordinate for the upper right corner")
        .def("center", &box2d<double>::center,
             "Returns the coordinates of the center of the bounding box.\n"
             "\n"
             "Example:\n"
             ">>> e = Box2d(0, 0, 100, 100)\n"
             ">>> e.center()\n"
             "Coord(50, 50)\n")
        .def("center", re_center_p1,
             (arg("x"), arg("y")),
             "Moves the envelope so that the given coordinates become its new center.\n"
             "The width and the height are preserved.\n"
             "\n "
             "Example:\n"
             ">>> e = Box2d(0, 0, 100, 100)\n"
             ">>> e.center(60, 60)\n"
             ">>> e.center()\n"
             "Coord(60.0,60.0)\n"
             ">>> (e.width(), e.height())\n"
             "(100.0, 100.0)\n"
             ">>> e\n"
             "Box2d(10.0, 10.0, 110.0, 110.0)\n"
            )
        .def("center", re_center_p2,
             (arg("Coord")),
             "Moves the envelope so that the given coordinates become its new center.\n"
             "The width and the height are preserved.\n"
             "\n "
             "Example:\n"
             ">>> e = Box2d(0, 0, 100, 100)\n"
             ">>> e.center(Coord60, 60)\n"
             ">>> e.center()\n"
             "Coord(60.0,60.0)\n"
             ">>> (e.width(), e.height())\n"
             "(100.0, 100.0)\n"
             ">>> e\n"
             "Box2d(10.0, 10.0, 110.0, 110.0)\n"
            )
        .def("clip", clip,
             (arg("other")),
             "Clip the envelope based on the bounds of another envelope.\n"
             "\n "
             "Example:\n"
             ">>> e = Box2d(0, 0, 100, 100)\n"
             ">>> e.center(Coord60, 60)\n"
             ">>> e.center()\n"
             "Coord(60.0,60.0)\n"
             ">>> (e.width(), e.height())\n"
             "(100.0, 100.0)\n"
             ">>> e\n"
             "Box2d(10.0, 10.0, 110.0, 110.0)\n"
            )
        .def("width", width_p1,
             (arg("new_width")),
             "Sets the width to new_width of the envelope preserving its center.\n"
             "\n "
             "Example:\n"
             ">>> e = Box2d(0, 0, 100, 100)\n"
             ">>> e.width(120)\n"
             ">>> e.center()\n"
             "Coord(50.0,50.0)\n"
             ">>> e\n"
             "Box2d(-10.0, 0.0, 110.0, 100.0)\n"
            )
        .def("width", width_p2,
             "Returns the width of this envelope.\n"
            )
        .def("height", height_p1,
             (arg("new_height")),
             "Sets the height to new_height of the envelope preserving its center.\n"
             "\n "
             "Example:\n"
             ">>> e = Box2d(0, 0, 100, 100)\n"
             ">>> e.height(120)\n"
             ">>> e.center()\n"
             "Coord(50.0,50.0)\n"
             ">>> e\n"
             "Box2d(0.0, -10.0, 100.0, 110.0)\n"
            )
        .def("height", height_p2,
             "Returns the height of this envelope.\n"
            )
        .def("expand_to_include",expand_to_include_p1,
             (arg("x"),arg("y")),
             "Expands this envelope to include the point given by x and y.\n"
             "\n"
             "Example:\n",
             ">>> e = Box2d(0, 0, 100, 100)\n"
             ">>> e.expand_to_include(110, 110)\n"
             ">>> e\n"
             "Box2d(0.0, 00.0, 110.0, 110.0)\n"
            )
        .def("expand_to_include",expand_to_include_p2,
             (arg("p")),
             "Equivalent to expand_to_include(p.x, p.y)\n"
            )
        .def("expand_to_include",expand_to_include_p3,
             (arg("other")),
             "Equivalent to:\n"
             "  expand_to_include(other.minx, other.miny)\n"
             "  expand_to_include(other.maxx, other.maxy)\n"
            )
        .def("contains",contains_p1,
             (arg("x"),arg("y")),
             "Returns True iff this envelope contains the point\n"
             "given by x and y.\n"
            )
        .def("contains",contains_p2,
             (arg("p")),
             "Equivalent to contains(p.x, p.y)\n"
            )
        .def("contains",contains_p3,
             (arg("other")),
             "Equivalent to:\n"
             "  contains(other.minx, other.miny) and contains(other.maxx, other.maxy)\n"
            )
        .def("intersects",intersects_p1,
             (arg("x"),arg("y")),
             "Returns True iff this envelope intersects the point\n"
             "given by x and y.\n"
             "\n"
             "Note: For points, intersection is equivalent\n"
             "to containment, i.e. the following holds:\n"
             "   e.contains(x, y) == e.intersects(x, y)\n"
            )
        .def("intersects",intersects_p2,
             (arg("p")),
             "Equivalent to contains(p.x, p.y)\n")
        .def("intersects",intersects_p3,
             (arg("other")),
             "Returns True iff this envelope intersects the other envelope,\n"
             "This relationship is symmetric."
             "\n"
             "Example:\n"
             ">>> e1 = Box2d(0, 0, 100, 100)\n"
             ">>> e2 = Box2d(50, 50, 150, 150)\n"
             ">>> e1.intersects(e2)\n"
             "True\n"
             ">>> e1.contains(e2)\n"
             "False\n"
            )
        .def("intersect",intersect,
             (arg("other")),
             "Returns the overlap of this envelope and the other envelope\n"
             "as a new envelope.\n"
             "\n"
             "Example:\n"
             ">>> e1 = Box2d(0, 0, 100, 100)\n"
             ">>> e2 = Box2d(50, 50, 150, 150)\n"
             ">>> e1.intersect(e2)\n"
             "Box2d(50.0, 50.0, 100.0, 100.0)\n"
            )
        .def(self == self) // __eq__
        .def(self != self) // __neq__
        .def(self + self)  // __add__
        //.def(self - self)  // __sub__
        .def(self * float()) // __mult__
        .def(float() * self)
        .def(self / float()) // __div__
        .def("__getitem__",&box2d<double>::operator[])
        .def_pickle(envelope_pickle_suite())
        ;
}
<|endoftext|>


<commit_before><commit_msg>fixed: function with 4 args (0.9)<commit_after><|endoftext|>


<commit_before>#include "object_manipulation_actions/actionExecutorInspectLocation.h"
#include <pluginlib/class_list_macros.h>
#include <ork_to_planning_scene_msgs/UpdatePlanningSceneFromOrkAction.h>
//#include <moveit/move_group_interface/move_group.h>
#include <control_msgs/SingleJointPositionActionFeedback.h>
#include <control_msgs/SingleJointPositionFeedback.h>
#include <tidyup_utils/stringutil.h>
#include <symbolic_planning_utils/extractPose.h>
#include <symbolic_planning_utils/planning_scene_monitor.h>
#include <symbolic_planning_utils/planning_scene_service.h>

#include <set>
#include <boost/foreach.hpp>
#define for_each BOOST_FOREACH

#include <pluginlib/class_loader.h>
#include <ros/ros.h>

PLUGINLIB_EXPORT_CLASS(object_manipulation_actions::ActionExecutorInspectLocation, continual_planning_executive::ActionExecutorInterface)

namespace object_manipulation_actions
{
ActionExecutorInspectLocation::ActionExecutorInspectLocation() :
		actionLiftTorso_("torso_controller/position_joint_action", true),
		actionPointHead_("head_traj_controller/point_head_action", true),
		actionOrkToPs_("ork_to_planning_scene", true)
{
	actionTimeOut_ = ros::Duration(30.0);
	torsoPosition_ = -1.0;
	setTorsoPosition_ = false;

	ROS_INFO("ActionExecutorInspectLocation::%s: Waiting for torso_controller/position_joint_action "
			"action server to start.", __func__);
	actionLiftTorso_.waitForServer();

	ROS_INFO("ActionExecutorInspectLocation::%s: Waiting for head_traj_controller/point_head_action "
			"action server to start.", __func__);
	actionPointHead_.waitForServer();

	ROS_INFO("ActionExecutorInspectLocation::%s: Waiting for ork_to_planning_scene "
			"action server to start.", __func__);
	actionOrkToPs_.waitForServer();

	ROS_INFO("ActionExecutorInspectLocation::%s: Action clients are ready", __func__);

    ros::NodeHandle nhPriv("~");
    // Namespace is "/continual_planning_executive"(/vdist_head_to_table)
    nhPriv.param("vdist_head_to_table", vdist_head_to_table_, 0.8);
    nhPriv.param("vdist_threshold", vdist_threshold_, 0.002);
    nhPriv.param("min_torso_vel", min_torso_vel_, 0.0001);
    nhPriv.param("stallThreshold", stallThreshold_, 5);

    add_tables_ = true;
	verify_planning_scene_update_ = true;

	psi_.reset(new symbolic_planning_utils::PlanningSceneMonitor());
	//psi_.reset(new symbolic_planning_utils::PlanningSceneService());
}

ActionExecutorInspectLocation::~ActionExecutorInspectLocation()
{
}

void ActionExecutorInspectLocation::initialize(const std::deque<std::string> & arguments)
{
	ROS_ASSERT(arguments.size() >= 3);
	action_name_ = arguments[0];
	action_topic_ = arguments[1];
	for (int i = 2; i < arguments.size(); i++)
	{
		predicate_names_.push_back(arguments[i]);
	}

}

bool ActionExecutorInspectLocation::canExecute(const DurativeAction & a, const SymbolicState & currentState) const
{
	return a.name == action_name_;
}

bool ActionExecutorInspectLocation::executeBlocking(const DurativeAction & a, SymbolicState & currentState)
{
	ROS_ASSERT(a.parameters.size() == 2);
	std::string mani_loc = a.parameters[0];
	std::string table 	 = a.parameters[1];

	// get tablePose
	geometry_msgs::PoseStamped tablePose;
	if (!symbolic_planning_utils::extractPoseStampedFromSymbolicState(currentState, table, tablePose))
	{
		ROS_ERROR("ActionExecutorInspectLocation::%s: Could not extract pose of table:%s from symbolic state", __func__, table.c_str());
		return false;
	}

	if (!executeLiftTorso(tablePose))
		return false;

	if (!executePointHead(tablePose))
		return false;

	if (!executeUpdatePlanningSceneFromORK(currentState, table, mani_loc))
		return false;

	renameTableCollisionObject(table);

	return true;
}

void ActionExecutorInspectLocation::cancelAction()
{
}

void ActionExecutorInspectLocation::feedbackLiftTorso(const control_msgs::SingleJointPositionFeedbackConstPtr& feedback)
{
	if (setTorsoPosition_)
	{
		torsoPosition_ = feedback->position;
		actionLiftTorso_.cancelGoal();
		setTorsoPosition_ = false;
		return;
	}

	if (fabs(feedback->velocity) < min_torso_vel_)
	{
		if (startStallTime_ == 0)
			startStallTime_ = ros::Time::now().toSec();
		// waited longer than stallThreshold_ -> torso is stalled
		else if ((ros::Time::now().toSec() - startStallTime_) > stallThreshold_)
		{
			ROS_WARN("ActionExecutorInspectLocation::%s: Torso stalled - limit reached (Position: %lf, Velocity: %lf)",
					__func__, feedback->position, feedback->velocity);
			actionLiftTorso_.cancelGoal();
			control_msgs::SingleJointPositionGoal liftTorsoGoal;
			liftTorsoGoal.position = feedback->position;
			actionLiftTorso_.sendGoal(liftTorsoGoal);
		}
	}

	ROS_DEBUG_STREAM_THROTTLE(0.10, "Torso Joint Position: " << feedback->position << " , Velocity: " << feedback->velocity << " , Error: " << feedback->error);

}

bool ActionExecutorInspectLocation::executeLiftTorso(const geometry_msgs::PoseStamped tablePose)
{
	// compute difference in height between head_mount_link and table
    // transform tablePose into frame of /base link
    geometry_msgs::PoseStamped table_transformed;
    try {
        tf_.waitForTransform("/base_link", tablePose.header.frame_id, tablePose.header.stamp,
                ros::Duration(0.5));
        tf_.transformPose("/base_link", tablePose, table_transformed);
    } catch (tf::TransformException& ex) {
        ROS_ERROR("%s", ex.what());
        return false;
    }

    ROS_DEBUG_STREAM("table pose" << tablePose);
    ROS_DEBUG_STREAM("table pose transformed" << table_transformed);

    // transform headPose into frame of /base link
    tf::Pose tfHead;
    geometry_msgs::PoseStamped headPose;
    headPose.header.frame_id = "/head_mount_link";
    headPose.header.stamp = ros::Time::now();
    geometry_msgs::Quaternion q;
    q.x = 0;
    q.y = 0;
    q.z = 0;
    q.w = 1;
    headPose.pose.orientation = q;
    geometry_msgs::Point p;
    p.x = 0;
    p.y = 0;
    p.z = 0;
    headPose.pose.position = p;

    geometry_msgs::PoseStamped head_transformed;
    try {
        tf_.waitForTransform("/map", headPose.header.frame_id, headPose.header.stamp,
                ros::Duration(0.5));
        tf_.transformPose("/map", headPose, head_transformed);
    } catch (tf::TransformException& ex) {
        ROS_ERROR("%s", ex.what());
        return false;
    }
    ROS_DEBUG_STREAM("head pose transformed" << head_transformed);

    double distance = fabs(head_transformed.pose.position.z - table_transformed.pose.position.z);
    ROS_DEBUG("Distance: %lf, head: %lf, table: %lf", distance, head_transformed.pose.position.z, table_transformed.pose.position.z);
    if (vdist_head_to_table_ - vdist_threshold_ < distance &&
    	distance < vdist_head_to_table_ + vdist_threshold_)
    	// head_mount_link is about vdist_head_to_table_ above table, no need to lift torso
    	return true;

    setTorsoPosition();

	ROS_INFO("ActionExecutorInspectLocation::%s: Sending LiftTorso request.", __func__);
	control_msgs::SingleJointPositionGoal liftTorsoGoal;
	liftTorsoGoal.position = torsoPosition_ + vdist_head_to_table_ - distance;

	ROS_DEBUG_STREAM("Lift torso about : " << torsoPosition_ << " + " << vdist_head_to_table_ << " - " << distance <<
			" = " << torsoPosition_ + vdist_head_to_table_ - distance);

	startStallTime_ = 0;
	//actionLiftTorso_.sendGoal(liftTorsoGoal);
	// Checking if torso is stalled, if so cancel action and start new action with current position
	// Then actionLiftTorso will end immediately with success
	actionLiftTorso_.sendGoal(liftTorsoGoal,
		actionlib::SimpleActionClient<control_msgs::SingleJointPositionAction>::SimpleDoneCallback(), // = NULL
		actionlib::SimpleActionClient<control_msgs::SingleJointPositionAction>::SimpleActiveCallback(), // = NULL
		boost::bind(&ActionExecutorInspectLocation::feedbackLiftTorso, this, _1));

	bool finished_before_timeout = actionLiftTorso_.waitForResult(actionTimeOut_);
	if (finished_before_timeout)
	{
		actionlib::SimpleClientGoalState state = actionLiftTorso_.getState();
		ROS_DEBUG("ActionExecutorInspectLocation::%s: Lift Torso Action finished: %s", __func__, state.toString().c_str());
		if (state != actionlib::SimpleClientGoalState::SUCCEEDED)
		{
			ROS_ERROR("ActionExecutorInspectLocation::%s: Lift Torso Action failed.", __func__);
			return false;
		}
	}
	return true;
}

void ActionExecutorInspectLocation::setTorsoPosition()
{
	ROS_INFO("ActionExecutorInspectLocation::%s: Sending LiftTorso request.", __func__);
	control_msgs::SingleJointPositionGoal liftTorsoGoal;
	liftTorsoGoal.position = 0.32;
	setTorsoPosition_ = true;

	// http://library.isr.ist.utl.pt/docs/roswiki/actionlib_tutorials%282f%29Tutorials%282f%29Writing%2820%29a%2820%29Callback%2820%29Based%2820%29Simple%2820%29Action%2820%29Client.html
//	actionLiftTorso_.sendGoal(liftTorsoGoal,
//		boost::bind(&ActionExecutorInspectLocation::doneLiftTorso, this, _1, _2),
//		actionlib::SimpleActionClient<control_msgs::SingleJointPositionAction>::SimpleActiveCallback(),
//		actionlib::SimpleActionClient<control_msgs::SingleJointPositionAction>::SimpleFeedbackCallback());

	actionLiftTorso_.sendGoal(liftTorsoGoal,
		actionlib::SimpleActionClient<control_msgs::SingleJointPositionAction>::SimpleDoneCallback(), // = NULL
		actionlib::SimpleActionClient<control_msgs::SingleJointPositionAction>::SimpleActiveCallback(), // = NULL
		boost::bind(&ActionExecutorInspectLocation::feedbackLiftTorso, this, _1));

	actionLiftTorso_.waitForResult(actionTimeOut_);
}

bool ActionExecutorInspectLocation::executePointHead(const geometry_msgs::PoseStamped tablePose)
{
	ROS_INFO("ActionExecutorInspectLocation::%s: Sending PointHead request.", __func__);
	control_msgs::PointHeadGoal pointHeadGoal;
	geometry_msgs::PointStamped target;
	// Set the target pose to the pose of the table
	target.point = tablePose.pose.position;
	target.header = tablePose.header;
	pointHeadGoal.target = target;
	// Using x-axis of frame "head_mount_link" for pointing
	pointHeadGoal.pointing_axis.x = 1;
	pointHeadGoal.pointing_axis.y = 0;
	pointHeadGoal.pointing_axis.z = 0;
	pointHeadGoal.pointing_frame = "head_mount_link";

	actionPointHead_.sendGoal(pointHeadGoal);

	bool finished_before_timeout = actionPointHead_.waitForResult(actionTimeOut_);
	if (finished_before_timeout)
	{
		actionlib::SimpleClientGoalState state = actionPointHead_.getState();
		ROS_DEBUG("ActionExecutorInspectLocation::%s: Point Head Action finished: %s", __func__, state.toString().c_str());
		if (state != actionlib::SimpleClientGoalState::SUCCEEDED)
		{
			ROS_ERROR("ActionExecutorInspectLocation::%s: Point Head Action failed.", __func__);
			return false;
		}
	}
	return true;
}

bool ActionExecutorInspectLocation::executeUpdatePlanningSceneFromORK(SymbolicState& currentState,
		const std::string& tableName, const std::string& manipulationLocation)
{
	// execute action ork-to-planning-scene
	ROS_INFO("ActionExecutorInspectLocation::%s: Sending UpdatePlanningSceneFromORK request.", __func__);
	ork_to_planning_scene_msgs::UpdatePlanningSceneFromOrkGoal updatePSGoal;
	updatePSGoal.verify_planning_scene_update = verify_planning_scene_update_;
	updatePSGoal.add_tables = add_tables_;
	updatePSGoal.table_prefix = tableName;

	const multimap<string, string> objects = currentState.getTypedObjects();
	std::pair<multimap<string, string>::const_iterator, multimap<string, string>::const_iterator> iterators = objects.equal_range("movable_object");
	for (multimap<string, string>::const_iterator it = iterators.first; it != iterators.second; it++)
	{
		Predicate on;
		on.name = "object-on";
		on.parameters.push_back(it->second);
		on.parameters.push_back(tableName);
		bool value = false;
		currentState.hasBooleanPredicate(on, &value);
		if (value)
		{
			updatePSGoal.expected_objects.push_back(it->second);
		}
	}
	actionOrkToPs_.sendGoal(updatePSGoal);
	bool finished_before_timeout = actionOrkToPs_.waitForResult(actionTimeOut_);
	if (finished_before_timeout)
	{
		actionlib::SimpleClientGoalState state = actionOrkToPs_.getState();
		ROS_DEBUG("ActionExecutorInspectLocation::%s: ORK to Planning Scene Action finished: %s", __func__, state.toString().c_str());
		if (state == actionlib::SimpleClientGoalState::SUCCEEDED)
		{
	    	// delete all movable objects from symbolic state, and re-add the important objects later (from PS)
			const multimap<string, string> objects = currentState.getTypedObjects();
			std::pair<multimap<string, string>::const_iterator, multimap<string, string>::const_iterator> iterators =
			        objects.equal_range("manipulation_location");
			for (multimap<string, string>::const_iterator it = iterators.first; it != iterators.second; it++)
			{
				// also predicates with the objects are removed
				ROS_INFO("ActionExecutorInspectLocation::%s: %s, %s, false", __func__, predicate_names_[0].c_str(), it->second.c_str());
				currentState.setBooleanPredicate(predicate_names_[0], it->second, false);
			}

			ROS_INFO("Inspect location succeeded.");
			for_each(const string& predicate, predicate_names_)
			{
				currentState.setBooleanPredicate(predicate, manipulationLocation, true);
			}
		}
		else
		{
			ROS_ERROR("ActionExecutorInspectLocation::%s: ORK to Planning Scene Action failed.", __func__);
			return false;
		}
	}
	return true;
}

void ActionExecutorInspectLocation::renameTableCollisionObject(const std::string& tableName)
{
	moveit_msgs::CollisionObject tableCO;
	forEach (const moveit_msgs::CollisionObject& co, psi_->getCollisionObjects())
	{
		if (StringUtil::startsWith(co.id, tableName))
		{
			ROS_INFO("ActionExecutorInspectLocation::%s: Found object with id: %s, renaming to: %s", __func__, co.id.c_str(), tableName.c_str());
			tableCO = co;
			psi_->renameCollisionObject(tableName, tableCO);
		}
	}
}

}; // namespace
<commit_msg>removed deletion of location-inspected-recently<commit_after>#include "object_manipulation_actions/actionExecutorInspectLocation.h"
#include <pluginlib/class_list_macros.h>
#include <ork_to_planning_scene_msgs/UpdatePlanningSceneFromOrkAction.h>
//#include <moveit/move_group_interface/move_group.h>
#include <control_msgs/SingleJointPositionActionFeedback.h>
#include <control_msgs/SingleJointPositionFeedback.h>
#include <tidyup_utils/stringutil.h>
#include <symbolic_planning_utils/extractPose.h>
#include <symbolic_planning_utils/planning_scene_monitor.h>
#include <symbolic_planning_utils/planning_scene_service.h>

#include <set>
#include <boost/foreach.hpp>
#define for_each BOOST_FOREACH

#include <pluginlib/class_loader.h>
#include <ros/ros.h>

PLUGINLIB_EXPORT_CLASS(object_manipulation_actions::ActionExecutorInspectLocation, continual_planning_executive::ActionExecutorInterface)

namespace object_manipulation_actions
{
ActionExecutorInspectLocation::ActionExecutorInspectLocation() :
		actionLiftTorso_("torso_controller/position_joint_action", true),
		actionPointHead_("head_traj_controller/point_head_action", true),
		actionOrkToPs_("ork_to_planning_scene", true)
{
	actionTimeOut_ = ros::Duration(30.0);
	torsoPosition_ = -1.0;
	setTorsoPosition_ = false;

	ROS_INFO("ActionExecutorInspectLocation::%s: Waiting for torso_controller/position_joint_action "
			"action server to start.", __func__);
	actionLiftTorso_.waitForServer();

	ROS_INFO("ActionExecutorInspectLocation::%s: Waiting for head_traj_controller/point_head_action "
			"action server to start.", __func__);
	actionPointHead_.waitForServer();

	ROS_INFO("ActionExecutorInspectLocation::%s: Waiting for ork_to_planning_scene "
			"action server to start.", __func__);
	actionOrkToPs_.waitForServer();

	ROS_INFO("ActionExecutorInspectLocation::%s: Action clients are ready", __func__);

    ros::NodeHandle nhPriv("~");
    // Namespace is "/continual_planning_executive"(/vdist_head_to_table)
    nhPriv.param("vdist_head_to_table", vdist_head_to_table_, 0.8);
    nhPriv.param("vdist_threshold", vdist_threshold_, 0.002);
    nhPriv.param("min_torso_vel", min_torso_vel_, 0.0001);
    nhPriv.param("stallThreshold", stallThreshold_, 5);

    add_tables_ = true;
	verify_planning_scene_update_ = true;

	psi_.reset(new symbolic_planning_utils::PlanningSceneMonitor());
	//psi_.reset(new symbolic_planning_utils::PlanningSceneService());
}

ActionExecutorInspectLocation::~ActionExecutorInspectLocation()
{
}

void ActionExecutorInspectLocation::initialize(const std::deque<std::string> & arguments)
{
	ROS_ASSERT(arguments.size() >= 3);
	action_name_ = arguments[0];
	action_topic_ = arguments[1];
	for (int i = 2; i < arguments.size(); i++)
	{
		predicate_names_.push_back(arguments[i]);
	}

}

bool ActionExecutorInspectLocation::canExecute(const DurativeAction & a, const SymbolicState & currentState) const
{
	return a.name == action_name_;
}

bool ActionExecutorInspectLocation::executeBlocking(const DurativeAction & a, SymbolicState & currentState)
{
	ROS_ASSERT(a.parameters.size() == 2);
	std::string mani_loc = a.parameters[0];
	std::string table 	 = a.parameters[1];

	// get tablePose
	geometry_msgs::PoseStamped tablePose;
	if (!symbolic_planning_utils::extractPoseStampedFromSymbolicState(currentState, table, tablePose))
	{
		ROS_ERROR("ActionExecutorInspectLocation::%s: Could not extract pose of table:%s from symbolic state", __func__, table.c_str());
		return false;
	}

	if (!executeLiftTorso(tablePose))
		return false;

	if (!executePointHead(tablePose))
		return false;

	if (!executeUpdatePlanningSceneFromORK(currentState, table, mani_loc))
		return false;

	renameTableCollisionObject(table);

	return true;
}

void ActionExecutorInspectLocation::cancelAction()
{
}

void ActionExecutorInspectLocation::feedbackLiftTorso(const control_msgs::SingleJointPositionFeedbackConstPtr& feedback)
{
	if (setTorsoPosition_)
	{
		torsoPosition_ = feedback->position;
		actionLiftTorso_.cancelGoal();
		setTorsoPosition_ = false;
		return;
	}

	if (fabs(feedback->velocity) < min_torso_vel_)
	{
		if (startStallTime_ == 0)
			startStallTime_ = ros::Time::now().toSec();
		// waited longer than stallThreshold_ -> torso is stalled
		else if ((ros::Time::now().toSec() - startStallTime_) > stallThreshold_)
		{
			ROS_WARN("ActionExecutorInspectLocation::%s: Torso stalled - limit reached (Position: %lf, Velocity: %lf)",
					__func__, feedback->position, feedback->velocity);
			actionLiftTorso_.cancelGoal();
			control_msgs::SingleJointPositionGoal liftTorsoGoal;
			liftTorsoGoal.position = feedback->position;
			actionLiftTorso_.sendGoal(liftTorsoGoal);
		}
	}

	ROS_DEBUG_STREAM_THROTTLE(0.10, "Torso Joint Position: " << feedback->position << " , Velocity: " << feedback->velocity << " , Error: " << feedback->error);

}

bool ActionExecutorInspectLocation::executeLiftTorso(const geometry_msgs::PoseStamped tablePose)
{
	// compute difference in height between head_mount_link and table
    // transform tablePose into frame of /base link
    geometry_msgs::PoseStamped table_transformed;
    try {
        tf_.waitForTransform("/base_link", tablePose.header.frame_id, tablePose.header.stamp,
                ros::Duration(0.5));
        tf_.transformPose("/base_link", tablePose, table_transformed);
    } catch (tf::TransformException& ex) {
        ROS_ERROR("%s", ex.what());
        return false;
    }

    ROS_DEBUG_STREAM("table pose" << tablePose);
    ROS_DEBUG_STREAM("table pose transformed" << table_transformed);

    // transform headPose into frame of /base link
    tf::Pose tfHead;
    geometry_msgs::PoseStamped headPose;
    headPose.header.frame_id = "/head_mount_link";
    headPose.header.stamp = ros::Time::now();
    geometry_msgs::Quaternion q;
    q.x = 0;
    q.y = 0;
    q.z = 0;
    q.w = 1;
    headPose.pose.orientation = q;
    geometry_msgs::Point p;
    p.x = 0;
    p.y = 0;
    p.z = 0;
    headPose.pose.position = p;

    geometry_msgs::PoseStamped head_transformed;
    try {
        tf_.waitForTransform("/map", headPose.header.frame_id, headPose.header.stamp,
                ros::Duration(0.5));
        tf_.transformPose("/map", headPose, head_transformed);
    } catch (tf::TransformException& ex) {
        ROS_ERROR("%s", ex.what());
        return false;
    }
    ROS_DEBUG_STREAM("head pose transformed" << head_transformed);

    double distance = fabs(head_transformed.pose.position.z - table_transformed.pose.position.z);
    ROS_DEBUG("Distance: %lf, head: %lf, table: %lf", distance, head_transformed.pose.position.z, table_transformed.pose.position.z);
    if (vdist_head_to_table_ - vdist_threshold_ < distance &&
    	distance < vdist_head_to_table_ + vdist_threshold_)
    	// head_mount_link is about vdist_head_to_table_ above table, no need to lift torso
    	return true;

    setTorsoPosition();

	ROS_INFO("ActionExecutorInspectLocation::%s: Sending LiftTorso request.", __func__);
	control_msgs::SingleJointPositionGoal liftTorsoGoal;
	liftTorsoGoal.position = torsoPosition_ + vdist_head_to_table_ - distance;

	ROS_DEBUG_STREAM("Lift torso about : " << torsoPosition_ << " + " << vdist_head_to_table_ << " - " << distance <<
			" = " << torsoPosition_ + vdist_head_to_table_ - distance);

	startStallTime_ = 0;
	//actionLiftTorso_.sendGoal(liftTorsoGoal);
	// Checking if torso is stalled, if so cancel action and start new action with current position
	// Then actionLiftTorso will end immediately with success
	actionLiftTorso_.sendGoal(liftTorsoGoal,
		actionlib::SimpleActionClient<control_msgs::SingleJointPositionAction>::SimpleDoneCallback(), // = NULL
		actionlib::SimpleActionClient<control_msgs::SingleJointPositionAction>::SimpleActiveCallback(), // = NULL
		boost::bind(&ActionExecutorInspectLocation::feedbackLiftTorso, this, _1));

	bool finished_before_timeout = actionLiftTorso_.waitForResult(actionTimeOut_);
	if (finished_before_timeout)
	{
		actionlib::SimpleClientGoalState state = actionLiftTorso_.getState();
		ROS_DEBUG("ActionExecutorInspectLocation::%s: Lift Torso Action finished: %s", __func__, state.toString().c_str());
		if (state != actionlib::SimpleClientGoalState::SUCCEEDED)
		{
			ROS_ERROR("ActionExecutorInspectLocation::%s: Lift Torso Action failed.", __func__);
			return false;
		}
	}
	return true;
}

void ActionExecutorInspectLocation::setTorsoPosition()
{
	ROS_INFO("ActionExecutorInspectLocation::%s: Sending LiftTorso request.", __func__);
	control_msgs::SingleJointPositionGoal liftTorsoGoal;
	liftTorsoGoal.position = 0.32;
	setTorsoPosition_ = true;

	// http://library.isr.ist.utl.pt/docs/roswiki/actionlib_tutorials%282f%29Tutorials%282f%29Writing%2820%29a%2820%29Callback%2820%29Based%2820%29Simple%2820%29Action%2820%29Client.html
//	actionLiftTorso_.sendGoal(liftTorsoGoal,
//		boost::bind(&ActionExecutorInspectLocation::doneLiftTorso, this, _1, _2),
//		actionlib::SimpleActionClient<control_msgs::SingleJointPositionAction>::SimpleActiveCallback(),
//		actionlib::SimpleActionClient<control_msgs::SingleJointPositionAction>::SimpleFeedbackCallback());

	actionLiftTorso_.sendGoal(liftTorsoGoal,
		actionlib::SimpleActionClient<control_msgs::SingleJointPositionAction>::SimpleDoneCallback(), // = NULL
		actionlib::SimpleActionClient<control_msgs::SingleJointPositionAction>::SimpleActiveCallback(), // = NULL
		boost::bind(&ActionExecutorInspectLocation::feedbackLiftTorso, this, _1));

	actionLiftTorso_.waitForResult(actionTimeOut_);
}

bool ActionExecutorInspectLocation::executePointHead(const geometry_msgs::PoseStamped tablePose)
{
	ROS_INFO("ActionExecutorInspectLocation::%s: Sending PointHead request.", __func__);
	control_msgs::PointHeadGoal pointHeadGoal;
	geometry_msgs::PointStamped target;
	// Set the target pose to the pose of the table
	target.point = tablePose.pose.position;
	target.header = tablePose.header;
	pointHeadGoal.target = target;
	// Using x-axis of frame "head_mount_link" for pointing
	pointHeadGoal.pointing_axis.x = 1;
	pointHeadGoal.pointing_axis.y = 0;
	pointHeadGoal.pointing_axis.z = 0;
	pointHeadGoal.pointing_frame = "head_mount_link";

	actionPointHead_.sendGoal(pointHeadGoal);

	bool finished_before_timeout = actionPointHead_.waitForResult(actionTimeOut_);
	if (finished_before_timeout)
	{
		actionlib::SimpleClientGoalState state = actionPointHead_.getState();
		ROS_DEBUG("ActionExecutorInspectLocation::%s: Point Head Action finished: %s", __func__, state.toString().c_str());
		if (state != actionlib::SimpleClientGoalState::SUCCEEDED)
		{
			ROS_ERROR("ActionExecutorInspectLocation::%s: Point Head Action failed.", __func__);
			return false;
		}
	}
	return true;
}

bool ActionExecutorInspectLocation::executeUpdatePlanningSceneFromORK(SymbolicState& currentState,
		const std::string& tableName, const std::string& manipulationLocation)
{
	// execute action ork-to-planning-scene
	ROS_INFO("ActionExecutorInspectLocation::%s: Sending UpdatePlanningSceneFromORK request.", __func__);
	ork_to_planning_scene_msgs::UpdatePlanningSceneFromOrkGoal updatePSGoal;
	updatePSGoal.verify_planning_scene_update = verify_planning_scene_update_;
	updatePSGoal.add_tables = add_tables_;
	updatePSGoal.table_prefix = tableName;

	const multimap<string, string> objects = currentState.getTypedObjects();
	std::pair<multimap<string, string>::const_iterator, multimap<string, string>::const_iterator> iterators = objects.equal_range("movable_object");
	for (multimap<string, string>::const_iterator it = iterators.first; it != iterators.second; it++)
	{
		Predicate on;
		on.name = "object-on";
		on.parameters.push_back(it->second);
		on.parameters.push_back(tableName);
		bool value = false;
		currentState.hasBooleanPredicate(on, &value);
		if (value)
		{
			updatePSGoal.expected_objects.push_back(it->second);
		}
	}
	actionOrkToPs_.sendGoal(updatePSGoal);
	bool finished_before_timeout = actionOrkToPs_.waitForResult(actionTimeOut_);
	if (finished_before_timeout)
	{
		actionlib::SimpleClientGoalState state = actionOrkToPs_.getState();
		ROS_DEBUG("ActionExecutorInspectLocation::%s: ORK to Planning Scene Action finished: %s", __func__, state.toString().c_str());
		if (state == actionlib::SimpleClientGoalState::SUCCEEDED)
		{
			ROS_INFO("Inspect location succeeded.");
			for_each(const string& predicate, predicate_names_)
			{
				currentState.setBooleanPredicate(predicate, manipulationLocation, true);
			}
		}
		else
		{
			ROS_ERROR("ActionExecutorInspectLocation::%s: ORK to Planning Scene Action failed.", __func__);
			return false;
		}
	}
	return true;
}

void ActionExecutorInspectLocation::renameTableCollisionObject(const std::string& tableName)
{
	moveit_msgs::CollisionObject tableCO;
	forEach (const moveit_msgs::CollisionObject& co, psi_->getCollisionObjects())
	{
		if (StringUtil::startsWith(co.id, tableName))
		{
			ROS_INFO("ActionExecutorInspectLocation::%s: Found object with id: %s, renaming to: %s", __func__, co.id.c_str(), tableName.c_str());
			tableCO = co;
			psi_->renameCollisionObject(tableName, tableCO);
		}
	}
}

}; // namespace
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

#include "kudu/rpc/messenger.h"

#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

#include <gflags/gflags.h>
#include <glog/logging.h>
#include <list>
#include <mutex>
#include <set>
#include <string>

#include "kudu/gutil/gscoped_ptr.h"
#include "kudu/gutil/map-util.h"
#include "kudu/gutil/stl_util.h"
#include "kudu/gutil/strings/substitute.h"
#include "kudu/rpc/acceptor_pool.h"
#include "kudu/rpc/connection.h"
#include "kudu/rpc/constants.h"
#include "kudu/rpc/reactor.h"
#include "kudu/rpc/rpc_header.pb.h"
#include "kudu/rpc/rpc_service.h"
#include "kudu/rpc/rpcz_store.h"
#include "kudu/rpc/sasl_common.h"
#include "kudu/rpc/transfer.h"
#include "kudu/util/errno.h"
#include "kudu/util/flag_tags.h"
#include "kudu/util/metrics.h"
#include "kudu/util/monotime.h"
#include "kudu/util/net/socket.h"
#include "kudu/util/status.h"
#include "kudu/util/threadpool.h"
#include "kudu/util/trace.h"

using std::string;
using std::shared_ptr;
using strings::Substitute;

DEFINE_int32(rpc_default_keepalive_time_ms, 65000,
             "If an RPC connection from a client is idle for this amount of time, the server "
             "will disconnect the client.");
TAG_FLAG(rpc_default_keepalive_time_ms, advanced);

namespace kudu {
namespace rpc {

class Messenger;
class ServerBuilder;

MessengerBuilder::MessengerBuilder(std::string name)
    : name_(std::move(name)),
      connection_keepalive_time_(
          MonoDelta::FromMilliseconds(FLAGS_rpc_default_keepalive_time_ms)),
      num_reactors_(4),
      num_negotiation_threads_(4),
      coarse_timer_granularity_(MonoDelta::FromMilliseconds(100)) {}

MessengerBuilder& MessengerBuilder::set_connection_keepalive_time(const MonoDelta &keepalive) {
  connection_keepalive_time_ = keepalive;
  return *this;
}

MessengerBuilder& MessengerBuilder::set_num_reactors(int num_reactors) {
  num_reactors_ = num_reactors;
  return *this;
}

MessengerBuilder& MessengerBuilder::set_negotiation_threads(int num_negotiation_threads) {
  num_negotiation_threads_ = num_negotiation_threads;
  return *this;
}

MessengerBuilder& MessengerBuilder::set_coarse_timer_granularity(const MonoDelta &granularity) {
  coarse_timer_granularity_ = granularity;
  return *this;
}

MessengerBuilder &MessengerBuilder::set_metric_entity(
    const scoped_refptr<MetricEntity>& metric_entity) {
  metric_entity_ = metric_entity;
  return *this;
}

Status MessengerBuilder::Build(shared_ptr<Messenger> *msgr) {
  RETURN_NOT_OK(SaslInit(kSaslAppName)); // Initialize SASL library before we start making requests
  gscoped_ptr<Messenger> new_msgr(new Messenger(*this));
  Status build_status = new_msgr->Init();
  if (!build_status.ok()) {
    new_msgr->AllExternalReferencesDropped();
    return build_status;
  }

  // See docs on Messenger::retain_self_ for info about this odd hack.
  *msgr = shared_ptr<Messenger>(
    new_msgr.release(), std::mem_fun(&Messenger::AllExternalReferencesDropped));
  return Status::OK();
}

// See comment on Messenger::retain_self_ member.
void Messenger::AllExternalReferencesDropped() {
  Shutdown();
  CHECK(retain_self_.get());
  // If we have no more external references, then we no longer
  // need to retain ourself. We'll destruct as soon as all our
  // internal-facing references are dropped (ie those from reactor
  // threads).
  retain_self_.reset();
}

void Messenger::Shutdown() {
  // Since we're shutting down, it's OK to block.
  ThreadRestrictions::ScopedAllowWait allow_wait;

  std::lock_guard<percpu_rwlock> guard(lock_);
  if (closing_) {
    return;
  }
  VLOG(1) << "shutting down messenger " << name_;
  closing_ = true;

  DCHECK(rpc_services_.empty()) << "Unregister RPC services before shutting down Messenger";
  rpc_services_.clear();

  for (const shared_ptr<AcceptorPool>& acceptor_pool : acceptor_pools_) {
    acceptor_pool->Shutdown();
  }
  acceptor_pools_.clear();

  // Need to shut down negotiation pool before the reactors, since the
  // reactors close the Connection sockets, and may race against the negotiation
  // threads' blocking reads & writes.
  negotiation_pool_->Shutdown();

  for (Reactor* reactor : reactors_) {
    reactor->Shutdown();
  }
}

Status Messenger::AddAcceptorPool(const Sockaddr &accept_addr,
                                  shared_ptr<AcceptorPool>* pool) {
  Socket sock;
  RETURN_NOT_OK(sock.Init(0));
  RETURN_NOT_OK(sock.SetReuseAddr(true));
  RETURN_NOT_OK(sock.Bind(accept_addr));
  Sockaddr remote;
  RETURN_NOT_OK(sock.GetSocketAddress(&remote));
  shared_ptr<AcceptorPool> acceptor_pool(new AcceptorPool(this, &sock, remote));

  std::lock_guard<percpu_rwlock> guard(lock_);
  acceptor_pools_.push_back(acceptor_pool);
  *pool = acceptor_pool;
  return Status::OK();
}

// Register a new RpcService to handle inbound requests.
Status Messenger::RegisterService(const string& service_name,
                                  const scoped_refptr<RpcService>& service) {
  DCHECK(service);
  std::lock_guard<percpu_rwlock> guard(lock_);
  if (InsertIfNotPresent(&rpc_services_, service_name, service)) {
    return Status::OK();
  } else {
    return Status::AlreadyPresent("This service is already present");
  }
}

Status Messenger::UnregisterAllServices() {
  std::lock_guard<percpu_rwlock> guard(lock_);
  rpc_services_.clear();
  return Status::OK();
}

// Unregister an RpcService.
Status Messenger::UnregisterService(const string& service_name) {
  std::lock_guard<percpu_rwlock> guard(lock_);
  if (rpc_services_.erase(service_name)) {
    return Status::OK();
  } else {
    return Status::ServiceUnavailable(Substitute("service $0 not registered on $1",
                 service_name, name_));
  }
}

void Messenger::QueueOutboundCall(const shared_ptr<OutboundCall> &call) {
  Reactor *reactor = RemoteToReactor(call->conn_id().remote());
  reactor->QueueOutboundCall(call);
}

void Messenger::QueueInboundCall(gscoped_ptr<InboundCall> call) {
  shared_lock<rw_spinlock> guard(lock_.get_lock());
  scoped_refptr<RpcService>* service = FindOrNull(rpc_services_,
                                                  call->remote_method().service_name());
  if (PREDICT_FALSE(!service)) {
    Status s =  Status::ServiceUnavailable(Substitute("service $0 not registered on $1",
                                                      call->remote_method().service_name(), name_));
    LOG(INFO) << s.ToString();
    call.release()->RespondFailure(ErrorStatusPB::ERROR_NO_SUCH_SERVICE, s);
    return;
  }

  call->set_method_info((*service)->LookupMethod(call->remote_method()));

  // The RpcService will respond to the client on success or failure.
  WARN_NOT_OK((*service)->QueueInboundCall(std::move(call)), "Unable to handle RPC call");
}

void Messenger::RegisterInboundSocket(Socket *new_socket, const Sockaddr &remote) {
  Reactor *reactor = RemoteToReactor(remote);
  reactor->RegisterInboundSocket(new_socket, remote);
}

Messenger::Messenger(const MessengerBuilder &bld)
  : name_(bld.name_),
    closing_(false),
    rpcz_store_(new RpczStore()),
    metric_entity_(bld.metric_entity_),
    retain_self_(this) {
  for (int i = 0; i < bld.num_reactors_; i++) {
    reactors_.push_back(new Reactor(retain_self_, i, bld));
  }
  CHECK_OK(ThreadPoolBuilder("negotiator")
              .set_max_threads(bld.num_negotiation_threads_)
              .Build(&negotiation_pool_));
}

Messenger::~Messenger() {
  std::lock_guard<percpu_rwlock> guard(lock_);
  CHECK(closing_) << "Should have already shut down";
  STLDeleteElements(&reactors_);
}

Reactor* Messenger::RemoteToReactor(const Sockaddr &remote) {
  uint32_t hashCode = remote.HashCode();
  int reactor_idx = hashCode % reactors_.size();
  // This is just a static partitioning; we could get a lot
  // fancier with assigning Sockaddrs to Reactors.
  return reactors_[reactor_idx];
}

Status Messenger::Init() {
  Status status;
  for (Reactor* r : reactors_) {
    RETURN_NOT_OK(r->Init());
  }

  return Status::OK();
}

Status Messenger::DumpRunningRpcs(const DumpRunningRpcsRequestPB& req,
                                  DumpRunningRpcsResponsePB* resp) {
  shared_lock<rw_spinlock> guard(lock_.get_lock());
  for (Reactor* reactor : reactors_) {
    RETURN_NOT_OK(reactor->DumpRunningRpcs(req, resp));
  }
  return Status::OK();
}

void Messenger::ScheduleOnReactor(const boost::function<void(const Status&)>& func,
                                  MonoDelta when) {
  DCHECK(!reactors_.empty());

  // If we're already running on a reactor thread, reuse it.
  Reactor* chosen = nullptr;
  for (Reactor* r : reactors_) {
    if (r->IsCurrentThread()) {
      chosen = r;
    }
  }
  if (chosen == nullptr) {
    // Not running on a reactor thread, pick one at random.
    chosen = reactors_[rand() % reactors_.size()];
  }

  DelayedTask* task = new DelayedTask(func, when);
  chosen->ScheduleReactorTask(task);
}

const scoped_refptr<RpcService> Messenger::rpc_service(const string& service_name) const {
  std::lock_guard<percpu_rwlock> guard(lock_);
  scoped_refptr<RpcService> service;
  if (FindCopy(rpc_services_, service_name, &service)) {
    return service;
  } else {
    return scoped_refptr<RpcService>(nullptr);
  }
}

} // namespace rpc
} // namespace kudu
<commit_msg>KUDU-1719: Heap use-after-free and deadlock on Messenger::Init() failure<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

#include "kudu/rpc/messenger.h"

#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

#include <gflags/gflags.h>
#include <glog/logging.h>
#include <list>
#include <mutex>
#include <set>
#include <string>

#include "kudu/gutil/gscoped_ptr.h"
#include "kudu/gutil/map-util.h"
#include "kudu/gutil/stl_util.h"
#include "kudu/gutil/strings/substitute.h"
#include "kudu/rpc/acceptor_pool.h"
#include "kudu/rpc/connection.h"
#include "kudu/rpc/constants.h"
#include "kudu/rpc/reactor.h"
#include "kudu/rpc/rpc_header.pb.h"
#include "kudu/rpc/rpc_service.h"
#include "kudu/rpc/rpcz_store.h"
#include "kudu/rpc/sasl_common.h"
#include "kudu/rpc/transfer.h"
#include "kudu/util/errno.h"
#include "kudu/util/flag_tags.h"
#include "kudu/util/metrics.h"
#include "kudu/util/monotime.h"
#include "kudu/util/net/socket.h"
#include "kudu/util/status.h"
#include "kudu/util/threadpool.h"
#include "kudu/util/trace.h"

using std::string;
using std::shared_ptr;
using strings::Substitute;

DEFINE_int32(rpc_default_keepalive_time_ms, 65000,
             "If an RPC connection from a client is idle for this amount of time, the server "
             "will disconnect the client.");
TAG_FLAG(rpc_default_keepalive_time_ms, advanced);

namespace kudu {
namespace rpc {

class Messenger;
class ServerBuilder;

MessengerBuilder::MessengerBuilder(std::string name)
    : name_(std::move(name)),
      connection_keepalive_time_(
          MonoDelta::FromMilliseconds(FLAGS_rpc_default_keepalive_time_ms)),
      num_reactors_(4),
      num_negotiation_threads_(4),
      coarse_timer_granularity_(MonoDelta::FromMilliseconds(100)) {}

MessengerBuilder& MessengerBuilder::set_connection_keepalive_time(const MonoDelta &keepalive) {
  connection_keepalive_time_ = keepalive;
  return *this;
}

MessengerBuilder& MessengerBuilder::set_num_reactors(int num_reactors) {
  num_reactors_ = num_reactors;
  return *this;
}

MessengerBuilder& MessengerBuilder::set_negotiation_threads(int num_negotiation_threads) {
  num_negotiation_threads_ = num_negotiation_threads;
  return *this;
}

MessengerBuilder& MessengerBuilder::set_coarse_timer_granularity(const MonoDelta &granularity) {
  coarse_timer_granularity_ = granularity;
  return *this;
}

MessengerBuilder &MessengerBuilder::set_metric_entity(
    const scoped_refptr<MetricEntity>& metric_entity) {
  metric_entity_ = metric_entity;
  return *this;
}

Status MessengerBuilder::Build(shared_ptr<Messenger> *msgr) {
  RETURN_NOT_OK(SaslInit(kSaslAppName)); // Initialize SASL library before we start making requests
  Messenger* new_msgr(new Messenger(*this));
  Status build_status = new_msgr->Init();
  if (!build_status.ok()) {
    // 'new_msgr' will be freed when 'retain_self_' is reset, so no need to explicitly free it.
    new_msgr->AllExternalReferencesDropped();
    return build_status;
  }

  // See docs on Messenger::retain_self_ for info about this odd hack.
  *msgr = shared_ptr<Messenger>(
    new_msgr, std::mem_fun(&Messenger::AllExternalReferencesDropped));
  return Status::OK();
}

// See comment on Messenger::retain_self_ member.
void Messenger::AllExternalReferencesDropped() {
  Shutdown();
  CHECK(retain_self_.get());
  // If we have no more external references, then we no longer
  // need to retain ourself. We'll destruct as soon as all our
  // internal-facing references are dropped (ie those from reactor
  // threads).
  retain_self_.reset();
}

void Messenger::Shutdown() {
  // Since we're shutting down, it's OK to block.
  ThreadRestrictions::ScopedAllowWait allow_wait;

  std::lock_guard<percpu_rwlock> guard(lock_);
  if (closing_) {
    return;
  }
  VLOG(1) << "shutting down messenger " << name_;
  closing_ = true;

  DCHECK(rpc_services_.empty()) << "Unregister RPC services before shutting down Messenger";
  rpc_services_.clear();

  for (const shared_ptr<AcceptorPool>& acceptor_pool : acceptor_pools_) {
    acceptor_pool->Shutdown();
  }
  acceptor_pools_.clear();

  // Need to shut down negotiation pool before the reactors, since the
  // reactors close the Connection sockets, and may race against the negotiation
  // threads' blocking reads & writes.
  negotiation_pool_->Shutdown();

  for (Reactor* reactor : reactors_) {
    reactor->Shutdown();
  }
}

Status Messenger::AddAcceptorPool(const Sockaddr &accept_addr,
                                  shared_ptr<AcceptorPool>* pool) {
  Socket sock;
  RETURN_NOT_OK(sock.Init(0));
  RETURN_NOT_OK(sock.SetReuseAddr(true));
  RETURN_NOT_OK(sock.Bind(accept_addr));
  Sockaddr remote;
  RETURN_NOT_OK(sock.GetSocketAddress(&remote));
  shared_ptr<AcceptorPool> acceptor_pool(new AcceptorPool(this, &sock, remote));

  std::lock_guard<percpu_rwlock> guard(lock_);
  acceptor_pools_.push_back(acceptor_pool);
  *pool = acceptor_pool;
  return Status::OK();
}

// Register a new RpcService to handle inbound requests.
Status Messenger::RegisterService(const string& service_name,
                                  const scoped_refptr<RpcService>& service) {
  DCHECK(service);
  std::lock_guard<percpu_rwlock> guard(lock_);
  if (InsertIfNotPresent(&rpc_services_, service_name, service)) {
    return Status::OK();
  } else {
    return Status::AlreadyPresent("This service is already present");
  }
}

Status Messenger::UnregisterAllServices() {
  std::lock_guard<percpu_rwlock> guard(lock_);
  rpc_services_.clear();
  return Status::OK();
}

// Unregister an RpcService.
Status Messenger::UnregisterService(const string& service_name) {
  std::lock_guard<percpu_rwlock> guard(lock_);
  if (rpc_services_.erase(service_name)) {
    return Status::OK();
  } else {
    return Status::ServiceUnavailable(Substitute("service $0 not registered on $1",
                 service_name, name_));
  }
}

void Messenger::QueueOutboundCall(const shared_ptr<OutboundCall> &call) {
  Reactor *reactor = RemoteToReactor(call->conn_id().remote());
  reactor->QueueOutboundCall(call);
}

void Messenger::QueueInboundCall(gscoped_ptr<InboundCall> call) {
  shared_lock<rw_spinlock> guard(lock_.get_lock());
  scoped_refptr<RpcService>* service = FindOrNull(rpc_services_,
                                                  call->remote_method().service_name());
  if (PREDICT_FALSE(!service)) {
    Status s =  Status::ServiceUnavailable(Substitute("service $0 not registered on $1",
                                                      call->remote_method().service_name(), name_));
    LOG(INFO) << s.ToString();
    call.release()->RespondFailure(ErrorStatusPB::ERROR_NO_SUCH_SERVICE, s);
    return;
  }

  call->set_method_info((*service)->LookupMethod(call->remote_method()));

  // The RpcService will respond to the client on success or failure.
  WARN_NOT_OK((*service)->QueueInboundCall(std::move(call)), "Unable to handle RPC call");
}

void Messenger::RegisterInboundSocket(Socket *new_socket, const Sockaddr &remote) {
  Reactor *reactor = RemoteToReactor(remote);
  reactor->RegisterInboundSocket(new_socket, remote);
}

Messenger::Messenger(const MessengerBuilder &bld)
  : name_(bld.name_),
    closing_(false),
    rpcz_store_(new RpczStore()),
    metric_entity_(bld.metric_entity_),
    retain_self_(this) {
  for (int i = 0; i < bld.num_reactors_; i++) {
    reactors_.push_back(new Reactor(retain_self_, i, bld));
  }
  CHECK_OK(ThreadPoolBuilder("negotiator")
              .set_max_threads(bld.num_negotiation_threads_)
              .Build(&negotiation_pool_));
}

Messenger::~Messenger() {
  std::lock_guard<percpu_rwlock> guard(lock_);
  CHECK(closing_) << "Should have already shut down";
  STLDeleteElements(&reactors_);
}

Reactor* Messenger::RemoteToReactor(const Sockaddr &remote) {
  uint32_t hashCode = remote.HashCode();
  int reactor_idx = hashCode % reactors_.size();
  // This is just a static partitioning; we could get a lot
  // fancier with assigning Sockaddrs to Reactors.
  return reactors_[reactor_idx];
}

Status Messenger::Init() {
  Status status;
  for (Reactor* r : reactors_) {
    RETURN_NOT_OK(r->Init());
  }

  return Status::OK();
}

Status Messenger::DumpRunningRpcs(const DumpRunningRpcsRequestPB& req,
                                  DumpRunningRpcsResponsePB* resp) {
  shared_lock<rw_spinlock> guard(lock_.get_lock());
  for (Reactor* reactor : reactors_) {
    RETURN_NOT_OK(reactor->DumpRunningRpcs(req, resp));
  }
  return Status::OK();
}

void Messenger::ScheduleOnReactor(const boost::function<void(const Status&)>& func,
                                  MonoDelta when) {
  DCHECK(!reactors_.empty());

  // If we're already running on a reactor thread, reuse it.
  Reactor* chosen = nullptr;
  for (Reactor* r : reactors_) {
    if (r->IsCurrentThread()) {
      chosen = r;
    }
  }
  if (chosen == nullptr) {
    // Not running on a reactor thread, pick one at random.
    chosen = reactors_[rand() % reactors_.size()];
  }

  DelayedTask* task = new DelayedTask(func, when);
  chosen->ScheduleReactorTask(task);
}

const scoped_refptr<RpcService> Messenger::rpc_service(const string& service_name) const {
  std::lock_guard<percpu_rwlock> guard(lock_);
  scoped_refptr<RpcService> service;
  if (FindCopy(rpc_services_, service_name, &service)) {
    return service;
  } else {
    return scoped_refptr<RpcService>(nullptr);
  }
}

} // namespace rpc
} // namespace kudu
<|endoftext|>


<commit_before>#include "ImageLayer.hpp"
#include "../arch/mpi/mpi.h"
#include "structures/Image.hpp"

#include <algorithm>
#include <cassert>
#include <cstring>
#include <iostream>

namespace PV {

ImageLayer::ImageLayer(const char *name, HyPerCol *hc) { initialize(name, hc); }

int ImageLayer::countInputImages() {
   // Check if the input path ends in ".txt" and enable the file list if so
   std::string txt = ".txt";
   if (getInputPath().size() > txt.size()
       && getInputPath().compare(getInputPath().size() - txt.size(), txt.size(), txt) == 0) {
      mUsingFileList = true;

      // Calculate file positions for beginning of each frame
      populateFileList();
      InfoLog() << "File " << getInputPath() << " contains " << mFileList.size() << " frames\n";
      return mFileList.size();
   }
   else {
      mUsingFileList = false;
      return 1;
   }
}

std::string const &ImageLayer::getCurrentFilename(int localBatchElement, int mpiBatchIndex) const {
   if (mUsingFileList) {
      int blockBatchElement = localBatchElement + getLayerLoc()->nbatch * mpiBatchIndex;
      int inputIndex        = mBatchIndexer->getIndex(blockBatchElement);
      return mFileList.at(inputIndex);
   }
   else {
      return getInputPath();
   }
}

Response::Status ImageLayer::registerData(Checkpointer *checkpointer) {
   auto status = InputLayer::registerData(checkpointer);
   if (!Response::completed(status)) {
      return status;
   }
   mURLDownloadTemplate = checkpointer->getOutputPath() + "/temp.XXXXXX";
   return Response::SUCCESS;
}

void ImageLayer::populateFileList() {
   if (getMPIBlock()->getRank() == 0) {
      std::string line;
      mFileList.clear();
      InfoLog() << "Reading list: " << getInputPath() << "\n";
      std::ifstream infile(getInputPath(), std::ios_base::in);
      FatalIf(
            infile.fail(), "Unable to open \"%s\": %s\n", getInputPath().c_str(), strerror(errno));
      while (getline(infile, line, '\n')) {
         std::string noWhiteSpace = line;
         noWhiteSpace.erase(
               std::remove_if(noWhiteSpace.begin(), noWhiteSpace.end(), ::isspace),
               noWhiteSpace.end());
         if (!noWhiteSpace.empty()) {
            mFileList.push_back(noWhiteSpace);
         }
      }
   }
}

Buffer<float> ImageLayer::retrieveData(int inputIndex) {
   std::string filename;
   if (mUsingFileList) {
      filename = mFileList.at(inputIndex);
   }
   else {
      filename = getInputPath();
   }
   readImage(filename);

   if (mImage->getFeatures() != getLayerLoc()->nf) {
      switch (getLayerLoc()->nf) {
         case 1: // Grayscale
            mImage->convertToGray(false);
            break;
         case 2: // Grayscale + Alpha
            mImage->convertToGray(true);
            break;
         case 3: // RGB
            mImage->convertToColor(false);
            break;
         case 4: // RGBA
            mImage->convertToColor(true);
            break;
         default:
            Fatal() << "Failed to read " << filename << ": Could not convert "
                    << mImage->getFeatures() << " channels to " << getLayerLoc()->nf << std::endl;
            break;
      }
   }

   Buffer<float> result(
         mImage->asVector(), mImage->getWidth(), mImage->getHeight(), getLayerLoc()->nf);
   return result;
}

void ImageLayer::readImage(std::string filename) {
   const PVLayerLoc *loc = getLayerLoc();
   bool usingTempFile    = false;

   // Attempt to download our input file if we've been passed a URL or AWS path
   if (filename.find("://") != std::string::npos) {
      usingTempFile          = true;
      std::string extension  = filename.substr(filename.find_last_of("."));
      std::string pathstring = mURLDownloadTemplate + extension;
      char tempStr[256];
      strcpy(tempStr, pathstring.c_str());
      int tempFileID = mkstemps(tempStr, extension.size());
      pathstring     = std::string(tempStr);
      FatalIf(tempFileID < 0, "Cannot create temp image file.\n");
      std::string systemstring;

      if (filename.find("s3://") != std::string::npos) {
         systemstring = std::string("aws s3 cp \'") + filename + std::string("\' ") + pathstring;
      }
      else { // URLs other than s3://
         systemstring = std::string("wget -O ") + pathstring + std::string(" \'") + filename
                        + std::string("\'");
      }

      filename              = pathstring;
      const int numAttempts = 5;
      for (int attemptNum = 0; attemptNum < numAttempts; attemptNum++) {
         if (system(systemstring.c_str()) == 0) {
            break;
         }
         sleep(1);
         FatalIf(
               attemptNum == numAttempts - 1,
               "download command \"%s\" failed: %s.  Exiting\n",
               systemstring.c_str(),
               strerror(errno));
      }
   }

   mImage = std::unique_ptr<Image>(new Image(std::string(filename)));

   FatalIf(
         usingTempFile && remove(filename.c_str()),
         "remove(\"%s\") failed.  Exiting.\n",
         filename.c_str());
}

std::string ImageLayer::describeInput(int index) {
   std::string description("");
   if (mUsingFileList) {
      description = mFileList.at(index);
   }
   return description;
}
}
<commit_msg>ImageLayer checks whether list of files is empty.<commit_after>#include "ImageLayer.hpp"
#include "../arch/mpi/mpi.h"
#include "structures/Image.hpp"

#include <algorithm>
#include <cassert>
#include <cstring>
#include <iostream>

namespace PV {

ImageLayer::ImageLayer(const char *name, HyPerCol *hc) { initialize(name, hc); }

int ImageLayer::countInputImages() {
   // Check if the input path ends in ".txt" and enable the file list if so
   std::string txt = ".txt";
   if (getInputPath().size() > txt.size()
       && getInputPath().compare(getInputPath().size() - txt.size(), txt.size(), txt) == 0) {
      mUsingFileList = true;

      // Calculate file positions for beginning of each frame
      populateFileList();
      InfoLog() << "File " << getInputPath() << " contains " << mFileList.size() << " frames\n";
      return mFileList.size();
   }
   else {
      mUsingFileList = false;
      return 1;
   }
}

std::string const &ImageLayer::getCurrentFilename(int localBatchElement, int mpiBatchIndex) const {
   if (mUsingFileList) {
      int blockBatchElement = localBatchElement + getLayerLoc()->nbatch * mpiBatchIndex;
      int inputIndex        = mBatchIndexer->getIndex(blockBatchElement);
      return mFileList.at(inputIndex);
   }
   else {
      return getInputPath();
   }
}

Response::Status ImageLayer::registerData(Checkpointer *checkpointer) {
   auto status = InputLayer::registerData(checkpointer);
   if (!Response::completed(status)) {
      return status;
   }
   mURLDownloadTemplate = checkpointer->getOutputPath() + "/temp.XXXXXX";
   return Response::SUCCESS;
}

void ImageLayer::populateFileList() {
   if (getMPIBlock()->getRank() == 0) {
      std::string line;
      mFileList.clear();
      InfoLog() << "Reading list: " << getInputPath() << "\n";
      std::ifstream infile(getInputPath(), std::ios_base::in);
      FatalIf(
            infile.fail(), "Unable to open \"%s\": %s\n", getInputPath().c_str(), strerror(errno));
      while (getline(infile, line, '\n')) {
         std::string noWhiteSpace = line;
         noWhiteSpace.erase(
               std::remove_if(noWhiteSpace.begin(), noWhiteSpace.end(), ::isspace),
               noWhiteSpace.end());
         if (!noWhiteSpace.empty()) {
            mFileList.push_back(noWhiteSpace);
         }
      }
      FatalIf(
            mFileList.empty(),
            "%s inputPath file list \"%s\" is empty.\n",
            getDescription_c(),
            getInputPath().c_str());
   }
}

Buffer<float> ImageLayer::retrieveData(int inputIndex) {
   std::string filename;
   if (mUsingFileList) {
      filename = mFileList.at(inputIndex);
   }
   else {
      filename = getInputPath();
   }
   readImage(filename);

   if (mImage->getFeatures() != getLayerLoc()->nf) {
      switch (getLayerLoc()->nf) {
         case 1: // Grayscale
            mImage->convertToGray(false);
            break;
         case 2: // Grayscale + Alpha
            mImage->convertToGray(true);
            break;
         case 3: // RGB
            mImage->convertToColor(false);
            break;
         case 4: // RGBA
            mImage->convertToColor(true);
            break;
         default:
            Fatal() << "Failed to read " << filename << ": Could not convert "
                    << mImage->getFeatures() << " channels to " << getLayerLoc()->nf << std::endl;
            break;
      }
   }

   Buffer<float> result(
         mImage->asVector(), mImage->getWidth(), mImage->getHeight(), getLayerLoc()->nf);
   return result;
}

void ImageLayer::readImage(std::string filename) {
   const PVLayerLoc *loc = getLayerLoc();
   bool usingTempFile    = false;

   // Attempt to download our input file if we've been passed a URL or AWS path
   if (filename.find("://") != std::string::npos) {
      usingTempFile          = true;
      std::string extension  = filename.substr(filename.find_last_of("."));
      std::string pathstring = mURLDownloadTemplate + extension;
      char tempStr[256];
      strcpy(tempStr, pathstring.c_str());
      int tempFileID = mkstemps(tempStr, extension.size());
      pathstring     = std::string(tempStr);
      FatalIf(tempFileID < 0, "Cannot create temp image file.\n");
      std::string systemstring;

      if (filename.find("s3://") != std::string::npos) {
         systemstring = std::string("aws s3 cp \'") + filename + std::string("\' ") + pathstring;
      }
      else { // URLs other than s3://
         systemstring = std::string("wget -O ") + pathstring + std::string(" \'") + filename
                        + std::string("\'");
      }

      filename              = pathstring;
      const int numAttempts = 5;
      for (int attemptNum = 0; attemptNum < numAttempts; attemptNum++) {
         if (system(systemstring.c_str()) == 0) {
            break;
         }
         sleep(1);
         FatalIf(
               attemptNum == numAttempts - 1,
               "download command \"%s\" failed: %s.  Exiting\n",
               systemstring.c_str(),
               strerror(errno));
      }
   }

   mImage = std::unique_ptr<Image>(new Image(std::string(filename)));

   FatalIf(
         usingTempFile && remove(filename.c_str()),
         "remove(\"%s\") failed.  Exiting.\n",
         filename.c_str());
}

std::string ImageLayer::describeInput(int index) {
   std::string description("");
   if (mUsingFileList) {
      description = mFileList.at(index);
   }
   return description;
}
}
<|endoftext|>


<commit_before>#include "master.hpp"

namespace factor
{

void init_globals()
{
	init_mvm();
}

void factor_vm::default_parameters(vm_parameters *p)
{
	p->image_path = NULL;

	p->datastack_size = 32 * sizeof(cell);
	p->retainstack_size = 32 * sizeof(cell);

#ifdef FACTOR_PPC
	p->callstack_size = 256 * sizeof(cell);
#else
	p->callstack_size = 128 * sizeof(cell);
#endif

	p->code_size = 8 * sizeof(cell);
	p->young_size = sizeof(cell) / 4;
	p->aging_size = sizeof(cell) / 2;
	p->tenured_size = 24 * sizeof(cell);

	p->max_pic_size = 3;

	p->fep = false;
	p->signals = true;

#ifdef WINDOWS
	p->console = false;
#else
	p->console = true;
#endif

	p->callback_size = 256;
}

bool factor_vm::factor_arg(const vm_char* str, const vm_char* arg, cell* value)
{
	int val;
	if(SSCANF(str,arg,&val) > 0)
	{
		*value = val;
		return true;
	}
	else
		return false;
}

void factor_vm::init_parameters_from_args(vm_parameters *p, int argc, vm_char **argv)
{
	default_parameters(p);
	p->executable_path = argv[0];

	int i = 0;

	for(i = 1; i < argc; i++)
	{
		vm_char *arg = argv[i];
		if(STRCMP(arg,STRING_LITERAL("--")) == 0) break;
		else if(factor_arg(arg,STRING_LITERAL("-datastack=%d"),&p->datastack_size));
		else if(factor_arg(arg,STRING_LITERAL("-retainstack=%d"),&p->retainstack_size));
		else if(factor_arg(arg,STRING_LITERAL("-callstack=%d"),&p->callstack_size));
		else if(factor_arg(arg,STRING_LITERAL("-young=%d"),&p->young_size));
		else if(factor_arg(arg,STRING_LITERAL("-aging=%d"),&p->aging_size));
		else if(factor_arg(arg,STRING_LITERAL("-tenured=%d"),&p->tenured_size));
		else if(factor_arg(arg,STRING_LITERAL("-codeheap=%d"),&p->code_size));
		else if(factor_arg(arg,STRING_LITERAL("-pic=%d"),&p->max_pic_size));
		else if(factor_arg(arg,STRING_LITERAL("-callbacks=%d"),&p->callback_size));
		else if(STRCMP(arg,STRING_LITERAL("-fep")) == 0) p->fep = true;
		else if(STRCMP(arg,STRING_LITERAL("-nosignals")) == 0) p->signals = false;
		else if(STRNCMP(arg,STRING_LITERAL("-i="),3) == 0) p->image_path = arg + 3;
		else if(STRCMP(arg,STRING_LITERAL("-console")) == 0) p->console = true;
	}
}

/* Compile code in boot image so that we can execute the startup quotation */
void factor_vm::prepare_boot_image()
{
	std::cout << "*** Stage 2 early init... ";
	fflush(stdout);

	compile_all_words();
	update_code_heap_words(true);
	initialize_all_quotations();
	special_objects[OBJ_STAGE2] = true_object;

	std::cout << "done\n";
}

void factor_vm::init_factor(vm_parameters *p)
{
	/* Kilobytes */
	p->datastack_size = align_page(p->datastack_size << 10);
	p->retainstack_size = align_page(p->retainstack_size << 10);
	p->callstack_size = align_page(p->callstack_size << 10);
	p->callback_size = align_page(p->callback_size << 10);

	/* Megabytes */
	p->young_size <<= 20;
	p->aging_size <<= 20;
	p->tenured_size <<= 20;
	p->code_size <<= 20;

	/* Disable GC during init as a sanity check */
	gc_off = true;

	/* OS-specific initialization */
	early_init();

	const vm_char *executable_path = vm_executable_path();

	if(executable_path)
		p->executable_path = executable_path;

	if(p->image_path == NULL)
		p->image_path = default_image_path();

	srand((unsigned int)system_micros());
	init_ffi();
	init_contexts(p->datastack_size,p->retainstack_size,p->callstack_size);
	init_callbacks(p->callback_size);
	load_image(p);
	init_c_io();
	init_inline_caching(p->max_pic_size);
	if(p->signals)
		init_signals();

	if(p->console)
		open_console();

	init_profiler();

	special_objects[OBJ_CPU] = allot_alien(false_object,(cell)FACTOR_CPU_STRING);
	special_objects[OBJ_OS] = allot_alien(false_object,(cell)FACTOR_OS_STRING);
	special_objects[OBJ_CELL_SIZE] = tag_fixnum(sizeof(cell));
	special_objects[OBJ_EXECUTABLE] = allot_alien(false_object,(cell)p->executable_path);
	special_objects[OBJ_ARGS] = false_object;
	special_objects[OBJ_EMBEDDED] = false_object;
	special_objects[OBJ_VM_COMPILER] = allot_alien(false_object,(cell)FACTOR_COMPILER_VERSION);

	/* We can GC now */
	gc_off = false;

	if(!to_boolean(special_objects[OBJ_STAGE2]))
		prepare_boot_image();
}

/* May allocate memory */
void factor_vm::pass_args_to_factor(int argc, vm_char **argv)
{
	growable_array args(this);

	for(fixnum i = 1; i < argc; i++)
		args.add(allot_alien(false_object,(cell)argv[i]));

	args.trim();
	special_objects[OBJ_ARGS] = args.elements.value();
}

void factor_vm::start_factor(vm_parameters *p)
{
	if(p->fep) factorbug();

	c_to_factor_toplevel(special_objects[OBJ_STARTUP_QUOT]);
}

void factor_vm::stop_factor()
{
	c_to_factor_toplevel(special_objects[OBJ_SHUTDOWN_QUOT]);
}

char *factor_vm::factor_eval_string(char *string)
{
	char *(*callback)(char *) = (char *(*)(char *))alien_offset(special_objects[OBJ_EVAL_CALLBACK]);
	return callback(string);
}

void factor_vm::factor_eval_free(char *result)
{
	free(result);
}

void factor_vm::factor_yield()
{
	void (*callback)() = (void (*)())alien_offset(special_objects[OBJ_YIELD_CALLBACK]);
	callback();
}

void factor_vm::factor_sleep(long us)
{
	void (*callback)(long) = (void (*)(long))alien_offset(special_objects[OBJ_SLEEP_CALLBACK]);
	callback(us);
}

void factor_vm::start_standalone_factor(int argc, vm_char **argv)
{
	vm_parameters p;
	default_parameters(&p);
	init_parameters_from_args(&p,argc,argv);
	init_factor(&p);
	pass_args_to_factor(argc,argv);
	start_factor(&p);
}

factor_vm *new_factor_vm()
{
	factor_vm *newvm = new factor_vm();
	register_vm_with_thread(newvm);
	thread_vms[thread_id()] = newvm;

	return newvm;
}

VM_C_API void start_standalone_factor(int argc, vm_char **argv)
{
	factor_vm *newvm = new_factor_vm();
	return newvm->start_standalone_factor(argc,argv);
}

}
<commit_msg>vm: try a smaller call stack size on OpenBSD again, now that x86-32 stack frames are smaller<commit_after>#include "master.hpp"

namespace factor
{

void init_globals()
{
	init_mvm();
}

void factor_vm::default_parameters(vm_parameters *p)
{
	p->image_path = NULL;

	p->datastack_size = 32 * sizeof(cell);
	p->retainstack_size = 32 * sizeof(cell);

#if defined(__OpenBSD__) && defined(FACTOR_X86)
	p->callstack_size = 64 * sizeof(cell);
#elif defined(FACTOR_PPC)
	p->callstack_size = 256 * sizeof(cell);
#else
	p->callstack_size = 128 * sizeof(cell);
#endif

	p->code_size = 8 * sizeof(cell);
	p->young_size = sizeof(cell) / 4;
	p->aging_size = sizeof(cell) / 2;
	p->tenured_size = 24 * sizeof(cell);

	p->max_pic_size = 3;

	p->fep = false;
	p->signals = true;

#ifdef WINDOWS
	p->console = false;
#else
	p->console = true;
#endif

	p->callback_size = 256;
}

bool factor_vm::factor_arg(const vm_char* str, const vm_char* arg, cell* value)
{
	int val;
	if(SSCANF(str,arg,&val) > 0)
	{
		*value = val;
		return true;
	}
	else
		return false;
}

void factor_vm::init_parameters_from_args(vm_parameters *p, int argc, vm_char **argv)
{
	default_parameters(p);
	p->executable_path = argv[0];

	int i = 0;

	for(i = 1; i < argc; i++)
	{
		vm_char *arg = argv[i];
		if(STRCMP(arg,STRING_LITERAL("--")) == 0) break;
		else if(factor_arg(arg,STRING_LITERAL("-datastack=%d"),&p->datastack_size));
		else if(factor_arg(arg,STRING_LITERAL("-retainstack=%d"),&p->retainstack_size));
		else if(factor_arg(arg,STRING_LITERAL("-callstack=%d"),&p->callstack_size));
		else if(factor_arg(arg,STRING_LITERAL("-young=%d"),&p->young_size));
		else if(factor_arg(arg,STRING_LITERAL("-aging=%d"),&p->aging_size));
		else if(factor_arg(arg,STRING_LITERAL("-tenured=%d"),&p->tenured_size));
		else if(factor_arg(arg,STRING_LITERAL("-codeheap=%d"),&p->code_size));
		else if(factor_arg(arg,STRING_LITERAL("-pic=%d"),&p->max_pic_size));
		else if(factor_arg(arg,STRING_LITERAL("-callbacks=%d"),&p->callback_size));
		else if(STRCMP(arg,STRING_LITERAL("-fep")) == 0) p->fep = true;
		else if(STRCMP(arg,STRING_LITERAL("-nosignals")) == 0) p->signals = false;
		else if(STRNCMP(arg,STRING_LITERAL("-i="),3) == 0) p->image_path = arg + 3;
		else if(STRCMP(arg,STRING_LITERAL("-console")) == 0) p->console = true;
	}
}

/* Compile code in boot image so that we can execute the startup quotation */
void factor_vm::prepare_boot_image()
{
	std::cout << "*** Stage 2 early init... ";
	fflush(stdout);

	compile_all_words();
	update_code_heap_words(true);
	initialize_all_quotations();
	special_objects[OBJ_STAGE2] = true_object;

	std::cout << "done\n";
}

void factor_vm::init_factor(vm_parameters *p)
{
	/* Kilobytes */
	p->datastack_size = align_page(p->datastack_size << 10);
	p->retainstack_size = align_page(p->retainstack_size << 10);
	p->callstack_size = align_page(p->callstack_size << 10);
	p->callback_size = align_page(p->callback_size << 10);

	/* Megabytes */
	p->young_size <<= 20;
	p->aging_size <<= 20;
	p->tenured_size <<= 20;
	p->code_size <<= 20;

	/* Disable GC during init as a sanity check */
	gc_off = true;

	/* OS-specific initialization */
	early_init();

	const vm_char *executable_path = vm_executable_path();

	if(executable_path)
		p->executable_path = executable_path;

	if(p->image_path == NULL)
		p->image_path = default_image_path();

	srand((unsigned int)system_micros());
	init_ffi();
	init_contexts(p->datastack_size,p->retainstack_size,p->callstack_size);
	init_callbacks(p->callback_size);
	load_image(p);
	init_c_io();
	init_inline_caching(p->max_pic_size);
	if(p->signals)
		init_signals();

	if(p->console)
		open_console();

	init_profiler();

	special_objects[OBJ_CPU] = allot_alien(false_object,(cell)FACTOR_CPU_STRING);
	special_objects[OBJ_OS] = allot_alien(false_object,(cell)FACTOR_OS_STRING);
	special_objects[OBJ_CELL_SIZE] = tag_fixnum(sizeof(cell));
	special_objects[OBJ_EXECUTABLE] = allot_alien(false_object,(cell)p->executable_path);
	special_objects[OBJ_ARGS] = false_object;
	special_objects[OBJ_EMBEDDED] = false_object;
	special_objects[OBJ_VM_COMPILER] = allot_alien(false_object,(cell)FACTOR_COMPILER_VERSION);

	/* We can GC now */
	gc_off = false;

	if(!to_boolean(special_objects[OBJ_STAGE2]))
		prepare_boot_image();
}

/* May allocate memory */
void factor_vm::pass_args_to_factor(int argc, vm_char **argv)
{
	growable_array args(this);

	for(fixnum i = 1; i < argc; i++)
		args.add(allot_alien(false_object,(cell)argv[i]));

	args.trim();
	special_objects[OBJ_ARGS] = args.elements.value();
}

void factor_vm::start_factor(vm_parameters *p)
{
	if(p->fep) factorbug();

	c_to_factor_toplevel(special_objects[OBJ_STARTUP_QUOT]);
}

void factor_vm::stop_factor()
{
	c_to_factor_toplevel(special_objects[OBJ_SHUTDOWN_QUOT]);
}

char *factor_vm::factor_eval_string(char *string)
{
	char *(*callback)(char *) = (char *(*)(char *))alien_offset(special_objects[OBJ_EVAL_CALLBACK]);
	return callback(string);
}

void factor_vm::factor_eval_free(char *result)
{
	free(result);
}

void factor_vm::factor_yield()
{
	void (*callback)() = (void (*)())alien_offset(special_objects[OBJ_YIELD_CALLBACK]);
	callback();
}

void factor_vm::factor_sleep(long us)
{
	void (*callback)(long) = (void (*)(long))alien_offset(special_objects[OBJ_SLEEP_CALLBACK]);
	callback(us);
}

void factor_vm::start_standalone_factor(int argc, vm_char **argv)
{
	vm_parameters p;
	default_parameters(&p);
	init_parameters_from_args(&p,argc,argv);
	init_factor(&p);
	pass_args_to_factor(argc,argv);
	start_factor(&p);
}

factor_vm *new_factor_vm()
{
	factor_vm *newvm = new factor_vm();
	register_vm_with_thread(newvm);
	thread_vms[thread_id()] = newvm;

	return newvm;
}

VM_C_API void start_standalone_factor(int argc, vm_char **argv)
{
	factor_vm *newvm = new_factor_vm();
	return newvm->start_standalone_factor(argc,argv);
}

}
<|endoftext|>