diff --git a/include/dynamic-graph/real-time-logger.h b/include/dynamic-graph/real-time-logger.h index 55dea17f3fe0af88181eedf74baea4d8901d86be..b0a4283e2994a44ac034343b288777cc407a30fe 100644 --- a/include/dynamic-graph/real-time-logger.h +++ b/include/dynamic-graph/real-time-logger.h @@ -23,6 +23,8 @@ # include <boost/shared_ptr.hpp> # include <dynamic-graph/config.hh> +# include <dynamic-graph/debug.h> + namespace dynamicgraph { @@ -50,7 +52,8 @@ namespace dynamicgraph { public: RTLoggerStream (RealTimeLogger* logger, std::ostream& os) : logger_(logger), os_ (os) {} - template <typename T> RTLoggerStream& operator<< (T t) { os_ << t; return *this; } + template <typename T> inline RTLoggerStream& operator<< (T t) { os_ << t; return *this; } + inline RTLoggerStream& operator<< (std::ostream& (*pf)(std::ostream&)) { os_ << pf; return *this; } ~RTLoggerStream(); private: @@ -65,6 +68,10 @@ namespace dynamicgraph class DYNAMIC_GRAPH_DLLAPI RealTimeLogger { public: + static RealTimeLogger& instance(); + + static void destroy(); + /// \todo add an argument to preallocate the internal string to a given size. RealTimeLogger (const std::size_t& bufferSize); @@ -72,9 +79,6 @@ namespace dynamicgraph inline void addOutputStream (const LoggerStreamPtr_t& os) { outputs_.push_back(os); } - /// The function to be called by the thread who exports the outputs - //void spin (); - /// Write next message to output. /// It does nothing if the buffer is empty. /// \return true if it wrote something @@ -104,7 +108,7 @@ namespace dynamicgraph return backIdx_ + buffer_.size() - frontIdx_; } - inline std::size_t getBufferSize () { return buffer_.capacity(); } + inline std::size_t getBufferSize () { return buffer_.size(); } ~RealTimeLogger (); @@ -121,7 +125,21 @@ namespace dynamicgraph /// Index of the slot where to write next value (does not contain valid data). std::size_t backIdx_; std::ostream oss_; + + struct thread; + + static RealTimeLogger* instance_; + static thread* thread_; }; } // end of namespace dynamicgraph +#ifdef ENABLE_RT_LOG +# define dgADD_OSTREAM_TO_RTLOG(ostr) ::dynamicgraph::RealTimeLogger::instance() \ + .addOutputStream(::dynamicgraph::LoggerStreamPtr_t(new ::dynamicgraph::LoggerIOStream(ostr))) +# define dgRTLOG() ::dynamicgraph::RealTimeLogger::instance().front() +#else // ENABLE_RT_LOG +# define dgADD_OSTREAM_TO_RTLOG(ostr) struct __end_with_semicolon +# define dgRTLOG() if (1) ; else __null_stream() +#endif + #endif //! DYNAMIC_GRAPH_LOGGER_REAL_TIME_H diff --git a/src/debug/real-time-logger.cpp b/src/debug/real-time-logger.cpp index 4386b5806bbb419a1b03d2deb8a6da87990278a5..d98f98cc0ec370240488a79d606073678be612ec 100644 --- a/src/debug/real-time-logger.cpp +++ b/src/debug/real-time-logger.cpp @@ -19,6 +19,9 @@ #include <dynamic-graph/real-time-logger.h> +#include <boost/thread/thread.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> + namespace dynamicgraph { RealTimeLogger::RealTimeLogger (const std::size_t& bufferSize) @@ -68,4 +71,47 @@ namespace dynamicgraph os_ << std::ends; if (logger_ != NULL) logger_->frontReady(); } + + struct RealTimeLogger::thread + { + bool requestShutdown_; + boost::thread t_; + + thread (RealTimeLogger* logger) + : requestShutdown_ (false) + , t_ (&thread::spin, this, logger) + {} + + void spin (RealTimeLogger* logger) + { + while (!requestShutdown_ || !logger->empty()) + { + // If the logger did not write anything, it means the buffer is empty. + // Do a pause + if (!logger->spinOnce()) + boost::this_thread::sleep(boost::posix_time::milliseconds(100)); + } + } + }; + + RealTimeLogger* RealTimeLogger::instance_ = NULL; + RealTimeLogger::thread* RealTimeLogger::thread_ = NULL; + + RealTimeLogger& RealTimeLogger::instance() + { + if (instance_ == NULL) { + instance_ = new RealTimeLogger (1000); + thread_ = new thread (instance_); + } + return *instance_; + } + + void RealTimeLogger::destroy () + { + if (instance_ == NULL) return; + thread_->requestShutdown_ = true; + thread_->t_.join(); + delete instance_; + delete thread_; + } } diff --git a/tests/real-time-logger.cpp b/tests/real-time-logger.cpp index 064ae1003b8a70caa7817c4954acf42f838ec34a..055a3650dfe2c658c5a48dbece4563007d5da1b1 100644 --- a/tests/real-time-logger.cpp +++ b/tests/real-time-logger.cpp @@ -18,6 +18,8 @@ */ #include <iostream> + +#define ENABLE_RT_LOG #include <dynamic-graph/real-time-logger.h> #define BOOST_TEST_MODULE real_time_logger @@ -25,7 +27,6 @@ #include <boost/test/unit_test.hpp> #include <boost/test/output_test_stream.hpp> -#include <boost/thread.hpp> #include <boost/thread/thread.hpp> #include <boost/date_time/posix_time/posix_time.hpp> @@ -51,33 +52,20 @@ BOOST_AUTO_TEST_CASE (monothread) rtl.spinOnce(); } -bool requestShutdown = false; -void spin (RealTimeLogger* logger) -{ - while (!requestShutdown || !logger->empty()) - { - // If the logger did not write anything, it means the buffer is empty. - // Do a pause - if (!logger->spinOnce()) - boost::this_thread::sleep(boost::posix_time::milliseconds(100)); - } -} - BOOST_AUTO_TEST_CASE (multithread) { - RealTimeLogger rtl (10); - rtl.addOutputStream (LoggerStreamPtr_t (new LoggerIOStream(std::cout))); - - boost::thread loggerThread (spin, &rtl); + RealTimeLogger& rtl = RealTimeLogger::instance(); + dgADD_OSTREAM_TO_RTLOG (std::cout); - for (int i = 0; i < 10; ++i) { - boost::this_thread::sleep(boost::posix_time::milliseconds(20)); + for (std::size_t i = 0; i < rtl.getBufferSize()-1; ++i) rtl.front() << "Call number " << i << '\n'; + for (std::size_t i = 0; i < 12; ++i) { + boost::this_thread::sleep(boost::posix_time::milliseconds(20)); + rtl.front() << "Call number " << i << std::endl; BOOST_CHECK (!rtl.full()); } - rtl.front() << "This call should appear in the output" << '\n'; + dgRTLOG() << "This call should appear in the output" << '\n'; - requestShutdown = true; - loggerThread.join(); + RealTimeLogger::destroy(); }