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
#define TIMER_HPP
#include <signal.h> // sigset_t
#include <time.h> // timer_t
class Timer
{
@ -20,14 +22,18 @@ public:
const time_t initExpr_sec = 0,
const long initExpr_nsec = 0 );
void wait();
void stopTimer();
void gracefulStop();
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
@ -39,7 +45,6 @@ private:
timer_t m_timerId;
bool m_periodic;
bool m_running;
sigset_t m_mask;
}; // class Timer

@ -1,5 +1,5 @@
#ifndef TIMERTHREAD_HPP
#define TIMERTHREAD_HPP
#ifndef TIMERTHREAD_MULTIMAP_HPP
#define TIMERTHREAD_MULTIMAP_HPP
#include "Thread.hpp"
@ -23,7 +23,7 @@ public:
class TimerThread : public Thread
class TimerThreadMultimap : public Thread
{
private:
@ -36,9 +36,9 @@ private:
public:
TimerThread();
TimerThreadMultimap();
virtual ~TimerThread();
virtual ~TimerThreadMultimap();
void addTimerUser( TimerUser* user,
const time_t expiration,
@ -81,7 +81,7 @@ private:
ConditionVariable m_condVar;
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
/// @note not used now
/// @note not used now, all signals are caught by sigwaitinfo
// static void sigHandler(int sig, siginfo_t *si, void *uc)
// {
// TRACE_STATIC;
//
// }
@ -21,18 +20,10 @@ struct sigaction& sigActionInit( struct sigaction &sigAct, const int signal )
// sigAct.sa_sigaction = sigHandler;
sigemptyset( &sigAct.sa_mask );
sigaddset( &sigAct.sa_mask, signal );
sigaction( signal, &sigAct, 0 );
// sigaction( signal, &sigAct, 0 );
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 )
: m_signal( signal )
@ -40,7 +31,6 @@ Timer::Timer( const int signal )
, m_timerId( 0 )
, m_periodic( false )
, m_running( true )
, m_mask( sigSetInit( m_mask, m_signal ) )
{
TRACE;
}
@ -49,7 +39,12 @@ Timer::~Timer()
{
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);
if ( not m_running ) return;
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();
@ -102,9 +100,12 @@ void Timer::wait()
while ( m_running ) {
sigwaitinfo( &(m_sigAction.sa_mask), &sigInfo);
if ( not m_running ) return;
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();
}
@ -117,11 +118,14 @@ void Timer::stopTimer()
{
TRACE;
// 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
}
@ -129,5 +133,7 @@ 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
}

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

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

