<commit_before>#include <OgreSceneNode.h>
#include <OgreSceneManager.h>

#include <tf/transform_listener.h>

#include <rviz/visualization_manager.h>
#include <rviz/properties/color_property.h>
#include <rviz/properties/float_property.h>
#include <rviz/properties/int_property.h>
#include <rviz/frame_manager.h>

#include <boost/foreach.hpp>

#include "effort_visual.h"

#include "effort_display.h"

#include <urdf/model.h>

namespace rviz
{

    JointInfo::JointInfo(const std::string name, rviz::Property* parent_category) {
        name_ = name;
        effort_ = 0;
        max_effort_ = 0;
        last_update_ = ros::Time::now();

        //info->category_ = new Property( QString::fromStdString( info->name_ ) , QVariant(), "", joints_category_);
        category_ = new rviz::Property( QString::fromStdString( name_ ) , true, "", parent_category, SLOT( updateVisibility() ), this);

        effort_property_ = new rviz::FloatProperty( "Effort", 0, "Effort value of this joint.", category_);
        effort_property_->setReadOnly( true );

        max_effort_property_ = new rviz::FloatProperty( "Max Effort", 0, "Max Effort value of this joint.", category_);
        max_effort_property_->setReadOnly( true );
    }

    JointInfo::~JointInfo() {
    }

    void JointInfo::updateVisibility() {
        bool enabled = getEnabled();
    }

    void JointInfo::setEffort(double e) {
        effort_property_->setFloat(e);
        effort_ = e;
    }
    double JointInfo::getEffort() { return effort_; }
    void JointInfo::setMaxEffort(double m) {
        max_effort_property_->setFloat(m);
        max_effort_ = m;
    }
    double JointInfo::getMaxEffort() { return max_effort_; }

    bool JointInfo::getEnabled() const
    {
        return category_->getValue().toBool();
    }

    JointInfo* EffortDisplay::getJointInfo( const std::string& joint)
    {
        M_JointInfo::iterator it = joints_.find( joint );
        if ( it == joints_.end() )
            {
                return NULL;
            }

        return it->second;
    }

    JointInfo* EffortDisplay::createJoint(const std::string &joint)
    {
        JointInfo *info = new JointInfo(joint, this);
        joints_.insert( std::make_pair( joint, info ) );
        return info;
    }

    ///
    EffortDisplay::EffortDisplay()
    {
	alpha_property_ =
	    new rviz::FloatProperty( "Alpha", 1.0,
                                     "0 is fully transparent, 1.0 is fully opaque.",
                                     this, SLOT( updateColorAndAlpha() ));

	width_property_ =
	    new rviz::FloatProperty( "Width", 0.02,
                                     "Width to drow effort circle",
                                     this, SLOT( updateColorAndAlpha() ));

	scale_property_ =
	    new rviz::FloatProperty( "Scale", 1.0,
                                     "Scale to drow effort circle",
                                     this, SLOT( updateColorAndAlpha() ));

	history_length_property_ =
	    new rviz::IntProperty( "History Length", 1,
                                   "Number of prior measurements to display.",
                                   this, SLOT( updateHistoryLength() ));
        history_length_property_->setMin( 1 );
        history_length_property_->setMax( 100000 );

        robot_description_property_ =
            new rviz::StringProperty( "Robot Description", "robot_description",
                                      "Name of the parameter to search for to load the robot description.",
                                      this, SLOT( updateRobotDescription() ) );

        joints_category_ =
            new rviz::Property("Joints", QVariant(), "", this);
    }

    void EffortDisplay::onInitialize()
    {
        MFDClass::onInitialize();
        updateHistoryLength();
    }

    EffortDisplay::~EffortDisplay()
    {
        //delete robot_model_; // sharead pointer
    }

    // Clear the visuals by deleting their objects.
    void EffortDisplay::reset()
    {
        MFDClass::reset();
        visuals_.clear();
    }

    void EffortDisplay::clear()
    {
        clearStatuses();
        robot_description_.clear();
    }

    // Set the current color and alpha values for each visual.
    void EffortDisplay::updateColorAndAlpha()
    {
        float width = width_property_->getFloat();
        float scale = scale_property_->getFloat();

        for( size_t i = 0; i < visuals_.size(); i++ )
            {
                visuals_[ i ]->setWidth( width );
                visuals_[ i ]->setScale( scale );
            }
    }

    void EffortDisplay::updateRobotDescription()
    {
        if( isEnabled() )
            {
                load();
                context_->queueRender();
            }
    }

    // Set the number of past visuals to show.
    void EffortDisplay::updateHistoryLength( )
    {
        visuals_.rset_capacity(history_length_property_->getInt());
    }

    void EffortDisplay::load()
    {
	// get robot_description
	std::string content;
	if (!update_nh_.getParam( robot_description_property_->getStdString(), content) )  {
            std::string loc;
            if( update_nh_.searchParam( robot_description_property_->getStdString(), loc ))
                {
                    update_nh_.getParam( loc, content );
                }
            else
                {
                    clear();
                    setStatus( rviz::StatusProperty::Error, "URDF",
                               "Parameter [" + robot_description_property_->getString()
                               + "] does not exist, and was not found by searchParam()" );
                    return;
                }
            }

        if( content.empty() )
            {
                clear();
                setStatus( rviz::StatusProperty::Error, "URDF", "URDF is empty" );
                return;
            }

        if( content == robot_description_ )
            {
                return;
            }

        robot_description_ = content;

	robot_model_ = boost::shared_ptr<urdf::Model>(new urdf::Model());
	if (!robot_model_->initString(content))
	{
	    ROS_ERROR("Unable to parse URDF description!");
            setStatus( rviz::StatusProperty::Error, "URDF", "Unable to parse robot model description!");
	    return;
	}
        setStatus(rviz::StatusProperty::Ok, "URDF", "Robot model parserd Ok");
	for (std::map<std::string, boost::shared_ptr<urdf::Joint> >::iterator it = robot_model_->joints_.begin(); it != robot_model_->joints_.end(); it ++ ) {
            boost::shared_ptr<urdf::Joint> joint = it->second;
	    if ( joint->type == urdf::Joint::REVOLUTE ) {
                std::string joint_name = it->first;
		boost::shared_ptr<urdf::JointLimits> limit = joint->limits;
                joints_[joint_name] = createJoint(joint_name);
                //joints_[joint_name]->max_effort_property_->setFloat(limit->effort);
                //joints_[joint_name]->max_effort_property_->setReadOnly( true );
                joints_[joint_name]->setMaxEffort(limit->effort);
            }
        }
    }

    void EffortDisplay::onEnable()
    {
        load();
    }

    void EffortDisplay::onDisable()
    {
        clear();
    }

#if 0
    void EffortDisplay::setRobotDescription( const std::string& description_param )
    {
        description_param_ = description_param;

        propertyChanged(robot_description_property_);

        if ( isEnabled() )
            {
                load();
                unsubscribe();
                subscribe();
                causeRender();
            }
    }

    void EffortDisplay::setAllEnabled(bool enabled)
    {
        all_enabled_ = enabled;

        M_JointInfo::iterator it = joints_.begin();
        M_JointInfo::iterator end = joints_.end();
        for (; it != end; ++it)
            {
                JointInfo* joint = it->second;

                setJointEnabled(joint, enabled);
            }

        propertyChanged(all_enabled_property_);
    }

#endif
    // This is our callback to handle an incoming message.
    void EffortDisplay::processMessage( const sensor_msgs::JointState::ConstPtr& msg )
    {
        // We are keeping a circular buffer of visual pointers.  This gets
        // the next one, or creates and stores it if the buffer is not full
        boost::shared_ptr<EffortVisual> visual;
        if( visuals_.full() )
            {
                visual = visuals_.front();
            }
        else
            {
                visual.reset(new EffortVisual( context_->getSceneManager(), scene_node_, robot_model_ ));
            }

        V_string joints;
        int joint_num = msg->name.size();
        if (joint_num!=msg->effort.size())
        {
            std::string tmp_error="Received a joint state msg with different joint names and efforts size!";
            ROS_ERROR(tmp_error.c_str());
            setStatus( rviz::StatusProperty::Error, "TOPIC", QString::fromStdString(tmp_error));
            return;
        }
        for (int i = 0; i < joint_num; i++ )
        {
            std::string joint_name = msg->name[i];
            JointInfo* joint_info = getJointInfo(joint_name);
            if ( !joint_info ) continue; // skip joints..

            // set effort
            joint_info->setEffort(msg->effort[i]);

            // update effort property ???
            if ( ros::Time::now() - joint_info->last_update_ > ros::Duration(0.2) ) {
                joint_info->last_update_ = ros::Time::now();
            }

	    const urdf::Joint* joint = robot_model_->getJoint(joint_name).get();
	    int joint_type = joint->type;
	    if ( joint_type == urdf::Joint::REVOLUTE )
	    {
		// we expects that parent_link_name equals to frame_id.
		std::string parent_link_name = joint->child_link_name;
		Ogre::Quaternion orientation;
		Ogre::Vector3 position;

		// Here we call the rviz::FrameManager to get the transform from the
		// fixed frame to the frame in the header of this Effort message.  If
		// it fails, we can't do anything else so we return.
		if( !context_->getFrameManager()->getTransform( parent_link_name,
                                                                ros::Time(),
                                                                //msg->header.stamp, // ???
                                                                position, orientation ))
		{
		    ROS_DEBUG( "Error transforming from frame '%s' to frame '%s'",
			       parent_link_name.c_str(), qPrintable( fixed_frame_) );
		    continue;
		}
;
		tf::Vector3 axis_joint(joint->axis.x, joint->axis.y, joint->axis.z);
		tf::Vector3 axis_z(0,0,1);
		tf::Quaternion axis_rotation(tf::tfCross(axis_joint, axis_z), tf::tfAngle(axis_joint, axis_z));
		if ( std::isnan(axis_rotation.x()) ||
		     std::isnan(axis_rotation.y()) ||
		     std::isnan(axis_rotation.z()) ) axis_rotation = tf::Quaternion::getIdentity();

		tf::Quaternion axis_orientation(orientation.x, orientation.y, orientation.z, orientation.w);
		tf::Quaternion axis_rot = axis_orientation * axis_rotation;
		Ogre::Quaternion joint_orientation(Ogre::Real(axis_rot.w()), Ogre::Real(axis_rot.x()), Ogre::Real(axis_rot.y()), Ogre::Real(axis_rot.z()));
		visual->setFramePosition( joint_name, position );
		visual->setFrameOrientation( joint_name, joint_orientation );
                visual->setFrameEnabled( joint_name, joint_info->getEnabled() );
	    }
	}

	// Now set or update the contents of the chosen visual.
        float scale = scale_property_->getFloat();
        float width = width_property_->getFloat();
        visual->setWidth( width );
        visual->setScale( scale );
	visual->setMessage( msg );

        visuals_.push_back(visual);
    }

} // end namespace rviz

