TimerThreadMultimap is the slow TimerThread implementation now. Timer got smarter: get the timerId from siginfo, it can now expanded to a thread and then a timerthread+threadpool to call the expired functions

master
Denes Matetelki 14 years ago
parent f39d876cc2
commit 34ed5628ec

@ -1,9 +1,11 @@
#ifndef TIMER_HPP #ifndef TIMER_HPP
#define TIMER_HPP #define TIMER_HPP
#include <signal.h> // sigset_t #include <signal.h> // sigset_t
#include <time.h> // timer_t #include <time.h> // timer_t
class Timer class Timer
{ {
@ -20,14 +22,18 @@ public:
const time_t initExpr_sec = 0, const time_t initExpr_sec = 0,
const long initExpr_nsec = 0 ); const long initExpr_nsec = 0 );
void wait(); void wait();
void stopTimer(); void stopTimer();
void gracefulStop(); void gracefulStop();
private: private:
void notifyAndRemove( const timespec t );
// after turning on all warnings, gcc reports that the class has pointer // 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 // data members (time_t, which is a long int by the way) so copy ctor and
// assign op shall be declared // assign op shall be declared
@ -39,7 +45,6 @@ private:
timer_t m_timerId; timer_t m_timerId;
bool m_periodic; bool m_periodic;
bool m_running; bool m_running;
sigset_t m_mask;
}; // class Timer }; // class Timer

