New make target: reset, which removes all generated files. Doxygen file and doc target added. New singleton Logger class. New TimerThread class. Cafe of broken dreams: ./other: ConcurrentMultiMap, Semaphore.cpp. run_test asks y/n question to run gdb if core created. test_Common.hpp to init Logger for tests.
parent
a87978afef
commit
e7e383fd7f
@ -1,35 +1,65 @@
|
|||||||
#ifndef COMMON_HPP
|
#ifndef COMMON_HPP
|
||||||
#define COMMON_HPP
|
#define COMMON_HPP
|
||||||
|
|
||||||
|
#include <cstring> // rindex
|
||||||
|
#include <string> // string
|
||||||
|
|
||||||
#include <iostream>
|
#include "Logger.hpp"
|
||||||
|
|
||||||
#ifndef NOTRACE
|
|
||||||
#define TRACE(x) std::cout << x << " " << __PRETTY_FUNCTION__ << \
|
|
||||||
" : " << __LINE__ << std::endl
|
|
||||||
|
|
||||||
#else
|
#include <time.h> // timespec, CLOCK_REALTIME
|
||||||
/// @todo Get rid of the "warning: statement has no effect" compiler msgs
|
|
||||||
#define TRACE(x) ""
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
#include <typeinfo> //typeid
|
||||||
|
#include <stdexcept> // runtime_error
|
||||||
|
#include <sstream> // ostringstream
|
||||||
|
|
||||||
#define STRINGIZE(c) #c
|
inline timespec addSecTotimespec(const long int & sec)
|
||||||
|
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
inline timespec intIntervalTotimespec(const int & interval)
|
|
||||||
{
|
{
|
||||||
timespec abs_time;
|
timespec abs_time;
|
||||||
clock_gettime ( CLOCK_REALTIME, &abs_time );
|
clock_gettime ( CLOCK_REALTIME, &abs_time );
|
||||||
abs_time.tv_nsec += interval * 1000000;
|
abs_time.tv_sec += sec;
|
||||||
if ( abs_time.tv_nsec >= 1000000000 ) {
|
|
||||||
abs_time.tv_nsec -= 1000000000;
|
|
||||||
abs_time.tv_sec += 1;
|
|
||||||
}
|
|
||||||
return abs_time;
|
return abs_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline const char* extractFilename( const char *path )
|
||||||
|
{
|
||||||
|
char const * f = rindex(path, '/');
|
||||||
|
if (f) return ++f;
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class BadConversion : public std::runtime_error
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
BadConversion(std::string const& s) : std::runtime_error(s) { }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline std::string stringify(T const& x)
|
||||||
|
{
|
||||||
|
std::ostringstream o;
|
||||||
|
if (!(o << x))
|
||||||
|
throw BadConversion(std::string("stringify(") + typeid(x).name() + ")");
|
||||||
|
return o.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline std::string getTime( void )
|
||||||
|
{
|
||||||
|
time_t tim = time( NULL );
|
||||||
|
struct tm * now = localtime( &tim );
|
||||||
|
|
||||||
|
std::string ret = stringify(now->tm_hour) + ":" +
|
||||||
|
stringify(now->tm_min) + ":" +
|
||||||
|
stringify(now->tm_sec);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // COMMON_HPP
|
#endif // COMMON_HPP
|
||||||
|
@ -0,0 +1,88 @@
|
|||||||
|
#ifndef LOGGER_HPP
|
||||||
|
#define LOGGER_HPP
|
||||||
|
|
||||||
|
#include "Singleton.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <set>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
|
||||||
|
class Logger : public Singleton<Logger>
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum LogLevel {
|
||||||
|
EMERG = 0, // system is unusable
|
||||||
|
ALERT, // action must be taken immediately
|
||||||
|
CRIT, // critical conditions
|
||||||
|
ERR, // error conditions
|
||||||
|
WARNING, // warning conditions
|
||||||
|
NOTICE, // normal but significant condition
|
||||||
|
INFO, // informational
|
||||||
|
DEBUG, // debug-level messages
|
||||||
|
FINEST
|
||||||
|
};
|
||||||
|
|
||||||
|
Logger() {}
|
||||||
|
virtual ~Logger() { m_ostream->flush(); }
|
||||||
|
|
||||||
|
static void init(std::ostream& log_stream );
|
||||||
|
|
||||||
|
static void setLogLevel ( const LogLevel loglevel );
|
||||||
|
inline static LogLevel getLoglevel() { return m_logLevel; }
|
||||||
|
|
||||||
|
static void log_pointer( const LogLevel loglevel,
|
||||||
|
const void* msg,
|
||||||
|
const char* file,
|
||||||
|
int line,
|
||||||
|
const char* function);
|
||||||
|
|
||||||
|
static void log_string( const LogLevel loglevel,
|
||||||
|
const char* msg,
|
||||||
|
const char* file,
|
||||||
|
int line,
|
||||||
|
const char* function);
|
||||||
|
|
||||||
|
static void msg (const char* text);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Logger( const Logger& );
|
||||||
|
Logger& operator=( const Logger& );
|
||||||
|
|
||||||
|
static LogLevel m_logLevel;
|
||||||
|
static std::ostream *m_ostream;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef NO_TRACE
|
||||||
|
#define MAX_LOFLEVEL Logger::DEBUG
|
||||||
|
#else
|
||||||
|
#define MAX_LOFLEVEL Logger::FINEST
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define TRACE \
|
||||||
|
if(MAX_LOFLEVEL >= Logger::FINEST && \
|
||||||
|
Logger::getInstance()->getLoglevel() >= Logger::FINEST ) \
|
||||||
|
Logger::getInstance()->log_pointer( \
|
||||||
|
Logger::FINEST, this, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
|
||||||
|
else (void)0
|
||||||
|
|
||||||
|
|
||||||
|
#define LOG(level, msg) \
|
||||||
|
if (MAX_LOFLEVEL >= level && \
|
||||||
|
Logger::getInstance()->getLoglevel() >= Logger::FINEST ) \
|
||||||
|
Logger::getInstance()->log_string( \
|
||||||
|
level, msg, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
|
||||||
|
else (void)0
|
||||||
|
|
||||||
|
|
||||||
|
/// @todo remove this
|
||||||
|
#define MSG(text) Logger::getInstance()->msg(text)
|
||||||
|
|
||||||
|
|
||||||
|
#endif // LOGGER_HPP
|
@ -0,0 +1,65 @@
|
|||||||
|
#ifndef TIMERTHREAD_HPP
|
||||||
|
#define TIMERTHREAD_HPP
|
||||||
|
|
||||||
|
|
||||||
|
#include "Thread.hpp"
|
||||||
|
#include "Mutex.hpp"
|
||||||
|
#include "ConditionVariable.hpp"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <ctime> // time_t
|
||||||
|
|
||||||
|
class TimerUser
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void timerExpired( void ) = 0;
|
||||||
|
virtual void timerDestroyed( void ) = 0;
|
||||||
|
|
||||||
|
virtual ~TimerUser() {}
|
||||||
|
|
||||||
|
}; // class TimerUser
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class TimerThread : public Thread
|
||||||
|
{
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
time_t periodTime;
|
||||||
|
TimerUser* user;
|
||||||
|
} UserEntry;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
TimerThread();
|
||||||
|
|
||||||
|
virtual ~TimerThread();
|
||||||
|
|
||||||
|
void addTimerUser(TimerUser* user,
|
||||||
|
const time_t expiration,
|
||||||
|
const time_t periodTime = 0 );
|
||||||
|
|
||||||
|
bool removeTimerUser ( UserEntry userEntry );
|
||||||
|
|
||||||
|
// override to signal as well
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void* run( void );
|
||||||
|
|
||||||
|
|
||||||
|
Mutex m_mutex;
|
||||||
|
ConditionVariable m_condVar;
|
||||||
|
std::multimap<time_t, UserEntry> m_users;
|
||||||
|
|
||||||
|
}; // class TimerThread
|
||||||
|
|
||||||
|
|
||||||
|
#endif // TIMERTHREAD_HPP
|
@ -0,0 +1,138 @@
|
|||||||
|
#ifndef CONCURRENTMULTIMAP_HPP
|
||||||
|
#define CONCURRENTMULTIMAP_HPP
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Mutex.hpp"
|
||||||
|
#include "ConditionVariable.hpp"
|
||||||
|
#include "ScopedLock.hpp"
|
||||||
|
#include "Common.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
template < typename T1, typename T2 >
|
||||||
|
class ConcurrentMultiMap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
class CancelledException {};
|
||||||
|
|
||||||
|
ConcurrentMultiMap()
|
||||||
|
: m_mutex()
|
||||||
|
, m_condVar(m_mutex)
|
||||||
|
, m_cancelled(false)
|
||||||
|
, m_map()
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
~ConcurrentMultiMap()
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
typename std::multimap<T1, T2>::iterator begin()
|
||||||
|
{
|
||||||
|
return m_map.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
typename std::multimap<T1, T2>::const_iterator begin() const
|
||||||
|
{
|
||||||
|
return m_map.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
typename std::multimap<T1, T2>::iterator end()
|
||||||
|
{
|
||||||
|
return m_map.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
typename std::multimap<T1, T2>::const_iterator end() const
|
||||||
|
{
|
||||||
|
return m_map.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void add(T1 key, T2 value)
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
ScopedLock sl(m_mutex);
|
||||||
|
if (m_cancelled) throw CancelledException();
|
||||||
|
m_map.insert( std::make_pair<T1, T1>( key, value) );
|
||||||
|
m_condVar.signal();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool erase( T1 key )
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
ScopedLock sl( m_mutex );
|
||||||
|
if ( m_map.erase(key) > 0 ) {
|
||||||
|
m_condVar.signal();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool removeValue( T2 value )
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
ScopedLock sl(m_mutex);
|
||||||
|
typename std::multimap<T1, T2>::iterator it;
|
||||||
|
for ( it = m_map.begin(); it != m_map.end(); it++ ) {
|
||||||
|
if (it->second == value) {
|
||||||
|
m_map.erase(it);
|
||||||
|
m_condVar.signal();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
typename std::pair< std::multimap<T1, T2>::iterator, std::multimap<T1, T2>::iterator > equal_range ( const T1& key )
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
ScopedLock sl( m_mutex );
|
||||||
|
return m_map.equal_range(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
T1 waitAndGetFirstKey()
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
ScopedLock sl(m_mutex);
|
||||||
|
|
||||||
|
while ( m_map.empty() and not m_cancelled) {
|
||||||
|
m_condVar.wait();
|
||||||
|
}
|
||||||
|
if (m_cancelled) throw CancelledException();
|
||||||
|
|
||||||
|
return m_map.begin()->first;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
ScopedLock sl(m_mutex);
|
||||||
|
if (m_cancelled) throw CancelledException();
|
||||||
|
return m_map.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cancel( void )
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
ScopedLock sl(m_mutex);
|
||||||
|
m_cancelled = true;
|
||||||
|
m_condVar.broadcast();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
ConcurrentMultiMap& operator=( const ConcurrentMultiMap& );
|
||||||
|
ConcurrentMultiMap( const ConcurrentMultiMap& );
|
||||||
|
|
||||||
|
mutable Mutex m_mutex;
|
||||||
|
ConditionVariable m_condVar;
|
||||||
|
bool m_cancelled;
|
||||||
|
std::multimap<T1, T2> m_map;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CONCURRENTMULTIMAP_HPP
|
@ -0,0 +1,58 @@
|
|||||||
|
#include "Semaphore.hpp"
|
||||||
|
|
||||||
|
#include "ScopedLock.hpp"
|
||||||
|
#include "Common.hpp"
|
||||||
|
|
||||||
|
Semaphore::Semaphore( int maxCount )
|
||||||
|
: m_maxCount( maxCount )
|
||||||
|
, m_mutex()
|
||||||
|
{
|
||||||
|
TRACE(this);
|
||||||
|
sem_init( &m_semaphore, 0, maxCount );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Semaphore::~Semaphore( void )
|
||||||
|
{
|
||||||
|
TRACE(this);
|
||||||
|
sem_destroy( &m_semaphore );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Semaphore::lock( int interval )
|
||||||
|
{
|
||||||
|
TRACE(this);
|
||||||
|
if ( interval == 0 ) {
|
||||||
|
return sem_wait( &m_semaphore );
|
||||||
|
} else {
|
||||||
|
timespec tspec = intIntervalTotimespec( interval );
|
||||||
|
return sem_timedwait( &m_semaphore, &tspec );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Semaphore::tryLock( void )
|
||||||
|
{
|
||||||
|
TRACE(this);
|
||||||
|
return sem_trywait( &m_semaphore );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Semaphore::unLock( void )
|
||||||
|
{
|
||||||
|
TRACE(this);
|
||||||
|
ScopedLock sl(m_mutex); // is it needed?
|
||||||
|
int value;
|
||||||
|
sem_getvalue( &m_semaphore, &value);
|
||||||
|
if ( value == m_maxCount ) return -1;
|
||||||
|
return sem_post( &m_semaphore );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Semaphore::getCount( void ) const
|
||||||
|
{
|
||||||
|
TRACE(this);
|
||||||
|
int retval;
|
||||||
|
sem_getvalue( &m_semaphore, &retval );
|
||||||
|
return retval;
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
#include "Common.hpp"
|
||||||
|
|
@ -0,0 +1,55 @@
|
|||||||
|
#include "Logger.hpp"
|
||||||
|
|
||||||
|
#include <time.h> //time
|
||||||
|
|
||||||
|
|
||||||
|
void Logger::init(std::ostream& log_stream )
|
||||||
|
{
|
||||||
|
m_ostream = &log_stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Logger::setLogLevel ( const LogLevel loglevel )
|
||||||
|
{
|
||||||
|
m_logLevel = loglevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Logger::log_pointer( const LogLevel loglevel,
|
||||||
|
const void* msg,
|
||||||
|
const char* file,
|
||||||
|
int line,
|
||||||
|
const char* function)
|
||||||
|
{
|
||||||
|
*m_ostream << getTime() << " "
|
||||||
|
<< extractFilename(file) << ":"
|
||||||
|
<< line << " "
|
||||||
|
<< function << " "
|
||||||
|
<< "\"" << msg << "\""
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Logger::log_string( const LogLevel loglevel,
|
||||||
|
const char* msg,
|
||||||
|
const char* file,
|
||||||
|
int line,
|
||||||
|
const char* function)
|
||||||
|
{
|
||||||
|
*m_ostream << getTime() << " "
|
||||||
|
<< extractFilename(file) << ":"
|
||||||
|
<< line << " "
|
||||||
|
<< function << " "
|
||||||
|
<< "\"" << msg << "\""
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::msg(const char* text)
|
||||||
|
{
|
||||||
|
*m_ostream << text << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Logger::LogLevel Logger::m_logLevel = Logger::FINEST;
|
||||||
|
std::ostream* Logger::m_ostream = 0;
|
@ -0,0 +1,117 @@
|
|||||||
|
#include "TimerThread.hpp"
|
||||||
|
|
||||||
|
#include "Common.hpp"
|
||||||
|
#include "ScopedLock.hpp"
|
||||||
|
|
||||||
|
#include <errno.h> // ETIMEDOUT
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
TimerThread::TimerThread()
|
||||||
|
: m_mutex()
|
||||||
|
, m_condVar(m_mutex)
|
||||||
|
, m_users()
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TimerThread::~TimerThread()
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TimerThread::addTimerUser(TimerUser* user,
|
||||||
|
const time_t expiration,
|
||||||
|
const time_t periodTime)
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
ScopedLock sl( m_mutex );
|
||||||
|
UserEntry userEntry = { periodTime, user };
|
||||||
|
m_users.insert( std::pair<time_t, UserEntry>( expiration, userEntry ) );
|
||||||
|
m_condVar.signal();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool TimerThread::removeTimerUser ( UserEntry userEntry )
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
ScopedLock sl( m_mutex );
|
||||||
|
std::multimap<time_t, UserEntry>::iterator it;
|
||||||
|
bool found(false);
|
||||||
|
for ( it = m_users.begin(); it != m_users.end(); it++ ) {
|
||||||
|
if ( it->second.user == userEntry.user ) {
|
||||||
|
m_users.erase(it);
|
||||||
|
m_condVar.signal();
|
||||||
|
found = true; // one usercan be registered multiple times
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
// override to signal as well
|
||||||
|
void TimerThread::stop()
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
ScopedLock sl( m_mutex );
|
||||||
|
m_isRunning = false;
|
||||||
|
m_condVar.signal();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void* TimerThread::run( void )
|
||||||
|
{
|
||||||
|
TRACE;
|
||||||
|
time_t nextExpiration;
|
||||||
|
|
||||||
|
std::multimap<time_t, UserEntry> tmp;
|
||||||
|
std::multimap<time_t, UserEntry>::iterator it;
|
||||||
|
std::pair<std::multimap<time_t, UserEntry>::iterator,
|
||||||
|
std::multimap<time_t, UserEntry>::iterator> ret;
|
||||||
|
|
||||||
|
while( m_isRunning ) {
|
||||||
|
|
||||||
|
while ( m_users.empty() and m_isRunning ) {
|
||||||
|
m_condVar.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( not m_isRunning) {
|
||||||
|
LOG( Logger::FINEST, "return empty handed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
nextExpiration = m_users.begin()->first;
|
||||||
|
|
||||||
|
// timer deleted / added, get nextExpiration again
|
||||||
|
if ( m_condVar.wait( nextExpiration ) != ETIMEDOUT ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// notify & remove
|
||||||
|
/// @todo lock here?
|
||||||
|
// m_mutex.lock();
|
||||||
|
ret = m_users.equal_range( nextExpiration );
|
||||||
|
|
||||||
|
/// @todo modify key values in multimap, must be a better way
|
||||||
|
tmp.clear();
|
||||||
|
for ( it = ret.first; it != ret.second; it++ ) {
|
||||||
|
it->second.user->timerExpired();
|
||||||
|
if ( it->second.periodTime ) tmp.insert(std::pair<time_t, UserEntry>(
|
||||||
|
it->second.periodTime, it->second ) );
|
||||||
|
}
|
||||||
|
m_users.erase( nextExpiration );
|
||||||
|
m_users.insert( tmp.begin(), tmp.end() );
|
||||||
|
// m_mutex.unlock();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( not m_users.empty() ) {
|
||||||
|
LOG( Logger::FINEST, "return full handed");
|
||||||
|
for ( it = m_users.begin(); it != m_users.end(); it++ ) {
|
||||||
|
it->second.user->timerDestroyed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
#ifndef TEST_COMMON_HPP
|
||||||
|
#define TEST_COMMON_HPP
|
||||||
|
|
||||||
|
#include <cxxtest/TestSuite.h>
|
||||||
|
#include <cxxtest/GlobalFixture.h>
|
||||||
|
|
||||||
|
#include "Common.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
class TestCommon : public CxxTest::GlobalFixture
|
||||||
|
{
|
||||||
|
bool setUpWorld()
|
||||||
|
{
|
||||||
|
Logger::createInstance();
|
||||||
|
Logger::init(std::cout);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tearDownWorld()
|
||||||
|
{
|
||||||
|
Logger::destroy();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
static TestCommon testCommon;
|
||||||
|
|
||||||
|
#define TEST_HEADER \
|
||||||
|
MSG( std::string("\n+++ ").append(__PRETTY_FUNCTION__).append(" +++\n").c_str());
|
||||||
|
|
||||||
|
|
||||||
|
#endif // TEST_COMMON_HPP
|
@ -0,0 +1,91 @@
|
|||||||
|
#include <cxxtest/TestSuite.h>
|
||||||
|
|
||||||
|
#include "test_Common.hpp"
|
||||||
|
|
||||||
|
#include "TimerThread.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
class TestTimerThread : public CxxTest::TestSuite
|
||||||
|
{
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
class DummyTimerUser : public TimerUser
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
DummyTimerUser( void ) : m_counter(0) { TRACE; }
|
||||||
|
~DummyTimerUser( void ) { TRACE; }
|
||||||
|
void timerExpired( void ) { TRACE; m_counter++; }
|
||||||
|
void timerDestroyed( void ) { TRACE; m_counter += 100; }
|
||||||
|
|
||||||
|
int m_counter;
|
||||||
|
|
||||||
|
}; // class DummyTimerUser
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void testBasic( void )
|
||||||
|
{
|
||||||
|
TEST_HEADER;
|
||||||
|
TimerThread* tt = new TimerThread();
|
||||||
|
tt->start();
|
||||||
|
sleep(1);
|
||||||
|
|
||||||
|
DummyTimerUser *user = new DummyTimerUser();
|
||||||
|
tt->addTimerUser( user, 2 );
|
||||||
|
|
||||||
|
sleep(4);
|
||||||
|
tt->stop();
|
||||||
|
sleep(1);
|
||||||
|
|
||||||
|
TS_ASSERT_EQUALS( user->m_counter, 1 );
|
||||||
|
|
||||||
|
delete tt;
|
||||||
|
delete user;
|
||||||
|
}
|
||||||
|
|
||||||
|
void testPeriodic( void )
|
||||||
|
{
|
||||||
|
TEST_HEADER;
|
||||||
|
TimerThread* tt = new TimerThread();
|
||||||
|
tt->start();
|
||||||
|
sleep(1);
|
||||||
|
|
||||||
|
DummyTimerUser *user = new DummyTimerUser();
|
||||||
|
tt->addTimerUser( user, 2, 1 );
|
||||||
|
|
||||||
|
sleep(6);
|
||||||
|
tt->stop();
|
||||||
|
sleep(1);
|
||||||
|
|
||||||
|
TS_ASSERT_EQUALS( user->m_counter, 104 );
|
||||||
|
|
||||||
|
delete tt;
|
||||||
|
delete user;
|
||||||
|
}
|
||||||
|
|
||||||
|
void testDestroyed( void )
|
||||||
|
{
|
||||||
|
TEST_HEADER;
|
||||||
|
TimerThread* tt = new TimerThread();
|
||||||
|
tt->start();
|
||||||
|
sleep(1);
|
||||||
|
|
||||||
|
DummyTimerUser *user = new DummyTimerUser();
|
||||||
|
tt->addTimerUser( user, 10 );
|
||||||
|
|
||||||
|
sleep(2);
|
||||||
|
tt->stop();
|
||||||
|
sleep(1);
|
||||||
|
|
||||||
|
TS_ASSERT_EQUALS( user->m_counter, 100 );
|
||||||
|
|
||||||
|
delete tt;
|
||||||
|
delete user;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
Loading…
Reference in new issue