// Tell pluginlib about this class.  It is important to do this in
// global scope, outside our package's namespace.
#include <pluginlib/class_list_macros.h>
PLUGINLIB_EXPORT_CLASS( rviz::EffortDisplay, rviz::Display )

<commit_msg>[style] whitespace cleanup<commit_after>#include <OgreSceneNode.h>
#include <OgreSceneManager.h>

#include <tf/transform_listener.h>

#include <rviz/visualization_manager.h>
#include <rviz/properties/color_property.h>
#include <rviz/properties/float_property.h>
#include <rviz/properties/int_property.h>
#include <rviz/frame_manager.h>

#include <boost/foreach.hpp>

#include "effort_visual.h"

#include "effort_display.h"

#include <urdf/model.h>

namespace rviz
{

    JointInfo::JointInfo(const std::string name, rviz::Property* parent_category) {
        name_ = name;
        effort_ = 0;
        max_effort_ = 0;
        last_update_ = ros::Time::now();

        //info->category_ = new Property( QString::fromStdString( info->name_ ) , QVariant(), "", joints_category_);
        category_ = new rviz::Property( QString::fromStdString( name_ ) , true, "", parent_category, SLOT( updateVisibility() ), this);

        effort_property_ = new rviz::FloatProperty( "Effort", 0, "Effort value of this joint.", category_);
        effort_property_->setReadOnly( true );

        max_effort_property_ = new rviz::FloatProperty( "Max Effort", 0, "Max Effort value of this joint.", category_);
        max_effort_property_->setReadOnly( true );
    }

    JointInfo::~JointInfo() {
    }

    void JointInfo::updateVisibility() {
        bool enabled = getEnabled();
    }

    void JointInfo::setEffort(double e) {
        effort_property_->setFloat(e);
        effort_ = e;
    }
    double JointInfo::getEffort() { return effort_; }
    void JointInfo::setMaxEffort(double m) {
        max_effort_property_->setFloat(m);
        max_effort_ = m;
    }
    double JointInfo::getMaxEffort() { return max_effort_; }

    bool JointInfo::getEnabled() const
    {
        return category_->getValue().toBool();
    }

    JointInfo* EffortDisplay::getJointInfo( const std::string& joint)
    {
        M_JointInfo::iterator it = joints_.find( joint );
        if ( it == joints_.end() )
            {
                return NULL;
            }

        return it->second;
    }

    JointInfo* EffortDisplay::createJoint(const std::string &joint)
    {
        JointInfo *info = new JointInfo(joint, this);
        joints_.insert( std::make_pair( joint, info ) );
        return info;
    }

    ///
    EffortDisplay::EffortDisplay()
    {
	alpha_property_ =
	    new rviz::FloatProperty( "Alpha", 1.0,
                                     "0 is fully transparent, 1.0 is fully opaque.",
                                     this, SLOT( updateColorAndAlpha() ));

	width_property_ =
	    new rviz::FloatProperty( "Width", 0.02,
                                     "Width to drow effort circle",
                                     this, SLOT( updateColorAndAlpha() ));

	scale_property_ =
	    new rviz::FloatProperty( "Scale", 1.0,
                                     "Scale to drow effort circle",
                                     this, SLOT( updateColorAndAlpha() ));

	history_length_property_ =
	    new rviz::IntProperty( "History Length", 1,
                                   "Number of prior measurements to display.",
                                   this, SLOT( updateHistoryLength() ));
        history_length_property_->setMin( 1 );
        history_length_property_->setMax( 100000 );

        robot_description_property_ =
            new rviz::StringProperty( "Robot Description", "robot_description",
                                      "Name of the parameter to search for to load the robot description.",
                                      this, SLOT( updateRobotDescription() ) );

        joints_category_ =
            new rviz::Property("Joints", QVariant(), "", this);
    }

    void EffortDisplay::onInitialize()
    {
        MFDClass::onInitialize();
        updateHistoryLength();
    }

    EffortDisplay::~EffortDisplay()
    {
        //delete robot_model_; // sharead pointer
    }

    // Clear the visuals by deleting their objects.
    void EffortDisplay::reset()
    {
        MFDClass::reset();
        visuals_.clear();
    }

    void EffortDisplay::clear()
    {
        clearStatuses();
        robot_description_.clear();
    }

    // Set the current color and alpha values for each visual.
    void EffortDisplay::updateColorAndAlpha()
    {
        float width = width_property_->getFloat();
        float scale = scale_property_->getFloat();

        for( size_t i = 0; i < visuals_.size(); i++ )
            {
                visuals_[ i ]->setWidth( width );
                visuals_[ i ]->setScale( scale );
            }
    }

    void EffortDisplay::updateRobotDescription()
    {
        if( isEnabled() )
            {
                load();
                context_->queueRender();
            }
    }

    // Set the number of past visuals to show.
    void EffortDisplay::updateHistoryLength( )
    {
        visuals_.rset_capacity(history_length_property_->getInt());
    }

    void EffortDisplay::load()
    {
	// get robot_description
	std::string content;
	if (!update_nh_.getParam( robot_description_property_->getStdString(), content) )  {
            std::string loc;
            if( update_nh_.searchParam( robot_description_property_->getStdString(), loc ))
                {
                    update_nh_.getParam( loc, content );
                }
            else
                {
                    clear();
                    setStatus( rviz::StatusProperty::Error, "URDF",
                               "Parameter [" + robot_description_property_->getString()
                               + "] does not exist, and was not found by searchParam()" );
                    return;
                }
            }

        if( content.empty() )
            {
                clear();
                setStatus( rviz::StatusProperty::Error, "URDF", "URDF is empty" );
                return;
            }

        if( content == robot_description_ )
            {
                return;
            }

        robot_description_ = content;

	robot_model_ = boost::shared_ptr<urdf::Model>(new urdf::Model());
	if (!robot_model_->initString(content))
	{
	    ROS_ERROR("Unable to parse URDF description!");
            setStatus( rviz::StatusProperty::Error, "URDF", "Unable to parse robot model description!");
	    return;
	}
        setStatus(rviz::StatusProperty::Ok, "URDF", "Robot model parserd Ok");
	for (std::map<std::string, boost::shared_ptr<urdf::Joint> >::iterator it = robot_model_->joints_.begin(); it != robot_model_->joints_.end(); it ++ ) {
            boost::shared_ptr<urdf::Joint> joint = it->second;
	    if ( joint->type == urdf::Joint::REVOLUTE ) {
                std::string joint_name = it->first;
		boost::shared_ptr<urdf::JointLimits> limit = joint->limits;
                joints_[joint_name] = createJoint(joint_name);
                //joints_[joint_name]->max_effort_property_->setFloat(limit->effort);
                //joints_[joint_name]->max_effort_property_->setReadOnly( true );
                joints_[joint_name]->setMaxEffort(limit->effort);
            }
        }
    }

    void EffortDisplay::onEnable()
    {
        load();
    }

    void EffortDisplay::onDisable()
    {
        clear();
    }

#if 0
    void EffortDisplay::setRobotDescription( const std::string& description_param )
    {
        description_param_ = description_param;

        propertyChanged(robot_description_property_);

        if ( isEnabled() )
            {
                load();
                unsubscribe();
                subscribe();
                causeRender();
            }
    }

