From 63e46639a254a1ad7362dd02517e0721f20ad68e Mon Sep 17 00:00:00 2001
From: Thomas Moulard <thomas.moulard@gmail.com>
Date: Tue, 28 Feb 2012 01:38:33 +0100
Subject: [PATCH] Improve spinner management.

---
 include/dynamic_graph_bridge/ros_init.hh |  6 +++-
 src/interpreter.cpp                      |  3 +-
 src/ros_export.cpp                       | 12 ++------
 src/ros_export.hh                        |  3 +-
 src/ros_import.cpp                       |  3 +-
 src/ros_import.hh                        |  2 +-
 src/ros_init.cpp                         | 36 ++++++++++++++++++++----
 src/ros_joint_state.cpp                  | 14 ++-------
 src/ros_joint_state.hh                   |  2 +-
 9 files changed, 49 insertions(+), 32 deletions(-)

diff --git a/include/dynamic_graph_bridge/ros_init.hh b/include/dynamic_graph_bridge/ros_init.hh
index e7dea47..996d244 100644
--- a/include/dynamic_graph_bridge/ros_init.hh
+++ b/include/dynamic_graph_bridge/ros_init.hh
@@ -4,7 +4,11 @@
 
 namespace dynamicgraph
 {
-  ros::NodeHandle& rosInit();
+  ros::NodeHandle& rosInit (bool createAsyncSpinner);
+
+  /// \brief Return spinner or throw an exception if spinner
+  /// creation has been disabled at startup.
+  ros::AsyncSpinner& spinner ();
 
 } // end of namespace dynamicgraph.
 
diff --git a/src/interpreter.cpp b/src/interpreter.cpp
index a9b4e8a..db9efb6 100644
--- a/src/interpreter.cpp
+++ b/src/interpreter.cpp
@@ -3,7 +3,8 @@
 
 int main ()
 {
-  ros::NodeHandle& nodeHandle = dynamicgraph::rosInit ();
+  // we spin explicitly so we do not need an async spinner here.
+  ros::NodeHandle& nodeHandle = dynamicgraph::rosInit (false);
   dynamicgraph::Interpreter interpreter (nodeHandle);
   ros::spin ();
 }
diff --git a/src/ros_export.cpp b/src/ros_export.cpp
index ea74ff6..0336ff4 100644
--- a/src/ros_export.cpp
+++ b/src/ros_export.cpp
@@ -119,12 +119,9 @@ namespace dynamicgraph
 
   RosExport::RosExport (const std::string& n)
     : dynamicgraph::Entity(n),
-      nh_ (rosInit ()),
-      bindedSignal_ (),
-      spinner_ (1)
+      nh_ (rosInit (true)),
+      bindedSignal_ ()
   {
-    spinner_.start ();
-
     std::string docstring;
     addCommand ("add",
 		new command::rosExport::Add
@@ -141,10 +138,7 @@ namespace dynamicgraph
   }
 
   RosExport::~RosExport ()
-  {
-    spinner_.stop ();
-    nh_.shutdown ();
-  }
+  {}
 
   void RosExport::display (std::ostream& os) const
   {
diff --git a/src/ros_export.hh b/src/ros_export.hh
index 800df9c..564ee64 100644
--- a/src/ros_export.hh
+++ b/src/ros_export.hh
@@ -99,9 +99,8 @@ namespace dynamicgraph
     template <typename T>
     friend class internal::Add;
   private:
-    ros::NodeHandle nh_;
+    ros::NodeHandle& nh_;
     std::map<std::string, bindedSignal_t> bindedSignal_;
-    ros::AsyncSpinner spinner_;
   };
 } // end of namespace dynamicgraph.
 
diff --git a/src/ros_import.cpp b/src/ros_import.cpp
index 1f007a4..6fdde8c 100644
--- a/src/ros_import.cpp
+++ b/src/ros_import.cpp
@@ -122,7 +122,8 @@ namespace dynamicgraph
 
   RosImport::RosImport (const std::string& n)
     : dynamicgraph::Entity(n),
