blob: 2a10b678cc32ba75a6710c3155dc1fc54a50028e [file] [log] [blame]
Zhenkai Zhu97019eb2013-01-08 00:21:43 -08001#ifndef EVENT_SCHEDULER_H
2#define EVENT_SCHEDULER_H
Zhenkai Zhubc2f6282013-01-08 16:40:58 -08003
4// use pthread
5
Zhenkai Zhu97019eb2013-01-08 00:21:43 -08006#include <event2/event.h>
Zhenkai Zhu97019eb2013-01-08 00:21:43 -08007#include <event2/thread.h>
8
9#include <boost/function.hpp>
10#include <boost/shared_ptr.hpp>
11#include <boost/random/mersenne_twister.hpp>
12#include <boost/random/uniform_real.hpp>
13#include <boost/random/variate_generator.hpp>
14#include <boost/exception/all.hpp>
Zhenkai Zhubc2f6282013-01-08 16:40:58 -080015#include <boost/thread/shared_mutex.hpp>
16#include <boost/thread/thread.hpp>
Zhenkai Zhu97019eb2013-01-08 00:21:43 -080017#include <math.h>
Zhenkai Zhubc2f6282013-01-08 16:40:58 -080018#include <map>
19#include <sys/time.h>
Zhenkai Zhu97019eb2013-01-08 00:21:43 -080020
21#define _OVERRIDE
22#ifdef __GNUC__
23#if __GNUC_MAJOR >= 4 && __GNUC_MINOR__ >= 7
24 #undef _OVERRIDE
25 #define _OVERRIDE override
26#endif // __GNUC__ version
27#endif // __GNUC__
28
29using namespace std;
30
Zhenkai Zhu4eabef12013-01-08 20:29:52 -080031// callback used by libevent
Zhenkai Zhubc2f6282013-01-08 16:40:58 -080032static void
33eventCallback(evutil_socket_t fd, short what, void *arg);
34
35class Scheduler;
36typedef boost::shared_ptr<Scheduler> SchedulerPtr;
37class IntervalGenerator;
38typedef boost::shared_ptr<IntervalGenerator> IntervalGeneratorPtr;
39class Task;
40typedef boost::shared_ptr<Task> TaskPtr;
41
42class IntervalGenerator
43{
44public:
45 virtual double
46 nextInterval() = 0;
47 static IntervalGeneratorPtr Null;
48};
Zhenkai Zhu97019eb2013-01-08 00:21:43 -080049
Zhenkai Zhu4eabef12013-01-08 20:29:52 -080050
Zhenkai Zhu97019eb2013-01-08 00:21:43 -080051class Task
52{
53public:
Zhenkai Zhu4eabef12013-01-08 20:29:52 -080054 // callback of this task
Zhenkai Zhubc2f6282013-01-08 16:40:58 -080055 typedef boost::function<void ()> Callback;
Zhenkai Zhu4eabef12013-01-08 20:29:52 -080056 // tag identifies this task, should be unique
Zhenkai Zhu97019eb2013-01-08 00:21:43 -080057 typedef string Tag;
Zhenkai Zhu4eabef12013-01-08 20:29:52 -080058 // used to match tasks
Zhenkai Zhubc2f6282013-01-08 16:40:58 -080059 typedef boost::function<bool (const TaskPtr &task)> TaskMatcher;
Zhenkai Zhu97019eb2013-01-08 00:21:43 -080060
Zhenkai Zhu4eabef12013-01-08 20:29:52 -080061 // generator is needed only when this is a periodic task
62 // two simple generators implementation (SimpleIntervalGenerator and RandomIntervalGenerator) are provided;
63 // if user needs more complex pattern in the intervals between calls, extend class IntervalGenerator
64
65 // Task is associated with Schedulers due to the requirement that libevent event is associated with an libevent event_base
Zhenkai Zhubc2f6282013-01-08 16:40:58 -080066 Task(const Callback &callback, const Tag &tag, const SchedulerPtr &scheduler, const IntervalGeneratorPtr &generator = IntervalGenerator::Null);
67 ~Task();
Zhenkai Zhu97019eb2013-01-08 00:21:43 -080068
69 virtual void
Zhenkai Zhubc2f6282013-01-08 16:40:58 -080070 run();
Zhenkai Zhu97019eb2013-01-08 00:21:43 -080071
72 Tag
73 tag() { return m_tag; }
74
Zhenkai Zhubc2f6282013-01-08 16:40:58 -080075 event *
76 ev() { return m_event; }
77
78 timeval *
79 tv() { return m_tv; }
80
81 void
82 setTv(double delay);
83
84 bool
85 isPeriodic() { return m_generator != IntervalGenerator::Null; }
86
Zhenkai Zhu4eabef12013-01-08 20:29:52 -080087 // Task needs to be resetted after the callback is invoked if it is to be schedule again; just for safety
Zhenkai Zhubc2f6282013-01-08 16:40:58 -080088 void
89 reset();
90
91protected:
92 void
93 selfClean();
Zhenkai Zhu97019eb2013-01-08 00:21:43 -080094
95protected:
96 Callback m_callback;
97 Tag m_tag;
Zhenkai Zhubc2f6282013-01-08 16:40:58 -080098 SchedulerPtr m_scheduler;
99 bool m_invoked;
100 event *m_event;
101 timeval *m_tv;
102 IntervalGeneratorPtr m_generator;
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800103};
104
Zhenkai Zhubc2f6282013-01-08 16:40:58 -0800105
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800106struct SchedulerException : virtual boost::exception, virtual exception { };
107
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800108class Scheduler
109{
110public:
111 Scheduler();
112 virtual ~Scheduler();
113
Zhenkai Zhu4eabef12013-01-08 20:29:52 -0800114 // start event scheduling
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800115 virtual void
116 start();
117
Zhenkai Zhu4eabef12013-01-08 20:29:52 -0800118 // stop event scheduling
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800119 virtual void
120 shutdown();
121
Zhenkai Zhu4eabef12013-01-08 20:29:52 -0800122 // add a one time task, delay is in seconds
123 // if task with the same tag exists, return false
Zhenkai Zhubc2f6282013-01-08 16:40:58 -0800124 virtual bool
125 addTask(const TaskPtr &task, double delay);
126
Zhenkai Zhu4eabef12013-01-08 20:29:52 -0800127 // add periodic task; task must have an interval generator
128 // if task with the same tag exists, return false
Zhenkai Zhubc2f6282013-01-08 16:40:58 -0800129 virtual bool
130 addTask(const TaskPtr &task);
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800131
Zhenkai Zhu4eabef12013-01-08 20:29:52 -0800132 // delete task by tag, regardless of whether it's invoked or not
133 // if no task is found, no effect
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800134 virtual void
Zhenkai Zhubc2f6282013-01-08 16:40:58 -0800135 deleteTask(const Task::Tag &tag);
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800136
Zhenkai Zhu4eabef12013-01-08 20:29:52 -0800137 // delete tasks by matcher, regardless of whether it's invoked or not
138 // this is flexiable in that you can use any form of criteria in finding tasks to delete
139 // but keep in mind this is a linear scan
140
141 // if no task is found, no effect
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800142 virtual void
Zhenkai Zhubc2f6282013-01-08 16:40:58 -0800143 deleteTask(const Task::TaskMatcher &matcher);
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800144
Zhenkai Zhu4eabef12013-01-08 20:29:52 -0800145 // for periodic tasks, reschedule the next invoke
146 // task must already have been added to the scheduler, otherwise this is no effect
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800147 virtual void
Zhenkai Zhubc2f6282013-01-08 16:40:58 -0800148 rescheduleTask(const Task::Tag &tag);
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800149
Zhenkai Zhubc2f6282013-01-08 16:40:58 -0800150 void
151 eventLoop();
152
153 event_base *
154 base() { return m_base; }
155
156 // used in test
157 int
158 size();
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800159
160protected:
Zhenkai Zhubc2f6282013-01-08 16:40:58 -0800161 bool
162 addToMap(const TaskPtr &task);
163
164protected:
165 typedef map<Task::Tag, TaskPtr> TaskMap;
166 typedef map<Task::Tag, TaskPtr>::iterator TaskMapIt;
167 typedef boost::shared_mutex Mutex;
168 typedef boost::unique_lock<Mutex> WriteLock;
169 typedef boost::shared_lock<Mutex> ReadLock;
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800170 TaskMap m_taskMap;
Zhenkai Zhubc2f6282013-01-08 16:40:58 -0800171 Mutex m_mutex;
172 event_base *m_base;
173 boost::thread m_thread;
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800174};
175
Zhenkai Zhu4eabef12013-01-08 20:29:52 -0800176
Zhenkai Zhubc2f6282013-01-08 16:40:58 -0800177class SimpleIntervalGenerator : public IntervalGenerator
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800178{
179public:
180 SimpleIntervalGenerator(double interval) : m_interval(interval) {}
181 ~SimpleIntervalGenerator(){}
182 virtual double
183 nextInterval() _OVERRIDE { return m_interval; }
184private:
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800185 double m_interval;
186};
187
Zhenkai Zhu4eabef12013-01-08 20:29:52 -0800188// generates intervals with uniform distribution
Zhenkai Zhubc2f6282013-01-08 16:40:58 -0800189class RandomIntervalGenerator : public IntervalGenerator
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800190{
Zhenkai Zhubc2f6282013-01-08 16:40:58 -0800191public:
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800192 typedef enum
193 {
Zhenkai Zhubc2f6282013-01-08 16:40:58 -0800194 UP = 1,
195 DOWN = 2,
196 EVEN = 3
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800197 } Direction;
198
199public:
Zhenkai Zhu4eabef12013-01-08 20:29:52 -0800200 // percent is random-range/interval; e.g. if interval is 10 and you wish the random-range to be 2
201 // e.g. 9 ~ 11, percent = 0.2
202 // direction shifts the random range; e.g. in the above example, UP would produce a range of
203 // 10 ~ 12, DOWN of 8 ~ 10, and EVEN of 9 ~ 11
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800204 RandomIntervalGenerator(double interval, double percent, Direction direction = EVEN);
205 ~RandomIntervalGenerator(){}
206 virtual double
207 nextInterval() _OVERRIDE;
208
209private:
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800210 inline double fractional(double x) { double dummy; return abs(modf(x, &dummy)); }
211
212private:
213 typedef boost::mt19937 RNG_TYPE;
214 RNG_TYPE m_rng;
215 boost::uniform_real<> m_dist;
Zhenkai Zhubc2f6282013-01-08 16:40:58 -0800216 boost::variate_generator<RNG_TYPE &, boost::uniform_real<> > m_random;
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800217 Direction m_direction;
218 double m_interval;
219 double m_percent;
220
221};
222#endif // EVENT_SCHEDULER_H