Skip to content
Snippets Groups Projects
Commit 73a016f0 authored by Joseph Mirabel's avatar Joseph Mirabel Committed by Olivier Stasse
Browse files

Add macros to use real time logs.

parent 3b391ca7
No related branches found
No related tags found
No related merge requests found
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
# include <boost/shared_ptr.hpp> # include <boost/shared_ptr.hpp>
# include <dynamic-graph/config.hh> # include <dynamic-graph/config.hh>
# include <dynamic-graph/debug.h>
namespace dynamicgraph namespace dynamicgraph
{ {
...@@ -50,7 +52,8 @@ namespace dynamicgraph ...@@ -50,7 +52,8 @@ namespace dynamicgraph
{ {
public: public:
RTLoggerStream (RealTimeLogger* logger, std::ostream& os) : logger_(logger), os_ (os) {} 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(); ~RTLoggerStream();
private: private:
...@@ -65,6 +68,10 @@ namespace dynamicgraph ...@@ -65,6 +68,10 @@ namespace dynamicgraph
class DYNAMIC_GRAPH_DLLAPI RealTimeLogger class DYNAMIC_GRAPH_DLLAPI RealTimeLogger
{ {
public: public:
static RealTimeLogger& instance();
static void destroy();
/// \todo add an argument to preallocate the internal string to a given size. /// \todo add an argument to preallocate the internal string to a given size.
RealTimeLogger (const std::size_t& bufferSize); RealTimeLogger (const std::size_t& bufferSize);
...@@ -72,9 +79,6 @@ namespace dynamicgraph ...@@ -72,9 +79,6 @@ namespace dynamicgraph
inline void addOutputStream (const LoggerStreamPtr_t& os) { outputs_.push_back(os); } 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. /// Write next message to output.
/// It does nothing if the buffer is empty. /// It does nothing if the buffer is empty.
/// \return true if it wrote something /// \return true if it wrote something
...@@ -104,7 +108,7 @@ namespace dynamicgraph ...@@ -104,7 +108,7 @@ namespace dynamicgraph
return backIdx_ + buffer_.size() - frontIdx_; return backIdx_ + buffer_.size() - frontIdx_;
} }
inline std::size_t getBufferSize () { return buffer_.capacity(); } inline std::size_t getBufferSize () { return buffer_.size(); }
~RealTimeLogger (); ~RealTimeLogger ();
...@@ -121,7 +125,21 @@ namespace dynamicgraph ...@@ -121,7 +125,21 @@ namespace dynamicgraph
/// Index of the slot where to write next value (does not contain valid data). /// Index of the slot where to write next value (does not contain valid data).
std::size_t backIdx_; std::size_t backIdx_;
std::ostream oss_; std::ostream oss_;
struct thread;
static RealTimeLogger* instance_;
static thread* thread_;
}; };
} // end of namespace dynamicgraph } // 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 #endif //! DYNAMIC_GRAPH_LOGGER_REAL_TIME_H
...@@ -19,6 +19,9 @@ ...@@ -19,6 +19,9 @@
#include <dynamic-graph/real-time-logger.h> #include <dynamic-graph/real-time-logger.h>
#include <boost/thread/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
namespace dynamicgraph namespace dynamicgraph
{ {
RealTimeLogger::RealTimeLogger (const std::size_t& bufferSize) RealTimeLogger::RealTimeLogger (const std::size_t& bufferSize)
...@@ -68,4 +71,47 @@ namespace dynamicgraph ...@@ -68,4 +71,47 @@ namespace dynamicgraph
os_ << std::ends; os_ << std::ends;
if (logger_ != NULL) logger_->frontReady(); 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_;
}
} }
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
*/ */
#include <iostream> #include <iostream>
#define ENABLE_RT_LOG
#include <dynamic-graph/real-time-logger.h> #include <dynamic-graph/real-time-logger.h>
#define BOOST_TEST_MODULE real_time_logger #define BOOST_TEST_MODULE real_time_logger
...@@ -25,7 +27,6 @@ ...@@ -25,7 +27,6 @@
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <boost/test/output_test_stream.hpp> #include <boost/test/output_test_stream.hpp>
#include <boost/thread.hpp>
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time.hpp>
...@@ -51,33 +52,20 @@ BOOST_AUTO_TEST_CASE (monothread) ...@@ -51,33 +52,20 @@ BOOST_AUTO_TEST_CASE (monothread)
rtl.spinOnce(); 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) BOOST_AUTO_TEST_CASE (multithread)
{ {
RealTimeLogger rtl (10); RealTimeLogger& rtl = RealTimeLogger::instance();
rtl.addOutputStream (LoggerStreamPtr_t (new LoggerIOStream(std::cout))); dgADD_OSTREAM_TO_RTLOG (std::cout);
boost::thread loggerThread (spin, &rtl);
for (int i = 0; i < 10; ++i) { for (std::size_t i = 0; i < rtl.getBufferSize()-1; ++i)
boost::this_thread::sleep(boost::posix_time::milliseconds(20));
rtl.front() << "Call number " << i << '\n'; 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()); 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; RealTimeLogger::destroy();
loggerThread.join();
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment