<commit_before>/*************************************************************************/
/*  skeleton_editor_plugin.cpp                                           */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
/*                                                                       */
/* 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 "skeleton_editor_plugin.h"

#include "scene/3d/collision_shape.h"
#include "scene/3d/physics_body.h"
#include "scene/3d/physics_joint.h"
#include "scene/resources/capsule_shape.h"
#include "scene/resources/sphere_shape.h"
#include "spatial_editor_plugin.h"

void SkeletonEditor::_on_click_option(int p_option) {
	if (!skeleton) {
		return;
	}

	switch (p_option) {
		case MENU_OPTION_CREATE_PHYSICAL_SKELETON: {
			create_physical_skeleton();
		} break;
	}
}

void SkeletonEditor::create_physical_skeleton() {
	UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
	Node *owner = skeleton == get_tree()->get_edited_scene_root() ? skeleton : skeleton->get_owner();

	const int bc = skeleton->get_bone_count();

	if (!bc) {
		return;
	}

	Vector<BoneInfo> bones_infos;
	bones_infos.resize(bc);

	for (int bone_id = 0; bc > bone_id; ++bone_id) {

		const int parent = skeleton->get_bone_parent(bone_id);

		if (parent < 0) {

			bones_infos.write[bone_id].relative_rest = skeleton->get_bone_rest(bone_id);

		} else {

			const int parent_parent = skeleton->get_bone_parent(parent);

			bones_infos.write[bone_id].relative_rest = bones_infos[parent].relative_rest * skeleton->get_bone_rest(bone_id);

			/// create physical bone on parent
			if (!bones_infos[parent].physical_bone) {

				bones_infos.write[parent].physical_bone = create_physical_bone(parent, bone_id, bones_infos);

				ur->create_action(TTR("Create physical bones"));
				ur->add_do_method(skeleton, "add_child", bones_infos[parent].physical_bone);
				ur->add_do_reference(bones_infos[parent].physical_bone);
				ur->add_undo_method(skeleton, "remove_child", bones_infos[parent].physical_bone);
				ur->commit_action();

				bones_infos[parent].physical_bone->set_bone_name(skeleton->get_bone_name(parent));
				bones_infos[parent].physical_bone->set_owner(owner);
				bones_infos[parent].physical_bone->get_child(0)->set_owner(owner); // set shape owner

				/// Create joint between parent of parent
				if (-1 != parent_parent) {

					bones_infos[parent].physical_bone->set_joint_type(PhysicalBone::JOINT_TYPE_PIN);
				}
			}
		}
	}
}

PhysicalBone *SkeletonEditor::create_physical_bone(int bone_id, int bone_child_id, const Vector<BoneInfo> &bones_infos) {

	real_t half_height(skeleton->get_bone_rest(bone_child_id).origin.length() * 0.5);
	real_t radius(half_height * 0.2);

	CapsuleShape *bone_shape_capsule = memnew(CapsuleShape);
	bone_shape_capsule->set_height((half_height - radius) * 2);
	bone_shape_capsule->set_radius(radius);

	CollisionShape *bone_shape = memnew(CollisionShape);
	bone_shape->set_shape(bone_shape_capsule);

	Transform body_transform;
	body_transform.origin = Vector3(0, 0, -half_height);

	Transform joint_transform;
	joint_transform.origin = Vector3(0, 0, half_height);

	PhysicalBone *physical_bone = memnew(PhysicalBone);
	physical_bone->add_child(bone_shape);
	physical_bone->set_name("Physical Bone " + skeleton->get_bone_name(bone_id));
	physical_bone->set_body_offset(body_transform);
	physical_bone->set_joint_offset(joint_transform);
	return physical_bone;
}

void SkeletonEditor::edit(Skeleton *p_node) {

	skeleton = p_node;
}

void SkeletonEditor::_notification(int p_what) {
	if (p_what == NOTIFICATION_ENTER_TREE) {
		get_tree()->connect("node_removed", this, "_node_removed");
	}
}

void SkeletonEditor::_node_removed(Node *p_node) {

	if (p_node == skeleton) {
		skeleton = NULL;
		options->hide();
	}
}

void SkeletonEditor::_bind_methods() {
	ClassDB::bind_method("_on_click_option", &SkeletonEditor::_on_click_option);
	ClassDB::bind_method("_node_removed", &SkeletonEditor::_node_removed);
}

SkeletonEditor::SkeletonEditor() {
	skeleton = NULL;
	options = memnew(MenuButton);
	SpatialEditor::get_singleton()->add_control_to_menu_panel(options);

	options->set_text(TTR("Skeleton"));
	options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Skeleton", "EditorIcons"));

	options->get_popup()->add_item(TTR("Create physical skeleton"), MENU_OPTION_CREATE_PHYSICAL_SKELETON);

	options->get_popup()->connect("id_pressed", this, "_on_click_option");
	options->hide();
}

SkeletonEditor::~SkeletonEditor() {}

void SkeletonEditorPlugin::edit(Object *p_object) {
	skeleton_editor->edit(Object::cast_to<Skeleton>(p_object));
}

bool SkeletonEditorPlugin::handles(Object *p_object) const {
	return p_object->is_class("Skeleton");
}

void SkeletonEditorPlugin::make_visible(bool p_visible) {
	if (p_visible) {
		skeleton_editor->options->show();
	} else {

		skeleton_editor->options->hide();
		skeleton_editor->edit(NULL);
	}
}

SkeletonEditorPlugin::SkeletonEditorPlugin(EditorNode *p_node) {
	editor = p_node;
	skeleton_editor = memnew(SkeletonEditor);
	editor->get_viewport()->add_child(skeleton_editor);
}

SkeletonEditorPlugin::~SkeletonEditorPlugin() {}
<commit_msg>Create physical skeleton collider orientation fix<commit_after>/*************************************************************************/
/*  skeleton_editor_plugin.cpp                                           */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
/*                                                                       */
/* 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 "skeleton_editor_plugin.h"

#include "scene/3d/collision_shape.h"
#include "scene/3d/physics_body.h"
#include "scene/3d/physics_joint.h"
#include "scene/resources/capsule_shape.h"
#include "scene/resources/sphere_shape.h"
#include "spatial_editor_plugin.h"

void SkeletonEditor::_on_click_option(int p_option) {
	if (!skeleton) {
		return;
	}

	switch (p_option) {
		case MENU_OPTION_CREATE_PHYSICAL_SKELETON: {
			create_physical_skeleton();
		} break;
	}
}

void SkeletonEditor::create_physical_skeleton() {
	UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
	Node *owner = skeleton == get_tree()->get_edited_scene_root() ? skeleton : skeleton->get_owner();

	const int bc = skeleton->get_bone_count();

	if (!bc) {
		return;
	}

	Vector<BoneInfo> bones_infos;
	bones_infos.resize(bc);

	for (int bone_id = 0; bc > bone_id; ++bone_id) {

		const int parent = skeleton->get_bone_parent(bone_id);

		if (parent < 0) {

			bones_infos.write[bone_id].relative_rest = skeleton->get_bone_rest(bone_id);

		} else {

			const int parent_parent = skeleton->get_bone_parent(parent);

			bones_infos.write[bone_id].relative_rest = bones_infos[parent].relative_rest * skeleton->get_bone_rest(bone_id);

			/// create physical bone on parent
			if (!bones_infos[parent].physical_bone) {

				bones_infos.write[parent].physical_bone = create_physical_bone(parent, bone_id, bones_infos);

				ur->create_action(TTR("Create physical bones"));
				ur->add_do_method(skeleton, "add_child", bones_infos[parent].physical_bone);
				ur->add_do_reference(bones_infos[parent].physical_bone);
				ur->add_undo_method(skeleton, "remove_child", bones_infos[parent].physical_bone);
				ur->commit_action();

				bones_infos[parent].physical_bone->set_bone_name(skeleton->get_bone_name(parent));
				bones_infos[parent].physical_bone->set_owner(owner);
				bones_infos[parent].physical_bone->get_child(0)->set_owner(owner); // set shape owner

				/// Create joint between parent of parent
				if (-1 != parent_parent) {

					bones_infos[parent].physical_bone->set_joint_type(PhysicalBone::JOINT_TYPE_PIN);
				}
			}
		}
	}
}

PhysicalBone *SkeletonEditor::create_physical_bone(int bone_id, int bone_child_id, const Vector<BoneInfo> &bones_infos) {

	real_t half_height(skeleton->get_bone_rest(bone_child_id).origin.length() * 0.5);
	real_t radius(half_height * 0.2);

	CapsuleShape *bone_shape_capsule = memnew(CapsuleShape);
	bone_shape_capsule->set_height((half_height - radius) * 2);
	bone_shape_capsule->set_radius(radius);

	CollisionShape *bone_shape = memnew(CollisionShape);
	bone_shape->set_shape(bone_shape_capsule);

	Transform capsule_transform;
	capsule_transform.basis = Basis(Vector3(1, 0, 0), Vector3(0, 0, 1), Vector3(0, -1, 0));
	bone_shape->set_transform(capsule_transform);

	Transform body_transform;
	body_transform.origin = Vector3(0, 0, -half_height);

	Transform joint_transform;
	joint_transform.origin = Vector3(0, 0, half_height);

	PhysicalBone *physical_bone = memnew(PhysicalBone);
	physical_bone->add_child(bone_shape);
	physical_bone->set_name("Physical Bone " + skeleton->get_bone_name(bone_id));
	physical_bone->set_body_offset(body_transform);
	physical_bone->set_joint_offset(joint_transform);
	return physical_bone;
}

void SkeletonEditor::edit(Skeleton *p_node) {

	skeleton = p_node;
}

void SkeletonEditor::_notification(int p_what) {
	if (p_what == NOTIFICATION_ENTER_TREE) {
		get_tree()->connect("node_removed", this, "_node_removed");
	}
}

void SkeletonEditor::_node_removed(Node *p_node) {

	if (p_node == skeleton) {
		skeleton = NULL;
		options->hide();
	}
}

void SkeletonEditor::_bind_methods() {
	ClassDB::bind_method("_on_click_option", &SkeletonEditor::_on_click_option);
	ClassDB::bind_method("_node_removed", &SkeletonEditor::_node_removed);
}

SkeletonEditor::SkeletonEditor() {
	skeleton = NULL;
	options = memnew(MenuButton);
	SpatialEditor::get_singleton()->add_control_to_menu_panel(options);

	options->set_text(TTR("Skeleton"));
	options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Skeleton", "EditorIcons"));

	options->get_popup()->add_item(TTR("Create physical skeleton"), MENU_OPTION_CREATE_PHYSICAL_SKELETON);

	options->get_popup()->connect("id_pressed", this, "_on_click_option");
	options->hide();
}

SkeletonEditor::~SkeletonEditor() {}

void SkeletonEditorPlugin::edit(Object *p_object) {
	skeleton_editor->edit(Object::cast_to<Skeleton>(p_object));
}

bool SkeletonEditorPlugin::handles(Object *p_object) const {
	return p_object->is_class("Skeleton");
}

void SkeletonEditorPlugin::make_visible(bool p_visible) {
	if (p_visible) {
		skeleton_editor->options->show();
	} else {

		skeleton_editor->options->hide();
		skeleton_editor->edit(NULL);
	}
}

SkeletonEditorPlugin::SkeletonEditorPlugin(EditorNode *p_node) {
	editor = p_node;
	skeleton_editor = memnew(SkeletonEditor);
	editor->get_viewport()->add_child(skeleton_editor);
}

SkeletonEditorPlugin::~SkeletonEditorPlugin() {}
<|endoftext|>


<commit_before>#include "sdfloader.hpp"

Scene* loadSDF(std::string const& file) {
        Scene* out = new Scene;
        std::ifstream sdf;
        std::vector<std::string> lines;
        sdf.open(file);
        if(sdf.is_open()) {
                std::string line;
                while(getline(sdf, line)) {
                        lines.push_back(line);
                }
                sdf.close();
        }
        else {
                std::cout << "File could not be opened!" << std::endl;
                return out;
        }

        for (auto line : lines) {
                std::stringstream stream(line);
                std::string word;
                std::vector<std::string> words;
                while(stream.good()) {
                        stream >> word;
                        words.push_back(word);
                }

                if(words[0] == "#") {}

                if(words[0] == "define") {
                        if(words[1] == "material") {
                                std::string name = words[2];
                                Color ka{std::stof(words[3]),
                                        std::stof(words[4]),
                                        std::stof(words[5])};
                                Color kd{std::stof(words[6]),
                                        std::stof(words[7]),
                                        std::stof(words[8])};
                                Color ks{std::stof(words[9]),
                                        std::stof(words[10]),
                                        std::stof(words[11])};
                                float m = std::stof(words[12]);
                                out->materials.push_back(Material{name, ka, kd, ks, m});
                        }
                }
        }
        return out;
}<commit_msg>Add some more definitions and error handling.<commit_after>#include "sdfloader.hpp"

Scene* loadSDF(std::string const& file) {
        Scene* out = new Scene;
        std::ifstream sdf;
        std::vector<std::string> lines;
        sdf.open(file);
        if(sdf.is_open()) {
                std::string line;
                while(getline(sdf, line)) {
                        lines.push_back(line);
                }
                sdf.close();
        }
        else {
                std::cout << "File could not be opened!" << std::endl;
                return out;
        }

        int i = 0;

        for (auto line : lines) {
                i++;
                std::stringstream stream(line);
                std::string word;
                std::vector<std::string> words;
                while(stream.good()) {
                        stream >> word;
                        words.push_back(word);
                }

                if(words[0] == "#") {}

                else if(words[0] == "define") {
                        if(words[1] == "material") {
                                Color ka{std::stof(words[3]),
                                        std::stof(words[4]),
                                        std::stof(words[5])};
                                Color kd{std::stof(words[6]),
                                        std::stof(words[7]),
                                        std::stof(words[8])};
                                Color ks{std::stof(words[9]),
                                        std::stof(words[10]),
                                        std::stof(words[11])};
                                out->materials[words[2]] = Material{words[2],
                                        ka, kd, ks, std::stof(words[12])};
                        }
                        else if(words[1] == "shape") {
                                if(words[2] == "sphere") {
                                        glm::vec3 center{std::stof(words[4]),
                                                std::stof(words[5]),
                                                std::stof(words[6])};
                                        out->shapes.push_back(new Sphere{center,
                                                std::stof(words[7]), words[3],
                                                out->materials[words[8]]});
                                }
                                else if(words[2] == "box") {
                                        glm::vec3 min{std::stof(words[4]),
                                                std::stof(words[5]),
                                                std::stof(words[6])};
                                        glm::vec3 max{std::stof(words[7]),
                                                std::stof(words[8]),
                                                std::stof(words[9])};
                                        out->shapes.push_back(new Box{min, max,
                                                words[3],
                                                out->materials[words[10]]});
                                }
                                else {
                                        std::cout << "Syntax error in line " <<
                                        i << "!" << std::endl;
                                        std::cout << "Unknown object: " <<
                                        words[2] << std::endl;
                                }
                        }
                        /*
                        else if(words[1] == "light") {
                                glm::vec3 pos{std::stof(words[3]),
                                        std::stof(words[4]),
                                        std::stof(words[5])};
                                Color La{std::stof(words[6]),
                                        std::stof(words[7]),
                                        std::stof(words[8])};
                                Color Ld{std::stof(words[9]),
                                        std::stof(words[10]),
                                        std::stof(words[11])};
                                out->lights.push_back(Light{words[3], pos, La,
                                        Ld});
                        }
                        */
                        else {
                                std::cout << "Syntax error in line " << i <<
                                "!" << std::endl;
                                std::cout << "Unknown object: " << words[1] <<
                                std::endl;
                        }
                }
                /*
                else if(words[0] == "camera") {
                        out->camera.name = words[1];
                        out->camera.fov-x = std::stof(words[2]);
                }

                else if(words[0] == "render") {
                        ----
                        TODO: write parser for rendering
                        ----
                }
                */
                else {
                        std::cout << "Syntax error in line " << i << "!" <<
                        std::endl;
                        std::cout << "Unknown object: " << words[0] <<
                        std::endl;
                }
        }
        return out;
}<|endoftext|>


