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.

master
Denes Matetelki 14 years ago
parent a87978afef
commit e7e383fd7f

@ -3,3 +3,39 @@ project (CPP_UTILS_LIB)
add_subdirectory (build)
add_subdirectory (test)
find_package(Doxygen)
if(DOXYGEN_FOUND)
add_custom_target(doc ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/doxyfile)
endif(DOXYGEN_FOUND)
add_custom_target(reset
COMMAND rm -rf html
COMMAND rm -rf CMakeFiles
COMMAND rm -rf Makefile
COMMAND rm -rf cmake_install.cmake
COMMAND rm -rf CMakeCache.txt
COMMAND rm -rf build/CMakeFiles
COMMAND rm -rf build/Makefile
COMMAND rm -rf build/cmake_install.cmake
COMMAND rm -rf build/CMakeCache.txt
COMMAND rm -rf build/*.a
COMMAND rm -rf test/CMakeFiles
COMMAND rm -rf test/Makefile
COMMAND rm -rf test/cmake_install.cmake
COMMAND rm -rf test/CMakeCache.txt
COMMAND rm -rf test/CTestTestfile.cmake
COMMAND rm -rf test/cov
COMMAND rm -rf test/*core
COMMAND rm -rf test/*.gcno
COMMAND rm -rf test/lcov*.info
COMMAND rm -rf test/leak.log
COMMAND rm -rf test/test.out
COMMAND rm -rf test/generated_main.cpp
COMMAND rm -rf test/test
)

1679
doxyfile

File diff suppressed because it is too large Load Diff

@ -1,35 +1,65 @@
#ifndef 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
/// @todo Get rid of the "warning: statement has no effect" compiler msgs
#define TRACE(x) ""
#endif
#include <time.h> // timespec, CLOCK_REALTIME
#include <typeinfo> //typeid
#include <stdexcept> // runtime_error
#include <sstream> // ostringstream
#define STRINGIZE(c) #c
#include <time.h>
inline timespec intIntervalTotimespec(const int & interval)
inline timespec addSecTotimespec(const long int & sec)
{
timespec abs_time;
clock_gettime ( CLOCK_REALTIME, &abs_time );
abs_time.tv_nsec += interval * 1000000;
if ( abs_time.tv_nsec >= 1000000000 ) {
abs_time.tv_nsec -= 1000000000;
abs_time.tv_sec += 1;
}
abs_time.tv_sec += sec;
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

@ -18,23 +18,25 @@ class ConcurrentQueue {
public:
ConcurrentQueue()
: m_cancelled(false)
: m_queue()
, m_cancelled(false)
, m_mutex()
, m_condVar(m_mutex)
{
TRACE(this);
TRACE;
}
~ConcurrentQueue()
{
TRACE(this);
TRACE;
}
void push(const T task)
{
TRACE(this);
TRACE;
ScopedLock sl(m_mutex);
if (m_cancelled) throw CancelledException();
m_queue.push( task );
@ -44,7 +46,7 @@ class ConcurrentQueue {
bool tryPop(T &popped_value)
{
TRACE(this);
TRACE;
ScopedLock sl(m_mutex);
if (m_cancelled) throw CancelledException();
if ( m_queue.empty() ) return false;
@ -57,7 +59,7 @@ class ConcurrentQueue {
T waitAndPop()
{
TRACE(this);
TRACE;
ScopedLock sl(m_mutex);
while ( m_queue.empty() and not m_cancelled) {
@ -73,7 +75,7 @@ class ConcurrentQueue {
bool empty() const
{
TRACE(this);
TRACE;
ScopedLock sl(m_mutex);
if (m_cancelled) throw CancelledException();
return m_queue.empty();
@ -82,7 +84,7 @@ class ConcurrentQueue {
void cancel()
{
TRACE(this);
TRACE;
ScopedLock sl(m_mutex);
m_cancelled = true;
m_condVar.broadcast();

@ -12,7 +12,7 @@ public:
ConditionVariable(Mutex& mutex);
~ConditionVariable();
int wait(const int interval = 0);
int wait(const long int intervalSec = 0);
int signal();
int broadcast();

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

@ -11,9 +11,24 @@ public:
Mutex(int kind = PTHREAD_MUTEX_DEFAULT);
~Mutex();
/**
* Locks mutex. If already locked, the calling thread shall block until
* the mutex becomes available.
* @returns If successful, zero; otherwise, an error number.
*/
int lock();
/**
*
*/
int unlock();
bool tryLock(const int interval = 0);
/**
* If currently locked, the call shall return immediately.
* @returns Zero if a lock acquired. Otherwise, an error number.
*/
int tryLock(const long int intervalSec = 0);
pthread_mutex_t* getPThreadMutex();

@ -13,7 +13,7 @@ public:
Semaphore( int maxCount = 1 );
~Semaphore( void );
bool lock( int interval = 0 );
bool lock( const long int intervalSec = 0 );
bool unLock( void );
int getCount( void ) const;

@ -2,14 +2,16 @@
#define SINGLETON_HPP
#include "Common.hpp"
#include "Logger.hpp"
template<typename T>
class Singleton
{
protected:
Singleton() { TRACE("Simgleton::Singleton()"); }
virtual ~Singleton() { TRACE("Simgleton::~Singleton()"); }
Singleton() {};
virtual ~Singleton() {};
private:
@ -20,23 +22,20 @@ public:
static void createInstance()
{
TRACE("Simgleton::createInstance()");
if ( not m_instance ) {
m_instance = new T();
}
}
static T* getInstance()
inline static T* getInstance()
{
TRACE("Simgleton::getInstance()");
return m_instance;
}
static void destroy()
{
TRACE("Simgleton::destroy()");
if ( m_instance ) {
delete m_instance;
}

@ -9,15 +9,15 @@ class Task
public:
// Task() {};
// virtual ~Task() {};
virtual ~Task() {};
virtual void run () = 0;
virtual bool isItStucked () const = 0;
protected:
time_t m_startedToRun;
time_t m_timeOut;
// time_t m_startedToRun;
// time_t m_timeOut;
};

@ -13,7 +13,7 @@ public:
void start();
void* join() const;
void stop();
virtual void stop();
void sendSignal( const int nSignal ) const;
private:

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

@ -7,28 +7,26 @@
ConditionVariable::ConditionVariable(Mutex& mutex)
: m_mutex(mutex)
{
TRACE(this);
TRACE;
pthread_cond_init( &m_condVar, 0 );
}
ConditionVariable::~ConditionVariable()
{
TRACE(this);
TRACE;
pthread_cond_destroy( &m_condVar );
}
int ConditionVariable::wait(const int interval)
int ConditionVariable::wait(const long int intervalSec)
{
TRACE(this);
if ( interval == 0 ) {
TRACE;
if ( intervalSec == 0 ) {
return pthread_cond_wait( &m_condVar,
m_mutex.getPThreadMutex() );
} else {
timespec tspec = intIntervalTotimespec(interval);
TRACE("interval: " << interval << " tspec.tv_sec: " << tspec.tv_sec << " tspec.tv_nsec: " << tspec.tv_nsec );
timespec tspec = addSecTotimespec(intervalSec);
return pthread_cond_timedwait( &m_condVar,
m_mutex.getPThreadMutex(),
&tspec);
@ -38,13 +36,13 @@ int ConditionVariable::wait(const int interval)
int ConditionVariable::signal()
{
TRACE(this);
TRACE;
return pthread_cond_signal( &m_condVar );
}
int ConditionVariable::broadcast()
{
TRACE(this);
TRACE;
return pthread_cond_broadcast( &m_condVar );
}

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

@ -1,12 +1,13 @@
#include "Mutex.hpp"
#include "Common.hpp"
#include <time.h>
Mutex::Mutex(int kind)
{
TRACE(this);
TRACE;
if ( kind == PTHREAD_MUTEX_DEFAULT ) {
pthread_mutex_init( &m_mutex, 0 );
} else {
@ -20,34 +21,33 @@ Mutex::Mutex(int kind)
Mutex::~Mutex()
{
TRACE(this);
TRACE;
pthread_mutex_destroy ( &m_mutex );
}
int Mutex::lock()
{
TRACE(this);
TRACE;
return pthread_mutex_lock( &m_mutex );
}
int Mutex::unlock()
{
TRACE(this);
TRACE;
return pthread_mutex_unlock ( &m_mutex );
}
bool Mutex::tryLock(const int interval)
int Mutex::tryLock(const long int intervalSec)
{
TRACE(this);
if ( interval == 0 ) {
int result = pthread_mutex_trylock ( &m_mutex );
return result == 0;
TRACE;
if ( intervalSec == 0 ) {
return pthread_mutex_trylock ( &m_mutex );
} else {
timespec tspec = intIntervalTotimespec(interval);
return pthread_mutex_timedlock ( &m_mutex, &tspec ) == 0;
timespec tspec = addSecTotimespec( intervalSec );
return pthread_mutex_timedlock ( &m_mutex, &tspec );
}
}

@ -4,13 +4,13 @@
ScopedLock::ScopedLock( Mutex& mutex) : m_mutex(mutex)
{
TRACE(this);
TRACE;
m_mutex.lock();
}
ScopedLock::~ScopedLock()
{
TRACE(this);
TRACE;
m_mutex.unlock();
}

@ -3,44 +3,45 @@
#include "ScopedLock.hpp"
#include "Common.hpp"
Semaphore::Semaphore( int maxCount )
: m_maxCount( maxCount )
, m_count( maxCount )
, m_mutex()
, m_condVar(m_mutex)
{
TRACE(this);
TRACE;
}
Semaphore::~Semaphore( void )
{
TRACE(this);
TRACE;
}
bool Semaphore::lock( int interval )
bool Semaphore::lock( const long int intervalSec )
{
TRACE(this);
TRACE;
ScopedLock sl(m_mutex);
if ( m_count == 0 ) {
if ( m_condVar.wait(interval) != 0 ) {
if ( m_condVar.wait(intervalSec) != 0 ) {
return false;
}
}
m_count -= 1;
m_count--;
return true;
}
bool Semaphore::unLock( void )
{
TRACE(this);
TRACE;
ScopedLock sc(m_mutex);
if ( m_count == m_maxCount ) {
return false;
}
m_count += 1;
m_count++;
m_condVar.signal();
return true;
}
@ -48,7 +49,7 @@ bool Semaphore::unLock( void )
int Semaphore::getCount( void ) const
{
TRACE(this);
TRACE;
ScopedLock sc(m_mutex);
return m_count;
}

@ -4,24 +4,25 @@
#include <signal.h>
#include <iostream>
Thread::Thread()
: m_isRunning(false)
, m_threadHandler( 0 )
{
TRACE(this);
TRACE;
}
Thread::~Thread()
{
TRACE(this);
TRACE;
}
void Thread::start()
{
TRACE(this);
TRACE;
m_isRunning = true;
pthread_create( &m_threadHandler, NULL, threadStarter, ( void* )this );
}
@ -29,7 +30,7 @@ void Thread::start()
void* Thread::join() const
{
TRACE(this);
TRACE;
void* retVal;
pthread_join( m_threadHandler, &retVal );
return retVal;
@ -38,20 +39,20 @@ void* Thread::join() const
void Thread::stop()
{
TRACE(this);
TRACE;
m_isRunning = false;
}
void Thread::sendSignal( const int nSignal ) const
{
TRACE(this);
TRACE;
pthread_kill( m_threadHandler, nSignal );
}
void* Thread::threadStarter( void* pData )
{
TRACE("Thread::threadStarter");
LOG(Logger::FINEST, "static");
return static_cast<Thread *>(pData)->run();
}

@ -3,13 +3,15 @@
ThreadPool::ThreadPool()
: m_threads()
, m_tasks()
{
TRACE(this);
TRACE;
}
ThreadPool::~ThreadPool()
{
TRACE(this);
TRACE;
std::vector<Thread*>::iterator it;
for( it = m_threads.begin() ; it != m_threads.end(); it++ )
{
@ -20,28 +22,28 @@ ThreadPool::~ThreadPool()
void ThreadPool::pushTask( Task* task )
{
TRACE(this);
TRACE;
m_tasks.push(task);
}
Task* ThreadPool::popTask()
{
TRACE(this);
TRACE;
return m_tasks.waitAndPop();
}
void ThreadPool::pushWorkerThread( Thread * thread)
{
TRACE(this);
TRACE;
m_threads.push_back( thread );
}
void ThreadPool::startWorkerThreads()
{
TRACE(this);
TRACE;
std::vector<Thread*>::iterator it;
for( it = m_threads.begin() ; it != m_threads.end(); it++ )
{
@ -52,7 +54,7 @@ void ThreadPool::startWorkerThreads()
void ThreadPool::stop()
{
TRACE(this);
TRACE;
std::vector<Thread*>::iterator it;
for( it = m_threads.begin() ; it != m_threads.end(); it++ )
{
@ -65,7 +67,7 @@ void ThreadPool::stop()
void ThreadPool::join() const
{
TRACE(this);
TRACE;
std::vector<Thread*>::const_iterator it;
for( it = m_threads.begin() ; it != m_threads.end(); it++ )
{

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

@ -3,19 +3,24 @@ add_definitions( ${CXX_FLAGS} )
find_package(CxxTest)
if(CXXTEST_FOUND)
set(CXXTEST_USE_PERL TRUE)
include_directories(${CXXTEST_INCLUDE_DIR} ../include)
enable_testing()
CXXTEST_ADD_TEST(test
generated_main.cpp
set(CXXTEST_USE_PERL TRUE)
# set(CXXTEST_TESTGEN_ARGS "")
test_Singelton.hpp
test_Mutex.hpp
test_ScopedLock.hpp
test_ConditionalVariable.hpp
test_Thread.hpp
test_ThreadPool.hpp
test_Semaphore.hpp
)
target_link_libraries(test CppUtils gcov)
include_directories(${CXXTEST_INCLUDE_DIR} ../include)
enable_testing()
CXXTEST_ADD_TEST(test
generated_main.cpp
test_Common.hpp
test_Singelton.hpp
test_Mutex.hpp
test_ScopedLock.hpp
test_ConditionalVariable.hpp
test_Thread.hpp
test_ThreadPool.hpp
test_Semaphore.hpp
test_TimerThread.hpp
)
target_link_libraries(test CppUtils gcov)
endif()

@ -3,6 +3,20 @@
# Usage:
# ./run_test.sh <TEST_BINARY>
function yesno()
{
while true; do
read -p "$* (y/n)[y]" yn
if [ "$yn" = '' ]; then yn="y"; fi
case "$yn" in
[Yy]* ) return 0;;
[Nn]* ) return 1;;
* ) echo "Please answer y/n.";;
esac
done
}
pre="\E[00;33m"
fail="\E[00;31m"
post="\E[00;00m"
@ -62,6 +76,9 @@ if [ $retval -ne 0 ]; then
if [ "$cores" != "" ]; then
echo -e "${pre}Core file generated: ${post}"
echo $cores
if yesno "run 'gdb $test $cores' ?"; then
gdb $test $cores
fi
fi
exit -1
fi

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

@ -1,9 +1,10 @@
#include <cxxtest/TestSuite.h>
#include "Common.hpp"
#include "test_Common.hpp"
#include "Mutex.hpp"
#include <errno.h> // EDEADLK, EPERM
#include <errno.h> // EDEADLK, EPERM, ETIMEDOUT
class TestMutex : public CxxTest::TestSuite
{
@ -13,17 +14,19 @@ public:
void testBasic( void )
{
TEST_HEADER;
Mutex m;
TS_ASSERT_EQUALS ( m.lock() , 0 );
// TS_ASSERT_EQUALS ( m.lock() , 0 ); that would be a deadlock
TS_ASSERT_EQUALS ( m.tryLock(0), false );
TS_ASSERT_EQUALS ( m.tryLock(2), false );
TS_ASSERT_EQUALS ( m.tryLock(0), EBUSY );
TS_ASSERT_EQUALS ( m.tryLock(2), ETIMEDOUT );
TS_ASSERT_EQUALS ( m.unlock() , 0 );
TS_ASSERT_EQUALS ( m.unlock() , 0 );
}
void testErrorCheck( void )
{
TEST_HEADER;
Mutex m(PTHREAD_MUTEX_ERRORCHECK);
TS_ASSERT_EQUALS ( m.lock() , 0 );
TS_ASSERT_EQUALS ( m.lock(), EDEADLK );
@ -34,6 +37,7 @@ public:
void testRecursive( void )
{
TEST_HEADER;
Mutex m(PTHREAD_MUTEX_RECURSIVE);
TS_ASSERT_EQUALS ( m.lock() , 0 );
TS_ASSERT_EQUALS ( m.lock() , 0 );

@ -3,6 +3,7 @@
#define private public // need to reach private variables
#include "Common.hpp"
#include "test_Common.hpp"
#include "Mutex.hpp"
class TestPThreadWrappers : public CxxTest::TestSuite
@ -13,6 +14,7 @@ public:
void testMutexBasic( void )
{
TEST_HEADER;
Mutex m;
m.lock();
TS_ASSERT_EQUALS ( m.tryLock(0), 0 );
@ -21,6 +23,7 @@ public:
void testMutexCreate( void )
{
TEST_HEADER;
Mutex m(PTHREAD_MUTEX_ERRORCHECK);
m.lock();
TS_ASSERT_EQUALS ( m.lock(), 1 );

@ -1,6 +1,7 @@
#include <cxxtest/TestSuite.h>
#include "ScopedLock.hpp"
#include "test_Common.hpp"
class TestScopedLock : public CxxTest::TestSuite
@ -11,13 +12,14 @@ public:
void testBasic( void )
{
TEST_HEADER;
Mutex m;
{
ScopedLock sl(m);
TS_ASSERT_EQUALS ( m.tryLock(0), false );
TS_ASSERT_EQUALS ( m.tryLock(0), EBUSY );
}
TS_ASSERT_EQUALS ( m.tryLock(0), true );
TS_ASSERT_EQUALS ( m.tryLock(0), 0 );
}
};

@ -3,6 +3,7 @@
#include "Semaphore.hpp"
#include "Thread.hpp"
#include "Common.hpp"
#include "test_Common.hpp"
class TestSemaphore : public CxxTest::TestSuite
{
@ -10,6 +11,7 @@ public:
void testBasic( void )
{
TEST_HEADER;
Semaphore s;
TS_ASSERT_EQUALS( s.getCount(), 1 );
@ -30,27 +32,27 @@ private:
ThreadClassWithSemaphore(Semaphore &semaphore)
: m_semaphore(semaphore)
{
TRACE(this);
TRACE;
}
~ThreadClassWithSemaphore() {
TRACE(this);
TRACE;
}
bool use( int timeout = 0 ) {
TRACE(this);
bool retval = m_semaphore.lock(timeout);
return retval;
TRACE;
return m_semaphore.lock(timeout);
}
bool release( void ) {
TRACE(this);
TRACE;
return m_semaphore.unLock();
}
private:
void* run( void ) {
TRACE(this);
TRACE;
while (m_isRunning) {
sleep(1);
}
@ -65,6 +67,8 @@ public:
void testWithTwoThreads( void )
{
TEST_HEADER;
Semaphore semaphore(2);
TS_ASSERT_EQUALS( semaphore.getCount(), 2 );

@ -2,12 +2,16 @@
#define private public // need to reach Singleton's private m_instance
#include "Singleton.hpp"
#include "Common.hpp"
#include "test_Common.hpp"
#include "Singleton.hpp"
class TestSingletonSuite : public CxxTest::TestSuite
{
private:
class BasicSingleton : public Singleton<BasicSingleton>
{
public:
@ -18,6 +22,8 @@ public:
void testBasic( void )
{
TEST_HEADER;
// no instance yet
TS_ASSERT_EQUALS (BasicSingleton::getInstance(), (BasicSingleton*)0);
@ -48,12 +54,14 @@ public:
* EvilClass and implements the expensice calls with dummy ones) to TestMe
*/
private:
class TestMe
{
public:
int fv()
{
TRACE(this);
TRACE;
return EvilClass::getInstance()->getValue();
}
};
@ -63,7 +71,7 @@ public:
public:
virtual int getValue(void)
{
TRACE(this);
TRACE;
return 665;
}
};
@ -73,13 +81,17 @@ public:
public:
int getValue(void)
{
TRACE(this);
TRACE;
return 13;
}
};
public:
void testAdvancedTest( void )
{
TEST_HEADER;
TestMe tm;
EvilClass::createInstance();

@ -1,5 +1,7 @@
#include <cxxtest/TestSuite.h>
#include "test_Common.hpp"
#include "Thread.hpp"
#include "Common.hpp"
#include "Mutex.hpp"
@ -15,19 +17,11 @@ private:
class ThreadClass : public Thread
{
// public:
// ThreadClass() { TRACE(this); }
// ~ThreadClass() { TRACE(this); }
private:
// ThreadClass(const ThreadClass&) : Thread() { TRACE(this); }
// ThreadClass& operator=(const ThreadClass&) { TRACE(this); return*this; }
void* run( void ) {
TRACE(this);
TRACE;
void* retVal = malloc(sizeof(int));
*((int*)retVal) = 14;
@ -39,6 +33,7 @@ public:
void testBasic( void )
{
TEST_HEADER;
ThreadClass *m = new ThreadClass;
m->start();
@ -60,18 +55,18 @@ private:
public:
ThreadClassWithSignal() {
TRACE(this);
TRACE;
signal(SIGINT, signal_handler);
}
~ThreadClassWithSignal() {
TRACE(this);
TRACE;
}
private:
void* run( void ) {
TRACE(this);
TRACE;
/** @note the function will get stopped before it finishes sleeping
* If signal arrives after malloc, it will be a memory leak.
@ -85,9 +80,7 @@ private:
static void signal_handler(int sig)
{
TRACE("ThreadClassWithSignal::signal_handler");
if (sig==SIGINT) {
TRACE("signal_handler got SIGINT");
void* retVal = malloc(sizeof(int));
*((int*)retVal) = 16;
@ -102,6 +95,7 @@ public:
void testSignalSend( void )
{
TEST_HEADER;
ThreadClassWithSignal *m2 = new ThreadClassWithSignal;
m2->start();
sleep(1);

@ -6,7 +6,7 @@
#include "Thread.hpp"
#include "ThreadPool.hpp"
#include "Common.hpp"
#include "test_Common.hpp"
@ -18,20 +18,20 @@ class TestThreadPoolSuite : public CxxTest::TestSuite
public:
DummyTask() { m_timeOut = 5; TRACE(this); }
DummyTask() { /*m_timeOut = 5*/; TRACE; }
void run()
{
TRACE(this);
m_startedToRun = time(NULL);
TRACE("I'm a task...");
m_startedToRun = 0;
TRACE;
// m_startedToRun = time(NULL);
LOG( Logger::FINEST, "I'm a task...");
// m_startedToRun = 0;
}
bool isItStucked () const
{
TRACE(this);
return ( m_startedToRun + m_timeOut < time(NULL) );
TRACE;
return false;
}
};
@ -43,14 +43,14 @@ class TestThreadPoolSuite : public CxxTest::TestSuite
WorkerThread( ThreadPool& tp )
: m_tp(tp)
{
TRACE(this);
TRACE;
}
private:
void* run()
{
TRACE(this);
TRACE;
while ( m_isRunning )
{
Task* task(0);
@ -59,7 +59,7 @@ class TestThreadPoolSuite : public CxxTest::TestSuite
task->run();
delete task;
} catch (CancelledException) {
TRACE("Now I die.");
LOG( Logger::FINEST, "Now I die.");
}
}
return 0;
@ -73,6 +73,7 @@ public:
void testBasic()
{
TEST_HEADER;
ThreadPool* tp = new ThreadPool();
Thread* wt1 = new WorkerThread(*tp);

@ -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…
Cancel
Save