@ -1,5 +1,5 @@
#ifndef TIMERTHREAD_HPP #ifndef TIMERTHREAD_MULTIMAP_HPP
#define TIMERTHREAD_HPP #define TIMERTHREAD_MULTIMAP_HPP
#include "Thread.hpp" #include "Thread.hpp"
@ -23,7 +23,7 @@ public:
class TimerThread : public Thread class TimerThreadMultimap : public Thread
{ {
private: private:
@ -36,9 +36,9 @@ private:
public: public:
TimerThread(); TimerThreadMultimap();
virtual ~TimerThread(); virtual ~TimerThreadMultimap();
void addTimerUser( TimerUser* user, void addTimerUser( TimerUser* user,
const time_t expiration, const time_t expiration,
@ -81,7 +81,7 @@ private:
ConditionVariable m_condVar; ConditionVariable m_condVar;
std::multimap< timespec, UserEntry, timespec_cmp> m_users; std::multimap< timespec, UserEntry, timespec_cmp> m_users;
}; // class TimerThread }; // class TimerThreadMultimap
#endif // TIMERTHREAD_HPP #endif // TIMERTHREAD_MULTIMAP_HPP

@ -7,11 +7,10 @@
#include <string.h> // strerror #include <string.h> // strerror
/// @note not used now /// @note not used now, all signals are caught by sigwaitinfo
// static void sigHandler(int sig, siginfo_t *si, void *uc) // static void sigHandler(int sig, siginfo_t *si, void *uc)
// { // {
// TRACE_STATIC; // TRACE_STATIC;
//
// } // }
@ -21,18 +20,10 @@ struct sigaction& sigActionInit( struct sigaction &sigAct, const int signal )
// sigAct.sa_sigaction = sigHandler; // sigAct.sa_sigaction = sigHandler;
sigemptyset( &sigAct.sa_mask ); sigemptyset( &sigAct.sa_mask );
sigaddset( &sigAct.sa_mask, signal ); sigaddset( &sigAct.sa_mask, signal );
sigaction( signal, &sigAct, 0 ); // sigaction( signal, &sigAct, 0 );
return sigAct; return sigAct;
} }
sigset_t& sigSetInit( sigset_t &sigSet, const int signal )
{
sigemptyset( &sigSet );
sigaddset(&sigSet, signal );
sigprocmask(SIG_SETMASK, &sigSet, NULL);
return sigSet;
}
Timer::Timer( const int signal ) Timer::Timer( const int signal )
: m_signal( signal ) : m_signal( signal )
@ -40,7 +31,6 @@ Timer::Timer( const int signal )
, m_timerId( 0 ) , m_timerId( 0 )
, m_periodic( false ) , m_periodic( false )
, m_running( true ) , m_running( true )
, m_mask( sigSetInit( m_mask, m_signal ) )
{ {
TRACE; TRACE;
} }
@ -49,7 +39,12 @@ Timer::~Timer()
{ {
TRACE; TRACE;
sigprocmask(SIG_UNBLOCK, &m_mask, NULL); struct itimerspec its;
its.it_value.tv_sec = 0;
its.it_value.tv_nsec = 0;
timer_settime( m_timerId, 0, &its, 0 );
// pthread_sigmask( SIG_UNBLOCK, &m_mask, 0 );
} }
@ -92,9 +87,12 @@ void Timer::wait()
sigwaitinfo( &(m_sigAction.sa_mask), &sigInfo); sigwaitinfo( &(m_sigAction.sa_mask), &sigInfo);
if ( not m_running ) return;
tidp = (long*)sigInfo.si_value.sival_ptr; tidp = (long*)sigInfo.si_value.sival_ptr;
// LOG( Logger::FINEST, ( std::string( "Timer expired with ID: " ) +
// stringify( (timer_t)*tidp ) ).c_str() ); // LOG( Logger::FINEST, ( std::string( "got signal: " ) +
// stringify( sigInfo.si_signo ) +
// " from: " + stringify( (timer_t)*tidp ) ).c_str() );
timerExpired(); timerExpired();
@ -102,9 +100,12 @@ void Timer::wait()
while ( m_running ) { while ( m_running ) {
sigwaitinfo( &(m_sigAction.sa_mask), &sigInfo); sigwaitinfo( &(m_sigAction.sa_mask), &sigInfo);
if ( not m_running ) return;
tidp = (long*)sigInfo.si_value.sival_ptr; tidp = (long*)sigInfo.si_value.sival_ptr;
// LOG( Logger::FINEST, ( std::string( "Timer expired with ID:" ) +
// stringify( (timer_t)*tidp ) ).c_str() ); // LOG( Logger::FINEST, ( std::string( "got periodic signal: " ) +
// stringify( sigInfo.si_signo ) +
// " from: " + stringify( (timer_t)*tidp ) ).c_str() );
periodicTimerExpired(); periodicTimerExpired();
} }
@ -117,11 +118,14 @@ void Timer::stopTimer()
{ {
TRACE; TRACE;
// disarm timer
struct itimerspec its; struct itimerspec its;
its.it_value.tv_sec = 0; its.it_value.tv_sec = 0;
its.it_value.tv_nsec = 0; its.it_value.tv_nsec = 0;
timer_settime( m_timerId, 0, &its, 0 ); timer_settime( m_timerId, 0, &its, 0 );
m_running = false; m_running = false;
/// @note sigwaitinfo waiting state, don't forget to send a last signal
} }
@ -129,5 +133,7 @@ void Timer::gracefulStop()
{ {
TRACE; TRACE;
// if it's periodic, use stopTimer
m_running = false; m_running = false;
/// @note sigwaitinfo waiting state, don't forget to send a last signal
} }

@ -1,4 +1,4 @@
#include "TimerThread.hpp" #include "TimerThreadMultimap.hpp"
#include "Common.hpp" #include "Common.hpp"
#include "ScopedLock.hpp" #include "ScopedLock.hpp"
@ -7,7 +7,7 @@
TimerThread::TimerThread() TimerThreadMultimap::TimerThreadMultimap()
: Thread() : Thread()
, m_mutex() , m_mutex()
, m_condVar( m_mutex ) , m_condVar( m_mutex )
@ -17,13 +17,13 @@ TimerThread::TimerThread()
} }
TimerThread::~TimerThread() TimerThreadMultimap::~TimerThreadMultimap()
{ {
TRACE; TRACE;
} }
void TimerThread::addTimerUser( TimerUser* user, void TimerThreadMultimap::addTimerUser( TimerUser* user,
const time_t expiration, const time_t expiration,
const time_t periodTime ) const time_t periodTime )
{ {
@ -36,7 +36,7 @@ void TimerThread::addTimerUser( TimerUser* user,
} }
void TimerThread::addTimerUser( TimerUser* user, void TimerThreadMultimap::addTimerUser( TimerUser* user,
const timespec expiration, const timespec expiration,
const timespec periodTime ) const timespec periodTime )
{ {
@ -55,7 +55,7 @@ void TimerThread::addTimerUser( TimerUser* user,
} }
bool TimerThread::removeTimerUser( TimerUser* timerUser ) bool TimerThreadMultimap::removeTimerUser( TimerUser* timerUser )
{ {
TRACE; TRACE;
ScopedLock sl( m_mutex ); ScopedLock sl( m_mutex );
@ -78,7 +78,7 @@ bool TimerThread::removeTimerUser( TimerUser* timerUser )
} }
void TimerThread::stop() void TimerThreadMultimap::stop()
{ {
TRACE; TRACE;
ScopedLock sl( m_mutex ); ScopedLock sl( m_mutex );
@ -87,7 +87,7 @@ void TimerThread::stop()
} }
void TimerThread::notifyAndRemove( const timespec t ) void TimerThreadMultimap::notifyAndRemove( const timespec t )
{ {
TRACE; TRACE;
ScopedLock sl( m_mutex ); ScopedLock sl( m_mutex );
@ -119,7 +119,7 @@ void TimerThread::notifyAndRemove( const timespec t )
} }
void* TimerThread::run( void ) void* TimerThreadMultimap::run( void )
{ {
TRACE; TRACE;
timespec nextExpiration; timespec nextExpiration;

@ -25,7 +25,7 @@ if(CXXTEST_FOUND)
test_Semaphore.hpp test_Semaphore.hpp
test_Timer.hpp test_Timer.hpp
test_Common.hpp test_Common.hpp
test_TimerThread.hpp test_TimerThreadMultimap.hpp
) )
target_link_libraries(test CppUtils gcov) target_link_libraries(test CppUtils gcov)
endif() endif()

@ -37,7 +37,7 @@ if [ ! -e $test ]; then
exit 1 exit 1
fi fi
echo -e "${pre}Reset & remove files${post}" echo -e "${pre}Reset & remove lcov, $test.out and core files${post}"
# coverage # coverage
lcov --directory . -z lcov --directory . -z
rm -f ./lcov.info rm -f ./lcov.info
@ -73,6 +73,7 @@ if [ $retval -ne 0 ]; then
if [ $retval -ne 137 ]; then if [ $retval -ne 137 ]; then
echo -e "${pre}Failed checks:${post}" echo -e "${pre}Failed checks:${post}"
# TODO print the previous line too
cat $test.out | grep "Error:" | awk -F"/test/" '{ print $2 }' cat $test.out | grep "Error:" | awk -F"/test/" '{ print $2 }'
fi fi
@ -85,6 +86,7 @@ if [ $retval -ne 0 ]; then
gdb $test $cores -ex "set width 1000" -ex "thread apply all bt" -ex q > gdb.out gdb $test $cores -ex "set width 1000" -ex "thread apply all bt" -ex q > gdb.out
./gdb_out_parser.pl gdb.out ./gdb_out_parser.pl gdb.out
echo ""
if yesno "run 'gdb $test $cores' ?"; then if yesno "run 'gdb $test $cores' ?"; then
gdb $test $cores gdb $test $cores
fi fi
@ -114,3 +116,8 @@ echo -e "${pre}Checking the coverage results${post}"
echo -e "${pre}Checking leak results${post}" echo -e "${pre}Checking leak results${post}"
./leak_check.pl leak.log ./leak_check.pl leak.log
if [ $? == 1 ]; then
if yesno "run 'vim leak.log' ?"; then
vim leak.log
fi
fi

@ -12,68 +12,6 @@
class TestTimer : public CxxTest::TestSuite class TestTimer : public CxxTest::TestSuite
{ {
private:
class DummyTimer : public Timer
{
public:
DummyTimer(int maxPeriodicCount = 5, const int signal = SIGALRM)
: Timer(signal)
, m_counter(0)
, m_maxPeriodicCount(maxPeriodicCount)
{
TRACE;
}
void timerExpired()
{
TRACE;
m_counter += 100;
}
void periodicTimerExpired()
{
TRACE;
static int count = 0;
m_counter++;
count++;
if ( count >= m_maxPeriodicCount ) {
stopTimer();
}
}
int m_counter;
private:
int m_maxPeriodicCount;
};
public:
void testBasic( void )
{
TEST_HEADER;
DummyTimer t;
t.createTimer(2);
t.wait();
TS_ASSERT_EQUALS( t.m_counter, 100 );
}
void testBasicPeriodic( void )
{
TEST_HEADER;
DummyTimer t;
t.createTimer(2,0,1);
t.wait();
TS_ASSERT_EQUALS( t.m_counter, 105 );
}
private: private:
class DummyTimerThread : public Timer, public Thread class DummyTimerThread : public Timer, public Thread
@ -89,10 +27,23 @@ private:
: Timer( signal ) : Timer( signal )
, m_counter( 0 ) , m_counter( 0 )
, m_maxPeriodicCount( maxPeriodicCount ) , m_maxPeriodicCount( maxPeriodicCount )
, m_signal ( signal )
, m_interval_sec( interval_sec ) , m_interval_sec( interval_sec )
, m_interval_nsec( interval_nsec ) , m_interval_nsec( interval_nsec )
, m_initExpr_sec( initExpr_sec ) , m_initExpr_sec( initExpr_sec )
, m_initExpr_nsec( initExpr_nsec ) , 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; TRACE;
} }
@ -130,11 +81,18 @@ private:
} }
} }
void stop()
{
stopTimer();
sendSignal( m_signal );
}
int m_counter; int m_counter;
private: private:
int m_maxPeriodicCount; int m_maxPeriodicCount;
int m_signal;
time_t m_interval_sec; time_t m_interval_sec;
long m_interval_nsec; long m_interval_nsec;
time_t m_initExpr_sec; time_t m_initExpr_sec;
@ -152,7 +110,7 @@ private:
sigset_t set; sigset_t set;
sigemptyset( &set ); sigemptyset( &set );
sigaddset( &set, SIGALRM ); sigaddset( &set, SIGALRM );
sigprocmask(SIG_BLOCK, &set, NULL); pthread_sigmask( SIG_BLOCK, &set, 0 );
DummyTimerThread t(5); DummyTimerThread t(5);
@ -161,6 +119,56 @@ private:
t.join(); t.join();
TS_ASSERT_EQUALS( t.m_counter, 100 ); TS_ASSERT_EQUALS( t.m_counter, 100 );
pthread_sigmask( SIG_UNBLOCK, &set, 0 );
}
void testStopTimerThread( void )
{
TEST_HEADER;
// the main thread shall ignore the SIGALRM
sigset_t set;
sigemptyset( &set );
sigaddset( &set, SIGALRM );
pthread_sigmask( SIG_BLOCK, &set, 0 );
DummyTimerThread t(5, SIGALRM, 10);
t.start();
sleep(1);
t.stop();
t.join();
TS_ASSERT_EQUALS( t.m_counter, 0 );
pthread_sigmask( SIG_UNBLOCK, &set, 0 );
}
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 );
DummyTimerThread t( 1000,
SIGALRM,
1, 0,
1, 0 );
t.start();
sleep(4);
t.stop();
sleep(2);
t.join();
TS_ASSERT_EQUALS( t.m_counter, 102 );
pthread_sigmask( SIG_UNBLOCK, &set, 0 );
} }
void testCustomSignal( void ) void testCustomSignal( void )
@ -173,20 +181,17 @@ private:
sigset_t set; sigset_t set;
sigemptyset( &set ); sigemptyset( &set );
sigaddset( &set, customSignal ); sigaddset( &set, customSignal );
sigprocmask( SIG_BLOCK, &set, NULL); pthread_sigmask( SIG_BLOCK, &set, 0 );
DummyTimerThread t( 5, customSignal ); DummyTimerThread t( 5, customSignal );
t.start(); t.start();
// timespec ts = { 4, 0 };
// nanosleep( &ts , 0 );
sleep(4); sleep(4);
t.join(); t.join();
TS_ASSERT_EQUALS( t.m_counter, 100 ); TS_ASSERT_EQUALS( t.m_counter, 100 );
sigprocmask( SIG_UNBLOCK, &set, NULL ); pthread_sigmask( SIG_UNBLOCK, &set, 0 );
} }
void testTimerThreadHighFreq( void ) void testTimerThreadHighFreq( void )
@ -197,26 +202,29 @@ private:
sigset_t set; sigset_t set;
sigemptyset( &set ); sigemptyset( &set );
sigaddset( &set, SIGALRM ); sigaddset( &set, SIGALRM );
sigprocmask(SIG_BLOCK, &set, NULL); pthread_sigmask( SIG_BLOCK, &set, 0 );
int nano = 1000000000; // 10^9 int nano = 1000000000; // 10^9
int freq = 80000; int freq = 200;
DummyTimerThread t( INT_MAX - 1, DummyTimerThread t( INT_MAX - 1,
SIGALRM, SIGALRM,
1, 0, 1, 0,
0, nano / freq ); 0, nano / freq );
t.start(); t.start();
int circle = 10; int circle = 4;
sleep( 1 + circle ); sleep( 1 + circle );
t.gracefulStop(); t.stop();
t.join(); t.join();
// expected 800000 + 100 got 795510 // expected 800000 + 100 got 795510
// accurcy: ~ > 99.5% // accurcy: ~ > 99.5%
TS_ASSERT_DELTA ( t.m_counter, 100 + freq * circle, (100 + freq * circle) * 0.995); TS_ASSERT_DELTA ( t.m_counter, 100 + freq * circle, (100 + freq * circle) * 0.995);
sigprocmask( SIG_UNBLOCK, &set, NULL ); LOG( Logger::FINEST, ( std::string( "got: " ) + stringify( t.m_counter ) + " "
+ "expected: " + stringify( 100 + freq * circle ) ).c_str() );
pthread_sigmask( SIG_UNBLOCK, &set, 0 );
} }
}; };

