From dfe58dc4ce340e97d31202f16d02f5dfd61b7cc9 Mon Sep 17 00:00:00 2001 From: Denes Matetelki Date: Wed, 27 Apr 2011 17:09:04 +0200 Subject: [PATCH] TimerThreadMultimap went back to the 'cafe of broken dreams' folder again, logger handle levels, Timer starts new threads when time is over --- include/Logger.hpp | 9 +- include/Timer.hpp | 45 ++- {src => other}/TimerThreadMultimap.cpp | 0 {include => other}/TimerThreadMultimap.hpp | 24 +- src/Logger.cpp | 14 +- src/Mutex.cpp | 1 + src/Timer.cpp | 107 +++----- test/CMakeLists.txt | 2 +- test/test_Timer.hpp | 301 ++++++++++----------- test/test_TimerThreadMultimap.hpp | 2 +- test/valgrind.supp | 11 + 11 files changed, 252 insertions(+), 264 deletions(-) rename {src => other}/TimerThreadMultimap.cpp (100%) rename {include => other}/TimerThreadMultimap.hpp (87%) diff --git a/include/Logger.hpp b/include/Logger.hpp index b1fd75a..907f639 100644 --- a/include/Logger.hpp +++ b/include/Logger.hpp @@ -35,12 +35,13 @@ public: static void log_pointer( const void* msg, const char* file, - int line, + const int line, const char* function); - static void log_string( const char* msg, + static void log_string( const int level, + const char* msg, const char* file, - int line, + const int line, const char* function); static void msg (const char* text); @@ -79,7 +80,7 @@ private: #define LOG(level, msg) \ if ( Logger::getInstance()->getLoglevel() >= Logger::FINEST ) \ Logger::getInstance()->log_string( \ - msg, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ + level, msg, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ else (void)0 #endif diff --git a/include/Timer.hpp b/include/Timer.hpp index 3945d3b..b67f80d 100644 --- a/include/Timer.hpp +++ b/include/Timer.hpp @@ -4,46 +4,43 @@ #include // sigset_t #include // timer_t +#include - -class Timer +class TimerUser { public: - Timer( const int signal = SIGALRM ); + virtual void timerExpired() = 0; + virtual void timerDestroyed() = 0; - virtual ~Timer(); - virtual void timerExpired() {}; - virtual void periodicTimerExpired() {}; + virtual ~TimerUser() {} - void createTimer( const time_t interval_sec, - const long interval_nsec = 0, - const time_t initExpr_sec = 0, - const long initExpr_nsec = 0 ); +}; // class TimerUser - void wait(); +class Timer +{ - void stopTimer(); +public: - void gracefulStop(); + Timer(); + virtual ~Timer(); + + timer_t createTimer( TimerUser *m_timerUser, + const time_t interval_sec, + const long interval_nsec = 0, + const time_t initExpr_sec = 0, + const long initExpr_nsec = 0 ); -private: - void notifyAndRemove( const timespec t ); + void stopTimer( timer_t timerId ); - // after turning on all warnings, gcc reports that the class has pointer - // data members (time_t, which is a long int by the way) so copy ctor and - // assign op shall be declared - Timer( const Timer& timer ); - Timer& operator=( const Timer& ); - int m_signal; - timer_t m_timerId; - bool m_periodic; - bool m_running; +private: + + std::map< timer_t, TimerUser* > m_timerUsers; }; // class Timer diff --git a/src/TimerThreadMultimap.cpp b/other/TimerThreadMultimap.cpp similarity index 100% rename from src/TimerThreadMultimap.cpp rename to other/TimerThreadMultimap.cpp diff --git a/include/TimerThreadMultimap.hpp b/other/TimerThreadMultimap.hpp similarity index 87% rename from include/TimerThreadMultimap.hpp rename to other/TimerThreadMultimap.hpp index 09a55f4..c664e59 100644 --- a/include/TimerThreadMultimap.hpp +++ b/other/TimerThreadMultimap.hpp @@ -9,17 +9,19 @@ #include #include // timespec -class TimerUser -{ - -public: - - virtual void timerExpired() = 0; - virtual void timerDestroyed() = 0; - - virtual ~TimerUser() {} - -}; // class TimerUser +#include "Timer.hpp" // TimerUser + +// class TimerUser +// { +// +// public: +// +// virtual void timerExpired() = 0; +// virtual void timerDestroyed() = 0; +// +// virtual ~TimerUser() {} +// +// }; // class TimerUser diff --git a/src/Logger.cpp b/src/Logger.cpp index b352ccb..437e768 100644 --- a/src/Logger.cpp +++ b/src/Logger.cpp @@ -19,7 +19,7 @@ void Logger::setLogLevel ( const LogLevel loglevel ) void Logger::log_pointer( const void* msg, const char* file, - int line, + const int line, const char* function) { *m_ostream << getTime() << " " @@ -32,17 +32,23 @@ void Logger::log_pointer( const void* msg, } -void Logger::log_string( const char* msg, +void Logger::log_string( const int level, + const char* msg, const char* file, - int line, + const int line, const char* function) { + const char *color; + if ( level <= WARNING ) { color = COLOR_F_FG( F_BOLD, FG_RED ); } + else if ( level <= INFO ) { color = COLOR_F_FG( F_BOLD, FG_WHITE); } + else { color = COLOR_F_FG( F_BOLD, FG_BROWN); } + *m_ostream << getTime() << " " << COLOR( FG_GREEN ) << extractFilename(file) << COLOR_RESET << ":" << COLOR( FG_BROWN ) << line << COLOR_RESET << " " << COLOR( FG_CYAN ) << function << COLOR_RESET << " " - << COLOR_F_FG( F_BOLD, FG_BROWN ) << "\"" << msg << "\"" + << color << "\"" << msg << "\"" << COLOR_RESET << std::endl; } diff --git a/src/Mutex.cpp b/src/Mutex.cpp index 46e9b28..6b7d54e 100644 --- a/src/Mutex.cpp +++ b/src/Mutex.cpp @@ -17,6 +17,7 @@ Mutex::Mutex( int kind ) { TRACE; if ( kind != PTHREAD_MUTEX_DEFAULT ) { + /// @bug passing local variables address pthread_mutexattr_t attr; pthread_mutexattr_init( &attr ); pthread_mutexattr_settype( &attr, kind ); diff --git a/src/Timer.cpp b/src/Timer.cpp index 0129eed..9b750a1 100644 --- a/src/Timer.cpp +++ b/src/Timer.cpp @@ -3,13 +3,18 @@ #include "Common.hpp" #include // sigset_t +#include +#include + +void notifyFunction(union sigval sigVal) +{ + TRACE_STATIC; + + ((TimerUser *)(sigVal.sival_ptr))->timerExpired(); +} -Timer::Timer( const int signal ) - : m_signal( signal ) - , m_timerId( 0 ) - , m_periodic( false ) - , m_running( true ) +Timer::Timer() : m_timerUsers() { TRACE; } @@ -21,11 +26,18 @@ Timer::~Timer() struct itimerspec its; its.it_value.tv_sec = 0; its.it_value.tv_nsec = 0; - timer_settime( m_timerId, 0, &its, 0 ); + + std::map< timer_t, TimerUser* >::iterator it; + for ( it = m_timerUsers.begin(); it != m_timerUsers.end(); it++ ) { + timer_settime( it->first , 0, &its, 0 ); + it->second->timerDestroyed(); + } + m_timerUsers.clear(); } -void Timer::createTimer( const time_t interval_sec, +timer_t Timer::createTimer( TimerUser *timerUser, + const time_t interval_sec, const long interval_nsec, const time_t initExpr_sec, const long initExpr_nsec ) @@ -34,13 +46,15 @@ void Timer::createTimer( const time_t interval_sec, // create timer struct sigevent sigev; - sigev.sigev_notify = SIGEV_SIGNAL; - sigev.sigev_signo = m_signal; - sigev.sigev_value.sival_ptr = &m_timerId; - timer_create( CLOCK_REALTIME, &sigev, &m_timerId ); + timer_t timerId; - LOG( Logger::FINEST, ( std::string( "Timer created with ID: " ) + - stringify( m_timerId ) ).c_str() ); + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_value.sival_ptr = timerUser; + sigev.sigev_notify_function = notifyFunction; + sigev.sigev_notify_attributes = 0; + + /// @bug passing address of local variable + timer_create( CLOCK_REALTIME, &sigev, &timerId ); // arm it struct itimerspec its; @@ -49,71 +63,28 @@ void Timer::createTimer( const time_t interval_sec, its.it_interval.tv_sec = initExpr_sec; its.it_interval.tv_nsec = initExpr_nsec; - if ( initExpr_sec != 0 or initExpr_nsec != 0 ) m_periodic = true; - timer_settime( m_timerId, 0, &its, 0 ); -} - - -void Timer::wait() -{ - TRACE; - - /// @note timerID is acquired from the siginfo after all - long* tidp; - siginfo_t sigInfo; - - sigset_t sigSet; - sigemptyset( &sigSet ); - sigaddset( &sigSet, m_signal ); - - sigwaitinfo( &sigSet, &sigInfo); - if ( not m_running ) return; - tidp = (long*)sigInfo.si_value.sival_ptr; - -// LOG( Logger::FINEST, ( std::string( "got signal: " ) + -// stringify( sigInfo.si_signo ) + -// " from: " + stringify( (timer_t)*tidp ) ).c_str() ); - - timerExpired(); - - if ( m_periodic ) { - while ( m_running ) { - - sigwaitinfo( &sigSet, &sigInfo); - if ( not m_running ) return; - tidp = (long*)sigInfo.si_value.sival_ptr; - -// LOG( Logger::FINEST, ( std::string( "got periodic signal: " ) + -// stringify( sigInfo.si_signo ) + -// " from: " + stringify( (timer_t)*tidp ) ).c_str() ); - - periodicTimerExpired(); - } - } + timer_settime( timerId, 0, &its, 0 ); + m_timerUsers.insert( std::make_pair( timerId, timerUser ) ); + return timerId; } -void Timer::stopTimer() +void Timer::stopTimer( timer_t timerId ) { TRACE; + /// @bug why is this needed? + timer_t tmp = timerId; + // disarm timer struct itimerspec its; its.it_value.tv_sec = 0; its.it_value.tv_nsec = 0; - timer_settime( m_timerId, 0, &its, 0 ); - - m_running = false; - /// @note sigwaitinfo waiting state, don't forget to send a last signal -} - - -void Timer::gracefulStop() -{ - TRACE; + if ( timer_settime( tmp, 0, &its, 0 ) == -1 ) { + LOG( Logger::ERR, strerror( errno ) ); + } - // if it's periodic, use stopTimer - m_running = false; - /// @note sigwaitinfo waiting state, don't forget to send a last signal + m_timerUsers[ tmp ]->timerDestroyed(); + m_timerUsers.erase( tmp ); } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c7db2d9..8aaa7d8 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -25,7 +25,7 @@ if(CXXTEST_FOUND) test_Semaphore.hpp test_Timer.hpp test_Common.hpp - test_TimerThreadMultimap.hpp +# test_TimerThreadMultimap.hpp ) target_link_libraries(test CppUtils gcov) endif() diff --git a/test/test_Timer.hpp b/test/test_Timer.hpp index f00711a..6b6f1ff 100644 --- a/test/test_Timer.hpp +++ b/test/test_Timer.hpp @@ -14,217 +14,216 @@ class TestTimer : public CxxTest::TestSuite private: - class DummyTimerThread : public Timer, public Thread + class DummyTimerUser : public TimerUser { public: - DummyTimerThread( const int maxPeriodicCount = INT_MAX - 1, - const int signal = SIGALRM, - const time_t interval_sec = 2, - const long interval_nsec = 0, - const time_t initExpr_sec = 0, - const long initExpr_nsec = 0 ) - : Timer( signal ) - , m_counter( 0 ) - , m_maxPeriodicCount( maxPeriodicCount ) - , m_signal ( signal ) - , m_interval_sec( interval_sec ) - , m_interval_nsec( interval_nsec ) - , m_initExpr_sec( initExpr_sec ) - , m_initExpr_nsec( initExpr_nsec ) - { - TRACE; - LOG( Logger::FINEST, ( std::string( "params: " ) + - stringify( maxPeriodicCount ) + " " + - stringify( signal ) + " " + - stringify( interval_sec ) + " " + - stringify( interval_nsec ) + " " + - stringify( initExpr_sec ) + " " + - stringify( initExpr_nsec ) ).c_str() ); - } - - ~DummyTimerThread() - { - TRACE; - } - - private: - - void* run() - { - TRACE; - createTimer( m_interval_sec, - m_interval_nsec, - m_initExpr_sec, - m_initExpr_nsec ); - wait(); - return 0; - } + DummyTimerUser() : m_counter( 0 ) { TRACE; } + void timerExpired() { /*TRACE;*/ m_counter += 100; } + void timerDestroyed() { TRACE; m_counter++; }; + + int m_counter; + + }; // class TimerUser public: - void timerExpired() - { - TRACE; - m_counter += 100; - } - - inline void periodicTimerExpired() - { - // logging take too much time at high freq - // TRACE; - static int count = 0; - m_counter++; - count++; - if ( count >= m_maxPeriodicCount ) { - stop(); - } - } - - void stop() - { - stopTimer(); - sendSignal( m_signal ); - } + void testBasicTimerThread( void ) + { + TEST_HEADER; - int m_counter; + DummyTimerUser timerUser; + Timer timer; - private: + timer.createTimer( &timerUser, 2 ); + sleep( 4 ); + // no destroy - int m_maxPeriodicCount; - int m_signal; - time_t m_interval_sec; - long m_interval_nsec; - time_t m_initExpr_sec; - long m_initExpr_nsec; + TS_ASSERT_EQUALS( timerUser.m_counter, 100 ); + } - }; // class DummyTimerThread - public: + void testStopTimerThread( void ) + { + TEST_HEADER; - void testBasicTimerThread( void ) + DummyTimerUser timerUser; + Timer timer; + + timer_t timerId = timer.createTimer( &timerUser, 10 ); + sleep( 2 ); + timer.stopTimer( timerId ); + + TS_ASSERT_EQUALS( timerUser.m_counter, 1 ); + } + + + + + void testPeriodicTimerThread( void ) { TEST_HEADER; - // the main thread shall ignore the SIGALRM - sigset_t set; - sigemptyset( &set ); - sigaddset( &set, SIGALRM ); - pthread_sigmask( SIG_BLOCK, &set, 0 ); + DummyTimerUser timerUser; + Timer timer; - DummyTimerThread t(5); + timer_t timerId = timer.createTimer( &timerUser, + 1, 0, + 1, 0 ); - t.start(); sleep(4); - t.join(); + timer.stopTimer( timerId ); - TS_ASSERT_EQUALS( t.m_counter, 100 ); + sleep(4); // did it really stopped? + TS_ASSERT_EQUALS( timerUser.m_counter, 400 + 1 ); - pthread_sigmask( SIG_UNBLOCK, &set, 0 ); } - void testStopTimerThread( void ) + + void testTimerThreadHighFreq( void ) { TEST_HEADER; - // the main thread shall ignore the SIGALRM - sigset_t set; - sigemptyset( &set ); - sigaddset( &set, SIGALRM ); - pthread_sigmask( SIG_BLOCK, &set, 0 ); + int nano = 1000000000; // 10^9 + int freq = 200; - DummyTimerThread t(5, SIGALRM, 10); + DummyTimerUser timerUser; + Timer timer; - t.start(); - sleep(1); - t.stop(); - t.join(); + timer_t timerId = timer.createTimer( &timerUser, + 1, 0, + 0, nano / freq ); - TS_ASSERT_EQUALS( t.m_counter, 0 ); + int circle = 2; + sleep( 1 + circle ); + timer.stopTimer( timerId ); - pthread_sigmask( SIG_UNBLOCK, &set, 0 ); + TS_ASSERT_DELTA ( timerUser.m_counter, 100 * freq * circle + 1, + (100 * freq * circle + 1 ) * 0.9); + sleep(1); } - void testPeriodicTimerThread( void ) + void testOneUserManyTimers( void ) { TEST_HEADER; - // the main thread shall ignore the SIGALRM - sigset_t set; - sigemptyset( &set ); - sigaddset( &set, SIGALRM ); - pthread_sigmask( SIG_BLOCK, &set, 0 ); + DummyTimerUser timerUser; + Timer timer; + + timer_t timerId = timer.createTimer( &timerUser, + 1, 0, + 1, 0 ); - DummyTimerThread t( 1000, - SIGALRM, - 1, 0, - 1, 0 ); + timer_t timerId2 = timer.createTimer( &timerUser, + 1, 0, + 2, 0 ); + + timer_t timerId3 = timer.createTimer( &timerUser, + 1, 0, + 3, 0 ); + + sleep(4); + timer.stopTimer( timerId ); + TS_ASSERT_EQUALS( timerUser.m_counter, 400 + 200 + 200 + 1 ); - t.start(); sleep(4); - t.stop(); - sleep(2); - t.join(); + TS_ASSERT_EQUALS( timerUser.m_counter, 400 + 200 + 200 + 200 + 100 + 1 ); - TS_ASSERT_EQUALS( t.m_counter, 102 ); + timer.stopTimer( timerId2 ); + timer.stopTimer( timerId3 ); + + sleep(1); + TS_ASSERT_EQUALS( timerUser.m_counter, 400 + 200 + 200 + 200 + 100 + 3 ); - pthread_sigmask( SIG_UNBLOCK, &set, 0 ); } - void testCustomSignal( void ) + void testMenyUserManyTimers( void ) { TEST_HEADER; - int customSignal = SIGRTMIN; + DummyTimerUser timerUser; + DummyTimerUser timerUser2; + DummyTimerUser timerUser3; + + Timer timer; + + timer_t timerId = timer.createTimer( &timerUser, + 1, 0, + 1, 0 ); + + timer_t timerId2 = timer.createTimer( &timerUser, + 1, 0, + 2, 0 ); + + timer_t timerId3 = timer.createTimer( &timerUser, + 1, 0, + 3, 0 ); - // the main thread shall ignore the customSignal - sigset_t set; - sigemptyset( &set ); - sigaddset( &set, customSignal ); - pthread_sigmask( SIG_BLOCK, &set, 0 ); + timer_t timerId4 = timer.createTimer( &timerUser2, + 1, 0, + 1, 0 ); + + timer_t timerId5 = timer.createTimer( &timerUser2, + 1, 0, + 2, 0 ); - DummyTimerThread t( 5, customSignal ); - t.start(); sleep(4); - t.join(); + TS_ASSERT_EQUALS( timerUser.m_counter, 400 + 200 + 200 ); + TS_ASSERT_EQUALS( timerUser2.m_counter, 400 + 200 ); - TS_ASSERT_EQUALS( t.m_counter, 100 ); + timer.stopTimer( timerId ); + timer.stopTimer( timerId2 ); + timer.stopTimer( timerId3 ); + timer.stopTimer( timerId4 ); + timer.stopTimer( timerId5 ); - pthread_sigmask( SIG_UNBLOCK, &set, 0 ); + sleep(1); } - void testTimerThreadHighFreq( void ) + void test2Timer( void ) { TEST_HEADER; - // the main thread shall ignore the SIGALRM - sigset_t set; - sigemptyset( &set ); - sigaddset( &set, SIGALRM ); - pthread_sigmask( SIG_BLOCK, &set, 0 ); + DummyTimerUser timerUser; + DummyTimerUser timerUser2; + DummyTimerUser itmerUser3; - int nano = 1000000000; // 10^9 - int freq = 200; - DummyTimerThread t( INT_MAX - 1, - SIGALRM, - 1, 0, - 0, nano / freq ); + Timer timer; + Timer timer2; - t.start(); - int circle = 4; - sleep( 1 + circle ); - t.stop(); - t.join(); + timer_t timerId = timer.createTimer( &timerUser, + 1, 0, + 1, 0 ); + + timer_t timerId2 = timer.createTimer( &timerUser, + 1, 0, + 2, 0 ); - // expected 800000 + 100 got 795510 - // accurcy: ~ > 99.5% - TS_ASSERT_DELTA ( t.m_counter, 100 + freq * circle, (100 + freq * circle) * 0.995); + timer_t timerId3 = timer2.createTimer( &timerUser, + 1, 0, + 3, 0 ); - LOG( Logger::FINEST, ( std::string( "got: " ) + stringify( t.m_counter ) + " " - + "expected: " + stringify( 100 + freq * circle ) ).c_str() ); + timer_t timerId4 = timer.createTimer( &timerUser2, + 1, 0, + 1, 0 ); - pthread_sigmask( SIG_UNBLOCK, &set, 0 ); + timer_t timerId5 = timer2.createTimer( &timerUser2, + 1, 0, + 2, 0 ); + + + sleep(4); + TS_ASSERT_EQUALS( timerUser.m_counter, 400 + 200 + 200 ); + TS_ASSERT_EQUALS( timerUser2.m_counter, 400 + 200 ); + + timer.stopTimer( timerId ); + timer.stopTimer( timerId2 ); + timer2.stopTimer( timerId3 ); + timer.stopTimer( timerId4 ); + timer2.stopTimer( timerId5 ); + + sleep(1); } }; diff --git a/test/test_TimerThreadMultimap.hpp b/test/test_TimerThreadMultimap.hpp index 7e45eb7..79668fd 100644 --- a/test/test_TimerThreadMultimap.hpp +++ b/test/test_TimerThreadMultimap.hpp @@ -118,7 +118,7 @@ public: sleep(6); tt->stop(); - sleep(1); + sleep(2); TS_ASSERT_EQUALS( user->m_counter, 104 ); // 4 times // TS_ASSERT_EQUALS( user2->m_counter, perMinute*4 ); diff --git a/test/valgrind.supp b/test/valgrind.supp index 5cb07ab..77628ba 100644 --- a/test/valgrind.supp +++ b/test/valgrind.supp @@ -116,3 +116,14 @@ ... fun:main } + +{ + disarm timer time_t mess + Memcheck:Param + timer_settime(value) + fun:timer_settime@@GLIBC_2.3.3 + fun:_ZN5Timer9stopTimerEPv + ... + fun:main +} +