    void EffortDisplay::setAllEnabled(bool enabled)
    {
        all_enabled_ = enabled;

        M_JointInfo::iterator it = joints_.begin();
        M_JointInfo::iterator end = joints_.end();
        for (; it != end; ++it)
            {
                JointInfo* joint = it->second;

                setJointEnabled(joint, enabled);
            }

        propertyChanged(all_enabled_property_);
    }

#endif
    // This is our callback to handle an incoming message.
    void EffortDisplay::processMessage( const sensor_msgs::JointState::ConstPtr& msg )
    {
        // We are keeping a circular buffer of visual pointers.  This gets
        // the next one, or creates and stores it if the buffer is not full
        boost::shared_ptr<EffortVisual> visual;
        if (visuals_.full())
        {
            visual = visuals_.front();
        }
        else
        {
            visual.reset(new EffortVisual(context_->getSceneManager(), scene_node_, robot_model_));
        }

        V_string joints;
        int joint_num = msg->name.size();
        if (joint_num != msg->effort.size())
        {
            std::string tmp_error = "Received a joint state msg with different joint names and efforts size!";
            ROS_ERROR(tmp_error.c_str());
            setStatus(rviz::StatusProperty::Error, "TOPIC", QString::fromStdString(tmp_error));
            return;
        }
        for (int i = 0; i < joint_num; ++i)
        {
            std::string joint_name = msg->name[i];
            JointInfo* joint_info = getJointInfo(joint_name);
            if ( !joint_info ) continue; // skip joints..

            // set effort
            joint_info->setEffort(msg->effort[i]);

            // update effort property ???
            if ((ros::Time::now() - joint_info->last_update_) > ros::Duration(0.2))
            {
                joint_info->last_update_ = ros::Time::now();
            }

	    const urdf::Joint* joint = robot_model_->getJoint(joint_name).get();
	    int joint_type = joint->type;
	    if ( joint_type == urdf::Joint::REVOLUTE )
	    {
		// we expects that parent_link_name equals to frame_id.
		std::string parent_link_name = joint->child_link_name;
		Ogre::Quaternion orientation;
		Ogre::Vector3 position;

		// Here we call the rviz::FrameManager to get the transform from the
		// fixed frame to the frame in the header of this Effort message.  If
		// it fails, we can't do anything else so we return.
		if( !context_->getFrameManager()->getTransform( parent_link_name,
                                                                ros::Time(),
                                                                //msg->header.stamp, // ???
                                                                position, orientation ))
		{
		    ROS_DEBUG( "Error transforming from frame '%s' to frame '%s'",
			       parent_link_name.c_str(), qPrintable( fixed_frame_) );
		    continue;
		}
;
		tf::Vector3 axis_joint(joint->axis.x, joint->axis.y, joint->axis.z);
		tf::Vector3 axis_z(0,0,1);
		tf::Quaternion axis_rotation(tf::tfCross(axis_joint, axis_z), tf::tfAngle(axis_joint, axis_z));
		if ( std::isnan(axis_rotation.x()) ||
		     std::isnan(axis_rotation.y()) ||
		     std::isnan(axis_rotation.z()) ) axis_rotation = tf::Quaternion::getIdentity();

		tf::Quaternion axis_orientation(orientation.x, orientation.y, orientation.z, orientation.w);
		tf::Quaternion axis_rot = axis_orientation * axis_rotation;
		Ogre::Quaternion joint_orientation(Ogre::Real(axis_rot.w()), Ogre::Real(axis_rot.x()), Ogre::Real(axis_rot.y()), Ogre::Real(axis_rot.z()));
		visual->setFramePosition( joint_name, position );
		visual->setFrameOrientation( joint_name, joint_orientation );
                visual->setFrameEnabled( joint_name, joint_info->getEnabled() );
	    }
	}

	// Now set or update the contents of the chosen visual.
        float scale = scale_property_->getFloat();
        float width = width_property_->getFloat();
        visual->setWidth( width );
        visual->setScale( scale );
	visual->setMessage( msg );

        visuals_.push_back(visual);
    }

} // end namespace rviz

// Tell pluginlib about this class.  It is important to do this in
// global scope, outside our package's namespace.
#include <pluginlib/class_list_macros.h>
PLUGINLIB_EXPORT_CLASS( rviz::EffortDisplay, rviz::Display )

<|endoftext|>


<commit_before>/**
 * @file
 *      exercise_05_23.cpp
 * @author
 *      Henrik Samuelsson, henrik.samuelsson(at)gmail.com
 * @brief
 *      Exercise 5.23 from the book C++ Primer (5th edition).
 * @details
 *      Write a program that reads two integers from the standard input and
 *      prints the result of dividing the first number by the second.
 */
#include <iostream>

using std::cin;
using std::cout;
using std::endl;

int main() {
    int dividend, divisor, quotient, remainder;

    cout << "Enter two integers that will be used for divison: ";
    cin >> dividend >> divisor;

    quotient = dividend / divisor;
    remainder = dividend % divisor;

    cout << endl;
    cout << dividend << " divided by " << divisor << " yields:" << endl;
    cout << "\t" <<"quotient = " << quotient << endl;
    cout << "\t" <<"remainder = " << remainder << endl;

    return 0;
}
<commit_msg>Edit exercise 5.24.<commit_after>/**
 * @file
 *      exercise_05_23.cpp
 * @author
 *      Henrik Samuelsson, henrik.samuelsson(at)gmail.com
 * @brief
 *      Exercise 5.23 from the book C++ Primer (5th edition).
 * @details
 *      Write a program that reads two integers from the standard input and
 *      prints the result of dividing the first number by the second.
 */
#include <iostream>

using std::cin;
using std::cout;
using std::endl;

int main() {
    int dividend, divisor, quotient, remainder;

    // Get input from the user.
    cout << "Enter two integers that will be used for division: ";
    cin >> dividend >> divisor;

    // Do the calculations.
    quotient = dividend / divisor;
    remainder = dividend % divisor;

    // Present the result.
    cout << endl;
    cout << dividend << " divided by " << divisor << " yields:" << endl;
    cout << "\t" <<"quotient = " << quotient << endl;
    cout << "\t" <<"remainder = " << remainder << endl;

    return 0;
}
<|endoftext|>


<commit_before>// Copyright 2008 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
const char *help = "\
second_derivative_estimator\n\
\n\
This program estimates by finite difference the second derivative of a cost\n\
function wrt a model's parameters, in a few directions.\n";

#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <cassert>

#include "Allocator.h"
#include "CmdLine.h"
#include "DiskXFile.h"
#include "MatDataSet.h"
#include "ClassFormatDataSet.h"
#include "OneHotClassFormat.h"
#include "ClassNLLCriterion.h"
#include "matrix.h"
#include "Parameters.h"
#include "communicating_stacked_autoencoder.h"
#include "pca_estimator.h"
#include "helpers.h"

#include "analysis_utilities.h"

using namespace Torch;

// ************
// *** MAIN ***
// ************
int main(int argc, char **argv)
{
  // The command-line flags
  int flag_n_inputs;
  int flag_n_classes;
  char *flag_data_filename;
  char *flag_data_label;
  char *flag_model_filename;
  char *flag_model_label;
  char *flag_directions_filename;
  char *flag_model_type;
  char *flag_criterion_type;

  int flag_n_directions;
  real flag_epsilon;

  int flag_max_load;
  bool flag_binary_mode;

  // The actual command line
  CmdLine cmd;
  cmd.info(help);

  cmd.addICmdArg("-n_inputs", &flag_n_inputs, "number of inputs");
  cmd.addICmdArg("-n_classes", &flag_n_classes, "number of targets");
  cmd.addSCmdArg("-data_filename", &flag_data_filename, "Filename for the data.");
  cmd.addSCmdArg("-data_label", &flag_data_label, "Label for the data, ie train/test.");
  cmd.addSCmdArg("-model_filename", &flag_model_filename, "the model filename");
  cmd.addSCmdArg("-model_label", &flag_model_label, "Label for describing the model.");
  cmd.addSCmdArg("-directions_filename", &flag_directions_filename, "the name of the file containing the directions");
  cmd.addSCmdArg("-model_type", &flag_model_type, "the type of the model: csae or linear.");
  cmd.addSCmdArg("-criterion_type", &flag_criterion_type, "the type of the criterion: 'mse' or 'class-nll'.");

  cmd.addICmdOption("-n_directions", &flag_n_directions, 7, "number directions to load from the file", true);
  cmd.addRCmdOption("-epsilon", &flag_epsilon, 1e-6, "stepsize for finite difference", true);
  cmd.addICmdOption("-max_load", &flag_max_load, -1, "max number of examples to load for train", true);
  cmd.addBCmdOption("-binary_mode", &flag_binary_mode, false, "binary mode for files", true);

  cmd.read(argc, argv);

  // Allocator
  Allocator *allocator = new Allocator;

  // Load the data
  MatDataSet matdata(flag_data_filename, flag_n_inputs, 1, false,
                                flag_max_load, flag_binary_mode);
  ClassFormatDataSet *data = new(allocator) ClassFormatDataSet(&matdata,flag_n_classes);
  OneHotClassFormat class_format(data);  // Not sure about this... what if not
                                          // all classes are in the test set?

  // Load the model
  GradientMachine *model = NULL;
  if (!strcmp(flag_model_type, "csae"))
    model = LoadCSAE(allocator, flag_model_filename);
  else if (!strcmp(flag_model_type, "linear"))
    model = LoadCoder(allocator, flag_model_filename);
  else
    error("model type %s is not supported.", flag_model_type);

  // Determine the number of parameters
  int n_params = GetNParams(model);

  // Criterion
  Criterion *criterion = NULL;
  if (!strcmp(flag_criterion_type, "mse"))
    criterion = new(allocator) MSECriterion(model->n_outputs);
  else if (!strcmp(flag_criterion_type, "class-nll"))
    criterion = new(allocator) ClassNLLCriterion(&class_format);
  else
    error("criterion type %s is not supported.", flag_criterion_type);

  // Load the directions
  Mat *directions = new(allocator) Mat(flag_n_directions, n_params);
  LoadDirections(flag_directions_filename, flag_n_directions, directions);

  // Evaluate the gradient
  Vec *gradient = new(allocator) Vec(n_params);
  EvaluateGradient(model, criterion, data, gradient);

  // For each direction:
  //    - project the gradient in the direction.
  //    - step in the direction
  //    - reevaluate the gradient and project it in the direction
  //    - return to initial position
  //    - compute the second derivative
  Vec* direction = new(allocator) Vec(NULL, n_params);
  Vec* gradient_pos_step = new(allocator) Vec(n_params);
  Vec* gradient_neg_step = new(allocator) Vec(n_params);
  real gradient_in_direction, gradient_in_direction_pos_step, gradient_in_direction_neg_step;
  real second_derivative;
  real variance;

  for (int i=0; i<flag_n_directions; i++) {
    direction->ptr = directions->ptr[i];
    assert( fabs(direction->norm2()-1.0) < 1e-6 );

    gradient_in_direction = direction->iP(gradient);

    // Compute the variance in the direction
    variance = EvaluateGradientVarianceInDirection(model, criterion, data, direction);

    // Positive step
    StepInParameterSpace(model, direction, flag_epsilon);
    EvaluateGradient(model, criterion, data, gradient_pos_step);
    gradient_in_direction_pos_step = direction->iP(gradient_pos_step);

    // Negative step
    StepInParameterSpace(model, direction, -2 * flag_epsilon);
    EvaluateGradient(model, criterion, data, gradient_neg_step);
    gradient_in_direction_neg_step = direction->iP(gradient_neg_step);

    // Return to original position
    StepInParameterSpace(model, direction, flag_epsilon);

    // Compute second derivative
    second_derivative = fabs(gradient_in_direction_pos_step-gradient_in_direction_neg_step) / (2*flag_epsilon);

    std::cout << "variance: " << variance << " 2nd derivative: " << second_derivative << std::endl;
  }

  delete allocator;
  return(0);
}
<commit_msg>New functionality:  - now outputing the second derivatives to a file<commit_after>// Copyright 2008 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
const char *help = "\
second_derivative_estimator\n\
\n\
This program estimates by finite difference the second derivative of a cost\n\
function wrt a model's parameters, in a few directions.\n";

