polardbxengine/extra/IS/consensus/include/thread_timer.h

224 lines
6.7 KiB
C++

/************************************************************************
*
* Copyright (c) 2016 Alibaba.com, Inc. All Rights Reserved
* $Id: thread_timer.h,v 1.0 11/22/2016 03:05:36 PM yingqiang.zyq(yingqiang.zyq@alibaba-inc.com) $
*
************************************************************************/
/**
* @file thread_timer.h
* @author yingqiang.zyq(yingqiang.zyq@alibaba-inc.com)
* @date 11/22/2016 03:05:36 PM
* @version 1.0
* @brief
*
**/
#ifndef thread_timer_INC
#define thread_timer_INC
#include <assert.h>
#include <atomic>
#include <mutex>
#include <thread>
#include <functional>
#include "ev.h"
//#include "easyNet.h"
//#include "service.h"
namespace alisql {
class Service;
/* ThreadTimerService based on ev_timer, for thread safe, dynamic create */
typedef void (*TimerCallback)(void *);
class ThreadTimerService {
public:
class LoopData {
public:
LoopData() :shutdown(false) {
ev_async_init(&asyncWatcher, ThreadTimerService::loopAsync);
}
std::recursive_mutex lock;
ev_async asyncWatcher;
bool shutdown;
};
ThreadTimerService();
virtual ~ThreadTimerService();
/*
void *timeoutData;
TimerCallback timerCallback;
double timeoutVal;
std::atomic<double> lastResetTS;
void init(std::shared_ptr<Service> srv, TimerCallback cb, void *ptr) {
srv_= srv;timerCallback= cb;timeoutData= ptr;
}
int start(uint64_t timeout, bool needRandom= false);
int setTimeout(uint64_t timeout, bool needRandom= false);
int resetTimer(bool isStop= false);
static void timerCallbackInternal(struct ev_loop *loop, ev_timer *w, int revents);
*/
struct ev_loop *getEvLoop() {return loop_;}
void ldlock() {ld_->lock.lock();}
void ldunlock() {ld_->lock.unlock();}
/* Should under ldlock */
void wakeup() {ev_async_send(loop_, &ld_->asyncWatcher);}
//void startService();
//void stopService();
static void mainService(EV_P);
static void loopRelease(EV_P);
static void loopAcquire(EV_P);
static void loopAsync(EV_P, ev_async *w, int revents);
protected:
/*
std::atomic<uint64_t> isTimerInited_;
std::atomic<uint64_t> isStoped_;
ev_timer timer_;
std::shared_ptr<Service> srv_;
//easy_baseth_t *thread_;
*/
std::mutex lock_;
struct ev_loop *loop_;
LoopData *ld_;
std::thread *thread_;
};
class ThreadTimer {
public:
typedef enum State {
Repeatable= 1,
Oneshot= 2,
/* Stage Timer always repeatable, and have two stages. */
Stage= 3,
} TimerType;
struct CallbackBase;
typedef std::shared_ptr<CallbackBase> CallbackType;
typedef std::weak_ptr<CallbackBase> CallbackWeakType;
struct CallbackBase {
virtual void run() = 0;
};
template<typename Callable>
struct Callback : public CallbackBase{
Callable cb;
Callback(Callable&& f) : cb(std::forward<Callable>(f)) {}
virtual void run() {cb();}
};
template<typename Callable, typename... Args>
void init(ThreadTimerService *tts, std::shared_ptr<Service> srv, double t, TimerType type, Callable&& f, Args&&... args)
{
service_ =tts;
srv_= srv;
time_= t;
type_= type;
randWeight_= 0;
#if (__GNUC__ >= 7)
callBackPtr= makeCallback(std::bind(std::forward<Callable>(f), std::forward<Args>(args)...));
#else
callBackPtr= makeCallback(std::__bind_simple(std::forward<Callable>(f), std::forward<Args>(args)...));
#endif
if (type_ == Oneshot)
{
ev_timer_init(&timer_, timerCallbackInternal, t, 0.0);
timer_.data= this;
start();
}
else
{
ev_timer_init(&timer_, timerCallbackInternal, t, t);
timer_.data= this;
}
}
template<typename Callable, typename... Args>
explicit
ThreadTimer(ThreadTimerService *tts, double t, TimerType type, Callable&& f, Args&&... args)
{
init(tts, nullptr, t, type, std::forward<Callable>(f), std::forward<Args>(args)...);
}
template<typename Callable, typename... Args>
explicit
ThreadTimer(ThreadTimerService *tts, const uint64_t t, TimerType type, Callable&& f, Args&&... args)
{
double ft= (double)t;
ft /= 1000;
init(tts, nullptr, ft, type, std::forward<Callable>(f), std::forward<Args>(args)...);
}
template<typename Callable, typename... Args>
explicit
ThreadTimer(ThreadTimerService *tts, std::shared_ptr<Service> srv, double t, TimerType type, Callable&& f, Args&&... args)
:service_(tts)
,srv_(srv)
,time_(t)
,type_(type)
,randWeight_(0)
{
init(tts, srv, t, type, std::forward<Callable>(f), std::forward<Args>(args)...);
}
template<typename Callable, typename... Args>
explicit
ThreadTimer(ThreadTimerService *tts, std::shared_ptr<Service> srv, const uint64_t t, TimerType type, Callable&& f, Args&&... args)
:service_(tts)
,srv_(srv)
,type_(type)
,randWeight_(0)
{
double ft= (double)t;
ft /= 1000;
init(tts, srv, ft, type, std::forward<Callable>(f), std::forward<Args>(args)...);
}
virtual ~ThreadTimer();
void start();
void restart(double t);
void restart();
void restart(uint64_t t, bool needRandom);
void stop();
TimerType getType() {return type_;}
double getTime() {return time_;}
double getStageExtraTime() {return stageExtraTime_;}
void setStageExtraTime(double baseTime);
void setRandWeight(uint64_t w) {randWeight_= w % 10;};
uint64_t getCurrentStage() {return currentStage_.load();};
uint64_t getAndSetStage();
std::shared_ptr<Service>& getService() {return srv_;}
/* we use callBackPtr as arg to avoid CallbackType destruct. */
static void callbackRunWeak(CallbackWeakType callBackPtr);
static void callbackRun(CallbackType callBackPtr);
//static void callbackRun(CallbackType callBackPtr) {assert(callBackPtr != nullptr);callBackPtr->run();}
static void timerCallbackInternal(struct ev_loop *loop, ev_timer *w, int revents);
CallbackType callBackPtr;
template<typename Callable>
std::shared_ptr<Callback<Callable>>
makeCallback(Callable&& f)
{
// Create and allocate full data structure, not base.
return std::make_shared<Callback<Callable>>(std::forward<Callable>(f));
}
protected:
ThreadTimerService *service_;
std::shared_ptr<Service> srv_;
double time_;
TimerType type_;
ev_timer timer_;
double stageExtraTime_;
std::atomic<uint64_t> currentStage_;
uint64_t randWeight_;
};
};/* end of namespace alisql */
#endif //#ifndef thread_timer_INC