-      nh_ (rosInit ()),
+      // rosImport do not use callback so do not create a useless spinner.
+      nh_ (rosInit (false)),
       bindedSignal_ (),
       trigger_ (boost::bind (&RosImport::trigger, this, _1, _2),
 		sotNOSIGNAL,
diff --git a/src/ros_import.hh b/src/ros_import.hh
index aff0cd2..c42723a 100644
--- a/src/ros_import.hh
+++ b/src/ros_import.hh
@@ -87,7 +87,7 @@ namespace dynamicgraph
     void add (const std::string& signal, const std::string& topic);
 
   private:
-    ros::NodeHandle nh_;
+    ros::NodeHandle& nh_;
     std::map<std::string, bindedSignal_t> bindedSignal_;
     dynamicgraph::SignalTimeDependent<int,int> trigger_;
     ros::Duration rate_;
diff --git a/src/ros_init.cpp b/src/ros_init.cpp
index fc7c83f..8253d10 100644
--- a/src/ros_init.cpp
+++ b/src/ros_init.cpp
@@ -1,3 +1,4 @@
+#include <stdexcept>
 #include <boost/make_shared.hpp>
 #include <boost/shared_ptr.hpp>
 
@@ -5,11 +6,24 @@
 
 namespace dynamicgraph
 {
-  boost::shared_ptr<ros::NodeHandle> nodeHandle;
+  struct GlobalRos
+  {
+    ~GlobalRos ()
+    {
+      if (spinner)
+	spinner->stop ();
+      if (nodeHandle)
+	nodeHandle->shutdown ();
+    }
+
+    boost::shared_ptr<ros::NodeHandle> nodeHandle;
+    boost::shared_ptr<ros::AsyncSpinner> spinner;
+  };
+  GlobalRos ros;
 
-  ros::NodeHandle& rosInit()
+  ros::NodeHandle& rosInit (bool createAsyncSpinner)
   {
-    if (!nodeHandle)
+    if (!ros.nodeHandle)
       {
 	int argc = 1;
 	char* arg0 = strdup("dynamic_graph_bridge");
@@ -17,8 +31,20 @@ namespace dynamicgraph
 	ros::init(argc, argv, "dynamic_graph_bridge");
 	free (arg0);
 
-	nodeHandle = boost::make_shared<ros::NodeHandle> ("dynamic_graph");
+	ros.nodeHandle = boost::make_shared<ros::NodeHandle> ("dynamic_graph");
+      }
+    if (!ros.spinner && createAsyncSpinner)
+      {
+	ros.spinner = boost::make_shared<ros::AsyncSpinner> (1);
+	ros.spinner->start ();
       }
-    return *nodeHandle;
+    return *ros.nodeHandle;
+  }
+
+  ros::AsyncSpinner& spinner ()
+  {
+    if (!ros.spinner)
+      throw std::runtime_error ("spinner has not been created");
+    return *ros.spinner;
   }
 } // end of namespace dynamicgraph.
diff --git a/src/ros_joint_state.cpp b/src/ros_joint_state.cpp
index eeddd68..b35fe82 100644
--- a/src/ros_joint_state.cpp
+++ b/src/ros_joint_state.cpp
@@ -3,6 +3,7 @@
 
 #include <dynamic-graph/factory.h>
 
+#include "dynamic_graph_bridge/ros_init.hh"
 #include "ros_joint_state.hh"
 #include "sot_to_ros.hh"
 
@@ -40,19 +41,10 @@ namespace dynamicgraph
 {
   DYNAMICGRAPH_FACTORY_ENTITY_PLUGIN(RosJointState, "RosJointState");
 
-  static const char* rosInit()
-  {
-    int argc = 1;
-    char* arg0 = strdup("ros_joint_state");
-    char* argv[] = {arg0, 0};
-    ros::init(argc, argv, "ros_joint_state");
-    free (arg0);
-    return "dynamic_graph";
-  }
-
   RosJointState::RosJointState (const std::string& n)
     : Entity (n),
-      nh_ (rosInit ()),
+      // do not use callbacks, so do not create a useless spinner
+      nh_ (rosInit (false)),
       state_ (0, MAKE_SIGNAL_STRING(name, true, "Vector", "state")),
       publisher_ (nh_, "joint_states", 5),
       jointState_ (),
diff --git a/src/ros_joint_state.hh b/src/ros_joint_state.hh
index ea9a1a6..9d9ff2b 100644
--- a/src/ros_joint_state.hh
+++ b/src/ros_joint_state.hh
@@ -28,7 +28,7 @@ namespace dynamicgraph
 
     int& trigger (int&, int);
   private:
-    ros::NodeHandle nh_;
+    ros::NodeHandle& nh_;
     signalVectorIn_t state_;
     realtime_tools::RealtimePublisher<sensor_msgs::JointState> publisher_;
     sensor_msgs::JointState jointState_;
-- 
GitLab