#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <cassert>

#include "Allocator.h"
#include "CmdLine.h"
#include "DiskXFile.h"
#include "MatDataSet.h"
#include "ClassFormatDataSet.h"
#include "OneHotClassFormat.h"
#include "ClassNLLCriterion.h"
#include "matrix.h"
#include "Parameters.h"
#include "communicating_stacked_autoencoder.h"
#include "pca_estimator.h"
#include "helpers.h"

#include "analysis_utilities.h"

using namespace Torch;

// ************
// *** MAIN ***
// ************
int main(int argc, char **argv)
{
  // The command-line flags
  int flag_n_inputs;
  int flag_n_classes;
  char *flag_data_filename;
  char *flag_data_label;
  char *flag_model_filename;
  char *flag_model_label;
  char *flag_directions_filename;
  char *flag_model_type;
  char *flag_criterion_type;
  int flag_is_centered;

  int flag_n_directions;
  real flag_epsilon;

  int flag_max_load;
  bool flag_binary_mode;
  char *flag_out_filename;

  // The actual command line
  CmdLine cmd;
  cmd.info(help);

  cmd.addICmdArg("-n_inputs", &flag_n_inputs, "number of inputs");
  cmd.addICmdArg("-n_classes", &flag_n_classes, "number of targets");
  cmd.addSCmdArg("-data_filename", &flag_data_filename, "Filename for the data.");
  cmd.addSCmdArg("-data_label", &flag_data_label, "Label for the data, ie train/test.");
  cmd.addSCmdArg("-model_filename", &flag_model_filename, "the model filename");
  cmd.addSCmdArg("-model_label", &flag_model_label, "Label for describing the model.");
  cmd.addSCmdArg("-directions_filename", &flag_directions_filename, "the name of the file containing the directions");
  cmd.addSCmdArg("-model_type", &flag_model_type, "the type of the model: csae or linear.");
  cmd.addSCmdArg("-criterion_type", &flag_criterion_type, "the type of the criterion: 'mse' or 'class-nll'.");
  cmd.addICmdArg("-is_centered", &flag_is_centered, "second moment (0) or variance (1).");

  cmd.addICmdOption("-n_directions", &flag_n_directions, 7, "number directions to load from the file", true);
  cmd.addRCmdOption("-epsilon", &flag_epsilon, 1e-6, "stepsize for finite difference", true);
  cmd.addICmdOption("-max_load", &flag_max_load, -1, "max number of examples to load for train", true);
  cmd.addBCmdOption("-binary_mode", &flag_binary_mode, false, "binary mode for files", true);
  cmd.addSCmdOption("-out_filename", &flag_out_filename, "second_derivatives.txt", "Name of the file to output to.", true);

  cmd.read(argc, argv);
  assert ( flag_is_centered == 0 || flag_is_centered == 1 );

  // Allocator
  Allocator *allocator = new Allocator;

  // Load the data
  MatDataSet matdata(flag_data_filename, flag_n_inputs, 1, false,
                                flag_max_load, flag_binary_mode);
  ClassFormatDataSet *data = new(allocator) ClassFormatDataSet(&matdata,flag_n_classes);
  OneHotClassFormat class_format(data);  // Not sure about this... what if not
                                          // all classes are in the test set?

  // Load the model
  GradientMachine *model = NULL;
  if (!strcmp(flag_model_type, "csae"))
    model = LoadCSAE(allocator, flag_model_filename);
  else if (!strcmp(flag_model_type, "linear"))
    model = LoadCoder(allocator, flag_model_filename);
  else
    error("model type %s is not supported.", flag_model_type);

  // Determine the number of parameters
  int n_params = GetNParams(model);
  std::cout << n_params << " parameters." << std::endl;

  // Criterion
  Criterion *criterion = NULL;
  if (!strcmp(flag_criterion_type, "mse"))
    criterion = new(allocator) MSECriterion(model->n_outputs);
  else if (!strcmp(flag_criterion_type, "class-nll"))
    criterion = new(allocator) ClassNLLCriterion(&class_format);
  else
    error("criterion type %s is not supported.", flag_criterion_type);

  // Load the directions
  Mat *directions = new(allocator) Mat(flag_n_directions, n_params);
  LoadDirections(flag_directions_filename, flag_n_directions, directions);

  // Evaluate the gradient
  Vec *gradient = new(allocator) Vec(n_params);
  EvaluateGradient(model, criterion, data, gradient);

  // For each direction:
  //    - project the gradient in the direction.
  //    - step in the direction
  //    - reevaluate the gradient and project it in the direction
  //    - return to initial position
  //    - compute the second derivative
  Vec* direction = new(allocator) Vec(NULL, n_params);
  Vec* gradient_pos_step = new(allocator) Vec(n_params);
  //Vec* gradient_neg_step = new(allocator) Vec(n_params);
  real gradient_in_direction, gradient_in_direction_pos_step;
  //real gradient_in_direction_neg_step;
  real second_derivative;
  //real variance;

  std::ofstream fd_second_der;
  fd_second_der.open(flag_out_filename);
  if (!fd_second_der.is_open())
    error("Could not open %s", flag_out_filename);

  for (int i=0; i<flag_n_directions; i++) {
    direction->ptr = directions->ptr[i];
    if( !(fabs(direction->norm2()-1.0) < 1e-6) )  {
      error("direction norm is not 1, but %d", direction->norm2());
    }

    gradient_in_direction = direction->iP(gradient);

    // Compute the variance in the direction
    //variance = EvaluateGradientVarianceInDirection(model, criterion, data, direction, flag_is_centered);

    // Positive step
    StepInParameterSpace(model, direction, flag_epsilon);
    EvaluateGradient(model, criterion, data, gradient_pos_step);
    gradient_in_direction_pos_step = direction->iP(gradient_pos_step);

    // Return to original position
    StepInParameterSpace(model, direction, -flag_epsilon);

    // Compute second derivative
    second_derivative = fabs(gradient_in_direction_pos_step-gradient_in_direction) / flag_epsilon;

    // Negative step
    //StepInParameterSpace(model, direction, -2 * flag_epsilon);
    //EvaluateGradient(model, criterion, data, gradient_neg_step);
    //gradient_in_direction_neg_step = direction->iP(gradient_neg_step);
    // Return to original position
    //StepInParameterSpace(model, direction, flag_epsilon);
    // Compute second derivative
    //second_derivative = fabs(gradient_in_direction_pos_step-gradient_in_direction_neg_step) / (2*flag_epsilon);

    //std::cout << "variance (or 2nd moment): " << variance << " 2nd derivative: " << second_derivative << std::endl;
    std::cout << second_derivative << std::endl;
    fd_second_der << second_derivative << std::endl;
  }

  fd_second_der.close();

  delete allocator;
  return(0);
}
<|endoftext|>


<commit_before><commit_msg>Dreamview: remove unused container_meta_ini flag && let kLoopIntervalMs inside loop<commit_after><|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "QtContextKeywords.h"

using namespace CPlusPlus;

static inline int classify4(const char *s) {
  if (s[0] == 'R') {
    if (s[1] == 'E') {
      if (s[2] == 'A') {
        if (s[3] == 'D') {
          return Token_READ;
        }
      }
    }
  }
  else if (s[0] == 'U') {
    if (s[1] == 'S') {
      if (s[2] == 'E') {
        if (s[3] == 'R') {
          return Token_USER;
        }
      }
    }
  }
  return Token_not_Qt_context_keyword;
}

static inline int classify5(const char *s) {
  if (s[0] == 'F') {
    if (s[1] == 'I') {
      if (s[2] == 'N') {
        if (s[3] == 'A') {
          if (s[4] == 'L') {
            return Token_FINAL;
          }
        }
      }
    }
  }
  else if (s[0] == 'R') {
    if (s[1] == 'E') {
      if (s[2] == 'S') {
        if (s[3] == 'E') {
          if (s[4] == 'T') {
            return Token_RESET;
          }
        }
      }
    }
  }
  else if (s[0] == 'W') {
    if (s[1] == 'R') {
      if (s[2] == 'I') {
        if (s[3] == 'T') {
          if (s[4] == 'E') {
            return Token_WRITE;
          }
        }
      }
    }
  }
  return Token_not_Qt_context_keyword;
}

static inline int classify6(const char *s) {
  if (s[0] == 'N') {
    if (s[1] == 'O') {
      if (s[2] == 'T') {
        if (s[3] == 'I') {
          if (s[4] == 'F') {
            if (s[5] == 'Y') {
              return Token_NOTIFY;
            }
          }
        }
      }
    }
  }
  else if (s[0] == 'S') {
    if (s[1] == 'T') {
      if (s[2] == 'O') {
        if (s[3] == 'R') {
          if (s[4] == 'E') {
            if (s[5] == 'D') {
              return Token_STORED;
            }
          }
        }
      }
    }
  }
  return Token_not_Qt_context_keyword;
}

