#include <cstdlib>
#include <utility>
-
-ExpiryTimer_Impl* ExpiryTimer_Impl::s_instance = nullptr;
-std::mutex ExpiryTimer_Impl::s_mutexForCreation;
-bool ExpiryTimer_Impl::isDestroyed = false;
+ExpiryTimer_Impl* ExpiryTimer_Impl::s_instance;
+std::once_flag ExpiryTimer_Impl::mflag;
ExpiryTimer_Impl::ExpiryTimer_Impl()
{
- threadNum = 0;
- checkThreadRun = false;
+ createChecker();
}
ExpiryTimer_Impl::~ExpiryTimer_Impl()
{
- isDestroyed = true;
- int status;
-
- pthread_join(checker_th, (void **)&status);
- pthread_detach(checker_th);
-}
-
-void ExpiryTimer_Impl::killTimer()
-{
- s_instance->~ExpiryTimer_Impl();
}
ExpiryTimer_Impl* ExpiryTimer_Impl::getInstance()
{
- if(isDestroyed)
- {
- new(s_instance) ExpiryTimer_Impl;
- atexit(killTimer);
- isDestroyed = false;
- }
- else if(s_instance == nullptr)
- {
- static ExpiryTimer_Impl tmp_instance;
- s_instance = &tmp_instance;
- }
+ std::call_once(mflag, [](){ s_instance = new ExpiryTimer_Impl; });
return s_instance;
}
-TimerID ExpiryTimer_Impl::requestTimer(long long sec, TimerCB cb)
+ExpiryTimer_Impl::Id ExpiryTimer_Impl::postTimer(DelayMilliSec msec, TimerCb cb)
{
- if(threadNum < EXPIRY_THREAD_LIST)
- {
- unsigned int timerID = generateTimerID();
- ExpiryTimer_Impl::getInstance()->registerCBTimer(sec, cb, timerID);
- return timerID;
- }
- else
- return OVERFLOW_THREAD_NUM;
+ Id retID;
+ retID = generateID();
+ milliSeconds delay(msec);
+ insertTimerCBInfo(countExpireTime(delay), cb, retID);
+
+ return retID;
}
-void ExpiryTimer_Impl::cancelTimer(TimerID timerID)
+bool ExpiryTimer_Impl::cancelTimer(Id timerID)
{
- for( auto it : mTimerCBList)
+ std::lock_guard<std::mutex> lockf(m_mutex);
+ bool ret = false;
+ for(auto it: mTimerCBList)
{
if(it.second.m_id == timerID)
{
- mTimerCBList.erase(it.first);
- timerIDList.remove(it.second.m_id);
+ if(mTimerCBList.erase(it.first)!=0)
+ ret = true;
+ else
+ ret = false;
}
}
+ return ret;
}
-void ExpiryTimer_Impl::registerCBTimer(long long countSEC, TimerCB _cb, TimerID id)
+void ExpiryTimer_Impl::insertTimerCBInfo(ExpiredTime msec, TimerCb cb, Id timerID)
{
- timerCBInfo newInfo = {id, _cb};
- mTimerCBList.insert(multimap<long long, ExpiryTimer_Impl::timerCBInfo>::value_type(countSEC, newInfo));
+ std::lock_guard<std::mutex> lockf(m_mutex);
+ TimerCBInfo newInfo = {timerID, cb};
+ mTimerCBList.insert(std::multimap<ExpiredTime, TimerCBInfo>::value_type(msec, newInfo));
+ m_cond.notify_all();
+}
- if (checkThreadRun == false)
- {
- initThCheck();
- }
+ExpiryTimer_Impl::ExpiredTime ExpiryTimer_Impl::countExpireTime(milliDelayTime msec)
+{
+ auto now = std::chrono::system_clock::now();
+ milliSeconds ret = std::chrono::duration_cast<milliSeconds>(now.time_since_epoch()) + msec;
+
+ return ret;
}
-void ExpiryTimer_Impl::checkTimeOut()
+ExpiryTimer_Impl::Id ExpiryTimer_Impl::generateID()
{
- while (1)
- {
- if(mTimerCBList.empty())
- {
- checkThreadRun = false;
- break;
- }
- else
+ srand(time(NULL));
+ Id retID = rand();
+
+ for(std::multimap<ExpiredTime, TimerCBInfo>::iterator it=mTimerCBList.begin(); it!=mTimerCBList.end(); ++it)
+ {
+ if((*it).second.m_id == retID || retID == 0)
{
- long long curSEC = getSeconds(0);
- long long expireTime;
- expireTime = mTimerCBList.begin()->first;
-
- if(curSEC >= expireTime)
- {
- initThExecutor(mTimerCBList.begin()->second);
- mTimerCBList.erase(mTimerCBList.begin());
- }
+ retID = rand();
+ it = mTimerCBList.begin();
}
- usleep(SLEEP_TIME);
- }
+ }
+ return retID;
}
-void* ExpiryTimer_Impl::threadChecker(void * msg)
+void ExpiryTimer_Impl::createChecker()
{
- if(s_instance != nullptr)
- s_instance->checkTimeOut();
- return NULL;
+ check = std::thread(&ExpiryTimer_Impl::doChecker, this);
}
-void ExpiryTimer_Impl::initThCheck()
+void ExpiryTimer_Impl::doChecker()
{
- int retThreadCreation;
-
- retThreadCreation = pthread_create(&checker_th, NULL, s_instance->threadChecker, NULL);
- if (retThreadCreation != 0)
- {
- return;
- }
- else
+ while(true)
{
- checkThreadRun = true;
- }
-}
+ std::unique_lock<std::mutex> ul(cond_mutex);
-void *ExpiryTimer_Impl::threadExecutor(void * msg)
-{
- TimerCB cb;
- timerCBInfo *curCBInfo;
- curCBInfo= (timerCBInfo *) msg;
+ if(mTimerCBList.empty())
+ {
+ m_cond.wait_for(ul, std::chrono::seconds(CHECKER_WAIT_TIME));
+ }
+ else
+ {
+ ExpiredTime expireTime;
+ expireTime = mTimerCBList.begin()->first;
- cb = curCBInfo->m_pCB;
- cb(curCBInfo->m_id);
+ auto now = std::chrono::system_clock::now();
+ milliSeconds waitTime = expireTime - std::chrono::duration_cast<milliSeconds>(now.time_since_epoch());
+ m_cond.wait_for(ul, waitTime);
- return NULL;
+ auto callTime = std::chrono::system_clock::now();
+ doExecutor(std::chrono::duration_cast<milliSeconds>(callTime.time_since_epoch()));
+ }
+ }
}
-void ExpiryTimer_Impl::initThExecutor(timerCBInfo cbInfo)
+void ExpiryTimer_Impl::doExecutor(ExpiredTime expireTime)
{
-
- int retThreadCreation;
- int status;
- pthread_t executor_th;
-
- retThreadCreation = pthread_create(&executor_th, NULL, ExpiryTimer_Impl::threadExecutor, (void *)&cbInfo);
- threadNum++;
-
- if (retThreadCreation != 0)
+ for(auto it: mTimerCBList)
{
- return;
- }
- else
- {
- pthread_join(executor_th, (void **)&status);
- pthread_detach(executor_th);
- threadNum--;
+ if(it.first <= expireTime)
+ {
+ new ExecutorThread(it.second);
+ mTimerCBList.erase(mTimerCBList.begin());
+ }
+ else
+ break;
}
}
-TimerID ExpiryTimer_Impl::generateTimerID()
+// ExecuterThread Class
+ExpiryTimer_Impl::ExecutorThread::ExecutorThread(TimerCBInfo cbInfo)
{
- srand(time(NULL));
- unsigned int retID = rand();
-
- for(auto it : timerIDList)
- {
- if(it == retID || retID == 0)
- {
- retID = rand();
- it = s_instance->timerIDList.front();
- }
- }
- timerIDList.push_back(retID);
+ execute = std::thread(&ExpiryTimer_Impl::ExecutorThread::executorFunc, this, cbInfo);
+}
- return retID;
+ExpiryTimer_Impl::ExecutorThread::~ExecutorThread()
+{
+ execute.detach();
}
-long long ExpiryTimer_Impl::getSeconds(long long sec)
+void ExpiryTimer_Impl::ExecutorThread::executorFunc(TimerCBInfo cbInfo)
{
- time_t curSEC;
- time(&curSEC);
- long long retSEC = curSEC + sec;
- return retSEC;
+ cbInfo.m_cb(cbInfo.m_id);
}
#ifndef _EXPIRY_TIMER_Impl_H_
#define _EXPIRY_TIMER_Impl_H_
-#include <mutex>
-#include <pthread.h>
+// CHECKER_WAIT_TIME : checker thread waits new request for 10000 seconds
+#define CHECKER_WAIT_TIME 10000
+
+#include <iostream>
#include <functional>
-#include <list>
#include <map>
-#include <iostream>
-#include <new>
-
-#define EXPIRY_THREAD_LIST 50
-#define OVERFLOW_THREAD_NUM -1
-// Current checker thread design have to get checking interval.
-// SLEEP_TIME value will be removed later.
-#define SLEEP_TIME 50000
-
-using namespace std;
-
-typedef unsigned int TimerID;
-typedef function<void*(TimerID)> TimerCB;
+#include <mutex>
+#include <thread>
+#include <chrono>
+#include <condition_variable>
class ExpiryTimer_Impl
{
+public:
+ typedef unsigned int Id;
+ typedef std::function<void*(Id)> TimerCb;
+
+ typedef long long DelayMilliSec;
+ typedef std::chrono::milliseconds milliSeconds;
+ typedef std::chrono::duration<int64_t, std::milli> milliDelayTime;
+ typedef std::chrono::duration<int64_t, std::milli> ExpiredTime;
+
private:
- struct timerCBInfo
+ struct TimerCBInfo
{
- TimerID m_id;
- TimerCB m_pCB;
+ Id m_id;
+ TimerCb m_cb;
};
- ExpiryTimer_Impl();
- ExpiryTimer_Impl(const ExpiryTimer_Impl & other);
- ~ExpiryTimer_Impl();
-
public:
-
- static ExpiryTimer_Impl * getInstance();
-
- TimerID requestTimer(long long sec, TimerCB);
- void cancelTimer(TimerID timerID);
+ ~ExpiryTimer_Impl();
private:
+ ExpiryTimer_Impl();
+
+public:
+ static ExpiryTimer_Impl* getInstance();
- static void killTimer();
- static void *threadExecutor(void * msg);
- static void *threadChecker(void * msg);
+ Id postTimer(DelayMilliSec, TimerCb);
+ bool cancelTimer(Id);
- void registerCBTimer(long long countSEC, TimerCB _cb, TimerID id);
- void initThCheck();
- void initThExecutor(timerCBInfo cbInfo);
- void checkTimeOut();
+private:
+ Id generateID();
- TimerID generateTimerID();
- long long getSeconds(long long sec);
+ void insertTimerCBInfo(ExpiredTime, TimerCb ,Id);
+ ExpiredTime countExpireTime(milliSeconds);
-public:
+ void createChecker();
+ void doChecker();
- list<TimerID> timerIDList;
+ void doExecutor(ExpiredTime);
private:
+ static ExpiryTimer_Impl* s_instance;
+ static std::once_flag mflag;
- static ExpiryTimer_Impl * s_instance;
- static mutex s_mutexForCreation;
- static bool isDestroyed;
+ std::multimap<ExpiredTime, TimerCBInfo> mTimerCBList;
- multimap<long long, timerCBInfo> mTimerCBList;
- bool checkThreadRun;
- list<int> mExecutorIndexList;
- int threadNum;
+ std::thread check;
+ std::mutex m_mutex;
+ std::mutex cond_mutex;
+ std::condition_variable m_cond;
- pthread_t checker_th;
- pthread_mutex_t checker_mutex;
+public:
+ class ExecutorThread
+ {
+ public:
+ ExecutorThread(TimerCBInfo);
+ ~ExecutorThread();
+
+ public:
+ void executorFunc(TimerCBInfo);
+
+ private:
+ std::thread execute;
+ };
};
+
#endif //_EXPIRY_TIMER_Impl_H_