TimerThreadMultimap went back to the 'cafe of broken dreams' folder again, logger handle levels, Timer starts new threads when time is over

master
Denes Matetelki 14 years ago
parent 06eebadba2
commit dfe58dc4ce

@ -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

@ -4,6 +4,19 @@
#include <signal.h> // sigset_t
#include <time.h> // timer_t
#include <map>
class TimerUser
{
public:
virtual void timerExpired() = 0;
virtual void timerDestroyed() = 0;
virtual ~TimerUser() {}
}; // class TimerUser
class Timer
@ -11,39 +24,23 @@ class Timer
public:
Timer( const int signal = SIGALRM );
Timer();
virtual ~Timer();
virtual void timerExpired() {};
virtual void periodicTimerExpired() {};
void createTimer( const time_t interval_sec,
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 );
void wait();
void stopTimer();
void gracefulStop();
void stopTimer( timer_t timerId );
private:
void notifyAndRemove( const timespec t );
// 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;
std::map< timer_t, TimerUser* > m_timerUsers;
}; // class Timer

@ -9,17 +9,19 @@
#include <map>
#include <time.h> // 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

@ -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;
}

@ -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 );

@ -3,13 +3,18 @@
#include "Common.hpp"
#include <signal.h> // sigset_t
#include <time.h>
#include <errno.h>
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
if ( timer_settime( tmp, 0, &its, 0 ) == -1 ) {
LOG( Logger::ERR, strerror( errno ) );
}
void Timer::gracefulStop()
{
TRACE;
// 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 );
}

@ -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()

@ -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;
}
DummyTimerUser() : m_counter( 0 ) { TRACE; }
void timerExpired() { /*TRACE;*/ m_counter += 100; }
void timerDestroyed() { TRACE; m_counter++; };
private:
int m_counter;
void* run()
{
TRACE;
createTimer( m_interval_sec,
m_interval_nsec,
m_initExpr_sec,
m_initExpr_nsec );
wait();
return 0;
}
}; // class TimerUser
public:
void timerExpired()
void testBasicTimerThread( void )
{
TRACE;
m_counter += 100;
}
TEST_HEADER;
inline void periodicTimerExpired()
{
// logging take too much time at high freq
// TRACE;
static int count = 0;
m_counter++;
count++;
if ( count >= m_maxPeriodicCount ) {
stop();
}
DummyTimerUser timerUser;
Timer timer;
timer.createTimer( &timerUser, 2 );
sleep( 4 );
// no destroy
TS_ASSERT_EQUALS( timerUser.m_counter, 100 );
}
void stop()
void testStopTimerThread( void )
{
stopTimer();
sendSignal( m_signal );
}
TEST_HEADER;
int m_counter;
DummyTimerUser timerUser;
Timer timer;
private:
timer_t timerId = timer.createTimer( &timerUser, 10 );
sleep( 2 );
timer.stopTimer( timerId );
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, 1 );
}
}; // class DummyTimerThread
public:
void testBasicTimerThread( void )
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;
DummyTimerThread t( 1000,
SIGALRM,
timer_t timerId = timer.createTimer( &timerUser,
1, 0,
1, 0 );
t.start();
timer_t timerId2 = timer.createTimer( &timerUser,
1, 0,
2, 0 );
timer_t timerId3 = timer.createTimer( &timerUser,
1, 0,
3, 0 );
sleep(4);
t.stop();
sleep(2);
t.join();
timer.stopTimer( timerId );
TS_ASSERT_EQUALS( timerUser.m_counter, 400 + 200 + 200 + 1 );
TS_ASSERT_EQUALS( t.m_counter, 102 );
sleep(4);
TS_ASSERT_EQUALS( timerUser.m_counter, 400 + 200 + 200 + 200 + 100 + 1 );
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;
// the main thread shall ignore the customSignal
sigset_t set;
sigemptyset( &set );
sigaddset( &set, customSignal );
pthread_sigmask( SIG_BLOCK, &set, 0 );
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 );
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,
Timer timer;
Timer timer2;
timer_t timerId = timer.createTimer( &timerUser,
1, 0,
0, nano / freq );
1, 0 );
t.start();
int circle = 4;
sleep( 1 + circle );
t.stop();
t.join();
timer_t timerId2 = timer.createTimer( &timerUser,
1, 0,
2, 0 );
timer_t timerId3 = timer2.createTimer( &timerUser,
1, 0,
3, 0 );
timer_t timerId4 = timer.createTimer( &timerUser2,
1, 0,
1, 0 );
timer_t timerId5 = timer2.createTimer( &timerUser2,
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);
LOG( Logger::FINEST, ( std::string( "got: " ) + stringify( t.m_counter ) + " "
+ "expected: " + stringify( 100 + freq * circle ) ).c_str() );
sleep(4);
TS_ASSERT_EQUALS( timerUser.m_counter, 400 + 200 + 200 );
TS_ASSERT_EQUALS( timerUser2.m_counter, 400 + 200 );
pthread_sigmask( SIG_UNBLOCK, &set, 0 );
timer.stopTimer( timerId );
timer.stopTimer( timerId2 );
timer2.stopTimer( timerId3 );
timer.stopTimer( timerId4 );
timer2.stopTimer( timerId5 );
sleep(1);
}
};

@ -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 );

@ -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
}

Loading…
Cancel
Save