static inline int classify8(const char *s) {
  if (s[0] == 'C') {
    if (s[1] == 'O') {
      if (s[2] == 'N') {
        if (s[3] == 'S') {
          if (s[4] == 'T') {
            if (s[5] == 'A') {
              if (s[6] == 'N') {
                if (s[7] == 'T') {
                  return Token_CONSTANT;
                }
              }
            }
          }
        }
      }
    }
  }
  return Token_not_Qt_context_keyword;
}

static inline int classify10(const char *s) {
  if (s[0] == 'D') {
    if (s[1] == 'E') {
      if (s[2] == 'S') {
        if (s[3] == 'I') {
          if (s[4] == 'G') {
            if (s[0] == 'N') {
              if (s[1] == 'A') {
                if (s[2] == 'B') {
                  if (s[3] == 'L') {
                    if (s[4] == 'E') {
                      return Token_DESIGNABLE;
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  else if (s[0] == 'S') {
    if (s[1] == 'C') {
      if (s[2] == 'R') {
        if (s[3] == 'I') {
          if (s[4] == 'P') {
            if (s[0] == 'T') {
              if (s[1] == 'A') {
                if (s[2] == 'B') {
                  if (s[3] == 'L') {
                    if (s[4] == 'E') {
                      return Token_SCRIPTABLE;
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  return Token_not_Qt_context_keyword;
}

int CPlusPlus::classifyQtContextKeyword(const char *s, int n) {
  switch (n) {
    case 4: return classify4(s);
    case 5: return classify5(s);
    case 6: return classify6(s);
    case 8: return classify8(s);
    case 10: return classify10(s);
    default: return Token_not_Qt_context_keyword;
  } // switch
}
<commit_msg>Fixed tokenizing bug.<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "QtContextKeywords.h"

using namespace CPlusPlus;

static inline int classify4(const char *s) {
  if (s[0] == 'R') {
    if (s[1] == 'E') {
      if (s[2] == 'A') {
        if (s[3] == 'D') {
          return Token_READ;
        }
      }
    }
  }
  else if (s[0] == 'U') {
    if (s[1] == 'S') {
      if (s[2] == 'E') {
        if (s[3] == 'R') {
          return Token_USER;
        }
      }
    }
  }
  return Token_not_Qt_context_keyword;
}

static inline int classify5(const char *s) {
  if (s[0] == 'F') {
    if (s[1] == 'I') {
      if (s[2] == 'N') {
        if (s[3] == 'A') {
          if (s[4] == 'L') {
            return Token_FINAL;
          }
        }
      }
    }
  }
  else if (s[0] == 'R') {
    if (s[1] == 'E') {
      if (s[2] == 'S') {
        if (s[3] == 'E') {
          if (s[4] == 'T') {
            return Token_RESET;
          }
        }
      }
    }
  }
  else if (s[0] == 'W') {
    if (s[1] == 'R') {
      if (s[2] == 'I') {
        if (s[3] == 'T') {
          if (s[4] == 'E') {
            return Token_WRITE;
          }
        }
      }
    }
  }
  return Token_not_Qt_context_keyword;
}

static inline int classify6(const char *s) {
  if (s[0] == 'N') {
    if (s[1] == 'O') {
      if (s[2] == 'T') {
        if (s[3] == 'I') {
          if (s[4] == 'F') {
            if (s[5] == 'Y') {
              return Token_NOTIFY;
            }
          }
        }
      }
    }
  }
  else if (s[0] == 'S') {
    if (s[1] == 'T') {
      if (s[2] == 'O') {
        if (s[3] == 'R') {
          if (s[4] == 'E') {
            if (s[5] == 'D') {
              return Token_STORED;
            }
          }
        }
      }
    }
  }
  return Token_not_Qt_context_keyword;
}

static inline int classify8(const char *s) {
  if (s[0] == 'C') {
    if (s[1] == 'O') {
      if (s[2] == 'N') {
        if (s[3] == 'S') {
          if (s[4] == 'T') {
            if (s[5] == 'A') {
              if (s[6] == 'N') {
                if (s[7] == 'T') {
                  return Token_CONSTANT;
                }
              }
            }
          }
        }
      }
    }
  }
  return Token_not_Qt_context_keyword;
}

static inline int classify10(const char *s) {
  if (s[0] == 'D') {
    if (s[1] == 'E') {
      if (s[2] == 'S') {
        if (s[3] == 'I') {
          if (s[4] == 'G') {
            if (s[5] == 'N') {
              if (s[6] == 'A') {
                if (s[7] == 'B') {
                  if (s[8] == 'L') {
                    if (s[9] == 'E') {
                      return Token_DESIGNABLE;
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  else if (s[0] == 'S') {
    if (s[1] == 'C') {
      if (s[2] == 'R') {
        if (s[3] == 'I') {
          if (s[4] == 'P') {
            if (s[5] == 'T') {
              if (s[6] == 'A') {
                if (s[7] == 'B') {
                  if (s[8] == 'L') {
                    if (s[9] == 'E') {
                      return Token_SCRIPTABLE;
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  return Token_not_Qt_context_keyword;
}

int CPlusPlus::classifyQtContextKeyword(const char *s, int n) {
  switch (n) {
    case 4: return classify4(s);
    case 5: return classify5(s);
    case 6: return classify6(s);
    case 8: return classify8(s);
    case 10: return classify10(s);
    default: return Token_not_Qt_context_keyword;
  } // switch
}
<|endoftext|>


<commit_before>/*****************************************************************************************
 *                                                                                *
 * OpenSpace                                                                             *
 *                                                                                *
 * Copyright (c) 2014-2017                                                               *
 *                                                                                *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this  *
 * software and associated documentation files (the "Software"), to deal in the Software *
 * without restriction, including without limitation the rights to use, copy, modify,    *
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    *
 * permit persons to whom the Software is furnished to do so, subject to the following   *
 * conditions:                                                                           *
 *                                                                                *
 * The above copyright notice and this permission notice shall be included in all copies *
 * or substantial portions of the Software.                                              *
 *                                                                                *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   *
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         *
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    *
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  *
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  *
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         *
 ****************************************************************************************/

#include <modules/newhorizons/util/sequenceparser.h>

#include <openspace/engine/openspaceengine.h>
#include <openspace/util/spicemanager.h>

#include <ghoul/logging/logmanager.h>

namespace {
    const std::string _loggerCat = "SequenceParser";
    const char* keyTranslation = "DataInputTranslation";

    const char* PlaybookIdentifierName = "Playbook";
}

namespace openspace {

std::map<std::string, ImageSubset> SequenceParser::getSubsetMap(){
    return _subsetMap;
}
std::vector<std::pair<std::string, TimeRange>> SequenceParser::getInstrumentTimes(){
    return _instrumentTimes;
}
std::vector<std::pair<double, std::string>> SequenceParser::getTargetTimes(){
    return _targetTimes;
}
std::vector<double> SequenceParser::getCaptureProgression(){
    return _captureProgression;
};

std::map<std::string, std::unique_ptr<Decoder>>& SequenceParser::getTranslation() {
    return _fileTranslation;
}

template <typename T>
void writeToBuffer(std::vector<char>& buffer, size_t& currentWriteLocation, T value) {
    if ((currentWriteLocation + sizeof(T)) > buffer.size())
        buffer.resize(2 * buffer.size());

    std::memmove(buffer.data() + currentWriteLocation, reinterpret_cast<const void*>(&value), sizeof(T));
    currentWriteLocation += sizeof(T);
}

template <>
void writeToBuffer<std::string>(std::vector<char>& buffer, size_t& currentWriteLocation, std::string value) {
    if ((currentWriteLocation + sizeof(uint8_t) + value.size()) > buffer.size())
        buffer.resize(2 * buffer.size());

    uint8_t length = static_cast<uint8_t>(value.size());
    std::memcpy(buffer.data() + currentWriteLocation, &length, sizeof(uint8_t));
    currentWriteLocation += sizeof(uint8_t);

    std::memmove(buffer.data() + currentWriteLocation, value.data(), length);
    currentWriteLocation += length;
}

void SequenceParser::sendPlaybookInformation(const std::string& name) {
    std::string fullName = std::string(PlaybookIdentifierName) + "_" + name;
    _messageIdentifier = OsEng.networkEngine().identifier(fullName);

    std::vector<char> buffer(1024);
    size_t currentWriteLocation = 0;

    // Protocol:
    // 4 bytes: Total number of bytes sent
    // 1 byte : Number of Targets (i)
    // i times: 1 byte (id), 1 byte (length j of name), j bytes (name)
    // 1 byte : Number of Instruments (i)
    // i times: 1 byte (id), 1 byte (length j of name), j bytes (name)
    // 4 byte: Number (n) of images
    // n times: 8 byte (beginning time), 8 byte (ending time), 1 byte (target id), 2 byte (instrument id)

    std::map<std::string, uint8_t> targetMap;
    uint8_t currentTargetId = 0;
    for (auto target : _subsetMap) {
        if (targetMap.find(target.first) == targetMap.end())
            targetMap[target.first] = currentTargetId++;
    }

    std::map<std::string, uint16_t> instrumentMap;
    uint16_t currentInstrumentId = 1;
    for (auto target : _subsetMap) {
        for (auto image : target.second._subset) {
            for (auto instrument : image.activeInstruments) {
                if (instrumentMap.find(instrument) == instrumentMap.end()) {
                    instrumentMap[instrument] = currentInstrumentId;
                    currentInstrumentId = currentInstrumentId << 1;
                }
            }
        }
    }

    writeToBuffer(buffer, currentWriteLocation, uint8_t(targetMap.size()));
    for (const std::pair<std::string, uint8_t>& p : targetMap) {
        writeToBuffer(buffer, currentWriteLocation, p.second);
        writeToBuffer(buffer, currentWriteLocation, p.first);
    }

    writeToBuffer(buffer, currentWriteLocation, uint8_t(instrumentMap.size()));
    for (const std::pair<std::string, uint16_t>& p : instrumentMap) {
        writeToBuffer(buffer, currentWriteLocation, p.second);
        writeToBuffer(buffer, currentWriteLocation, p.first);
    }

    uint32_t allImages = 0;
    for (auto target : _subsetMap)
        allImages += static_cast<uint32_t>(target.second._subset.size());
    writeToBuffer(buffer, currentWriteLocation, allImages);

    for (auto target : _subsetMap){
        for (auto image : target.second._subset){
            writeToBuffer(buffer, currentWriteLocation, image.timeRange.start);
            writeToBuffer(buffer, currentWriteLocation, image.timeRange.end);

            std::string timeBegin = SpiceManager::ref().dateFromEphemerisTime(image.timeRange.start);
            std::string timeEnd = SpiceManager::ref().dateFromEphemerisTime(image.timeRange.end);

            writeToBuffer(buffer, currentWriteLocation, timeBegin);
            writeToBuffer(buffer, currentWriteLocation, timeEnd);

            uint8_t targetId = targetMap[target.first];
            writeToBuffer(buffer, currentWriteLocation, targetId);
            uint16_t totalInstrumentId = 0;
            if (image.activeInstruments.empty()) {
                LERROR("Image had no active instruments");
            }

            for (auto instrument : image.activeInstruments) {
                uint16_t thisInstrumentId = instrumentMap[instrument];
                totalInstrumentId |= thisInstrumentId;
            }
            writeToBuffer(buffer, currentWriteLocation, totalInstrumentId);
        }
    }

    union {
        uint32_t value;
        std::array<char, sizeof(uint32_t)> data;
    } sizeBuffer;
    sizeBuffer.value = static_cast<uint32_t>(currentWriteLocation);
    buffer.insert(buffer.begin(), sizeBuffer.data.begin(), sizeBuffer.data.end());
    currentWriteLocation += sizeof(uint32_t);

    buffer.resize(currentWriteLocation);

    //OsEng.networkEngine()->publishMessage(PlaybookIdentifier, buffer);
    OsEng.networkEngine().setInitialConnectionMessage(_messageIdentifier, buffer);
}

}<commit_msg>Add missing include in SequenceParser<commit_after>/*****************************************************************************************
 *                                                                                *
 * OpenSpace                                                                             *
 *                                                                                *
 * Copyright (c) 2014-2017                                                               *
 *                                                                                *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this  *
 * software and associated documentation files (the "Software"), to deal in the Software *
 * without restriction, including without limitation the rights to use, copy, modify,    *
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    *
 * permit persons to whom the Software is furnished to do so, subject to the following   *
 * conditions:                                                                           *
 *                                                                                *
 * The above copyright notice and this permission notice shall be included in all copies *
 * or substantial portions of the Software.                                              *
 *                                                                                *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   *
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         *
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    *
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  *
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  *
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         *
 ****************************************************************************************/

#include <modules/newhorizons/util/sequenceparser.h>

#include <openspace/engine/openspaceengine.h>
#include <openspace/util/spicemanager.h>

#include <ghoul/logging/logmanager.h>

#include <cstring>

namespace {
    const std::string _loggerCat = "SequenceParser";
    const char* keyTranslation = "DataInputTranslation";

    const char* PlaybookIdentifierName = "Playbook";
}

namespace openspace {

std::map<std::string, ImageSubset> SequenceParser::getSubsetMap(){
    return _subsetMap;
}
std::vector<std::pair<std::string, TimeRange>> SequenceParser::getInstrumentTimes(){
    return _instrumentTimes;
}
std::vector<std::pair<double, std::string>> SequenceParser::getTargetTimes(){
    return _targetTimes;
}
std::vector<double> SequenceParser::getCaptureProgression(){
    return _captureProgression;
};

std::map<std::string, std::unique_ptr<Decoder>>& SequenceParser::getTranslation() {
    return _fileTranslation;
}

template <typename T>
void writeToBuffer(std::vector<char>& buffer, size_t& currentWriteLocation, T value) {
    if ((currentWriteLocation + sizeof(T)) > buffer.size())
        buffer.resize(2 * buffer.size());

    std::memmove(buffer.data() + currentWriteLocation, reinterpret_cast<const void*>(&value), sizeof(T));
    currentWriteLocation += sizeof(T);
}

template <>
void writeToBuffer<std::string>(std::vector<char>& buffer, size_t& currentWriteLocation, std::string value) {
    if ((currentWriteLocation + sizeof(uint8_t) + value.size()) > buffer.size())
        buffer.resize(2 * buffer.size());

    uint8_t length = static_cast<uint8_t>(value.size());
    std::memcpy(buffer.data() + currentWriteLocation, &length, sizeof(uint8_t));
    currentWriteLocation += sizeof(uint8_t);

    std::memmove(buffer.data() + currentWriteLocation, value.data(), length);
    currentWriteLocation += length;
}

void SequenceParser::sendPlaybookInformation(const std::string& name) {
    std::string fullName = std::string(PlaybookIdentifierName) + "_" + name;
    _messageIdentifier = OsEng.networkEngine().identifier(fullName);

    std::vector<char> buffer(1024);
    size_t currentWriteLocation = 0;

    // Protocol:
    // 4 bytes: Total number of bytes sent
    // 1 byte : Number of Targets (i)
    // i times: 1 byte (id), 1 byte (length j of name), j bytes (name)
    // 1 byte : Number of Instruments (i)
    // i times: 1 byte (id), 1 byte (length j of name), j bytes (name)
    // 4 byte: Number (n) of images
    // n times: 8 byte (beginning time), 8 byte (ending time), 1 byte (target id), 2 byte (instrument id)

    std::map<std::string, uint8_t> targetMap;
    uint8_t currentTargetId = 0;
    for (auto target : _subsetMap) {
        if (targetMap.find(target.first) == targetMap.end())
            targetMap[target.first] = currentTargetId++;
    }

    std::map<std::string, uint16_t> instrumentMap;
    uint16_t currentInstrumentId = 1;
    for (auto target : _subsetMap) {
        for (auto image : target.second._subset) {
            for (auto instrument : image.activeInstruments) {
                if (instrumentMap.find(instrument) == instrumentMap.end()) {
                    instrumentMap[instrument] = currentInstrumentId;
                    currentInstrumentId = currentInstrumentId << 1;
                }
            }
        }
    }

    writeToBuffer(buffer, currentWriteLocation, uint8_t(targetMap.size()));
    for (const std::pair<std::string, uint8_t>& p : targetMap) {
        writeToBuffer(buffer, currentWriteLocation, p.second);
        writeToBuffer(buffer, currentWriteLocation, p.first);
    }

    writeToBuffer(buffer, currentWriteLocation, uint8_t(instrumentMap.size()));
    for (const std::pair<std::string, uint16_t>& p : instrumentMap) {
        writeToBuffer(buffer, currentWriteLocation, p.second);
        writeToBuffer(buffer, currentWriteLocation, p.first);
    }

    uint32_t allImages = 0;
    for (auto target : _subsetMap)
        allImages += static_cast<uint32_t>(target.second._subset.size());
    writeToBuffer(buffer, currentWriteLocation, allImages);

    for (auto target : _subsetMap){
        for (auto image : target.second._subset){
            writeToBuffer(buffer, currentWriteLocation, image.timeRange.start);
            writeToBuffer(buffer, currentWriteLocation, image.timeRange.end);

            std::string timeBegin = SpiceManager::ref().dateFromEphemerisTime(image.timeRange.start);
            std::string timeEnd = SpiceManager::ref().dateFromEphemerisTime(image.timeRange.end);

            writeToBuffer(buffer, currentWriteLocation, timeBegin);
            writeToBuffer(buffer, currentWriteLocation, timeEnd);

            uint8_t targetId = targetMap[target.first];
            writeToBuffer(buffer, currentWriteLocation, targetId);
            uint16_t totalInstrumentId = 0;
            if (image.activeInstruments.empty()) {
                LERROR("Image had no active instruments");
            }

            for (auto instrument : image.activeInstruments) {
                uint16_t thisInstrumentId = instrumentMap[instrument];
                totalInstrumentId |= thisInstrumentId;
            }
            writeToBuffer(buffer, currentWriteLocation, totalInstrumentId);
        }
    }

    union {
        uint32_t value;
        std::array<char, sizeof(uint32_t)> data;
    } sizeBuffer;
    sizeBuffer.value = static_cast<uint32_t>(currentWriteLocation);
    buffer.insert(buffer.begin(), sizeBuffer.data.begin(), sizeBuffer.data.end());
    currentWriteLocation += sizeof(uint32_t);

    buffer.resize(currentWriteLocation);

    //OsEng.networkEngine()->publishMessage(PlaybookIdentifier, buffer);
    OsEng.networkEngine().setInitialConnectionMessage(_messageIdentifier, buffer);
}

}
<|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 <sched.h>
#include <unistd.h>

#include <linux/sched.h>

#include <vector>

#include <process/collect.hpp>

#include <stout/abort.hpp>
#include <stout/hashset.hpp>
#include <stout/path.hpp>
#include <stout/strings.hpp>

#include "linux/cgroups.hpp"

#include "mesos/resources.hpp"

#include "slave/containerizer/linux_launcher.hpp"

using namespace process;

using std::list;
using std::map;
using std::set;
using std::string;
using std::vector;

namespace mesos {
namespace internal {
namespace slave {

using state::RunState;

LinuxLauncher::LinuxLauncher(
    const Flags& _flags,
    int _namespaces,
    const string& _hierarchy)
  : flags(_flags),
    namespaces(_namespaces),
    hierarchy(_hierarchy) {}

// An old glibc might not have this symbol.
#ifndef CLONE_NEWNET
#define CLONE_NEWNET 0x40000000
#endif

Try<Launcher*> LinuxLauncher::create(const Flags& flags)
{
  Try<string> hierarchy = cgroups::prepare(
      flags.cgroups_hierarchy,
      "freezer",
      flags.cgroups_root);

  if (hierarchy.isError()) {
    return Error("Failed to create Linux launcher: " + hierarchy.error());
  }

  // Ensure that no other subsystem is attached to the hierarchy.
  Try<set<string> > subsystems = cgroups::subsystems(hierarchy.get());
  if (subsystems.isError()) {
    return Error(
        "Failed to get the list of attached subsystems for hierarchy " +
        hierarchy.get());
  } else if (subsystems.get().size() != 1) {
    return Error(
        "Unexpected subsystems found attached to the hierarchy " +
        hierarchy.get());
  }

  LOG(INFO) << "Using " << hierarchy.get()
            << " as the freezer hierarchy for the Linux launcher";

  int namespaces = 0;

#ifdef WITH_NETWORK_ISOLATOR
  // The network port mapping isolator requires network namespaces
  // (CLONE_NEWNET).
  if (strings::contains(flags.isolation, "network/port_mapping")) {
    namespaces |= CLONE_NEWNET;
  }
#endif

  if (strings::contains(flags.isolation, "filesystem/shared")) {
    namespaces |= CLONE_NEWNS;
  }

  // The pid namespace isolator requires pid and mount namespaces (CLONE_NEWPID
  // and CLONE_NEWNS).
  if (strings::contains(flags.isolation, "namespaces/pid")) {
    namespaces |= CLONE_NEWPID;
    namespaces |= CLONE_NEWNS;
  }

  return new LinuxLauncher(flags, namespaces, hierarchy.get());
}

Future<Nothing> _recover(const Future<list<Nothing> >& futures)
{
  return Nothing();
}

Future<Nothing> LinuxLauncher::recover(const std::list<state::RunState>& states)
{
  hashset<string> cgroups;

  foreach (const RunState& state, states) {
    if (state.id.isNone()) {
      return Failure("ContainerID is required to recover");
    }
    const ContainerID& containerId = state.id.get();

    Try<bool> exists = cgroups::exists(hierarchy, cgroup(containerId));

    if (!exists.get()) {
      // This may occur if the freezer cgroup was destroyed but the
      // slave dies before noticing this. The containerizer will
      // monitor the container's pid and notice that it has exited,
      // triggering destruction of the container.
      LOG(INFO) << "Couldn't find freezer cgroup for container " << containerId;
      continue;
    }

    if (state.forkedPid.isNone()) {
      return Failure("Executor pid is required to recover container " +
                     stringify(containerId));
    }
    pid_t pid = state.forkedPid.get();

    if (pids.containsValue(pid)) {
      // This should (almost) never occur. There is the possibility
      // that a new executor is launched with the same pid as one that
      // just exited (highly unlikely) and the slave dies after the
      // new executor is launched but before it hears about the
      // termination of the earlier executor (also unlikely).
      // Regardless, the launcher can't do anything sensible so this
      // is considered an error.
      return Failure("Detected duplicate pid " + stringify(pid) +
                     " for container " + stringify(containerId));
    }

    pids.put(containerId, pid);

    cgroups.insert(cgroup(containerId));
  }

  Try<vector<string> > orphans = cgroups::get(hierarchy, flags.cgroups_root);
  if (orphans.isError()) {
    return Failure(orphans.error());
  }

  list<Future<Nothing> > futures;

  foreach (const string& orphan, orphans.get()) {
    if (!cgroups.contains(orphan)) {
      LOG(INFO) << "Removing orphaned cgroup"
                << " '" << path::join("freezer", orphan) << "'";
      // We must wait for all cgroups to be destroyed; isolators
      // assume all processes have been terminated for any orphaned
      // containers before Isolator::recover() is called.
      futures.push_back(
          cgroups::destroy(hierarchy, orphan, cgroups::DESTROY_TIMEOUT));
    }
  }

  return collect(futures)
    .then(lambda::bind(&_recover, lambda::_1));
}

// Helper for clone() which expects an int(void*).
static int childMain(void* _func)
{
  const lambda::function<int()>* func =
    static_cast<const lambda::function<int()>*> (_func);

  return (*func)();
}

// The customized clone function which will be used by 'subprocess()'.
static pid_t clone(const lambda::function<int()>& func, int namespaces)
{
  // Stack for the child.
  // - unsigned long long used for best alignment.
  // - static is ok because each child gets their own copy after the clone.
  // - 8 MiB appears to be the default for "ulimit -s" on OSX and Linux.
  static unsigned long long stack[(8*1024*1024)/sizeof(unsigned long long)];

  LOG(INFO) << "Cloning child process with flags = " << namespaces;

  return ::clone(
      childMain,
      &stack[sizeof(stack)/sizeof(stack[0]) - 1],  // stack grows down.
      namespaces | SIGCHLD,   // Specify SIGCHLD as child termination signal.
      (void*) &func);
}

static int childSetup(
    int pipes[2],
    const Option<lambda::function<int()> >& setup)
{
  // In child.
  while (::close(pipes[1]) == -1 && errno == EINTR);

  // Do a blocking read on the pipe until the parent signals us to
  // continue.
  char dummy;
  ssize_t length;
  while ((length = ::read(pipes[0], &dummy, sizeof(dummy))) == -1 &&
         errno == EINTR);

  if (length != sizeof(dummy)) {
    ABORT("Failed to synchronize with parent");
  }

  while (::close(pipes[0]) == -1 && errno == EINTR);

  // Move to a different session (and new process group) so we're
  // independent from the slave's session (otherwise children will
  // receive SIGHUP if the slave exits).
  // TODO(idownes): perror is not listed as async-signal-safe and
  // should be reimplemented safely.
  // TODO(jieyu): Move this logic to the subprocess (i.e.,
  // mesos-containerizer launch).
  if (::setsid() == -1) {
    perror("Failed to put child in a new session");
    return 1;
  }

  if (setup.isSome()) {
    return setup.get()();
  }

  return 0;
}

Try<pid_t> LinuxLauncher::fork(
    const ContainerID& containerId,
    const string& path,
    const vector<string>& argv,
    const process::Subprocess::IO& in,
    const process::Subprocess::IO& out,
    const process::Subprocess::IO& err,
    const Option<flags::FlagsBase>& flags,
    const Option<map<string, string> >& environment,
    const Option<lambda::function<int()> >& setup)
{
  // Create a freezer cgroup for this container if necessary.
  Try<bool> exists = cgroups::exists(hierarchy, cgroup(containerId));
  if (exists.isError()) {
    return Error("Failed to check existence of freezer cgroup: " +
                 exists.error());
  }

  if (!exists.get()) {
    Try<Nothing> created = cgroups::create(hierarchy, cgroup(containerId));

    if (created.isError()) {
      return Error("Failed to create freezer cgroup: " + created.error());
    }
  }

  // Use a pipe to block the child until it's been moved into the
  // freezer cgroup.
  int pipes[2];

  // We assume this should not fail under reasonable conditions so we
  // use CHECK.
  CHECK_EQ(0, ::pipe(pipes));

  Try<Subprocess> child = subprocess(
      path,
      argv,
      in,
      out,
      err,
      flags,
      environment,
      lambda::bind(&childSetup, pipes, setup),
      lambda::bind(&clone, lambda::_1, namespaces));

  if (child.isError()) {
    return Error("Failed to clone child process: " + child.error());
  }

  // Parent.
  os::close(pipes[0]);

  // Move the child into the freezer cgroup. Any grandchildren will
  // also be contained in the cgroup.
  // TODO(jieyu): Move this logic to the subprocess (i.e.,
  // mesos-containerizer launch).
  Try<Nothing> assign = cgroups::assign(
      hierarchy,
      cgroup(containerId),
      child.get().pid());

  if (assign.isError()) {
    LOG(ERROR) << "Failed to assign process " << child.get().pid()
                << " of container '" << containerId << "'"
                << " to its freezer cgroup: " << assign.error();

    ::kill(child.get().pid(), SIGKILL);
    return Error("Failed to contain process");
  }

  // Now that we've contained the child we can signal it to continue
  // by writing to the pipe.
  char dummy;
  ssize_t length;
  while ((length = ::write(pipes[1], &dummy, sizeof(dummy))) == -1 &&
         errno == EINTR);

  os::close(pipes[1]);

  if (length != sizeof(dummy)) {
    // Ensure the child is killed.
    ::kill(child.get().pid(), SIGKILL);
    return Error("Failed to synchronize child process");
  }

  // Store the pid (session id and process group id) if this is the
  // first process forked for this container.
  if (!pids.contains(containerId)) {
    pids.put(containerId, child.get().pid());
  }

  return child.get().pid();
}

Future<Nothing> LinuxLauncher::destroy(const ContainerID& containerId)
{
  if (!pids.contains(containerId)) {
    return Failure("Unknown container");
  }

  pids.erase(containerId);

  return cgroups::destroy(
      hierarchy,
      cgroup(containerId),
      cgroups::DESTROY_TIMEOUT);
}

string LinuxLauncher::cgroup(const ContainerID& containerId)
{
  return path::join(flags.cgroups_root, containerId.value());
}

} // namespace slave {
} // namespace internal {
} // namespace mesos {
<commit_msg>Correctly recover pid in Linux launcher.<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 <sched.h>
#include <unistd.h>

#include <linux/sched.h>

#include <vector>

#include <process/collect.hpp>

#include <stout/abort.hpp>
#include <stout/hashset.hpp>
#include <stout/path.hpp>
#include <stout/strings.hpp>

#include "linux/cgroups.hpp"

#include "mesos/resources.hpp"

#include "slave/containerizer/linux_launcher.hpp"

using namespace process;

using std::list;
using std::map;
using std::set;
using std::string;
using std::vector;

namespace mesos {
namespace internal {
namespace slave {

using state::RunState;

LinuxLauncher::LinuxLauncher(
    const Flags& _flags,
    int _namespaces,
    const string& _hierarchy)
  : flags(_flags),
    namespaces(_namespaces),
    hierarchy(_hierarchy) {}

// An old glibc might not have this symbol.
#ifndef CLONE_NEWNET
#define CLONE_NEWNET 0x40000000
#endif

Try<Launcher*> LinuxLauncher::create(const Flags& flags)
{
  Try<string> hierarchy = cgroups::prepare(
      flags.cgroups_hierarchy,
      "freezer",
      flags.cgroups_root);

  if (hierarchy.isError()) {
    return Error("Failed to create Linux launcher: " + hierarchy.error());
  }

  // Ensure that no other subsystem is attached to the hierarchy.
  Try<set<string> > subsystems = cgroups::subsystems(hierarchy.get());
  if (subsystems.isError()) {
    return Error(
        "Failed to get the list of attached subsystems for hierarchy " +
        hierarchy.get());
  } else if (subsystems.get().size() != 1) {
    return Error(
        "Unexpected subsystems found attached to the hierarchy " +
        hierarchy.get());
  }

  LOG(INFO) << "Using " << hierarchy.get()
            << " as the freezer hierarchy for the Linux launcher";

  int namespaces = 0;

#ifdef WITH_NETWORK_ISOLATOR
  // The network port mapping isolator requires network namespaces
  // (CLONE_NEWNET).
  if (strings::contains(flags.isolation, "network/port_mapping")) {
    namespaces |= CLONE_NEWNET;
  }
#endif

  if (strings::contains(flags.isolation, "filesystem/shared")) {
    namespaces |= CLONE_NEWNS;
  }

  // The pid namespace isolator requires pid and mount namespaces (CLONE_NEWPID
  // and CLONE_NEWNS).
  if (strings::contains(flags.isolation, "namespaces/pid")) {
    namespaces |= CLONE_NEWPID;
    namespaces |= CLONE_NEWNS;
  }

  return new LinuxLauncher(flags, namespaces, hierarchy.get());
}

Future<Nothing> _recover(const Future<list<Nothing> >& futures)
{
  return Nothing();
}

Future<Nothing> LinuxLauncher::recover(const std::list<state::RunState>& states)
{
  hashset<string> cgroups;

  foreach (const RunState& state, states) {
    if (state.id.isNone()) {
      return Failure("ContainerID is required to recover");
    }
    const ContainerID& containerId = state.id.get();

    if (state.forkedPid.isNone()) {
      return Failure("Executor pid is required to recover container " +
                     stringify(containerId));
    }
    pid_t pid = state.forkedPid.get();

    if (pids.containsValue(pid)) {
      // This should (almost) never occur. There is the possibility
      // that a new executor is launched with the same pid as one that
      // just exited (highly unlikely) and the slave dies after the
      // new executor is launched but before it hears about the
      // termination of the earlier executor (also unlikely).
      // Regardless, the launcher can't do anything sensible so this
      // is considered an error.
      return Failure("Detected duplicate pid " + stringify(pid) +
                     " for container " + stringify(containerId));
    }

    // Store the pid now because if the freezer cgroup is absent
    // (slave terminated after the cgroup is destroyed but before it
    // was notified) then we'll still need it for the check in
    // destroy() when we clean up.
    pids.put(containerId, pid);

    Try<bool> exists = cgroups::exists(hierarchy, cgroup(containerId));

    if (!exists.get()) {
      // This may occur if the freezer cgroup was destroyed but the
      // slave dies before noticing this. The containerizer will
      // monitor the container's pid and notice that it has exited,
      // triggering destruction of the container.
      LOG(INFO) << "Couldn't find freezer cgroup for container "
                << containerId << ", assuming already destroyed";
      continue;
    }

    cgroups.insert(cgroup(containerId));
  }

  Try<vector<string> > orphans = cgroups::get(hierarchy, flags.cgroups_root);
  if (orphans.isError()) {
    return Failure(orphans.error());
  }

  list<Future<Nothing> > futures;

  foreach (const string& orphan, orphans.get()) {
    if (!cgroups.contains(orphan)) {
      LOG(INFO) << "Removing orphaned cgroup"
                << " '" << path::join("freezer", orphan) << "'";
      // We must wait for all cgroups to be destroyed; isolators
      // assume all processes have been terminated for any orphaned
      // containers before Isolator::recover() is called.
      futures.push_back(
          cgroups::destroy(hierarchy, orphan, cgroups::DESTROY_TIMEOUT));
    }
  }

  return collect(futures)
    .then(lambda::bind(&_recover, lambda::_1));
}

// Helper for clone() which expects an int(void*).
static int childMain(void* _func)
{
  const lambda::function<int()>* func =
    static_cast<const lambda::function<int()>*> (_func);

  return (*func)();
}

// The customized clone function which will be used by 'subprocess()'.
static pid_t clone(const lambda::function<int()>& func, int namespaces)
{
  // Stack for the child.
  // - unsigned long long used for best alignment.
  // - static is ok because each child gets their own copy after the clone.
  // - 8 MiB appears to be the default for "ulimit -s" on OSX and Linux.
  static unsigned long long stack[(8*1024*1024)/sizeof(unsigned long long)];

  LOG(INFO) << "Cloning child process with flags = " << namespaces;

  return ::clone(
      childMain,
      &stack[sizeof(stack)/sizeof(stack[0]) - 1],  // stack grows down.
      namespaces | SIGCHLD,   // Specify SIGCHLD as child termination signal.
      (void*) &func);
}

static int childSetup(
    int pipes[2],
    const Option<lambda::function<int()> >& setup)
{
  // In child.
  while (::close(pipes[1]) == -1 && errno == EINTR);

  // Do a blocking read on the pipe until the parent signals us to
  // continue.
  char dummy;
  ssize_t length;
  while ((length = ::read(pipes[0], &dummy, sizeof(dummy))) == -1 &&
         errno == EINTR);

  if (length != sizeof(dummy)) {
    ABORT("Failed to synchronize with parent");
  }

  while (::close(pipes[0]) == -1 && errno == EINTR);

  // Move to a different session (and new process group) so we're
  // independent from the slave's session (otherwise children will
  // receive SIGHUP if the slave exits).
  // TODO(idownes): perror is not listed as async-signal-safe and
  // should be reimplemented safely.
  // TODO(jieyu): Move this logic to the subprocess (i.e.,
  // mesos-containerizer launch).
  if (::setsid() == -1) {
    perror("Failed to put child in a new session");
    return 1;
  }

  if (setup.isSome()) {
    return setup.get()();
  }

  return 0;
}

Try<pid_t> LinuxLauncher::fork(
    const ContainerID& containerId,
    const string& path,
    const vector<string>& argv,
    const process::Subprocess::IO& in,
    const process::Subprocess::IO& out,
    const process::Subprocess::IO& err,
    const Option<flags::FlagsBase>& flags,
    const Option<map<string, string> >& environment,
    const Option<lambda::function<int()> >& setup)
{
  // Create a freezer cgroup for this container if necessary.
  Try<bool> exists = cgroups::exists(hierarchy, cgroup(containerId));
  if (exists.isError()) {
    return Error("Failed to check existence of freezer cgroup: " +
                 exists.error());
  }

  if (!exists.get()) {
    Try<Nothing> created = cgroups::create(hierarchy, cgroup(containerId));

    if (created.isError()) {
      return Error("Failed to create freezer cgroup: " + created.error());
    }
  }

  // Use a pipe to block the child until it's been moved into the
  // freezer cgroup.
  int pipes[2];

  // We assume this should not fail under reasonable conditions so we
  // use CHECK.
  CHECK_EQ(0, ::pipe(pipes));

  Try<Subprocess> child = subprocess(
      path,
      argv,
      in,
      out,
      err,
      flags,
      environment,
      lambda::bind(&childSetup, pipes, setup),
      lambda::bind(&clone, lambda::_1, namespaces));

  if (child.isError()) {
    return Error("Failed to clone child process: " + child.error());
  }

  // Parent.
  os::close(pipes[0]);

  // Move the child into the freezer cgroup. Any grandchildren will
  // also be contained in the cgroup.
  // TODO(jieyu): Move this logic to the subprocess (i.e.,
  // mesos-containerizer launch).
  Try<Nothing> assign = cgroups::assign(
      hierarchy,
      cgroup(containerId),
      child.get().pid());

  if (assign.isError()) {
    LOG(ERROR) << "Failed to assign process " << child.get().pid()
                << " of container '" << containerId << "'"
                << " to its freezer cgroup: " << assign.error();

    ::kill(child.get().pid(), SIGKILL);
    return Error("Failed to contain process");
  }

  // Now that we've contained the child we can signal it to continue
  // by writing to the pipe.
  char dummy;
  ssize_t length;
  while ((length = ::write(pipes[1], &dummy, sizeof(dummy))) == -1 &&
         errno == EINTR);

  os::close(pipes[1]);

  if (length != sizeof(dummy)) {
    // Ensure the child is killed.
    ::kill(child.get().pid(), SIGKILL);
    return Error("Failed to synchronize child process");
  }

  if (!pids.contains(containerId)) {
    pids.put(containerId, child.get().pid());
  }

  return child.get().pid();
}

Future<Nothing> LinuxLauncher::destroy(const ContainerID& containerId)
{
  if (!pids.contains(containerId)) {
    return Failure("Unknown container");
  }

  pids.erase(containerId);

  return cgroups::destroy(
      hierarchy,
      cgroup(containerId),
      cgroups::DESTROY_TIMEOUT);
}

string LinuxLauncher::cgroup(const ContainerID& containerId)
{
  return path::join(flags.cgroups_root, containerId.value());
}

} // namespace slave {
} // namespace internal {
} // namespace mesos {
<|endoftext|>