/************************************************************************ * * 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 #include #include #include #include #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 lastResetTS; void init(std::shared_ptr 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 isTimerInited_; std::atomic isStoped_; ev_timer timer_; std::shared_ptr 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 CallbackType; typedef std::weak_ptr CallbackWeakType; struct CallbackBase { virtual void run() = 0; }; template struct Callback : public CallbackBase{ Callable cb; Callback(Callable&& f) : cb(std::forward(f)) {} virtual void run() {cb();} }; template void init(ThreadTimerService *tts, std::shared_ptr 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(f), std::forward(args)...)); #else callBackPtr= makeCallback(std::__bind_simple(std::forward(f), std::forward(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 explicit ThreadTimer(ThreadTimerService *tts, double t, TimerType type, Callable&& f, Args&&... args) { init(tts, nullptr, t, type, std::forward(f), std::forward(args)...); } template 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(f), std::forward(args)...); } template explicit ThreadTimer(ThreadTimerService *tts, std::shared_ptr 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(f), std::forward(args)...); } template explicit ThreadTimer(ThreadTimerService *tts, std::shared_ptr 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(f), std::forward(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& 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 std::shared_ptr> makeCallback(Callable&& f) { // Create and allocate full data structure, not base. return std::make_shared>(std::forward(f)); } protected: ThreadTimerService *service_; std::shared_ptr srv_; double time_; TimerType type_; ev_timer timer_; double stageExtraTime_; std::atomic currentStage_; uint64_t randWeight_; }; };/* end of namespace alisql */ #endif //#ifndef thread_timer_INC