ROS2 quietly crashes when running as a forked process

asked 2020-05-09 07:27:40 -0500

cxrandolph gravatar image

updated 2020-05-09 09:13:24 -0500

Summary

I've created a simple process that forks, then launches one of two ROS2 nodes depending on which branch it is. However, the program simply quits upon instantiating a node. There is no error output. The only indication that something was wrong was when I echo the process exit code (echo $? -> 245)

Technical Details

  • Operating System: Ubuntu 19.10 Eoan
  • ROS Distribution: Eloquent

Notes

I have made sure that I can not calling any ROS2 init/shutdown code before I fork. It is only done after. Seeing as they should appear as independent processes to ROS2, I don't see why this causes a crash to happen.

Minimal Reproducible Example

I have a minimal example here that exhibits the behavior I have described in the summary:

#include <chrono>
#include <memory>
#include "rclcpp/rclcpp.hpp"
#include "tutorial_interfaces/msg/num.hpp"

extern "C" {
    #include <sched.h>
    #include <string.h>
    #include <unistd.h>
    #include <errno.h>
    #include <stdio.h>
    #include <sys/fcntl.h>
    #include <math.h>
    #include <time.h>
    #include <sys/time.h>
    #include <sys/wait.h>
}

using namespace std::chrono_literals;
using std::placeholders::_1;


/*
 *******************************************************************************
 *                             Class A Definition                              *
 *******************************************************************************
*/


class A : public rclcpp::Node {
public:

    A() : Node("A")
    {
        // Initialize publisher
        pub = this->create_publisher<tutorial_interfaces::msg::Num>("x", 10);

        // Create timer
        timer = this->create_wall_timer(100ms, std::bind(&A::dispatch_all, this));
    }

    void dispatch_all () 
    {
        auto msg = tutorial_interfaces::msg::Num();
        msg.num = 1;

        // Send a single high QoS message
        pub->publish(msg);

        // Print
        RCLCPP_INFO(this->get_logger(), "Done");
    }

private:

    // Publisher
    rclcpp::Publisher<tutorial_interfaces::msg::Num>::SharedPtr pub;

    // Timer
    rclcpp::TimerBase::SharedPtr timer;
};


/*
 *******************************************************************************
 *                             Class X Definition                              *
 *******************************************************************************
*/


class X : public rclcpp::Node {
public:
    X(): Node("X") {
        sub = this->create_subscription<tutorial_interfaces::msg::Num>("x", 10, std::bind(&X::cb, this, _1));
    }

private:

    // Subscription
    rclcpp::Subscription<tutorial_interfaces::msg::Num>::SharedPtr sub;

    // Callback
    void cb (const tutorial_interfaces::msg::Num::SharedPtr msg) const {
        RCLCPP_INFO(this->get_logger(), "X: Receivied %d", msg->num);
    }
};


/*
 *******************************************************************************
 *                                    Main                                     *
 *******************************************************************************
*/

int main (int argc, char *argv[])
{
    int set_result;
    int pid;
    int process_id = 0;


    // Fork a child process
    if ((pid = fork()) == -1) {
        fprintf(stderr, "Err: Bad fork: %s\n", strerror(errno));
    }

    // Identify child process
    if (pid == 0) {
        process_id++;
    }

    // Configure the core
    fprintf(stdout, "Fork #%d\n", process_id);

    // Init and launch ROS
    rclcpp::init(argc, argv);
    switch (process_id) {

        case 0: { // Process 0
            auto node_a = std::make_shared<A>();
            printf("Launching A on Fork #%d\n!", process_id);
            rclcpp::spin(node_a);
        }
        break;

        case 1: { // Process 1
            auto node_x = std::make_shared<X>();
            printf("Launching X on Fork #%d\n!", process_id);
            rclcpp::spin(std::make_shared<X>());
        }
        break;

        default: {
            fprintf(stderr, "Err: Unexpected case (%d)!\n", process_id);
            return -1;          
        }

    }
    rclcpp::shutdown();

    printf("Shutting down ... \n");

    // If parent - collect children
    if (process_id == 0) {
        wait(NULL);
    }

    return 0;
}
edit retag flag offensive close merge delete