Timer refactored

master
Denes Matetelki 13 years ago
parent ac8409c59e
commit 4bfa4165ff

@ -2,7 +2,6 @@
#define TIMER_HPP #define TIMER_HPP
#include <signal.h> // sigset_t
#include <time.h> // timer_t #include <time.h> // timer_t
#include <map> #include <map>
@ -29,18 +28,22 @@ public:
virtual ~Timer(); virtual ~Timer();
timer_t createTimer( TimerUser *m_timerUser, timer_t createTimer( TimerUser *m_timerUser,
const time_t interval_sec, clockid_t clockId = CLOCK_MONOTONIC );
const long interval_nsec = 0,
const time_t initExpr_sec = 0,
const long initExpr_nsec = 0 );
bool setTimer( timer_t timerId,
const time_t interval_sec,
const long interval_nsec = 0,
const time_t initExpr_sec = 0,
const long initExpr_nsec = 0 );
void stopTimer( timer_t timerId ); bool stopTimer( timer_t timerId );
private: private:
std::map< timer_t, TimerUser* > m_timerUsers; typedef std::map<timer_t, TimerUser*> TimerUserMap;
TimerUserMap m_timerUsers;
}; // class Timer }; // class Timer

@ -1,5 +1,6 @@
#include "Timer.hpp" #include "Timer.hpp"
#include "Logger.hpp"
#include "Common.hpp" #include "Common.hpp"
#include <signal.h> // sigset_t #include <signal.h> // sigset_t
@ -10,11 +11,12 @@ void notifyFunction(union sigval sigVal)
{ {
TRACE_STATIC; TRACE_STATIC;
((TimerUser *)(sigVal.sival_ptr))->timerExpired(); reinterpret_cast<TimerUser*>(sigVal.sival_ptr)->timerExpired();
} }
Timer::Timer() : m_timerUsers() Timer::Timer()
: m_timerUsers()
{ {
TRACE; TRACE;
} }
@ -23,68 +25,80 @@ Timer::~Timer()
{ {
TRACE; TRACE;
struct itimerspec its; for (TimerUserMap::iterator it = m_timerUsers.begin(); it != m_timerUsers.end(); )
its.it_value.tv_sec = 0; stopTimer((it++)->first);
its.it_value.tv_nsec = 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(); m_timerUsers.clear();
} }
timer_t Timer::createTimer( TimerUser *timerUser, timer_t Timer::createTimer( TimerUser *timerUser,
const time_t interval_sec, clockid_t clockId )
const long interval_nsec,
const time_t initExpr_sec,
const long initExpr_nsec )
{ {
TRACE; TRACE;
// create timer sigevent sigev;
struct sigevent sigev; timer_t timerId(0);
timer_t timerId;
sigev.sigev_notify = SIGEV_THREAD; sigev.sigev_notify = SIGEV_THREAD;
sigev.sigev_value.sival_ptr = timerUser; sigev.sigev_value.sival_ptr = timerUser;
sigev.sigev_notify_function = notifyFunction; sigev.sigev_notify_function = notifyFunction;
sigev.sigev_notify_attributes = 0; sigev.sigev_notify_attributes = 0;
/// @bug passing address of local variable if (timer_create(clockId, &sigev, &timerId) == -1) {
timer_create( CLOCK_REALTIME, &sigev, &timerId ); LOG_BEGIN(Logger::ERR)
LOG_PROP("Error message", strerror(errno))
LOG_END("Could create timer.");
return 0;
}
if (m_timerUsers.find(timerId) != m_timerUsers.end() ) {
LOG_BEGIN(Logger::ERR)
LOG_SPROP(timerId)
LOG_END("TimerId already in map.");
return 0;
}
m_timerUsers.insert(std::make_pair(timerId, timerUser));
return timerId;
}
// arm it
struct itimerspec its; bool Timer::setTimer( timer_t timerId,
const time_t interval_sec,
const long interval_nsec,
const time_t initExpr_sec,
const long initExpr_nsec )
{
itimerspec its;
its.it_value.tv_sec = interval_sec; its.it_value.tv_sec = interval_sec;
its.it_value.tv_nsec = interval_nsec; its.it_value.tv_nsec = interval_nsec;
its.it_interval.tv_sec = initExpr_sec; its.it_interval.tv_sec = initExpr_sec;
its.it_interval.tv_nsec = initExpr_nsec; its.it_interval.tv_nsec = initExpr_nsec;
timer_settime( timerId, 0, &its, 0 ); if (timer_settime( timerId, 0, &its, NULL ) == -1) {
m_timerUsers.insert( std::make_pair( timerId, timerUser ) ); LOG_BEGIN(Logger::ERR)
LOG_PROP("Error message", strerror(errno))
return timerId; LOG_END("Could set timer.");
return false;
}
return true;
} }
void Timer::stopTimer( timer_t timerId ) bool Timer::stopTimer( timer_t timerId )
{ {
TRACE; TRACE;
/// @bug why is this needed? if (m_timerUsers.find(timerId) == m_timerUsers.end() ) {
timer_t tmp = timerId; LOG_BEGIN(Logger::ERR)
LOG_SPROP(timerId)
// disarm timer LOG_END("TimerId is not in the map.");
struct itimerspec its; return false;
its.it_value.tv_sec = 0;
its.it_value.tv_nsec = 0;
if ( timer_settime( tmp, 0, &its, 0 ) == -1 ) {
LOG( Logger::ERR, strerror( errno ) );
} }
m_timerUsers[ tmp ]->timerDestroyed(); setTimer(timerId, 0);
m_timerUsers.erase( tmp ); m_timerUsers[timerId]->timerDestroyed();
m_timerUsers.erase(timerId);
return true;
} }

