From efab283199a1b6a872d34e498f05853ad2ccd2b7 Mon Sep 17 00:00:00 2001 From: Denes Matetelki Date: Wed, 13 Apr 2011 13:25:46 +0200 Subject: [PATCH] TimerThread is useful after all --- include/Common.hpp | 44 +++++- include/Logger.hpp | 6 +- include/Timer.hpp | 1 + {other => include}/TimerThread.hpp | 0 {other => src}/TimerThread.cpp | 0 test/CMakeLists.txt | 1 + test/test_TimerThread.hpp | 223 +++++++++++++++++++++++++++++ test/valgrind.supp | 11 +- 8 files changed, 269 insertions(+), 17 deletions(-) rename {other => include}/TimerThread.hpp (100%) rename {other => src}/TimerThread.cpp (100%) create mode 100644 test/test_TimerThread.hpp diff --git a/include/Common.hpp b/include/Common.hpp index 199e3f9..d9a9217 100644 --- a/include/Common.hpp +++ b/include/Common.hpp @@ -13,16 +13,19 @@ #include // runtime_error #include // ostringstream -inline timespec addTotimespec(const long int & sec, const long int & nsec) +const long NANO = 1000000000L; // 10^9 + + +inline timespec addTotimespec( const long int & sec, const long int & nsec) { - const int nano = 1000000000; // 10^9 + timespec abs_time; clock_gettime ( CLOCK_REALTIME, &abs_time ); long int nsecSum( abs_time.tv_nsec + nsec ); - if ( nsecSum >= nano ) { - abs_time.tv_sec += sec + nsecSum / nano; - abs_time.tv_nsec = nsecSum % nano; + if ( nsecSum >= NANO ) { + abs_time.tv_sec += sec + nsecSum / NANO; + abs_time.tv_nsec = nsecSum % NANO; } else { abs_time.tv_sec += sec; abs_time.tv_nsec += nsec; @@ -31,6 +34,37 @@ inline timespec addTotimespec(const long int & sec, const long int & nsec) } +inline timespec timespecAdd( timespec& t1, const timespec& t2 ) +{ + timespec result; + result.tv_sec = t1.tv_sec + t2.tv_sec ; + result.tv_nsec = t1.tv_nsec + t2.tv_nsec ; + if (result.tv_nsec >= NANO ) { + result.tv_sec++ ; + result.tv_nsec = result.tv_nsec - NANO; + } + return result; +} + +inline timespec timespecSubstract( timespec& t1, const timespec& t2 ) +{ + timespec result; + if ((t1.tv_sec < t2.tv_sec) || + ((t1.tv_sec == t2.tv_sec) && (t1.tv_nsec <= t2.tv_nsec))) { + result.tv_sec = result.tv_nsec = 0 ; + } else { + result.tv_sec = t1.tv_sec - t2.tv_sec ; + if (t1.tv_nsec < t2.tv_nsec) { + result.tv_nsec = t1.tv_nsec + NANO - t2.tv_nsec ; + result.tv_sec-- ; + } else { + result.tv_nsec = t1.tv_nsec - t2.tv_nsec ; + } + } + return result; +} + + inline const char* extractFilename( const char *path ) { char const * f = rindex(path, '/'); diff --git a/include/Logger.hpp b/include/Logger.hpp index 2fcb7c4..b1fd75a 100644 --- a/include/Logger.hpp +++ b/include/Logger.hpp @@ -58,9 +58,9 @@ private: #ifdef NO_TRACE - #define TRACE (void)0 - #define TRACE_STATIC (void)0 - #define LOG (void)0 + #define TRACE (void)0 + #define TRACE_STATIC (void)0 + #define LOG(level, msg) (void)0 #else diff --git a/include/Timer.hpp b/include/Timer.hpp index 16f68ee..579fffc 100644 --- a/include/Timer.hpp +++ b/include/Timer.hpp @@ -10,6 +10,7 @@ class Timer public: Timer(const int signal = SIGALRM ); + virtual ~Timer() {} virtual void timerExpired() {} diff --git a/other/TimerThread.hpp b/include/TimerThread.hpp similarity index 100% rename from other/TimerThread.hpp rename to include/TimerThread.hpp diff --git a/other/TimerThread.cpp b/src/TimerThread.cpp similarity index 100% rename from other/TimerThread.cpp rename to src/TimerThread.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b20f580..1f2a095 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -25,6 +25,7 @@ if(CXXTEST_FOUND) test_Semaphore.hpp test_Timer.hpp test_Common.hpp + test_TimerThread.hpp ) target_link_libraries(test CppUtils gcov) endif() diff --git a/test/test_TimerThread.hpp b/test/test_TimerThread.hpp new file mode 100644 index 0000000..899536b --- /dev/null +++ b/test/test_TimerThread.hpp @@ -0,0 +1,223 @@ +#include + +#include "Fixture.hpp" + +#define private public // reach TimerThread's private multimap + +#include "TimerThread.hpp" + +#include + + + + +class TestTimerThread : public CxxTest::TestSuite +{ + +private: + + class DummyTimerUser : public TimerUser + { + + public: + + DummyTimerUser( void ) : m_counter(0) { TRACE; } + ~DummyTimerUser( void ) { TRACE; } + void timerExpired( void ) { TRACE; m_counter++; } + void timerDestroyed( void ) { TRACE; m_counter += 100; } + + int m_counter; + + }; // class DummyTimerUser + + + +public: + + void nemtestBasic( void ) + { + TEST_HEADER; + TimerThread* tt = new TimerThread(); + tt->start(); + sleep(1); + + DummyTimerUser *user = new DummyTimerUser(); + tt->addTimerUser( user, 2 ); + + sleep(4); + tt->stop(); + sleep(1); + + TS_ASSERT_EQUALS( user->m_counter, 1 ); + + delete tt; + delete user; + } + + void nemtestBasicTimeSpec( void ) + { + TEST_HEADER; + TimerThread* tt = new TimerThread(); + tt->start(); + sleep(1); + + DummyTimerUser *user = new DummyTimerUser(); + timespec ts = { 1, 123 }; + tt->addTimerUser( user, ts ); + + sleep(4); + tt->stop(); + sleep(1); + + TS_ASSERT_EQUALS( user->m_counter, 1 ); + + delete tt; + delete user; + } + + void nemtestPeriodic( void ) + { + TEST_HEADER; + TimerThread* tt = new TimerThread(); + tt->start(); + sleep(1); + + DummyTimerUser *user = new DummyTimerUser(); + tt->addTimerUser( user, 2, 1 ); + + sleep(6); + tt->stop(); + sleep(1); + + TS_ASSERT_EQUALS( user->m_counter, 104 ); + + delete tt; + delete user; + } + + void testPeriodicTimeSpec( void ) + { + TEST_HEADER; + +// Logger::getInstance()->setLogLevel(Logger::DEBUG); + + TimerThread* tt = new TimerThread(); + tt->start(); + sleep(1); + + DummyTimerUser *user = new DummyTimerUser(); + timespec ts = { 2, 0 }; + timespec tsperiod = { 1, 0 }; + tt->addTimerUser( user, ts, tsperiod ); + + /// @bug What is wrong here? + DummyTimerUser *user2 = new DummyTimerUser(); + int perMinute = 2000; + timespec ts2 = { 0, 1000000000 / perMinute }; + tt->addTimerUser( user2, ts, ts2 ); + + sleep(6); + tt->stop(); + sleep(1); + + TS_ASSERT_EQUALS( user->m_counter, 100 + 4 ); // 4 times + TS_ASSERT_EQUALS( user2->m_counter, 100 + perMinute*4 ); + + delete tt; + delete user; + } + + void nemtestDestroyed( void ) + { + TEST_HEADER; + TimerThread* tt = new TimerThread(); + tt->start(); + sleep(1); + + DummyTimerUser *user = new DummyTimerUser(); + tt->addTimerUser( user, 10 ); + + sleep(2); + tt->stop(); + sleep(1); + + TS_ASSERT_EQUALS( user->m_counter, 100 ); + + delete tt; + delete user; + } + + void nemtestRemoved( void ) + { + TEST_HEADER; + TimerThread* tt = new TimerThread(); + tt->start(); + sleep(1); + + DummyTimerUser *user = new DummyTimerUser(); + DummyTimerUser *user2 = new DummyTimerUser(); + DummyTimerUser *user3 = new DummyTimerUser(); + tt->addTimerUser( user, 10 ); + tt->addTimerUser( user2, 13 ); + tt->addTimerUser( user3, 15 ); + + sleep(2); + TS_ASSERT_EQUALS( tt->m_users.size(), 3 ); + + + tt->removeTimerUser( user2 ); + sleep(1); + TS_ASSERT_EQUALS( tt->m_users.size(), 2 ); + + tt->removeTimerUser( user3 ); + sleep(1); + TS_ASSERT_EQUALS( tt->m_users.size(), 1 ); + + tt->removeTimerUser( user2 ); + sleep(1); + TS_ASSERT_EQUALS( tt->m_users.size(), 1 ); + + tt->removeTimerUser( user ); + sleep(1); + TS_ASSERT_EQUALS( tt->m_users.size(), 0 ); + + tt->stop(); + sleep(1); + + delete tt; + delete user; + delete user2; + delete user3; + } + + void nemtestRemovedMultiple( void ) + { + TEST_HEADER; + TimerThread* tt = new TimerThread(); + tt->start(); + sleep(1); + + DummyTimerUser *user = new DummyTimerUser(); + tt->addTimerUser( user, 10 ); + tt->addTimerUser( user, 12 ); + tt->addTimerUser( user, 13 ); + tt->addTimerUser( user, 14 ); + + TS_ASSERT_EQUALS( tt->m_users.size(), 4); + + sleep(2); + tt->removeTimerUser( user ); + sleep(2); + + TS_ASSERT_EQUALS( tt->m_users.size(), 0); + + sleep(1); + tt->stop(); + sleep(1); + + + delete tt; + delete user; + } + +}; diff --git a/test/valgrind.supp b/test/valgrind.supp index 26c2f66..c5eca56 100644 --- a/test/valgrind.supp +++ b/test/valgrind.supp @@ -71,23 +71,16 @@ { - creating a mere thread...what is your problem, valgrind + create thread Memcheck:Leak fun:calloc - fun:allocate_dtv fun:_dl_allocate_tls fun:pthread_create@@GLIBC_*.*.* - fun:_ZN6Thread5startEv ... - fun:_ZN7CxxTest19RealTestDescription3runEv - fun:_ZN7CxxTest10TestRunner7runTestERNS_15TestDescriptionE - fun:_ZN7CxxTest10TestRunner8runSuiteERNS_16SuiteDescriptionE - fun:_ZN7CxxTest10TestRunner8runWorldEv - fun:_ZN7CxxTest10TestRunner11runAllTestsERNS_12TestListenerE - fun:_ZN7CxxTest14ErrorFormatter3runEv fun:main } + { sigaction handling Memcheck:Param