blob: 2055598d047e18b9cff1b6814d50d8e342037214 [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
62 // Task is associated with Schedulers due to the requirement that libevent event is associated with an libevent event_base
Zhenkai Zhu66dc5a92013-01-08 21:41:15 -080063 Task(const Callback &callback, const Tag &tag, const SchedulerPtr &scheduler);
64 virtual ~Task();
Zhenkai Zhu97019eb2013-01-08 00:21:43 -080065
66 virtual void
Zhenkai Zhu66dc5a92013-01-08 21:41:15 -080067 run() = 0;
Zhenkai Zhu97019eb2013-01-08 00:21:43 -080068
69 Tag
70 tag() { return m_tag; }
71
Zhenkai Zhubc2f6282013-01-08 16:40:58 -080072 event *
73 ev() { return m_event; }
74
75 timeval *
76 tv() { return m_tv; }
77
Zhenkai Zhu66dc5a92013-01-08 21:41:15 -080078 // Task needs to be resetted after the callback is invoked if it is to be schedule again; just for safety
79 // it's called by scheduler automatically when addTask or rescheduleTask is called;
80 // Tasks should do preparation work here (e.g. set up new delay, etc. )
81 virtual void
82 reset() = 0;
83
84 // set delay
85 // This overrides whatever delay kept in m_tv
Zhenkai Zhubc2f6282013-01-08 16:40:58 -080086 void
87 setTv(double delay);
88
Zhenkai Zhu97019eb2013-01-08 00:21:43 -080089protected:
90 Callback m_callback;
91 Tag m_tag;
Zhenkai Zhubc2f6282013-01-08 16:40:58 -080092 SchedulerPtr m_scheduler;
93 bool m_invoked;
94 event *m_event;
95 timeval *m_tv;
Zhenkai Zhu97019eb2013-01-08 00:21:43 -080096};
97
Zhenkai Zhu66dc5a92013-01-08 21:41:15 -080098class OneTimeTask : public Task
99{
100public:
101 OneTimeTask(const Callback &callback, const Tag &tag, const SchedulerPtr &scheduler, double delay);
102 virtual ~OneTimeTask(){}
103
104 // invoke callback and mark self as invoked and deregister self from scheduler
105 virtual void
106 run() _OVERRIDE;
107
108 // after reset, the task is marked as un-invoked and can be add to scheduler again, with same delay
109 // if not invoked yet, no effect
110 virtual void
111 reset() _OVERRIDE;
112
113private:
114 // this is to deregister itself from scheduler automatically after invoke
115 void
116 deregisterSelf();
117};
118
119class PeriodicTask : public Task
120{
121public:
122 // generator is needed only when this is a periodic task
123 // two simple generators implementation (SimpleIntervalGenerator and RandomIntervalGenerator) are provided;
124 // if user needs more complex pattern in the intervals between calls, extend class IntervalGenerator
125 PeriodicTask(const Callback &callback, const Tag &tag, const SchedulerPtr &scheduler, const IntervalGeneratorPtr &generator);
126 virtual ~PeriodicTask(){}
127
128 // invoke callback, reset self and ask scheduler to schedule self with the next delay interval
129 virtual void
130 run() _OVERRIDE;
131
132 // set the next delay and mark as un-invoke
133 virtual void
134 reset() _OVERRIDE;
135
136private:
137 IntervalGeneratorPtr m_generator;
138};
Zhenkai Zhubc2f6282013-01-08 16:40:58 -0800139
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800140struct SchedulerException : virtual boost::exception, virtual exception { };
141
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800142class Scheduler
143{
144public:
145 Scheduler();
146 virtual ~Scheduler();
147
Zhenkai Zhu4eabef12013-01-08 20:29:52 -0800148 // start event scheduling
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800149 virtual void
150 start();
151
Zhenkai Zhu4eabef12013-01-08 20:29:52 -0800152 // stop event scheduling
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800153 virtual void
154 shutdown();
155
Zhenkai Zhu66dc5a92013-01-08 21:41:15 -0800156 // if task with the same tag exists, the task is not added and return false
Zhenkai Zhubc2f6282013-01-08 16:40:58 -0800157 virtual bool
158 addTask(const TaskPtr &task);
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800159
Zhenkai Zhu4eabef12013-01-08 20:29:52 -0800160 // delete task by tag, regardless of whether it's invoked or not
161 // if no task is found, no effect
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800162 virtual void
Zhenkai Zhubc2f6282013-01-08 16:40:58 -0800163 deleteTask(const Task::Tag &tag);
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800164
Zhenkai Zhu4eabef12013-01-08 20:29:52 -0800165 // delete tasks by matcher, regardless of whether it's invoked or not
166 // this is flexiable in that you can use any form of criteria in finding tasks to delete
167 // but keep in mind this is a linear scan
168
169 // if no task is found, no effect
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800170 virtual void
Zhenkai Zhubc2f6282013-01-08 16:40:58 -0800171 deleteTask(const Task::TaskMatcher &matcher);
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800172
Zhenkai Zhu4eabef12013-01-08 20:29:52 -0800173 // task must already have been added to the scheduler, otherwise this is no effect
Zhenkai Zhu66dc5a92013-01-08 21:41:15 -0800174 // this is usually used by PeriodicTask
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800175 virtual void
Zhenkai Zhubc2f6282013-01-08 16:40:58 -0800176 rescheduleTask(const Task::Tag &tag);
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800177
Zhenkai Zhubc2f6282013-01-08 16:40:58 -0800178 void
179 eventLoop();
180
181 event_base *
182 base() { return m_base; }
183
184 // used in test
185 int
186 size();
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800187
188protected:
Zhenkai Zhubc2f6282013-01-08 16:40:58 -0800189 bool
190 addToMap(const TaskPtr &task);
191
192protected:
193 typedef map<Task::Tag, TaskPtr> TaskMap;
194 typedef map<Task::Tag, TaskPtr>::iterator TaskMapIt;
195 typedef boost::shared_mutex Mutex;
196 typedef boost::unique_lock<Mutex> WriteLock;
197 typedef boost::shared_lock<Mutex> ReadLock;
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800198 TaskMap m_taskMap;
Zhenkai Zhubc2f6282013-01-08 16:40:58 -0800199 Mutex m_mutex;
200 event_base *m_base;
201 boost::thread m_thread;
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800202};
203
Zhenkai Zhu4eabef12013-01-08 20:29:52 -0800204
Zhenkai Zhubc2f6282013-01-08 16:40:58 -0800205class SimpleIntervalGenerator : public IntervalGenerator
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800206{
207public:
208 SimpleIntervalGenerator(double interval) : m_interval(interval) {}
209 ~SimpleIntervalGenerator(){}
210 virtual double
211 nextInterval() _OVERRIDE { return m_interval; }
212private:
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800213 double m_interval;
214};
215
Zhenkai Zhu4eabef12013-01-08 20:29:52 -0800216// generates intervals with uniform distribution
Zhenkai Zhubc2f6282013-01-08 16:40:58 -0800217class RandomIntervalGenerator : public IntervalGenerator
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800218{
Zhenkai Zhubc2f6282013-01-08 16:40:58 -0800219public:
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800220 typedef enum
221 {
Zhenkai Zhubc2f6282013-01-08 16:40:58 -0800222 UP = 1,
223 DOWN = 2,
224 EVEN = 3
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800225 } Direction;
226
227public:
Zhenkai Zhu4eabef12013-01-08 20:29:52 -0800228 // percent is random-range/interval; e.g. if interval is 10 and you wish the random-range to be 2
229 // e.g. 9 ~ 11, percent = 0.2
230 // direction shifts the random range; e.g. in the above example, UP would produce a range of
231 // 10 ~ 12, DOWN of 8 ~ 10, and EVEN of 9 ~ 11
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800232 RandomIntervalGenerator(double interval, double percent, Direction direction = EVEN);
233 ~RandomIntervalGenerator(){}
234 virtual double
235 nextInterval() _OVERRIDE;
236
237private:
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800238 inline double fractional(double x) { double dummy; return abs(modf(x, &dummy)); }
239
240private:
241 typedef boost::mt19937 RNG_TYPE;
242 RNG_TYPE m_rng;
243 boost::uniform_real<> m_dist;
Zhenkai Zhubc2f6282013-01-08 16:40:58 -0800244 boost::variate_generator<RNG_TYPE &, boost::uniform_real<> > m_random;
Zhenkai Zhu97019eb2013-01-08 00:21:43 -0800245 Direction m_direction;
246 double m_interval;
247 double m_percent;
248
249};
250#endif // EVENT_SCHEDULER_H