@ -18,9 +18,28 @@ private:
{ {
public: public:
DummyTimerUser() : m_counter( 0 ) { TRACE; } DummyTimerUser()
void timerExpired() { /*TRACE;*/ m_counter += 100; } : m_counter(0)
void timerDestroyed() { TRACE; m_counter++; }; {
TRACE;
}
~DummyTimerUser()
{
TRACE;
}
void timerExpired()
{
TRACE;
m_counter++;
}
void timerDestroyed()
{
TRACE;
m_counter += 100;
}
int m_counter; int m_counter;
@ -28,81 +47,59 @@ private:
public: public:
void testBasicTimerThread( void ) void testBasicTimer( void )
{ {
TEST_HEADER; TEST_HEADER;
DummyTimerUser timerUser; DummyTimerUser timerUser;
Timer timer; Timer timer;
timer.createTimer( &timerUser, 2 ); timer_t timerId = timer.createTimer( &timerUser );
timer.setTimer(timerId, 2);
sleep( 4 ); sleep( 4 );
// no destroy
TS_ASSERT_EQUALS( timerUser.m_counter, 100 ); // one expiration, no destroy
TS_ASSERT_EQUALS( timerUser.m_counter, 1 );
} }
void testStopTimerThread( void ) void testStopTimer( void )
{ {
TEST_HEADER; TEST_HEADER;
DummyTimerUser timerUser; DummyTimerUser timerUser;
Timer timer; Timer timer;
timer_t timerId = timer.createTimer( &timerUser, 10 ); timer_t timerId = timer.createTimer( &timerUser );
timer.setTimer(timerId, 10);
sleep( 2 ); sleep( 2 );
timer.stopTimer( timerId ); timer.stopTimer( timerId );
TS_ASSERT_EQUALS( timerUser.m_counter, 1 ); // no expiration, just destroy
TS_ASSERT_EQUALS( timerUser.m_counter, 100 );
} }
void testPeriodicTimer( void )
void testPeriodicTimerThread( void )
{ {
TEST_HEADER; TEST_HEADER;
DummyTimerUser timerUser; DummyTimerUser timerUser;
Timer timer; Timer timer;
timer_t timerId = timer.createTimer( &timerUser, timer_t timerId = timer.createTimer( &timerUser );
1, 0,
1, 0 ); // after 1 sec, expire periodically at each sec
timer.setTimer(timerId, 1, 0, 1, 0);
sleep(4); sleep(4);
timer.stopTimer( timerId ); timer.stopTimer( timerId );
sleep(4); // did it really stopped? // 1 destroy(stop) + 3 expiration (+- 1)
TS_ASSERT_EQUALS( timerUser.m_counter, 400 + 1 ); TS_ASSERT_DELTA( timerUser.m_counter, 103, 1 );
} }
void testTimerThreadHighFreq( void )
{
TEST_HEADER;
int nano = 1000000000; // 10^9
int freq = 200;
DummyTimerUser timerUser;
Timer timer;
timer_t timerId = timer.createTimer( &timerUser,
1, 0,
0, nano / freq );
int circle = 2;
sleep( 1 + circle );
timer.stopTimer( timerId );
TS_ASSERT_DELTA ( timerUser.m_counter, 100 * freq * circle + 1,
(100 * freq * circle + 1 ) * 0.9);
sleep(1);
}
void testOneUserManyTimers( void ) void testOneUserManyTimers( void )
{ {
TEST_HEADER; TEST_HEADER;
@ -110,31 +107,18 @@ private:
DummyTimerUser timerUser; DummyTimerUser timerUser;
Timer timer; Timer timer;
timer_t timerId = timer.createTimer( &timerUser, timer_t timerId = timer.createTimer( &timerUser );
1, 0, timer.setTimer(timerId, 1);
1, 0 );
timer_t timerId2 = timer.createTimer( &timerUser, timer_t timerId2 = timer.createTimer( &timerUser );
1, 0, timer.setTimer(timerId2, 2);
2, 0 );
timer_t timerId3 = timer.createTimer( &timerUser, timer_t timerId3 = timer.createTimer( &timerUser );
1, 0, timer.setTimer(timerId3, 3);
3, 0 );
sleep(4); sleep(4);
timer.stopTimer( timerId ); timer.stopTimer( timerId );
TS_ASSERT_EQUALS( timerUser.m_counter, 400 + 200 + 200 + 1 ); TS_ASSERT_EQUALS( timerUser.m_counter, 100 + 1 + 1 + 1 );
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 );
} }
void testMenyUserManyTimers( void ) void testMenyUserManyTimers( void )
@ -147,83 +131,58 @@ private:
Timer timer; Timer timer;
timer_t timerId = timer.createTimer( &timerUser, timer_t timerId = timer.createTimer( &timerUser );
1, 0, timer.setTimer(timerId, 1);
1, 0 ); timer_t timerId2 = timer.createTimer( &timerUser );
timer.setTimer(timerId2, 2);
timer_t timerId2 = timer.createTimer( &timerUser, timer_t timerId3 = timer.createTimer( &timerUser );
1, 0, timer.setTimer(timerId3, 3);
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 );
timer_t timerId4 = timer.createTimer( &timerUser2 );
timer.setTimer(timerId4, 1);
timer_t timerId5 = timer.createTimer( &timerUser2 );
timer.setTimer(timerId5, 2);
sleep(4); sleep(4);
TS_ASSERT_EQUALS( timerUser.m_counter, 400 + 200 + 200 ); TS_ASSERT_EQUALS( timerUser.m_counter, 1 + 1 + 1 );
TS_ASSERT_EQUALS( timerUser2.m_counter, 400 + 200 ); TS_ASSERT_EQUALS( timerUser2.m_counter, 1 + 1 );
TS_ASSERT_EQUALS( timerUser3.m_counter, 0 );
timer.stopTimer( timerId );
timer.stopTimer( timerId2 );
timer.stopTimer( timerId3 );
timer.stopTimer( timerId4 );
timer.stopTimer( timerId5 );
sleep(1);
} }
void test2Timer( void ) void test2Timer( void )
{ {
TEST_HEADER; TEST_HEADER;
DummyTimerUser timerUser; DummyTimerUser timerUser;
DummyTimerUser timerUser2;
DummyTimerUser itmerUser3;
Timer timer; Timer timer;
Timer timer2; Timer timer2;
timer_t timerId = timer.createTimer( &timerUser, timer_t timerId = timer.createTimer( &timerUser );
1, 0, timer.setTimer(timerId, 1);
1, 0 ); timer_t timerId2 = timer.createTimer( &timerUser );
timer.setTimer(timerId2, 2);
timer_t timerId2 = timer.createTimer( &timerUser, timer_t timerId3 = timer.createTimer( &timerUser );
1, 0, timer.setTimer(timerId3, 3);
2, 0 );
timer_t timerId3 = timer2.createTimer( &timerUser,
1, 0,
3, 0 );
timer_t timerId4 = timer.createTimer( &timerUser2, timer_t timerId4 = timer.createTimer( &timerUser );
1, 0, timer2.setTimer(timerId4, 1);
1, 0 ); timer_t timerId5 = timer.createTimer( &timerUser );
timer2.setTimer(timerId5, 2);
timer_t timerId5 = timer2.createTimer( &timerUser2,
1, 0,
2, 0 );
sleep(4); sleep(4);
TS_ASSERT_EQUALS( timerUser.m_counter, 400 + 200 + 200 ); TS_ASSERT_EQUALS( timerUser.m_counter, (1 + 1 + 1) + (1 + 1) );
TS_ASSERT_EQUALS( timerUser2.m_counter, 400 + 200 ); }
timer.stopTimer( timerId ); void testStopTimerWhichIsNotInTheMap()
timer.stopTimer( timerId2 ); {
timer2.stopTimer( timerId3 ); TEST_HEADER;
timer.stopTimer( timerId4 );
timer2.stopTimer( timerId5 ); Timer timer;
sleep(1); timer_t timerId = (void*)1234;
TS_ASSERT_EQUALS(timer.stopTimer( timerId ), false);
} }
}; };

Loading…
Cancel
Save