/×××××××××××Thread.h××××××××××××××/
#ifndef __THREAD__
#define __THREAD__
#ifdef WIN32
#include
#include
#else
#include
#include
#endif
using namespace std;
class ThreadException
{
private:
string msg;
public:
ThreadException(string m);
ThreadException(const char* m);
virtual ~ThreadException() {};
virtual string getMessage() const;
};
class Thread
{
protected:
string m_strName;
#ifdef WIN32
HANDLE m_hThread;
CRITICAL_SECTION m_hMutex;
LONG volatile itsWorkingThreadID;
LONG volatile itsRunningFlag;
LONG volatile itsSuspendedFlag;
#else
pthread_t m_hThread;
pthread_mutex_t m_hMutex;
pthread_mutex_t m_hSuspendMutex;
pthread_cond_t m_SuspendCondition;
unsigned long itsWorkingThreadID;
bool itsRunningFlag;
bool itsSuspendedFlag;
#endif
static bool itsShutdownInProgress;
public:
Thread(const char* nm);
virtual ~Thread();
const char* getName() const;
void start();
virtual void run();
static void sleep(long ms);
void suspend();
void resume();
void stop(bool cancel=true);
void setPriority(int p);
void setAffinity(unsigned cpu);
bool wait(long ms=5000);
void release();
bool is(const char* theName);
void running();
bool isRunning();
bool isSuspended();
static void shutdownInProgress();
static bool isShuttingDown() { return itsShutdownInProgress; };
static unsigned long threadID();
public:
// Thread priorities
static const int P_ABOVE_NORMAL;
static const int P_BELOW_NORMAL;
static const int P_HIGHEST;
static const int P_IDLE;
static const int P_LOWEST;
static const int P_NORMAL;
static const int P_CRITICAL;
};
extern "C"
{
#ifdef WIN32
unsigned int _ou_thread_proc(void* param);
#else
void* _ou_thread_proc(void* param);
#endif
}
#endif
/×××××××××××Thread.h××××××××××××××/
/××××××××××××××Thread.cpp×××××××××××××××××/
#define SILENT
#include "Thread.h"
#ifdef WIN32
const int Thread::P_ABOVE_NORMAL = THREAD_PRIORITY_ABOVE_NORMAL;
const int Thread::P_BELOW_NORMAL = THREAD_PRIORITY_BELOW_NORMAL;
const int Thread::P_HIGHEST = THREAD_PRIORITY_HIGHEST;
const int Thread::P_IDLE = THREAD_PRIORITY_IDLE;
const int Thread::P_LOWEST = THREAD_PRIORITY_LOWEST;
const int Thread::P_NORMAL = THREAD_PRIORITY_NORMAL;
const int Thread::P_CRITICAL = THREAD_PRIORITY_TIME_CRITICAL;
#define THREAD_NULL NULL
#define ASSIGN_LONG(dest,val) InterlockedExchange(&dest,val)
#define ASSIGN_BOOL(dest,val) InterlockedExchange(&dest,(LONG)val)
#define ASSIGN_PTR(dest,val) InterlockedExchangePointer(&dest,val)
#else
#include
const int Thread::P_ABOVE_NORMAL = 0;
const int Thread::P_BELOW_NORMAL = 1;
const int Thread::P_HIGHEST = 2;
const int Thread::P_IDLE = 3;
const int Thread::P_LOWEST = 4;
const int Thread::P_NORMAL = 5;
const int Thread::P_CRITICAL = 6;
#define THREAD_NULL 0
#define ASSIGN_LONG(dest,val) dest=val
#define ASSIGN_BOOL(dest,val) dest=val
#define ASSIGN_PTR(dest,val) dest=val
#endif
#define SUSPENDWAITMS 10
bool Thread::itsShutdownInProgress=false;
void Thread::running()
{
ASSIGN_BOOL(itsRunningFlag,true);
};
bool Thread::isRunning()
{
return (itsRunningFlag!=0) ? true : false;
};
bool Thread::isSuspended()
{
return (itsSuspendedFlag!=0) ? true : false;
};
void Thread::shutdownInProgress()
{
itsShutdownInProgress=true;
}
unsigned long Thread::threadID()
{
#ifdef WIN32
return GetCurrentThreadId();
#else
return (unsigned long)pthread_self();
#endif
}
/** Thread(const char* nm)
* overloaded constructor
* creates a Thread object identified by "nm"
**/
Thread::Thread(const char* nm)
{
m_hThread = THREAD_NULL;
m_strName = nm;
ASSIGN_BOOL(itsRunningFlag,false);
ASSIGN_BOOL(itsSuspendedFlag,false);
ASSIGN_LONG(itsWorkingThreadID,0);
#ifdef WIN32
InitializeCriticalSection(&m_hMutex);
#else
pthread_mutex_init(&m_hMutex,NULL);
#endif
}
Thread::~Thread()
{
if(m_hThread != THREAD_NULL)
{
stop(true);
}
#ifdef WIN32
DeleteCriticalSection(&m_hMutex);
#else
pthread_mutex_destroy(&m_hMutex);
#endif
}
/** getName()
* return the Thread object's name as a string
**/
const char* Thread::getName() const
{
return m_strName.c_str();
}
bool Thread::is(const char* theName)
{
return (m_strName==theName);
}
/** run()
* called by the thread callback _ou_thread_proc()
* to be overridden by child classes of Thread
**/
void Thread::run()
{
// Base run
}
/** sleep(long ms)
* holds back the thread's execution for
* "ms" milliseconds
**/
void Thread::sleep(long ms)
{
#ifdef WIN32
Sleep(ms);
#else
struct timespec abs_ts;
struct timespec rm_ts;
rm_ts.tv_sec = ms/1000;
rm_ts.tv_nsec = ms%1000 *1000000;
do
{
abs_ts.tv_sec = rm_ts.tv_sec;
abs_ts.tv_nsec = rm_ts.tv_nsec;
} while(nanosleep(&abs_ts,&rm_ts) < 0);
#endif
}
/** start()
* creates a low-level thread object and calls the
* run() function
**/
void Thread::start()
{
#ifdef WIN32
DWORD tid = 0;
m_hThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)_ou_thread_proc,(Thread*)this,0,&tid);
if(m_hThread == NULL)
{
throw ThreadException(string("Failed to create thread ->")+m_strName);
}
else
{
setPriority(Thread::P_NORMAL);
}
#else
pthread_mutex_init(&m_hSuspendMutex,NULL);
pthread_cond_init(&m_SuspendCondition,NULL);
int iret = pthread_create( &m_hThread, NULL, _ou_thread_proc,this);
if(iret!=0)
{
TRACE("Fail to create thread")
throw ThreadException(string("Failed to create thread ->")+m_strName);
}
#endif
}
/** stop()
* stops the running thread and frees the thread handle
**/
void Thread::stop(bool cancel)
{
if(itsRunningFlag)
{
ASSIGN_BOOL(itsRunningFlag,false);
#ifdef WIN32
if(isSuspended()==true)
resume();
if(cancel==true)
TerminateThread(m_hThread,NULL);
else
WaitForSingleObject(m_hThread,INFINITE);
CloseHandle(m_hThread);
#else
TRACE("Joining thread")
if(cancel==true)
pthread_cancel(m_hThread);
else
pthread_join(m_hThread,NULL);
TRACE("Thread cleanup")
pthread_mutex_destroy(&m_hSuspendMutex);
pthread_cond_destroy(&m_SuspendCondition);
#endif
m_hThread = THREAD_NULL;
}
}
/** setPriority(int tp)
* sets the priority of the thread to "tp"
* "tp" must be a valid priority defined in the
* Thread class
**/
void Thread::setPriority(int tp)
{
if(m_hThread == THREAD_NULL)
{
throw ThreadException("Thread object is null");
}
else
{
#ifdef WIN32
if(SetThreadPriority(m_hThread,tp) == 0)
{
throw ThreadException("Failed to set priority");
}
#endif
}
}
void Thread::setAffinity(unsigned cpu)
{
#ifdef WIN32
DWORD mask=1;
mask <<= cpu;
if(SetThreadAffinityMask(m_hThread,mask)==0)
throw ThreadException("Failed to set affinity");
#else
#ifdef HAVE_PTHREAD_SETAFFINITY_NP
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(cpu, &cpuset);
#ifndef P2_PTHREAD_SETAFFINITY
if(pthread_setaffinity_np(m_hThread, sizeof(cpuset), &cpuset)!=0)
throw ThreadException("Failed to set affinity");
#else
if(pthread_setaffinity_np(m_hThread, &cpuset)!=0)
throw ThreadException("Failed to set affinity");
#endif
#else
DISPLAY("Thread affinity not supported on this system")
#endif
#endif
sleep(0);
}
/** suspend()
* suspends the thread
**/
void Thread::suspend()
{
if(m_hThread == THREAD_NULL)
{
throw ThreadException(string("Thread object is null ->")+m_strName);
}
else
{
#ifdef WIN32
ASSIGN_BOOL(itsSuspendedFlag,true);
if(SuspendThread(m_hThread) < 0)
{
throw ThreadException(string("Failed to suspend thread ->")+m_strName);
}
#else
TRACE("Tread suspended")
pthread_mutex_lock(&m_hSuspendMutex);
TRACE("Cond mutex count=" << m_hSuspendMutex.__m_count)
TRACE("Cond lock status=" << m_hSuspendMutex.__m_lock.__status)
itsSuspendedFlag=true;
while(itsSuspendedFlag==true)
{
int ms=SUSPENDWAITMS;
struct timespec abs_ts;
struct timeval cur_tv;
gettimeofday(&cur_tv, NULL);
abs_ts.tv_sec = cur_tv.tv_sec + ms/1000;
abs_ts.tv_nsec = (cur_tv.tv_usec + ms%1000*1000)*1000;
// FIX by Steve Rodgers
if(abs_ts.tv_nsec > 999999999)
{
abs_ts.tv_sec++;
abs_ts.tv_nsec -= 1000000000;
}
// End fix
pthread_cond_timedwait(&m_SuspendCondition,&m_hSuspendMutex,&abs_ts);
TRACE("Cond condition lock status=" << m_SuspendCondition.__c_lock.__status)
if(itsRunningFlag==false)
{
TRACE("Resume thread for shutdown cleanup")
break;
}
}
pthread_mutex_unlock(&m_hSuspendMutex);
TRACE("Cond mutex count=" << m_hSuspendMutex.__m_count)
TRACE("Cond lock status=" << m_hSuspendMutex.__m_lock.__status)
TRACE("Thread resumed")
#endif
}
}
/** resume()
* resumes a suspended thread
**/
void Thread::resume()
{
if(m_hThread == THREAD_NULL)
{
throw ThreadException(string("Thread object is null ->")+m_strName);
}
else
{
#ifdef WIN32
if(ResumeThread(m_hThread) < 0)
{
throw ThreadException(string("Failed to resume thread ->")+m_strName);
}
else
{
ASSIGN_BOOL(itsSuspendedFlag,false);
}
#else
pthread_mutex_lock(&m_hSuspendMutex);
TRACE("Cond mutex count=" << m_hSuspendMutex.__m_count)
TRACE("Cond lock status=" << m_hSuspendMutex.__m_lock.__status)
itsSuspendedFlag=false;
pthread_cond_signal(&m_SuspendCondition);
TRACE("Cond condition lock status=" << m_SuspendCondition.__c_lock.__status)
pthread_mutex_unlock(&m_hSuspendMutex);
TRACE("Cond mutex count=" << m_hSuspendMutex.__m_count)
TRACE("Cond lock status=" << m_hSuspendMutex.__m_lock.__status)
#endif
}
}
/** wait(long ms)
* makes the thread suspend execution until the
* mutex is released by another thread.
* "ms" specifies a time-out for the wait operation.
* "ms" defaults to 5000 milli-seconds
**/
bool Thread::wait(long ms)
{
if(itsWorkingThreadID!=0)
{
}
#ifdef WIN32
Sleep(0);
EnterCriticalSection(&m_hMutex);
ASSIGN_LONG(itsWorkingThreadID,threadID());
#else
struct timespec abs_ts;
struct timeval cur_tv;
gettimeofday(&cur_tv, NULL);
abs_ts.tv_sec = cur_tv.tv_sec + ms/1000;
abs_ts.tv_nsec = (cur_tv.tv_usec + ms%1000*1000)*1000;
int res=pthread_mutex_timedlock(&m_hMutex,&abs_ts);
TRACE("Mutex count=" << m_hMutex.__m_count)
TRACE("Lock status=" << m_hMutex.__m_lock.__status)
switch(res)
{
case 0:
itsWorkingThreadID=threadID(); //++ v1.5
TRACE("Thread::wait - end")
return true;
case EINVAL:
throw ThreadException(string("pthread_mutex_timedlock: Invalid value ->")+m_strName);
break;
case ETIMEDOUT:
throw ThreadException(string("pthread_mutex_timedlock: Wait timed out ->")+m_strName);
break;
default:
throw ThreadException(string("pthread_mutex_timedlock: Unexpected value ->")+m_strName);
}
#endif
return false;
}
/** release()
* releases the mutex "m" and makes it
* available for other threads
**/
void Thread::release()
{
#ifdef WIN32
ASSIGN_LONG(itsWorkingThreadID,0L);
LeaveCriticalSection(&m_hMutex);
#else
pthread_mutex_unlock(&m_hMutex);
TRACE("Mutex count=" << m_hMutex.__m_count)
TRACE("Lock status=" << m_hMutex.__m_lock.__status)
#endif
}
// ThreadException
ThreadException::ThreadException(const char* m)
{
msg = m;
}
ThreadException::ThreadException(string m)
{
msg = m;
}
string ThreadException::getMessage() const
{
return msg;
}
// global thread callback
#ifdef WIN32
unsigned int _ou_thread_proc(void* param)
{
try
{
Thread* tp = (Thread*)param;
tp->running();
tp->run();
}
catch(...)
{
//DISPLAY("Unhandled exception in thread callback")
}
return 0;
}
#else
void* _ou_thread_proc(void* param)
{
TRACE("Start _ou_thread_proc")
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
try
{
Thread* tp = (Thread*)param;
tp->running();
TRACE("Thread " << tp->getName() << " started")
tp->run();
}
catch(...)
{
DISPLAY("Unhandled exception in thread callback")
}
TRACE("End _ou_thread_proc")
pthread_exit(NULL);
return NULL;
}
#endif
/××××××××××××××Thread.cpp×××××××××××××××/
/**************************RunTimeLog.h*******************************/
#ifndef __RUNTIMELOGG__
#define __RUNTIMELOGG__
#include
using namespace std;
#include
#include
#include "Thread.h"
class LogInfo
{
public:
enum LogLevel { INFO,WARNING,CRITICAL,DEBUG };
protected:
string itsLog; //v1.4
string itsFile; //v1.4
int itsLine;
enum LogLevel itsLevel;
string itsInstance;
public:
LogInfo(char* theLog);
LogInfo(const char* theLog);
LogInfo(char* theLog,const char* theFile,int theLine,enum LogLevel theLevel,const char* theInstance=NULL);
LogInfo(const char* theLog,const char* theFile,int theLine,enum LogLevel theLevel,const char* theInstance=NULL);
virtual ~LogInfo();
virtual const char* get() { return itsLog.c_str(); };
virtual const char* getFile() { return itsFile.c_str(); };
virtual int getLine() { return itsLine; };
virtual enum LogLevel getLevel() { return itsLevel; };
virtual void toStream(ostream& theStream);
virtual void WriteLog(FILE*);
};
class RunTimeLog : public Thread
{
protected:
static RunTimeLog* itsDefaultLogger;
//ofstream itsStream;
FILE* m_file;
public:
RunTimeLog(const char* theLoggerName);
virtual ~RunTimeLog();
//static void startDefaultLogger(const char* theFileName = NULL); // ++ v1.5
static void postToDefaultLogger(LogInfo* theMessage);
static void waitForCompletion();
static void switchLogFile();
void switchFile();
void post(LogInfo* theMessage);
void close();
LogInfo * pop();
virtual void run();
protected:
RunTimeLog();
private:
list
};
#ifndef SILENT
#define DEBUG(a) \
RunTimeLog::post(new LogInfo(a,__FILE__,__LINE__, LogMessage::DEBUG));
#else
#define DEBUG(a) ;
#endif
#define LOG(a) \
RunTimeLog::postToDefaultLogger(new LogInfo(a,__FILE__,__LINE__, LogInfo::INFO));
#define WARNING(a) \
RunTimeLog::postToDefaultLogger(new LogInfo(a,__FILE__,__LINE__, LogInfo::WARNING));
#define CRITICAL(a) \
RunTimeLog::postToDefaultLogger(new LogInfo(a,__FILE__,__LINE__, LogInfo::CRITICAL));
/*#define STARTLOGGER(a) \
RunTimeLog::startDefaultLogger(a);*/
#define STOPLOGGER() \
RunTimeLog::waitForCompletion();
#define SWITCHLOGFile \
RunTimeLog::switchLogFile();
#endif
/**************************RunTimeLog.h*******************************/
/******************************RunTimeLog.cpp************************************/
#define SILENT
#include "RunTimeLog.h"
#include
#include
RunTimeLog* RunTimeLog::itsDefaultLogger=NULL;
RunTimeLog * getRunLogInstance()
{
static RunTimeLog gRunLog("DefaultLogger");
return &gRunLog;
}
LogInfo::LogInfo(char* theLog)
:itsLog(theLog), itsFile(NULL),itsLine(0), itsLevel(INFO)
{
}
LogInfo::LogInfo(const char* theLog)
:itsLog(theLog), itsFile(""),itsLine(0), itsLevel(INFO)
{
}
LogInfo::LogInfo(char* theLog,const char* theFile,int theLine,enum LogLevel theLevel,const char* theInstance)
:itsLog(theLog),itsFile(theFile), itsLine(theLine), itsLevel(theLevel)
{
if(theInstance!=NULL)
itsInstance=theInstance+string("@");
}
LogInfo::LogInfo(const char* theLog,const char* theFile,int theLine,enum LogLevel theLevel,const char* theInstance)
:itsLog(theLog),itsFile(theFile), itsLine(theLine), itsLevel(theLevel)
{
if(theInstance!=NULL)
itsInstance=theInstance+string("@");
}
LogInfo::~LogInfo()
{
}
void LogInfo::toStream(ostream& theStream)
{
char aTimeString[40];
time_t aTime=time(NULL);
strftime(aTimeString,sizeof(aTimeString),"[%Y-%m-%d %H:%M:%S]", localtime(&aTime));
theStream << aTimeString;
switch(getLevel())
{
case LogInfo::WARNING:
theStream << " [WARN] ";
break;
case LogInfo::CRITICAL:
theStream << " [CRIT] ";
break;
case LogInfo::DEBUG:
theStream << " [DEBG] ";
break;
default:
theStream << " [INFO] ";
}
theStream << itsFile << "(" << itsInstance << itsLine << "): " << itsLog << endl;
}
void LogInfo::WriteLog(FILE* p_file)
{
string temp;
if (p_file == NULL)
{
return;
}
char aTimeString[40];
time_t aTime=time(NULL);
strftime(aTimeString,sizeof(aTimeString),"[%Y-%m-%d %H:%M:%S]", localtime(&aTime));
fprintf(p_file,aTimeString);
switch(getLevel())
{
case LogInfo::WARNING:
temp = " [WARN] ";
break;
case LogInfo::CRITICAL:
temp = " [CRIT] ";
break;
case LogInfo::DEBUG:
temp = " [DEBG] ";
break;
default:
temp = " [INFO] ";
}
//theStream << itsFile << "(" << itsInstance << itsLine << "): " << itsLog << endl;
fprintf(p_file,"%s%s(%s%d):%s\n", temp.c_str(), itsFile.c_str(), itsInstance.c_str(), itsLine, itsLog.c_str());
}
RunTimeLog::RunTimeLog()
:Thread("DefaultLogger")
{
start();
//itsStream.open("messages.log");
}
RunTimeLog::RunTimeLog(const char* theLoggerName)
:Thread(theLoggerName)
{
char aTimeString[40];
time_t aTime=time(NULL);
strftime(aTimeString,sizeof(aTimeString),"%Y%m%d", localtime(&aTime));
char logName[50];
memset(logName, '\0', sizeof(logName));
sprintf(logName, ".\\RTimelog\\%s.log", aTimeString);
_mkdir("RTimelog");
//itsStream.open(logName, fstream::in | fstream::out | fstream::app);
m_file = fopen(logName, "a");
start();
}
RunTimeLog::~RunTimeLog()
{
wait();
//itsStream.close();
if(m_file != NULL)
{
fclose(m_file);
}
release();
shutdownInProgress();
}
void RunTimeLog::postToDefaultLogger(LogInfo* theMessage)
{
if(isShuttingDown()) //++ v1.5
{
delete theMessage;
return;
}
getRunLogInstance()->post(theMessage);
/*if(itsDefaultLogger==NULL)
itsDefaultLogger=new RunTimeLog();
if(theMessage)
itsDefaultLogger->post(theMessage);*/
}
void RunTimeLog::waitForCompletion()
{
/*if(itsDefaultLogger!=NULL)
{
if(!isShuttingDown())
delete itsDefaultLogger;
itsDefaultLogger=NULL;
}*/
getRunLogInstance()->close();
}
void RunTimeLog::switchLogFile()
{
getRunLogInstance()->switchFile();
}
void RunTimeLog::close()
{
wait();
//itsStream.close();
if(m_file != NULL)
{
fclose(m_file);
}
release();
}
void RunTimeLog::switchFile()
{
close();
char aTimeString[40];
time_t aTime=time(NULL);
strftime(aTimeString,sizeof(aTimeString),"%Y%m%d", localtime(&aTime));
char logName[50];
memset(logName, '\0', sizeof(logName));
sprintf(logName, ".\\RTimelog\\%s.log", aTimeString);
_mkdir("RTimelog");
wait();
//itsStream.open(logName, fstream::in | fstream::out | fstream::app);
m_file = fopen(logName, "a");
release();
}
void RunTimeLog::post(LogInfo* theMessage)
{
if(isShuttingDown()) //++ v1.5
{
delete theMessage;
return;
}
wait();
m_lstLogInf.push_back(theMessage);
if(isSuspended()==true)
{
resume();
}
release();
}
LogInfo * RunTimeLog::pop()
{
if (m_lstLogInf.size() == 0)
{
return NULL;
}
LogInfo * p_loginf = m_lstLogInf.front();
m_lstLogInf.pop_front();
return p_loginf;
}
void RunTimeLog::run()
{
while(true)
{
if(m_hThread!=0)
{
try
{
while(true)
{
wait();
if(m_lstLogInf.size() == 0)
{
release();
break;
}
LogInfo* aMessage=pop();
if (aMessage == NULL)
{
release();
break;
}
release();
//aMessage->toStream(itsStream);
aMessage->WriteLog(m_file);
delete aMessage;
}
suspend();
}
catch(ThreadException& ex)
{
release();
}
catch(...)
{
release();
}
}
}
}
/******************************RunTimeLog.cpp************************************/