<commit_before>/* -------------------------------------------------------------------------- */
/* Copyright 2002-2008, Distributed Systems Architecture Group, Universidad   */
/* Complutense de Madrid (dsa-research.org)                                   */
/*                                                                            */
/* 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.                                             */
/* -------------------------------------------------------------------------- */

#include <signal.h>
#include <fcntl.h>

#include <string>
#include <iostream>
#include <sstream>

#include "MadManager.h"

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

MadManager::MadManager(vector<const Attribute*>& _mads):mad_conf(_mads)
{
    pthread_mutex_init(&mutex,0);
};

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

MadManager::~MadManager()
{
    pthread_mutex_destroy(&mutex);
};

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

extern "C" void * mad_manager_listener(
        void *                  _mm)
{
    MadManager * mm;

    mm = static_cast<MadManager *>(_mm);

    mm->listener();

    return 0;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

void MadManager::mad_manager_system_init()
{
    struct sigaction  act;

    act.sa_handler = SIG_IGN;
    act.sa_flags   = SA_RESTART;
    sigemptyset(&act.sa_mask);

    sigaction(SIGPIPE,&act,NULL);
};

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int MadManager::start()
{
    int             rc;
    int             pipes[2];

    lock();

    rc = pipe(pipes);

    if ( rc == -1)
    {
        goto error_pipe;
    }

    pipe_r = pipes[0];
    pipe_w = pipes[1];

    fcntl(pipe_r, F_SETFD, FD_CLOEXEC);
    fcntl(pipe_w, F_SETFD, FD_CLOEXEC);

    fds.push_back(pipe_r);

    rc = pthread_create(&listener_thread,
                        0,
                        mad_manager_listener,
                        (void *) this);
    if ( rc != 0 )
    {
        goto error_create;
    }

    unlock();

    return 0;

error_create:
    close(pipe_r);
    close(pipe_w);

error_pipe:

    unlock();

    return -1;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

void MadManager::stop()
{
    pthread_cancel(listener_thread);

    pthread_join(listener_thread,0);

    lock();

    close(pipe_r);

    close(pipe_w);

    for (unsigned int i=0;i<mads.size();i++)
    {
        delete mads[i];
    }

    unlock();
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int MadManager::add(Mad *mad)
{
    char    buf = 'A';
    int     rc;

    lock();

    rc = mad->start();

    if ( rc != 0 )
    {
        unlock();

        return -1;
    }

    mads.push_back(mad);

    write(pipe_w, &buf, sizeof(char));

    unlock();

    return 0;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

const Mad * MadManager::get(
    int     uid,
    const   string& name,
    const   string& value)
{
    unsigned int                        i;
    Mad *                               md = 0;
    multimap<string,string>::iterator   it;

    lock();

    for (i=0;i<mads.size();i++)
    {
        if (uid == mads[i]->uid)
        {
            it = mads[i]->attributes.find(name);

            if ((it != mads[i]->attributes.end()) &&
                    (it->second == value))
            {
                md = mads[i];
                break;
            }
        }
    }

    unlock();

    return md;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

void MadManager::listener()
{
    int             greater;
    unsigned int    i,j;
    int             rc,mrc;

    char            c;

    Mad *           mad;
    int             fd;
    fd_set          in_pipes;
    fd_set          rfds;
    struct timeval  tv;

    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);

    pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0);

    while (1)
    {
        lock();

        FD_ZERO(&in_pipes);

        for (i=0,greater=0; i < fds.size() ; i++)
        {
            FD_SET(fds[i], &in_pipes);

            if ( fds[i] > greater )
            {
                greater = fds[i];
            }
        }

        unlock();

        // Wait for a message
        rc = select(greater+1, &in_pipes, NULL, NULL, NULL);

        if ( rc <= 0 )
        {
            continue;
        }

        for (i=0; i< fds.size(); i++)
        {
            fd  = fds[i];

            if ( FD_ISSET(fd, &in_pipes) )
            {
                if ( fd == pipe_r ) // Driver added, update the fd vector
                {
                    read(fd, (void *) &c, sizeof(char));

                    lock();

                    fds.clear();

                    fds.push_back(pipe_r);

                    for (j=0;j<mads.size();j++)
                    {
                        fds.push_back(mads[j]->mad_nebula_pipe);
                    }

                    unlock();

                    continue;
                }

                mad = mads[i-1];

                buffer.str("");

                do
                {
                    FD_ZERO(&rfds);
                    FD_SET(mad->mad_nebula_pipe, &rfds);

                    tv.tv_sec  = 0;
                    tv.tv_usec = 25000;

                    rc = select(mad->mad_nebula_pipe+1,&rfds,0,0,&tv);

                    if ( rc <= 0 )
                    {
                        break;
                    }

                    rc = read(mad->mad_nebula_pipe,(void *) &c,sizeof(char));
                    buffer.put(c);
                }
                while ( rc > 0 && c != '\n');

                if ( rc <= 0 ) // Error reload the driver and recover
                {
                    mrc = mad->reload();

                    if ( mrc == 0 )
                    {
                        mad->recover();
                    }
                    else
                    {
                        lock();

                        mads.erase(mads.begin() + i - 1);

                        delete mad;

                        unlock();

                    }

                    continue;
                }
                else //MAD specific protocol
                {
                    string msg = buffer.str();

                    mad->protocol(msg);
                }
            }
        }
    }
};
<commit_msg>prevents seg fault for unknwon driver types<commit_after>/* -------------------------------------------------------------------------- */
/* Copyright 2002-2008, Distributed Systems Architecture Group, Universidad   */
/* Complutense de Madrid (dsa-research.org)                                   */
/*                                                                            */
/* 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.                                             */
/* -------------------------------------------------------------------------- */

#include <signal.h>
#include <fcntl.h>

#include <string>
#include <iostream>
#include <sstream>

#include "MadManager.h"

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

MadManager::MadManager(vector<const Attribute*>& _mads):mad_conf(_mads)
{
    pthread_mutex_init(&mutex,0);
};

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

MadManager::~MadManager()
{
    pthread_mutex_destroy(&mutex);
};

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

extern "C" void * mad_manager_listener(
        void *                  _mm)
{
    MadManager * mm;

    mm = static_cast<MadManager *>(_mm);

    mm->listener();

    return 0;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

void MadManager::mad_manager_system_init()
{
    struct sigaction  act;

    act.sa_handler = SIG_IGN;
    act.sa_flags   = SA_RESTART;
    sigemptyset(&act.sa_mask);

    sigaction(SIGPIPE,&act,NULL);
};

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int MadManager::start()
{
    int             rc;
    int             pipes[2];

    lock();

    rc = pipe(pipes);

    if ( rc == -1)
    {
        goto error_pipe;
    }

    pipe_r = pipes[0];
    pipe_w = pipes[1];

    fcntl(pipe_r, F_SETFD, FD_CLOEXEC);
    fcntl(pipe_w, F_SETFD, FD_CLOEXEC);

    fds.push_back(pipe_r);

    rc = pthread_create(&listener_thread,
                        0,
                        mad_manager_listener,
                        (void *) this);
    if ( rc != 0 )
    {
        goto error_create;
    }

    unlock();

    return 0;

error_create:
    close(pipe_r);
    close(pipe_w);

error_pipe:

    unlock();

    return -1;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

void MadManager::stop()
{
    pthread_cancel(listener_thread);

    pthread_join(listener_thread,0);

    lock();

    close(pipe_r);

    close(pipe_w);

    for (unsigned int i=0;i<mads.size();i++)
    {
        delete mads[i];
    }

    unlock();
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int MadManager::add(Mad *mad)
{
    char    buf = 'A';
    int     rc;

    if ( mad == 0 )
    {
    	return -1;
    }

    lock();

    rc = mad->start();

    if ( rc != 0 )
    {
        unlock();

        return -1;
    }

    mads.push_back(mad);

    write(pipe_w, &buf, sizeof(char));

    unlock();

    return 0;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

const Mad * MadManager::get(
    int     uid,
    const   string& name,
    const   string& value)
{
    unsigned int                        i;
    Mad *                               md = 0;
    multimap<string,string>::iterator   it;

    lock();

    for (i=0;i<mads.size();i++)
    {
        if (uid == mads[i]->uid)
        {
            it = mads[i]->attributes.find(name);

            if ((it != mads[i]->attributes.end()) &&
                    (it->second == value))
            {
                md = mads[i];
                break;
            }
        }
    }

    unlock();

    return md;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

void MadManager::listener()
{
    int             greater;
    unsigned int    i,j;
    int             rc,mrc;

    char            c;

    Mad *           mad;
    int             fd;
    fd_set          in_pipes;
    fd_set          rfds;
    struct timeval  tv;

    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);

    pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0);

    while (1)
    {
        lock();

        FD_ZERO(&in_pipes);

        for (i=0,greater=0; i < fds.size() ; i++)
        {
            FD_SET(fds[i], &in_pipes);

            if ( fds[i] > greater )
            {
                greater = fds[i];
            }
        }

        unlock();

        // Wait for a message
        rc = select(greater+1, &in_pipes, NULL, NULL, NULL);

        if ( rc <= 0 )
        {
            continue;
        }

        for (i=0; i< fds.size(); i++)
        {
            fd  = fds[i];

            if ( FD_ISSET(fd, &in_pipes) )
            {
                if ( fd == pipe_r ) // Driver added, update the fd vector
                {
                    read(fd, (void *) &c, sizeof(char));

                    lock();

                    fds.clear();

                    fds.push_back(pipe_r);

                    for (j=0;j<mads.size();j++)
                    {
                        fds.push_back(mads[j]->mad_nebula_pipe);
                    }

                    unlock();

                    continue;
                }

                mad = mads[i-1];

                buffer.str("");

                do
                {
                    FD_ZERO(&rfds);
                    FD_SET(mad->mad_nebula_pipe, &rfds);

                    tv.tv_sec  = 0;
                    tv.tv_usec = 25000;

                    rc = select(mad->mad_nebula_pipe+1,&rfds,0,0,&tv);

                    if ( rc <= 0 )
                    {
                        break;
                    }

                    rc = read(mad->mad_nebula_pipe,(void *) &c,sizeof(char));
                    buffer.put(c);
                }
                while ( rc > 0 && c != '\n');

                if ( rc <= 0 ) // Error reload the driver and recover
                {
                    mrc = mad->reload();

                    if ( mrc == 0 )
                    {
                        mad->recover();
                    }
                    else
                    {
                        lock();

                        mads.erase(mads.begin() + i - 1);

                        delete mad;

                        unlock();

                    }

                    continue;
                }
                else //MAD specific protocol
                {
                    string msg = buffer.str();

                    mad->protocol(msg);
                }
            }
        }
    }
};
<|endoftext|>


<commit_before>/*******************************************************************************
 * Copyright 2013-2014 Aerospike, 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.
 ******************************************************************************/

#include <node.h>
#include "client.h"
#include "./enums/enums.h"
using namespace v8;

/*******************************************************************************
 *  FUNCTIONS
 ******************************************************************************/

Handle<Value> client(const Arguments& args)
{
    NODE_ISOLATE_DECL;
    HANDLESCOPE;
    return scope.Close(AerospikeClient::NewInstance(args));
}

/**
 *  Aerospike key.
 *
 *      aerospike.key(namespace, set, value);
 *
 */
Handle<Value> key(const Arguments& args)
{
    NODE_ISOLATE;
    HANDLESCOPE;

    if ( args.Length() == 3 ) {
        Local<Object> key = Object::New();
        key->Set(String::NewSymbol("ns"), args[0]);
        key->Set(String::NewSymbol("set"), args[1]);
        key->Set(String::NewSymbol("key"), args[2]);
        return scope.Close(key);
    }

    return scope.Close(Undefined());
}

/**
 *  aerospike object.
 */
void Aerospike(Handle<Object> exports, Handle<Object> module)
{
    AerospikeClient::Init();

    exports->Set(String::NewSymbol("client"),   FunctionTemplate::New(client)->GetFunction());
    exports->Set(String::NewSymbol("key"),      FunctionTemplate::New(key)->GetFunction());
    exports->Set(String::NewSymbol("status"),   status());
    exports->Set(String::NewSymbol("policy"),   policy());
    exports->Set(String::NewSymbol("operator"), operators());
    exports->Set(String::NewSymbol("log"),      log());
}

NODE_MODULE(aerospike, Aerospike)
<commit_msg>Exposed LUA as a language type for UDF API.<commit_after>/*******************************************************************************
 * Copyright 2013-2014 Aerospike, 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.
 ******************************************************************************/

#include <node.h>
#include "client.h"
#include "./enums/enums.h"
using namespace v8;

/*******************************************************************************
 *  FUNCTIONS
 ******************************************************************************/

Handle<Value> client(const Arguments& args)
{
    NODE_ISOLATE_DECL;
    HANDLESCOPE;
    return scope.Close(AerospikeClient::NewInstance(args));
}

/**
 *  Aerospike key.
 *
 *      aerospike.key(namespace, set, value);
 *
 */
Handle<Value> key(const Arguments& args)
{
    NODE_ISOLATE;
    HANDLESCOPE;

    if ( args.Length() == 3 ) {
        Local<Object> key = Object::New();
        key->Set(String::NewSymbol("ns"), args[0]);
        key->Set(String::NewSymbol("set"), args[1]);
        key->Set(String::NewSymbol("key"), args[2]);
        return scope.Close(key);
    }

    return scope.Close(Undefined());
}

/**
 *  aerospike object.
 */
void Aerospike(Handle<Object> exports, Handle<Object> module)
{
    AerospikeClient::Init();

    exports->Set(String::NewSymbol("client"),   FunctionTemplate::New(client)->GetFunction());
    exports->Set(String::NewSymbol("key"),      FunctionTemplate::New(key)->GetFunction());
    exports->Set(String::NewSymbol("status"),   status());
    exports->Set(String::NewSymbol("policy"),   policy());
    exports->Set(String::NewSymbol("operator"), operators());
	exports->Set(String::NewSymbol("language"), languages());
    exports->Set(String::NewSymbol("log"),      log());
}

NODE_MODULE(aerospike, Aerospike)
<|endoftext|>


<commit_before>/*******************************************************************************
 * Copyright 2013-2017 Aerospike, 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.
 ******************************************************************************/

#include <node.h>
#include "enums.h"

using namespace v8;

#define set(__obj, __name, __value) __obj->Set(Nan::New(__name).ToLocalChecked(), Nan::New(__value))

Local<Object> ttl_enum_values()
{
    Nan::EscapableHandleScope scope;
    Local<Object> obj = Nan::New<Object>();
    set(obj, "NAMESPACE_DEFAULT", TTL_NAMESPACE_DEFAULT);
    set(obj, "NEVER_EXPIRE", TTL_NEVER_EXPIRE);
    set(obj, "DONT_UPDDATE", TTL_DONT_UPDATE);
    return scope.Escape(obj);
}
<commit_msg>Fix typo<commit_after>/*******************************************************************************
 * Copyright 2013-2017 Aerospike, 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.
 ******************************************************************************/

#include <node.h>
#include "enums.h"

using namespace v8;

#define set(__obj, __name, __value) __obj->Set(Nan::New(__name).ToLocalChecked(), Nan::New(__value))

Local<Object> ttl_enum_values()
{
    Nan::EscapableHandleScope scope;
    Local<Object> obj = Nan::New<Object>();
    set(obj, "NAMESPACE_DEFAULT", TTL_NAMESPACE_DEFAULT);
    set(obj, "NEVER_EXPIRE", TTL_NEVER_EXPIRE);
    set(obj, "DONT_UPDATE", TTL_DONT_UPDATE);
    return scope.Escape(obj);
}
<|endoftext|>


<commit_before>#include "dataload_ros.h"
#include <QTextStream>
#include <QFile>
#include <QMessageBox>
#include <QDebug>
#include <QApplication>
#include <QProgressDialog>
#include <QElapsedTimer>

#include <rosbag/view.h>

#include "../dialog_select_ros_topics.h"
#include "../shape_shifter_factory.hpp"
#include "../rule_editing.h"

DataLoadROS::DataLoadROS()
{
    _extensions.push_back( "bag");
}

const std::vector<const char*> &DataLoadROS::compatibleFileExtensions() const
{
    return _extensions;
}

PlotDataMap DataLoadROS::readDataFromFile(const QString &file_name,
                                          QString &load_configuration  )
{
    using namespace RosIntrospection;

    std::vector<std::pair<QString,QString>> all_topics;
    PlotDataMap plot_map;

    rosbag::Bag bag;
    try{
        bag.open( file_name.toStdString(), rosbag::bagmode::Read );
    }
    catch( rosbag::BagException&  ex)
    {
        QMessageBox::warning(0, tr("Error"),
                             QString("rosbag::open thrown an exception:\n")+
                             QString(ex.what()) );
        return plot_map;
    }

    rosbag::View bag_view ( bag, ros::TIME_MIN, ros::TIME_MAX, true );
    std::vector<const rosbag::ConnectionInfo *> connections = bag_view.getConnections();

    for(unsigned i=0;  i<connections.size(); i++)
    {
        const auto&  topic      =  connections[i]->topic;
        const auto&  md5sum     =  connections[i]->md5sum;
        const auto&  data_type  =  connections[i]->datatype;
        const auto&  definition =  connections[i]->msg_def;

        all_topics.push_back( std::make_pair(QString( topic.c_str()), QString( data_type.c_str()) ) );
        RosIntrospectionFactory::get().registerMessage(topic, md5sum, data_type, definition);
    }

    int count = 0;

    //----------------------------------
    QStringList default_topic_names = load_configuration.split(' ',QString::SkipEmptyParts);
    load_configuration.clear();

    DialogSelectRosTopics* dialog = new DialogSelectRosTopics( all_topics, default_topic_names );

    std::set<QString> topic_selected;

    if( dialog->exec() == QDialog::Accepted)
    {
        const auto& selected_items = dialog->getSelectedItems();
        for(const auto& item: selected_items)
        {
            QString topic = item;
            topic_selected.insert( topic );

            // change the names in load_configuration
            load_configuration.append( topic ).append(" ");
        }
        // load the rules
        if( dialog->checkBoxUseRenamingRules()->isChecked())
        {
            _rules = RuleEditing::getRenamingRules();
        }
    }

    //-----------------------------------
    QProgressDialog progress_dialog;
    progress_dialog.setLabelText("Loading... please wait");
    progress_dialog.setWindowModality( Qt::ApplicationModal );

    {
        // get the total number of messages
        rosbag::View bag_view_selected ( true );
        bag_view_selected.addQuery(bag, [&topic_selected](rosbag::ConnectionInfo const* connection)
        {
            return topic_selected.count( QString( connection->topic.c_str()) ) > 0;
        } );
        progress_dialog.setRange(0, bag_view_selected.size()-1);
    }

    progress_dialog.show();

    QElapsedTimer timer;
    timer.start();

    for(const QString& topic_name: topic_selected)
    {
        rosbag::View bag_view_reduced ( true );
        bag_view_reduced.addQuery(bag, [&topic_name](rosbag::ConnectionInfo const* connection)
        {
            return topic_name == QString( connection->topic.c_str() );
        } );

        ROSTypeFlat flat_container;

        const std::string topic  = topic_name.toStdString();

        SString topicname_SS( topic.data(),  topic.size() );
        // WORKAROUND. There are some problems related to renaming when the character / is
        // used as prefix. We will remove that here.
        if( topicname_SS.at(0) == '/' ) topicname_SS = SString( topic.data() +1,  topic.size()-1 );

        for(const rosbag::MessageInstance& msg: bag_view_reduced )
        {
            const auto& datatype   = msg.getDataType();
            auto msg_size = msg.size();

            std::vector<uint8_t> buffer ( msg_size );

            if( count++ %1000 == 0)
            {
                progress_dialog.setValue( count );
                QApplication::processEvents();

                if( progress_dialog.wasCanceled() ) {
                    return PlotDataMap();
                }
            }

            ros::serialization::OStream stream(buffer.data(), buffer.size());

            // this single line takes almost the entire time of the loop
            msg.write(stream);

            auto typelist = RosIntrospectionFactory::get().getRosTypeList( topic );
            if( !typelist )
            {
                throw std::runtime_error("Can't retrieve the ROSTypeList from RosIntrospectionFactory");
            }
            buildRosFlatType( *typelist, datatype, topicname_SS, buffer.data(), &flat_container);
            applyNameTransform( _rules[datatype], &flat_container );

            // apply time offsets
            double msg_time;

            if(dialog->checkBoxUseHeaderStamp()->isChecked() == false)
            {
                msg_time = msg.getTime().toSec();
            }
            else{
                auto offset = FlatContainedContainHeaderStamp(flat_container);
                if(offset){
                    msg_time = offset.value();
                }
                else{
                    msg_time = msg.getTime().toSec();
                }
            }

            for(const auto& it: flat_container.renamed_value )
            {
                std::string field_name( it.first.data(), it.first.size());

                auto plot_pair = plot_map.numeric.find( field_name );
                if( plot_pair == plot_map.numeric.end() )
                {
                    PlotDataPtr temp(new PlotData(field_name.c_str()));
                    auto res = plot_map.numeric.insert( std::make_pair(field_name, temp ) );
                    plot_pair = res.first;
                }

                PlotDataPtr& plot_data = plot_pair->second;
                plot_data->pushBack( PlotData::Point(msg_time, (double)it.second));
            } //end of for flat_container.renamed_value

            //-----------------------------------------
            // adding raw serialized topic for future uses.
            {
                auto plot_pair = plot_map.user_defined.find( topic );

                if( plot_pair == plot_map.user_defined.end() )
                {
                    PlotDataAnyPtr temp(new PlotDataAny(topic.c_str()));
                    auto res = plot_map.user_defined.insert( std::make_pair( topic, temp ) );
                    plot_pair = res.first;
                }
                PlotDataAnyPtr& plot_raw = plot_pair->second;
                plot_raw->pushBack( PlotDataAny::Point(msg_time, nonstd::any(std::move(buffer)) ));
            }
        }
    }
    qDebug() << "The loading operation took" << timer.elapsed() << "milliseconds";
    return plot_map;
}

DataLoadROS::~DataLoadROS()
{

}

<commit_msg>fix for very large rosbags<commit_after>#include "dataload_ros.h"
#include <QTextStream>
#include <QFile>
#include <QMessageBox>
#include <QDebug>
#include <QApplication>
#include <QProgressDialog>
#include <QElapsedTimer>
#include <QFileInfo>
#include <QProcess>
#include <rosbag/view.h>
#include <sys/sysinfo.h>

#include "../dialog_select_ros_topics.h"
#include "../shape_shifter_factory.hpp"
#include "../rule_editing.h"

DataLoadROS::DataLoadROS()
{
    _extensions.push_back( "bag");
}

const std::vector<const char*> &DataLoadROS::compatibleFileExtensions() const
{
    return _extensions;
}

size_t getAvailableRAM()
{
    struct sysinfo info;
    sysinfo(&info);
    return info.freeram;
}

PlotDataMap DataLoadROS::readDataFromFile(const QString &file_name,
                                          QString &load_configuration  )
{
    using namespace RosIntrospection;

    std::vector<std::pair<QString,QString>> all_topics;
    PlotDataMap plot_map;

    QFileInfo file_info(file_name);
    bool disable_caching = false;

    if(  file_info.size() > getAvailableRAM())
    {
        QMessageBox::StandardButton reply;
        reply = QMessageBox::question(0, tr("Carefull"),
                                      QString("Your system has %1 MB for free memory (RAM)\n"
                                              "You are trying to load file that is %2 MB.\n\n"
                                              "If you load all the topics, you might experience problems.\n\n"
                                              "Do you want to DISABLE caching for messages which exceed 100 KB?\n"
                                              "Typically this includes images, maps, pointclouds, etc.\n\n"
                                              "If you select [YES], those messages cannot be republished.")
                                      .arg(getAvailableRAM() / (1024*1024))
                                      .arg(file_info.size() / (1024*1024)) ,
                                      QMessageBox::Yes|QMessageBox::No);

        if (reply == QMessageBox::Yes) {
            disable_caching = true;
        }
    }

    rosbag::Bag bag;
    try{
        bag.open( file_name.toStdString(), rosbag::bagmode::Read );
    }
    catch( rosbag::BagException&  ex)
    {
        QMessageBox::warning(0, tr("Error"),
                             QString("rosbag::open thrown an exception:\n")+
                             QString(ex.what()) );
        return plot_map;
    }

    rosbag::View bag_view ( bag, ros::TIME_MIN, ros::TIME_MAX, true );
    std::vector<const rosbag::ConnectionInfo *> connections = bag_view.getConnections();

    for(unsigned i=0;  i<connections.size(); i++)
    {
        const auto&  topic      =  connections[i]->topic;
        const auto&  md5sum     =  connections[i]->md5sum;
        const auto&  data_type  =  connections[i]->datatype;
        const auto&  definition =  connections[i]->msg_def;

        all_topics.push_back( std::make_pair(QString( topic.c_str()), QString( data_type.c_str()) ) );
        RosIntrospectionFactory::get().registerMessage(topic, md5sum, data_type, definition);
    }

    int count = 0;

    //----------------------------------
    QStringList default_topic_names = load_configuration.split(' ',QString::SkipEmptyParts);
    load_configuration.clear();

    DialogSelectRosTopics* dialog = new DialogSelectRosTopics( all_topics, default_topic_names );

    std::set<QString> topic_selected;

    if( dialog->exec() == static_cast<int>(QDialog::Accepted) )
    {
        const auto& selected_items = dialog->getSelectedItems();
        for(const auto& item: selected_items)
        {
            QString topic = item;
            topic_selected.insert( topic );

            // change the names in load_configuration
            load_configuration.append( topic ).append(" ");
        }
        // load the rules
        if( dialog->checkBoxUseRenamingRules()->isChecked())
        {
            _rules = RuleEditing::getRenamingRules();
        }
    }

    //-----------------------------------
    QProgressDialog progress_dialog;
    progress_dialog.setLabelText("Loading... please wait");
    progress_dialog.setWindowModality( Qt::ApplicationModal );

    rosbag::View bag_view_selected ( true );
    bag_view_selected.addQuery(bag, [&topic_selected](rosbag::ConnectionInfo const* connection)
    {
        return topic_selected.count( QString( connection->topic.c_str()) ) > 0;
    } );
    progress_dialog.setRange(0, bag_view_selected.size()-1);

    progress_dialog.show();

    QElapsedTimer timer;
    timer.start();

    ROSTypeFlat flat_container;

    for(const rosbag::MessageInstance& msg: bag_view_selected )
    {
        const std::string& topic  = msg.getTopic();

        SString topicname_SS;
        // WORKAROUND. There are some problems related to renaming when the character / is
        // used as prefix. We will remove that here.
        if( topic.at(0) == '/' )
            topicname_SS = SString( topic.data() +1,  topic.size()-1 );
        else
            topicname_SS = SString( topic.data(),  topic.size() );

        const auto& datatype   = msg.getDataType();
        auto msg_size = msg.size();

        std::vector<uint8_t> buffer ( msg_size );

        if( count++ %1000 == 0)
        {
            progress_dialog.setValue( count );
            QApplication::processEvents();

            if( progress_dialog.wasCanceled() ) {
                return PlotDataMap();
            }
        }

        ros::serialization::OStream stream(buffer.data(), buffer.size());

        // this single line takes almost the entire time of the loop
        msg.write(stream);

        auto typelist = RosIntrospectionFactory::get().getRosTypeList( topic );
        if( !typelist )
        {
            throw std::runtime_error("Can't retrieve the ROSTypeList from RosIntrospectionFactory");
        }
        buildRosFlatType( *typelist, datatype, topicname_SS, buffer.data(), &flat_container);
        applyNameTransform( _rules[datatype], &flat_container );

        // apply time offsets
        double msg_time;

        if(dialog->checkBoxUseHeaderStamp()->isChecked() == false)
        {
            msg_time = msg.getTime().toSec();
        }
        else{
            auto offset = FlatContainedContainHeaderStamp(flat_container);
            if(offset){
                msg_time = offset.value();
            }
            else{
                msg_time = msg.getTime().toSec();
            }
        }

        for(const auto& it: flat_container.renamed_value )
        {
            std::string field_name( it.first.data(), it.first.size());

            auto plot_pair = plot_map.numeric.find( field_name );
            if( plot_pair == plot_map.numeric.end() )
            {
                PlotDataPtr temp(new PlotData(field_name.c_str()));
                auto res = plot_map.numeric.insert( std::make_pair(field_name, temp ) );
                plot_pair = res.first;
            }

            PlotDataPtr& plot_data = plot_pair->second;
            plot_data->pushBack( PlotData::Point(msg_time, (double)it.second));
        } //end of for flat_container.renamed_value

        //-----------------------------------------
        // adding raw serialized topic for future uses.
        if( !disable_caching &&  msg_size > 100*1024*1024)
        {
            auto plot_pair = plot_map.user_defined.find( topic );

            if( plot_pair == plot_map.user_defined.end() )
            {
                PlotDataAnyPtr temp(new PlotDataAny(topic.c_str()));
                auto res = plot_map.user_defined.insert( std::make_pair( topic, temp ) );
                plot_pair = res.first;
            }
            PlotDataAnyPtr& plot_raw = plot_pair->second;
            plot_raw->pushBack( PlotDataAny::Point(msg_time, nonstd::any(std::move(buffer)) ));
        }
    }

    qDebug() << "The loading operation took" << timer.elapsed() << "milliseconds";
    return plot_map;
}

DataLoadROS::~DataLoadROS()
{

}

<|endoftext|>


<commit_before>// This file is part of Poseidon.
// Copyleft 2020, LH_Mouse. All wrongs reserved.

#include "precompiled.hpp"
#include "core/config_file.hpp"
#include "static/main_config.hpp"
#include "static/async_logger.hpp"
#include "static/timer_driver.hpp"
#include "static/network_driver.hpp"
#include "static/worker_pool.hpp"
#include "static/fiber_scheduler.hpp"
#include "utilities.hpp"
#include <locale.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <dlfcn.h>

using namespace poseidon;

namespace {

[[noreturn]]
int
do_print_help_and_exit(const char* self)
  {
    ::printf(
//        1         2         3         4         5         6         7     |
// 3456789012345678901234567890123456789012345678901234567890123456789012345|
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""" R"'''''''''''''''(
Usage: %s [OPTIONS] [[--] DIRECTORY]

  -d      daemonize
  -h      show help message then exit
  -V      show version information then exit
  -v      enable verbose mode

Daemonization, if requested, is performed after loading config files. Early
failues are printed to standard error.

If DIRECTORY is specified, the working directory is switched there before
doing everything else.

Visit the homepage at <%s>.
Report bugs to <%s>.
)'''''''''''''''" """"""""""""""""""""""""""""""""""""""""""""""""""""""""+1,
// 3456789012345678901234567890123456789012345678901234567890123456789012345|
//        1         2         3         4         5         6         7     |
      self,
      PACKAGE_URL,
      PACKAGE_BUGREPORT);

    ::fflush(stdout);
    ::quick_exit(0);
  }

const char*
do_tell_build_time()
  {
    static char s_time_str[64];
    if(ROCKET_EXPECT(s_time_str[0]))
      return s_time_str;

    // Convert the build time to ISO 8601 format.
    ::tm tr;
    ::std::memset(&tr, 0, sizeof(tr));
    ::strptime(__DATE__ " " __TIME__, "%b %d %Y %H:%M:%S", &tr);
    ::strftime(s_time_str, sizeof(s_time_str), "%Y-%m-%d %H:%M:%S", &tr);
    return s_time_str;
  }

[[noreturn]]
int
do_print_version_and_exit()
  {
    ::printf(
//        1         2         3         4         5         6         7     |
// 3456789012345678901234567890123456789012345678901234567890123456789012345|
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""" R"'''''''''''''''(
%s [built on %s]

Visit the homepage at <%s>.
Report bugs to <%s>.
)'''''''''''''''" """"""""""""""""""""""""""""""""""""""""""""""""""""""""+1,
// 3456789012345678901234567890123456789012345678901234567890123456789012345|
//        1         2         3         4         5         6         7     |
      PACKAGE_STRING, do_tell_build_time(),
      PACKAGE_URL,
      PACKAGE_BUGREPORT);

    ::fflush(stdout);
    ::quick_exit(0);
  }

// We want to detect Ctrl-C.
atomic_signal exit_sig;

void
do_trap_exit_signal(int sig)
noexcept
  {
    // Trap Ctrl-C. Failure to set the signal handler is ignored.
    struct ::sigaction sigx = { };
    sigx.sa_handler = [](int n) { exit_sig.store(n);  };
    ::sigaction(sig, &sigx, nullptr);
  }

// Define command-line options here.
struct Command_Line_Options
  {
    // options
    bool daemonize = false;
    bool verbose = false;

    // non-options
    cow_string cd_here;
  };

// This may also be automatic objects. It is declared here for convenience.
Command_Line_Options cmdline;

// These are process exit status codes.
enum Exit_Code : uint8_t
  {
    exit_success            = 0,
    exit_system_error       = 1,
    exit_invalid_argument   = 2,
    exit_root_disallowed    = 3,
  };

[[noreturn]] ROCKET_NOINLINE
int
do_exit(Exit_Code code, const char* fmt, ...)
noexcept
  {
    // Sleep for a few moments so pending logs are flushed.
    Async_Logger::synchronize(1000);

    // Output the string to standard error.
    ::va_list ap;
    va_start(ap, fmt);
    ::vfprintf(stderr, fmt, ap);
    va_end(ap);

    // Perform fast exit.
    ::fflush(nullptr);
    ::quick_exit(static_cast<int>(code));
  }

ROCKET_NOINLINE
void
do_parse_command_line(int argc, char** argv)
  {
    bool help = false;
    bool version = false;

    opt<bool> daemonize;
    opt<bool> verbose;
    opt<cow_string> cd_here;

    // Check for some common options before calling `getopt()`.
    if(argc > 1) {
      if(::strcmp(argv[1], "--help") == 0)
        do_print_help_and_exit(argv[0]);

      if(::strcmp(argv[1], "--version") == 0)
        do_print_version_and_exit();
    }

    // Parse command-line options.
    int ch;
    while((ch = ::getopt(argc, argv, "+dhVv")) != -1) {
      // Identify a single option.
      switch(ch) {
        case 'd':
          daemonize = true;
          continue;

        case 'h':
          help = true;
          continue;

        case 'V':
          version = true;
          continue;

        case 'v':
          verbose = true;
          continue;
      }

      // `getopt()` will have written an error message to standard error.
      do_exit(exit_invalid_argument, "Try `%s -h` for help.\n",
                                     argv[0]);
    }

    // Check for early exit conditions.
    if(help)
      do_print_help_and_exit(argv[0]);

    if(version)
      do_print_version_and_exit();

    // If more arguments follow, they denote the working directory.
    if(argc - optind > 1)
      do_exit(exit_invalid_argument, "%s: too many arguments -- '%s'\n"
                                     "Try `%s -h` for help.\n",
                                     argv[0], argv[optind+1],
                                     argv[0]);

    if(argc - optind > 0)
      cd_here = cow_string(argv[optind]);

    // Daemonization mode is off by default.
    if(daemonize)
      cmdline.daemonize = *daemonize;

    // Verbose mode is off by default.
    if(verbose)
      cmdline.verbose = *verbose;

    // The default working directory is empty which means 'do not switch'.
    if(cd_here)
      cmdline.cd_here = ::std::move(*cd_here);
  }

ROCKET_NOINLINE
void
do_check_euid()
  {
    const auto file = Main_Config::copy();
    const auto qroot = file.get_bool_opt({"general","permit_root_startup"});
    if(qroot && *qroot)
      return;

    if(::geteuid() == 0)
      do_exit(exit_root_disallowed,
              "Please do not start this program as root.\n"
              "If you insist, you may set `general.permit_root_startup` in `main.conf`\n"
              "to `true` to bypass this check. Note that starting as root is considered\n"
              "insecure. An unprivileged user should have been created for this service.\n"
              "You have been warned.\n");
  }

ROCKET_NOINLINE
void
do_load_addons()
  {
    const auto file = Main_Config::copy();
    const auto qaddons = file.get_array_opt({"addons"});
    if(!qaddons)
      return;

    POSEIDON_LOG_DEBUG("List of add-ons to load:\n$1", *qaddons);

    for(const auto& addon : *qaddons) {
      // Load the shared library denoted by `addon`
      if(!addon.is_string())
        POSEIDON_THROW("Invalid add-on path (`$1` is not a string)", addon);

      const auto& path = addon.as_string();
      POSEIDON_LOG_INFO("Loading add-on: $1", path);

      if(!::dlopen(path.safe_c_str(), RTLD_NOW | RTLD_LOCAL | RTLD_NODELETE))
        POSEIDON_THROW("Error loading add-on '$1'\n"
                       "[`dlopen()` failed: $2]",
                       path, ::dlerror());

      POSEIDON_LOG_INFO("Finished loading add-on: $1", path);
    }
  }

}  // namespace

int
main(int argc, char** argv)
  try {
    // Select the C locale.
    // UTF-8 is required for wide-oriented standard streams.
    ::setlocale(LC_ALL, "C.UTF-8");

    // Note that this function shall not return in case of errors.
    do_parse_command_line(argc, argv);

    // Set current working directory if one is specified.
    if(cmdline.cd_here.size())
      if(::chdir(cmdline.cd_here.safe_c_str()) != 0)
        POSEIDON_THROW("Could not set working directory to '$2'\n"
                       "[`chdir()` failed: $1]",
                       format_errno(errno), cmdline.cd_here);

    // Load 'main.conf' before daemonization, so any earlier failures are
    // visible to the user.
    Main_Config::reload();
    Async_Logger::reload();
    Network_Driver::reload();
    Worker_Pool::reload();
    Fiber_Scheduler::reload();

    do_check_euid();

    // Daemonize the process before entering modal loop.
    if(cmdline.daemonize)
      if(::daemon(1, 0) != 0)
        POSEIDON_THROW("Could not daemonize process\n"
                       "[`chdir()` failed: $1]",
                       format_errno(errno));

    // Set name of the main thread. Failure to set the name is ignored.
    ::pthread_setname_np(::pthread_self(), "poseidon");

    // Disable cancellation for safety. Failure to set the cancel state is ignored.
    ::pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, nullptr);

    // Trap exit signals. Failure to set signal handlers is ignored.
    // This also makes stdio functions fail immediately.
    do_trap_exit_signal(SIGINT);
    do_trap_exit_signal(SIGTERM);
    do_trap_exit_signal(SIGHUP);
    do_trap_exit_signal(SIGALRM);

    // Ignore `SIGPIPE` for good.
    ::signal(SIGPIPE, SIG_IGN);

    // Start daemon threads.
    POSEIDON_LOG_INFO("Starting up: $1 (PID $2)", PACKAGE_STRING, ::getpid());
    Async_Logger::start();
    Timer_Driver::start();
    Network_Driver::start();
    do_load_addons();
    POSEIDON_LOG_INFO("Started up and running: $1 (PID $2)", PACKAGE_STRING, ::getpid());

    // Schedule fibers until a termination signal is caught.
    Fiber_Scheduler::modal_loop(exit_sig);
  }
  catch(exception& stdex) {
    // Print the message in `stdex`. There isn't much we can do.
    do_exit(exit_system_error, "%s\n[exception class `%s`]\n",
                               stdex.what(), typeid(stdex).name());
  }
<commit_msg>main: Check core file limit upon startup<commit_after>// This file is part of Poseidon.
// Copyleft 2020, LH_Mouse. All wrongs reserved.

#include "precompiled.hpp"
#include "core/config_file.hpp"
#include "static/main_config.hpp"
#include "static/async_logger.hpp"
#include "static/timer_driver.hpp"
#include "static/network_driver.hpp"
#include "static/worker_pool.hpp"
#include "static/fiber_scheduler.hpp"
#include "utilities.hpp"
#include <locale.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <dlfcn.h>
#include <sys/resource.h>

using namespace poseidon;

namespace {

[[noreturn]]
int
do_print_help_and_exit(const char* self)
  {
    ::printf(
//        1         2         3         4         5         6         7     |
// 3456789012345678901234567890123456789012345678901234567890123456789012345|
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""" R"'''''''''''''''(
Usage: %s [OPTIONS] [[--] DIRECTORY]

  -d      daemonize
  -h      show help message then exit
  -V      show version information then exit
  -v      enable verbose mode

Daemonization, if requested, is performed after loading config files. Early
failues are printed to standard error.

If DIRECTORY is specified, the working directory is switched there before
doing everything else.

Visit the homepage at <%s>.
Report bugs to <%s>.
)'''''''''''''''" """"""""""""""""""""""""""""""""""""""""""""""""""""""""+1,
// 3456789012345678901234567890123456789012345678901234567890123456789012345|
//        1         2         3         4         5         6         7     |
      self,
      PACKAGE_URL,
      PACKAGE_BUGREPORT);

    ::fflush(stdout);
    ::quick_exit(0);
  }

const char*
do_tell_build_time()
  {
    static char s_time_str[64];
    if(ROCKET_EXPECT(s_time_str[0]))
      return s_time_str;

    // Convert the build time to ISO 8601 format.
    ::tm tr;
    ::std::memset(&tr, 0, sizeof(tr));
    ::strptime(__DATE__ " " __TIME__, "%b %d %Y %H:%M:%S", &tr);
    ::strftime(s_time_str, sizeof(s_time_str), "%Y-%m-%d %H:%M:%S", &tr);
    return s_time_str;
  }

[[noreturn]]
int
do_print_version_and_exit()
  {
    ::printf(
//        1         2         3         4         5         6         7     |
// 3456789012345678901234567890123456789012345678901234567890123456789012345|
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""" R"'''''''''''''''(
%s [built on %s]

Visit the homepage at <%s>.
Report bugs to <%s>.
)'''''''''''''''" """"""""""""""""""""""""""""""""""""""""""""""""""""""""+1,
// 3456789012345678901234567890123456789012345678901234567890123456789012345|
//        1         2         3         4         5         6         7     |
      PACKAGE_STRING, do_tell_build_time(),
      PACKAGE_URL,
      PACKAGE_BUGREPORT);

    ::fflush(stdout);
    ::quick_exit(0);
  }

// We want to detect Ctrl-C.
atomic_signal exit_sig;

void
do_trap_exit_signal(int sig)
noexcept
  {
    // Trap Ctrl-C. Failure to set the signal handler is ignored.
    struct ::sigaction sigx = { };
    sigx.sa_handler = [](int n) { exit_sig.store(n);  };
    ::sigaction(sig, &sigx, nullptr);
  }

// Define command-line options here.
struct Command_Line_Options
  {
    // options
    bool daemonize = false;
    bool verbose = false;

    // non-options
    cow_string cd_here;
  };

// This may also be automatic objects. It is declared here for convenience.
Command_Line_Options cmdline;

// These are process exit status codes.
enum Exit_Code : uint8_t
  {
    exit_success            = 0,
    exit_system_error       = 1,
    exit_invalid_argument   = 2,
    exit_root_disallowed    = 3,
  };

[[noreturn]] ROCKET_NOINLINE
int
do_exit(Exit_Code code, const char* fmt, ...)
noexcept
  {
    // Sleep for a few moments so pending logs are flushed.
    Async_Logger::synchronize(1000);

    // Output the string to standard error.
    ::va_list ap;
    va_start(ap, fmt);
    ::vfprintf(stderr, fmt, ap);
    va_end(ap);

    // Perform fast exit.
    ::fflush(nullptr);
    ::quick_exit(static_cast<int>(code));
  }

ROCKET_NOINLINE
void
do_parse_command_line(int argc, char** argv)
  {
    bool help = false;
    bool version = false;

    opt<bool> daemonize;
    opt<bool> verbose;
    opt<cow_string> cd_here;

    // Check for some common options before calling `getopt()`.
    if(argc > 1) {
      if(::strcmp(argv[1], "--help") == 0)
        do_print_help_and_exit(argv[0]);

      if(::strcmp(argv[1], "--version") == 0)
        do_print_version_and_exit();
    }

    // Parse command-line options.
    int ch;
    while((ch = ::getopt(argc, argv, "+dhVv")) != -1) {
      // Identify a single option.
      switch(ch) {
        case 'd':
          daemonize = true;
          continue;

        case 'h':
          help = true;
          continue;

        case 'V':
          version = true;
          continue;

        case 'v':
          verbose = true;
          continue;
      }

      // `getopt()` will have written an error message to standard error.
      do_exit(exit_invalid_argument, "Try `%s -h` for help.\n",
                                     argv[0]);
    }

    // Check for early exit conditions.
    if(help)
      do_print_help_and_exit(argv[0]);

    if(version)
      do_print_version_and_exit();

    // If more arguments follow, they denote the working directory.
    if(argc - optind > 1)
      do_exit(exit_invalid_argument, "%s: too many arguments -- '%s'\n"
                                     "Try `%s -h` for help.\n",
                                     argv[0], argv[optind+1],
                                     argv[0]);

    if(argc - optind > 0)
      cd_here = cow_string(argv[optind]);

    // Daemonization mode is off by default.
    if(daemonize)
      cmdline.daemonize = *daemonize;

    // Verbose mode is off by default.
    if(verbose)
      cmdline.verbose = *verbose;

    // The default working directory is empty which means 'do not switch'.
    if(cd_here)
      cmdline.cd_here = ::std::move(*cd_here);
  }

ROCKET_NOINLINE
void
do_check_euid()
  {
    const auto file = Main_Config::copy();
    const auto qroot = file.get_bool_opt({"general","permit_root_startup"});
    if(qroot && *qroot)
      return;

    if(::geteuid() == 0)
      do_exit(exit_root_disallowed,
              "Please do not start this program as root.\n"
              "If you insist, you may set `general.permit_root_startup` in `main.conf`\n"
              "to `true` to bypass this check. Note that starting as root is considered\n"
              "insecure. An unprivileged user should have been created for this service.\n"
              "You have been warned.\n");
  }

ROCKET_NOINLINE
void
do_check_core_dump()
  {
    ::rlimit rlim;
    if(::getrlimit(RLIMIT_CORE, &rlim) != 0)
      POSEIDON_THROW("Could not get core dump limit\n"
                     "[`getrlimit()` failed: $1]",
                     format_errno(errno));

    if(rlim.rlim_cur <= 0)
      POSEIDON_LOG_WARN("Core dumps are disabled.\n"
                        "We highly suggest you enable them in case of crashes.\n"
                        "See `/etc/security/limits.conf` for details.");
  }

ROCKET_NOINLINE
void
do_load_addons()
  {
    const auto file = Main_Config::copy();
    const auto qaddons = file.get_array_opt({"addons"});
    if(!qaddons)
      return;

    POSEIDON_LOG_DEBUG("List of add-ons to load:\n$1", *qaddons);

    for(const auto& addon : *qaddons) {
      // Load the shared library denoted by `addon`
      if(!addon.is_string())
        POSEIDON_THROW("Invalid add-on path (`$1` is not a string)", addon);

      const auto& path = addon.as_string();
      POSEIDON_LOG_INFO("Loading add-on: $1", path);

      if(!::dlopen(path.safe_c_str(), RTLD_NOW | RTLD_LOCAL | RTLD_NODELETE))
        POSEIDON_THROW("Error loading add-on '$1'\n"
                       "[`dlopen()` failed: $2]",
                       path, ::dlerror());

      POSEIDON_LOG_INFO("Finished loading add-on: $1", path);
    }
  }

}  // namespace

int
main(int argc, char** argv)
  try {
    // Select the C locale.
    // UTF-8 is required for wide-oriented standard streams.
    ::setlocale(LC_ALL, "C.UTF-8");

    // Note that this function shall not return in case of errors.
    do_parse_command_line(argc, argv);

    // Set current working directory if one is specified.
    if(cmdline.cd_here.size())
      if(::chdir(cmdline.cd_here.safe_c_str()) != 0)
        POSEIDON_THROW("Could not set working directory to '$2'\n"
                       "[`chdir()` failed: $1]",
                       format_errno(errno), cmdline.cd_here);

    // Load 'main.conf' before daemonization, so any earlier failures are
    // visible to the user.
    Main_Config::reload();
    Async_Logger::reload();
    Network_Driver::reload();
    Worker_Pool::reload();
    Fiber_Scheduler::reload();

    do_check_euid();

    // Daemonize the process before entering modal loop.
    if(cmdline.daemonize)
      if(::daemon(1, 0) != 0)
        POSEIDON_THROW("Could not daemonize process\n"
                       "[`chdir()` failed: $1]",
                       format_errno(errno));

    // Set name of the main thread. Failure to set the name is ignored.
    ::pthread_setname_np(::pthread_self(), "poseidon");

    // Disable cancellation for safety. Failure to set the cancel state is ignored.
    ::pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, nullptr);

    // Trap exit signals. Failure to set signal handlers is ignored.
    // This also makes stdio functions fail immediately.
    do_trap_exit_signal(SIGINT);
    do_trap_exit_signal(SIGTERM);
    do_trap_exit_signal(SIGHUP);
    do_trap_exit_signal(SIGALRM);

    // Ignore `SIGPIPE` for good.
    ::signal(SIGPIPE, SIG_IGN);

    // Start daemon threads.
    POSEIDON_LOG_INFO("Starting up: $1 (PID $2)", PACKAGE_STRING, ::getpid());

    Async_Logger::start();
    Timer_Driver::start();
    Network_Driver::start();

    do_check_core_dump();
    do_load_addons();

    POSEIDON_LOG_INFO("Started up and running: $1 (PID $2)", PACKAGE_STRING, ::getpid());

    // Schedule fibers until a termination signal is caught.
    Fiber_Scheduler::modal_loop(exit_sig);
  }
  catch(exception& stdex) {
    // Print the message in `stdex`. There isn't much we can do.
    do_exit(exit_system_error, "%s\n[exception class `%s`]\n",
                               stdex.what(), typeid(stdex).name());
  }
<|endoftext|>


<commit_before>#define PRIMITIVES_MAIN_IMPL
#include <primitives/main.h>

#include <primitives/error_handling.h>

#include <iostream>
#include <exception>

#ifdef _WIN32
#include <Windows.h>
#endif

static int error = 1;

void exit_handler()
{
    if (error)
        debug_break_if_debugger_attached();
}

int main1(int argc, char *argv[])
{
    atexit(exit_handler);
    try
    {
        return error = PRIMITIVES_MAIN(argc, argv);
    }
    catch (const std::exception &e)
    {
        std::cerr << e.what() << std::endl;
    }
    catch (...)
    {
        std::cerr << "unknown exception" << std::endl;
    }
    return 2;
}

int main(int argc, char *argv[])
{
#ifdef _WIN32
    __try
    {
#endif
        return main1(argc, argv);
#ifdef _WIN32
    }
    //__except (EXCEPTION_CONTINUE_SEARCH)
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        std::cerr << "unknown SEH exception" << std::endl;
    }
#endif
    return 1;
}
<commit_msg>Execute error handler early.<commit_after>#define PRIMITIVES_MAIN_IMPL
#include <primitives/main.h>

#include <primitives/error_handling.h>

#include <iostream>
#include <exception>

#ifdef _WIN32
#include <Windows.h>
#endif

static int error = 1;

void exit_handler()
{
    if (error)
        debug_break_if_debugger_attached();
    error = 0; // clear flag to prevent double break
}

int main1(int argc, char *argv[])
{
    atexit(exit_handler);
    try
    {
        return error = PRIMITIVES_MAIN(argc, argv);
    }
    catch (const std::exception &e)
    {
        std::cerr << e.what() << std::endl;
    }
    catch (...)
    {
        std::cerr << "unknown exception" << std::endl;
    }
    exit_handler();
    return 2;
}

int main(int argc, char *argv[])
{
#ifdef _WIN32
    __try
    {
#endif
        return main1(argc, argv);
#ifdef _WIN32
    }
    //__except (EXCEPTION_CONTINUE_SEARCH)
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        std::cerr << "unknown SEH exception" << std::endl;
    }
#endif
    return 1;
}
<|endoftext|>


<commit_before>// Copyright (c) 2009 - Mozy, Inc.

#include "mordor/predef.h"

#include "stdoutlistener.h"

#include <iostream>

#include <boost/exception/all.hpp>

using namespace Mordor;
using namespace Mordor::Test;

StdoutListener::StdoutListener()
: m_tests(0),
  m_success(0),
  m_skip(0)
{}

void
StdoutListener::testStarted(const std::string &suite, const std::string &test)
{
    if (test != "<invariant>")
        ++m_tests;
    std::cout << "Running " << suite << "::" << test << ": ";
    std::cout.flush();
}

void
StdoutListener::testComplete(const std::string &suite, const std::string &test)
{
    if (test != "<invariant>")
        ++m_success;
    std::cout << "OK" << std::endl;
}

void
StdoutListener::testSkipped(const std::string &suite, const std::string &test)
{
    if (test != "<invariant>") {
        ++m_skip;
        --m_tests;
    }
    std::cout << "skipped" << std::endl;
}

void
StdoutListener::testAsserted(const std::string &suite, const std::string &test,
                             const Assertion &assertion)
{
    std::cerr << "Assertion: "
        << boost::current_exception_diagnostic_information() << std::endl;
    m_failures.push_back(std::make_pair(suite, test));
}

void
StdoutListener::testException(const std::string &suite, const std::string &test)
{
    std::cerr << "Unexpected exception: "
        << boost::current_exception_diagnostic_information() << std::endl;
    m_failures.push_back(std::make_pair(suite, test));
}

void
StdoutListener::testsComplete()
{
    std::cout << "Tests complete.  " << m_success << "/" << m_tests
        << " passed, " << m_skip << " skipped." << std::endl;
    if (!m_failures.empty()) {
        std::cout << "Failures:" << std::endl;
        for (std::vector<std::pair<std::string, std::string> >::iterator
            it = m_failures.begin();
            it != m_failures.end();
            ++it)
                std::cout << '\t' << it->first << "::" << it->second
                    << std::endl;
    }
}
<commit_msg>Add start time to the stdout of the mordor test suite runner.<commit_after>// Copyright (c) 2009 - Mozy, Inc.

#include "mordor/predef.h"
#include "mordor/config.h"
#include "stdoutlistener.h"

#include <iostream>

#include <boost/exception/all.hpp>

using namespace Mordor;
using namespace Mordor::Test;

static ConfigVar<bool>::ptr g_include_startime =
    Config::lookup<bool>("mordor.test.outputstarttime", true, "Print start time in test output");

StdoutListener::StdoutListener()
: m_tests(0),
  m_success(0),
  m_skip(0)
{}

void
StdoutListener::testStarted(const std::string &suite, const std::string &test)
{
    if (test != "<invariant>")
        ++m_tests;
    std::cout << "Running ";
    if( g_include_startime->val() )
        std::cout << "(" << time(NULL) << ") ";
    std::cout << suite << "::" << test << ": ";
    std::cout.flush();
}

void
StdoutListener::testComplete(const std::string &suite, const std::string &test)
{
    if (test != "<invariant>")
        ++m_success;
    std::cout << "OK" << std::endl;
}

void
StdoutListener::testSkipped(const std::string &suite, const std::string &test)
{
    if (test != "<invariant>") {
        ++m_skip;
        --m_tests;
    }
    std::cout << "skipped" << std::endl;
}

void
StdoutListener::testAsserted(const std::string &suite, const std::string &test,
                             const Assertion &assertion)
{
    std::cerr << "Assertion: "
        << boost::current_exception_diagnostic_information() << std::endl;
    m_failures.push_back(std::make_pair(suite, test));
}

void
StdoutListener::testException(const std::string &suite, const std::string &test)
{
    std::cerr << "Unexpected exception: "
        << boost::current_exception_diagnostic_information() << std::endl;
    m_failures.push_back(std::make_pair(suite, test));
}

void
StdoutListener::testsComplete()
{
    std::cout << "Tests complete.  " << m_success << "/" << m_tests
        << " passed, " << m_skip << " skipped." << std::endl;
    if (!m_failures.empty()) {
        std::cout << "Failures:" << std::endl;
        for (std::vector<std::pair<std::string, std::string> >::iterator
            it = m_failures.begin();
            it != m_failures.end();
            ++it)
                std::cout << '\t' << it->first << "::" << it->second
                    << std::endl;
    }
}
<|endoftext|>