@ -2,16 +2,16 @@
#include "Fixture.hpp" #include "Fixture.hpp"
#define private public // reach TimerThread's private multimap #define private public // reach TimerThreadMultimap's private multimap
#include "TimerThread.hpp" #include "TimerThreadMultimap.hpp"
#include <time.h> #include <time.h>
class TestTimerThread : public CxxTest::TestSuite class TestTimerThreadMultimap : public CxxTest::TestSuite
{ {
private: private:
@ -37,7 +37,7 @@ public:
void testBasic( void ) void testBasic( void )
{ {
TEST_HEADER; TEST_HEADER;
TimerThread* tt = new TimerThread(); TimerThreadMultimap* tt = new TimerThreadMultimap();
tt->start(); tt->start();
sleep(1); sleep(1);
@ -57,7 +57,7 @@ public:
void testBasicTimeSpec( void ) void testBasicTimeSpec( void )
{ {
TEST_HEADER; TEST_HEADER;
TimerThread* tt = new TimerThread(); TimerThreadMultimap* tt = new TimerThreadMultimap();
tt->start(); tt->start();
sleep(1); sleep(1);
@ -78,7 +78,7 @@ public:
void testPeriodic( void ) void testPeriodic( void )
{ {
TEST_HEADER; TEST_HEADER;
TimerThread* tt = new TimerThread(); TimerThreadMultimap* tt = new TimerThreadMultimap();
tt->start(); tt->start();
sleep(1); sleep(1);
@ -101,7 +101,7 @@ public:
// Logger::getInstance()->setLogLevel(Logger::DEBUG); // Logger::getInstance()->setLogLevel(Logger::DEBUG);
TimerThread* tt = new TimerThread(); TimerThreadMultimap* tt = new TimerThreadMultimap();
tt->start(); tt->start();
sleep(1); sleep(1);
@ -120,7 +120,7 @@ public:
tt->stop(); tt->stop();
sleep(1); sleep(1);
TS_ASSERT_EQUALS( user->m_counter, 4 ); // 4 times TS_ASSERT_EQUALS( user->m_counter, 104 ); // 4 times
// TS_ASSERT_EQUALS( user2->m_counter, perMinute*4 ); // TS_ASSERT_EQUALS( user2->m_counter, perMinute*4 );
delete tt; delete tt;
@ -131,7 +131,7 @@ public:
void testDestroyed( void ) void testDestroyed( void )
{ {
TEST_HEADER; TEST_HEADER;
TimerThread* tt = new TimerThread(); TimerThreadMultimap* tt = new TimerThreadMultimap();
tt->start(); tt->start();
sleep(1); sleep(1);
@ -151,7 +151,7 @@ public:
void testRemoved( void ) void testRemoved( void )
{ {
TEST_HEADER; TEST_HEADER;
TimerThread* tt = new TimerThread(); TimerThreadMultimap* tt = new TimerThreadMultimap();
tt->start(); tt->start();
sleep(1); sleep(1);
@ -194,7 +194,7 @@ public:
void testRemovedMultiple( void ) void testRemovedMultiple( void )
{ {
TEST_HEADER; TEST_HEADER;
TimerThread* tt = new TimerThread(); TimerThreadMultimap* tt = new TimerThreadMultimap();
tt->start(); tt->start();
sleep(1); sleep(1);

@ -39,12 +39,6 @@
} }
{
comparing void pointers
Memcheck:Addr4
fun:_ZN11TimerThread15removeTimerUserEPv
}
{ {
thread with signal thread with signal
Memcheck:Leak Memcheck:Leak
@ -102,3 +96,23 @@
fun:timer_create@@GLIBC_2.3.3 fun:timer_create@@GLIBC_2.3.3
} }
{
disarm timer
Memcheck:Param
timer_settime(value)
fun:timer_settime@@GLIBC_2.3.3
fun:_ZN5TimerD1Ev
...
fun:main
}
{
disarm timer 2
Memcheck:Param
timer_settime(value)
fun:timer_settime@@GLIBC_2.3.3
fun:_ZN5Timer9stopTimerEv
...
fun:main
}

Loading…
Cancel
Save