@ -37,7 +37,7 @@ if [ ! -e $test ]; then
exit 1
fi
echo -e "${pre}Reset & remove files${post}"
echo -e "${pre}Reset & remove lcov, $test.out and core files${post}"
# coverage
lcov --directory . -z
rm -f ./lcov.info
@ -73,6 +73,7 @@ if [ $retval -ne 0 ]; then
if [ $retval -ne 137 ]; then
echo -e "${pre}Failed checks:${post}"
# TODO print the previous line too
cat $test.out | grep "Error:" | awk -F"/test/" '{ print $2 }'
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_out_parser.pl gdb.out
echo ""
if yesno "run 'gdb $test $cores' ?"; then
gdb $test $cores
fi
@ -114,3 +116,8 @@ echo -e "${pre}Checking the coverage results${post}"
echo -e "${pre}Checking leak results${post}"
./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
{
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:
class DummyTimerThread : public Timer, public Thread
@ -89,10 +27,23 @@ private:
: 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;
}
@ -130,11 +81,18 @@ private:
}
}
void stop()
{
stopTimer();
sendSignal( m_signal );
}
int m_counter;
private:
int m_maxPeriodicCount;
int m_signal;
time_t m_interval_sec;
long m_interval_nsec;
time_t m_initExpr_sec;
@ -152,7 +110,7 @@ private:
sigset_t set;
sigemptyset( &set );
sigaddset( &set, SIGALRM );
sigprocmask(SIG_BLOCK, &set, NULL);
pthread_sigmask( SIG_BLOCK, &set, 0 );
DummyTimerThread t(5);
@ -161,6 +119,56 @@ private:
t.join();
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 )
@ -173,20 +181,17 @@ private:
sigset_t set;
sigemptyset( &set );
sigaddset( &set, customSignal );
sigprocmask( SIG_BLOCK, &set, NULL);
pthread_sigmask( SIG_BLOCK, &set, 0 );
DummyTimerThread t( 5, customSignal );
t.start();
// timespec ts = { 4, 0 };
// nanosleep( &ts , 0 );
sleep(4);
t.join();
TS_ASSERT_EQUALS( t.m_counter, 100 );
sigprocmask( SIG_UNBLOCK, &set, NULL );
pthread_sigmask( SIG_UNBLOCK, &set, 0 );
}
void testTimerThreadHighFreq( void )
@ -197,26 +202,29 @@ private:
sigset_t set;
sigemptyset( &set );
sigaddset( &set, SIGALRM );
sigprocmask(SIG_BLOCK, &set, NULL);
pthread_sigmask( SIG_BLOCK, &set, 0 );
int nano = 1000000000; // 10^9
int freq = 80000;
int freq = 200;
DummyTimerThread t( INT_MAX - 1,
SIGALRM,
1, 0,
0, nano / freq );
t.start();
int circle = 10;
int circle = 4;
sleep( 1 + circle );
t.gracefulStop();
t.stop();
t.join();
// expected 800000 + 100 got 795510
// accurcy: ~ > 99.5%
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"
#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>
class TestTimerThread : public CxxTest::TestSuite
class TestTimerThreadMultimap : public CxxTest::TestSuite
{
private:
@ -37,7 +37,7 @@ public:
void testBasic( void )
{
TEST_HEADER;
TimerThread* tt = new TimerThread();
TimerThreadMultimap* tt = new TimerThreadMultimap();
tt->start();
sleep(1);
@ -57,7 +57,7 @@ public:
void testBasicTimeSpec( void )
{
TEST_HEADER;
TimerThread* tt = new TimerThread();
TimerThreadMultimap* tt = new TimerThreadMultimap();
tt->start();
sleep(1);
@ -78,7 +78,7 @@ public:
void testPeriodic( void )
{
TEST_HEADER;
TimerThread* tt = new TimerThread();
TimerThreadMultimap* tt = new TimerThreadMultimap();
tt->start();
sleep(1);
@ -101,7 +101,7 @@ public:
// Logger::getInstance()->setLogLevel(Logger::DEBUG);
TimerThread* tt = new TimerThread();
TimerThreadMultimap* tt = new TimerThreadMultimap();
tt->start();
sleep(1);
@ -120,7 +120,7 @@ public:
tt->stop();
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 );
delete tt;
@ -131,7 +131,7 @@ public:
void testDestroyed( void )
{
TEST_HEADER;
TimerThread* tt = new TimerThread();
TimerThreadMultimap* tt = new TimerThreadMultimap();
tt->start();
sleep(1);
@ -151,7 +151,7 @@ public:
void testRemoved( void )
{
TEST_HEADER;
TimerThread* tt = new TimerThread();
TimerThreadMultimap* tt = new TimerThreadMultimap();
tt->start();
sleep(1);
@ -194,7 +194,7 @@ public:
void testRemovedMultiple( void )
{
TEST_HEADER;
TimerThread* tt = new TimerThread();
TimerThreadMultimap* tt = new TimerThreadMultimap();
tt->start();
sleep(1);

@ -39,12 +39,6 @@
}
{
comparing void pointers
Memcheck:Addr4
fun:_ZN11TimerThread15removeTimerUserEPv
}
{
thread with signal
Memcheck:Leak
@ -102,3 +96,23 @@
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