forked from cawka/ndn.cxx
diff --git a/scheduler/interval-generator.h b/scheduler/interval-generator.h
new file mode 100644
index 0000000..e480ecc
--- /dev/null
+++ b/scheduler/interval-generator.h
@@ -0,0 +1,33 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef INTERVAL_GENERATOR_H
+#define INTERVAL_GENERATOR_H
+
+#include <boost/shared_ptr.hpp>
+
+using namespace std;
+
+class IntervalGenerator;
+typedef boost::shared_ptr<IntervalGenerator> IntervalGeneratorPtr;
+
+class IntervalGenerator
+{
+public:
+ virtual ~IntervalGenerator () { }
+
+ virtual double
+ nextInterval() = 0;
+};
+
+
+#endif // INTERVAL_GENERATOR_H
diff --git a/scheduler/one-time-task.cc b/scheduler/one-time-task.cc
new file mode 100644
index 0000000..b3082af
--- /dev/null
+++ b/scheduler/one-time-task.cc
@@ -0,0 +1,43 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "one-time-task.h"
+#include "scheduler.h"
+
+OneTimeTask::OneTimeTask(const Callback &callback, const Tag &tag, const SchedulerPtr &scheduler, double delay)
+ : Task(callback, tag, scheduler)
+{
+ setTv(delay);
+}
+
+void
+OneTimeTask::run()
+{
+ if (!m_invoked)
+ {
+ m_callback();
+ m_invoked = true;
+ deregisterSelf();
+ }
+}
+
+void
+OneTimeTask::deregisterSelf()
+{
+ m_scheduler->deleteTask(m_tag);
+}
+
+void
+OneTimeTask::reset()
+{
+ m_invoked = false;
+}
diff --git a/scheduler/one-time-task.h b/scheduler/one-time-task.h
new file mode 100644
index 0000000..744ca90
--- /dev/null
+++ b/scheduler/one-time-task.h
@@ -0,0 +1,40 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef ONE_TIME_TASK_H
+#define ONE_TIME_TASK_H
+
+#include "task.h"
+
+class OneTimeTask : public Task
+{
+public:
+ OneTimeTask(const Callback &callback, const Tag &tag, const SchedulerPtr &scheduler, double delay);
+ virtual ~OneTimeTask(){}
+
+ // invoke callback and mark self as invoked and deregister self from scheduler
+ virtual void
+ run() _OVERRIDE;
+
+ // after reset, the task is marked as un-invoked and can be add to scheduler again, with same delay
+ // if not invoked yet, no effect
+ virtual void
+ reset() _OVERRIDE;
+
+private:
+ // this is to deregister itself from scheduler automatically after invoke
+ void
+ deregisterSelf();
+};
+
+
+#endif // EVENT_SCHEDULER_H
diff --git a/scheduler/periodic-task.cc b/scheduler/periodic-task.cc
new file mode 100644
index 0000000..110c4df
--- /dev/null
+++ b/scheduler/periodic-task.cc
@@ -0,0 +1,48 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "periodic-task.h"
+#include "logging.h"
+#include <utility>
+
+INIT_LOGGER ("Scheduler.PeriodicTask");
+
+PeriodicTask::PeriodicTask(const Callback &callback, const Tag &tag, const SchedulerPtr &scheduler,
+ IntervalGeneratorPtr generator)
+ : Task(callback, tag, scheduler)
+ , m_generator(generator)
+{
+}
+
+void
+PeriodicTask::run()
+{
+ if (!m_invoked)
+ {
+ m_invoked = true;
+ m_callback();
+
+ if (m_invoked)
+ {
+ // m_invoked getting back if it is rescheduled inside the callback
+ m_scheduler->rescheduleTask(m_tag);
+ }
+ }
+}
+
+void
+PeriodicTask::reset()
+{
+ m_invoked = false;
+ double interval = m_generator->nextInterval();
+ setTv(interval);
+}
diff --git a/scheduler/periodic-task.h b/scheduler/periodic-task.h
new file mode 100644
index 0000000..303dca4
--- /dev/null
+++ b/scheduler/periodic-task.h
@@ -0,0 +1,41 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef PERIODIC_TASK_H
+#define PERIODIC_TASK_H
+
+#include "task.h"
+#include "scheduler.h"
+#include "interval-generator.h"
+
+class PeriodicTask : public Task
+{
+public:
+ // generator is needed only when this is a periodic task
+ // two simple generators implementation (SimpleIntervalGenerator and RandomIntervalGenerator) are provided;
+ // if user needs more complex pattern in the intervals between calls, extend class IntervalGenerator
+ PeriodicTask(const Callback &callback, const Tag &tag, const SchedulerPtr &scheduler, IntervalGeneratorPtr generator);
+ virtual ~PeriodicTask(){}
+
+ // invoke callback, reset self and ask scheduler to schedule self with the next delay interval
+ virtual void
+ run() _OVERRIDE;
+
+ // set the next delay and mark as un-invoke
+ virtual void
+ reset() _OVERRIDE;
+
+private:
+ IntervalGeneratorPtr m_generator;
+};
+
+#endif // PERIODIC_TASK_H
diff --git a/scheduler/random-interval-generator.h b/scheduler/random-interval-generator.h
new file mode 100644
index 0000000..476578c
--- /dev/null
+++ b/scheduler/random-interval-generator.h
@@ -0,0 +1,80 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef RANDOM_INTERVAL_GENERATOR_H
+#define RANDOM_INTERVAL_GENERATOR_H
+
+#include "interval-generator.h"
+
+#include <boost/random/mersenne_twister.hpp>
+#include <boost/random/uniform_real.hpp>
+#include <boost/random/variate_generator.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+// generates intervals with uniform distribution
+class RandomIntervalGenerator : public IntervalGenerator
+{
+public:
+ typedef enum
+ {
+ UP = 1,
+ DOWN = 2,
+ EVEN = 3
+ } Direction;
+
+public:
+ // percent is random-range/interval; e.g. if interval is 10 and you wish the random-range to be 2
+ // e.g. 9 ~ 11, percent = 0.2
+ // direction shifts the random range; e.g. in the above example, UP would produce a range of
+ // 10 ~ 12, DOWN of 8 ~ 10, and EVEN of 9 ~ 11
+ RandomIntervalGenerator(double interval, double percent, Direction direction = EVEN)
+ // : m_rng(time(NULL))
+ : m_rng (static_cast<int> (boost::posix_time::microsec_clock::local_time().time_of_day ().total_nanoseconds ()))
+ , m_dist(0.0, fractional(percent))
+ , m_random(m_rng, m_dist)
+ , m_direction(direction)
+ , m_percent(percent)
+ , m_interval(interval)
+ { }
+
+ virtual ~RandomIntervalGenerator(){}
+
+ virtual double
+ nextInterval() _OVERRIDE
+ {
+ double percent = m_random();
+ double interval = m_interval;
+ switch (m_direction)
+ {
+ case UP: interval = m_interval * (1.0 + percent); break;
+ case DOWN: interval = m_interval * (1.0 - percent); break;
+ case EVEN: interval = m_interval * (1.0 - m_percent/2.0 + percent); break;
+ default: break;
+ }
+
+ return interval;
+ }
+
+private:
+ inline double fractional(double x) { double dummy; return abs(modf(x, &dummy)); }
+
+private:
+ typedef boost::mt19937 RNG_TYPE;
+ RNG_TYPE m_rng;
+ boost::uniform_real<> m_dist;
+ boost::variate_generator<RNG_TYPE &, boost::uniform_real<> > m_random;
+ Direction m_direction;
+ double m_percent;
+ double m_interval;
+
+};
+#endif // RANDOM_INTERVAL_GENERATOR_H
diff --git a/scheduler/scheduler-all.h b/scheduler/scheduler-all.h
new file mode 100644
index 0000000..388a74c
--- /dev/null
+++ b/scheduler/scheduler-all.h
@@ -0,0 +1,24 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef SCHEDULE_ALL_H
+#define SCHEDULE_ALL_H
+
+#include "scheduler/interval-generator.h"
+#include "scheduler/one-time-task.h"
+#include "scheduler/periodic-task.h"
+#include "scheduler/random-interval-generator.h"
+#include "scheduler/scheduler.h"
+#include "scheduler/simple-interval-generator.h"
+#include "scheduler/task.h"
+
+#endif
diff --git a/scheduler/scheduler.cc b/scheduler/scheduler.cc
new file mode 100644
index 0000000..02ac0c0
--- /dev/null
+++ b/scheduler/scheduler.cc
@@ -0,0 +1,338 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "scheduler.h"
+#include "one-time-task.h"
+#include "periodic-task.h"
+#include "logging.h"
+
+#include <utility>
+#include <boost/make_shared.hpp>
+
+INIT_LOGGER ("Scheduler");
+
+using namespace std;
+using namespace boost;
+
+#define EVLOOP_NO_EXIT_ON_EMPTY 0x04
+
+static void
+dummyCallback(evutil_socket_t fd, short what, void *arg)
+{
+ // 1 year later, that was a long run for the app
+ // let's wait for another year
+ timeval tv;
+ tv.tv_sec = 365 * 24 * 3600;
+ tv.tv_usec = 0;
+ event *ev = *(event **)arg;
+ int res = evtimer_add(ev, &tv);
+}
+
+// IntervalGeneratorPtr
+// IntervalGenerator:: Null;
+
+void errorCallback(int err)
+{
+ _LOG_ERROR ("Fatal error: " << err);
+}
+
+Scheduler::Scheduler()
+ : m_running(false)
+ , m_executor(1)
+{
+ event_set_fatal_callback(errorCallback);
+ evthread_use_pthreads();
+ m_base = event_base_new();
+
+ // This is a hack to prevent event_base_loop from exiting;
+ // the flag EVLOOP_NO_EXIT_ON_EMPTY is somehow ignored, at least on Mac OS X
+ // it's going to be scheduled to 10 years later
+ timeval tv;
+ tv.tv_sec = 365 * 24 * 3600;
+ tv.tv_usec = 0;
+ m_ev = evtimer_new(m_base, dummyCallback, &m_ev);
+ int res = evtimer_add(m_ev, &tv);
+ if (res < 0)
+ {
+ _LOG_ERROR("heck");
+ }
+}
+
+Scheduler::~Scheduler()
+{
+ shutdown ();
+ evtimer_del(m_ev);
+ event_free(m_ev);
+ event_base_free(m_base);
+}
+
+void
+Scheduler::eventLoop()
+{
+ while(true)
+ {
+ if (event_base_loop(m_base, EVLOOP_NO_EXIT_ON_EMPTY) < 0)
+ {
+ _LOG_DEBUG ("scheduler loop break error");
+ }
+ else
+ {
+ _LOG_DEBUG ("scheduler loop break normal");
+ }
+
+ {
+ ScopedLock lock(m_mutex);
+ if (!m_running)
+ {
+ _LOG_DEBUG ("scheduler loop break normal");
+ break;
+ }
+ }
+
+ // just to prevent craziness in CPU usage which supposedly should not happen
+ // after adding the dummy event
+ usleep(1000);
+ }
+}
+
+void
+Scheduler::execute(Executor::Job job)
+{
+ m_executor.execute(job);
+}
+
+void
+Scheduler::start()
+{
+ ScopedLock lock(m_mutex);
+ if (!m_running)
+ {
+ m_thread = boost::thread(&Scheduler::eventLoop, this);
+ m_executor.start();
+ m_running = true;
+ }
+}
+
+void
+Scheduler::shutdown()
+{
+ bool breakAndWait = false;
+ {
+ ScopedLock lock (m_mutex);
+ if (m_running)
+ {
+ m_running = false;
+ breakAndWait = true;
+ }
+ }
+
+ if (breakAndWait)
+ {
+ event_base_loopbreak(m_base);
+ m_executor.shutdown();
+ m_thread.join();
+ }
+}
+
+TaskPtr
+Scheduler::scheduleOneTimeTask (SchedulerPtr scheduler, double delay,
+ const Task::Callback &callback, const Task::Tag &tag)
+{
+ TaskPtr task = make_shared<OneTimeTask> (callback, tag, scheduler, delay);
+ if (scheduler->addTask (task))
+ return task;
+ else
+ return TaskPtr ();
+}
+
+TaskPtr
+Scheduler::schedulePeriodicTask (SchedulerPtr scheduler, IntervalGeneratorPtr delayGenerator,
+ const Task::Callback &callback, const Task::Tag &tag)
+{
+ TaskPtr task = make_shared<PeriodicTask> (callback, tag, scheduler, delayGenerator);
+
+ if (scheduler->addTask (task))
+ return task;
+ else
+ return TaskPtr ();
+}
+
+bool
+Scheduler::addTask(TaskPtr newTask, bool reset/* = true*/)
+{
+ if (addToMap(newTask))
+ {
+ if (reset)
+ {
+ newTask->reset();
+ }
+ int res = evtimer_add(newTask->ev(), newTask->tv());
+ if (res < 0)
+ {
+ _LOG_ERROR ("evtimer_add failed for " << newTask->tag());
+ }
+ return true;
+ }
+ else
+ {
+ _LOG_ERROR ("fail to add task: " << newTask->tag());
+ }
+
+ return false;
+}
+
+void
+Scheduler::deleteTask(TaskPtr task)
+{
+ deleteTask (task->tag ());
+}
+
+void
+Scheduler::rescheduleTask(TaskPtr task)
+{
+ ScopedLock lock(m_mutex);
+ TaskMapIt it = m_taskMap.find(task->tag());
+ if (it != m_taskMap.end())
+ {
+ TaskPtr task = it->second;
+ task->reset();
+ int res = evtimer_add(task->ev(), task->tv());
+ if (res < 0)
+ {
+ _LOG_ERROR ("evtimer_add failed for " << task->tag());
+ }
+ }
+ else
+ {
+ addTask(task);
+ }
+}
+
+void
+Scheduler::rescheduleTask(const Task::Tag &tag)
+{
+ ScopedLock lock(m_mutex);
+ TaskMapIt it = m_taskMap.find(tag);
+ if (it != m_taskMap.end())
+ {
+ TaskPtr task = it->second;
+ task->reset();
+ int res = evtimer_add(task->ev(), task->tv());
+ if (res < 0)
+ {
+ cout << "evtimer_add failed for " << task->tag() << endl;
+ }
+ }
+}
+
+void
+Scheduler::rescheduleTaskAt (const Task::Tag &tag, double time)
+{
+ ScopedLock lock(m_mutex);
+ TaskMapIt it = m_taskMap.find (tag);
+ if (it != m_taskMap.end())
+ {
+ TaskPtr task = it->second;
+ task->reset();
+ task->setTv (time);
+
+ int res = evtimer_add(task->ev(), task->tv());
+ if (res < 0)
+ {
+ _LOG_ERROR ("evtimer_add failed for " << task->tag());
+ }
+ }
+ else
+ {
+ _LOG_ERROR ("Task for tag " << tag << " not found");
+ }
+}
+
+void
+Scheduler::rescheduleTaskAt (TaskPtr task, double time)
+{
+ ScopedLock lock(m_mutex);
+ TaskMapIt it = m_taskMap.find(task->tag());
+ if (it != m_taskMap.end())
+ {
+ TaskPtr task = it->second;
+ task->reset();
+ task->setTv (time);
+
+ int res = evtimer_add(task->ev(), task->tv());
+ if (res < 0)
+ {
+ _LOG_ERROR ("evtimer_add failed for " << task->tag());
+ }
+ }
+ else
+ {
+ task->setTv (time); // force different time
+ addTask (task, false);
+ }
+}
+
+
+bool
+Scheduler::addToMap(TaskPtr task)
+{
+ ScopedLock lock(m_mutex);
+ if (m_taskMap.find(task->tag()) == m_taskMap.end())
+ {
+ m_taskMap.insert(make_pair(task->tag(), task));
+ return true;
+ }
+ return false;
+}
+
+void
+Scheduler::deleteTask(const Task::Tag &tag)
+{
+ ScopedLock lock(m_mutex);
+ TaskMapIt it = m_taskMap.find(tag);
+ if (it != m_taskMap.end())
+ {
+ TaskPtr task = it->second;
+ evtimer_del(task->ev());
+ m_taskMap.erase(it);
+ }
+}
+
+void
+Scheduler::deleteTask(const Task::TaskMatcher &matcher)
+{
+ ScopedLock lock(m_mutex);
+ TaskMapIt it = m_taskMap.begin();
+ while(it != m_taskMap.end())
+ {
+ TaskPtr task = it->second;
+ if (matcher(task))
+ {
+ evtimer_del(task->ev());
+ // Use post increment; map.erase invalidate the iterator that is beening erased,
+ // but does not invalidate other iterators. This seems to be the convention to
+ // erase something from C++ STL map while traversing.
+ m_taskMap.erase(it++);
+ }
+ else
+ {
+ ++it;
+ }
+ }
+}
+
+int
+Scheduler::size()
+{
+ ScopedLock lock(m_mutex);
+ return m_taskMap.size();
+}
diff --git a/scheduler/scheduler.h b/scheduler/scheduler.h
new file mode 100644
index 0000000..ffac5d2
--- /dev/null
+++ b/scheduler/scheduler.h
@@ -0,0 +1,138 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef SCHEDULER_H
+#define SCHEDULER_H
+
+#include <event2/event.h>
+#include <event2/thread.h>
+#include <event2/event-config.h>
+#include <event2/util.h>
+
+#include <boost/function.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <boost/exception/all.hpp>
+#include <boost/thread/recursive_mutex.hpp>
+#include <boost/thread/thread.hpp>
+#include <math.h>
+#include <map>
+#include <sys/time.h>
+
+#include "scheduler/task.h"
+#include "scheduler/interval-generator.h"
+#include "executor/executor.h"
+
+class Scheduler;
+typedef boost::shared_ptr<Scheduler> SchedulerPtr;
+
+/**
+ * @brief Scheduler class
+ */
+class Scheduler
+{
+public:
+ Scheduler();
+ virtual ~Scheduler();
+
+ // start event scheduling
+ virtual void
+ start();
+
+ // stop event scheduling
+ virtual void
+ shutdown();
+
+ // helper method to schedule one-time task
+ static TaskPtr
+ scheduleOneTimeTask (SchedulerPtr scheduler, double delay, const Task::Callback &callback, const Task::Tag &tag);
+
+ // helper method to schedule periodic task
+ static TaskPtr
+ schedulePeriodicTask (SchedulerPtr scheduler, IntervalGeneratorPtr delayGenerator,
+ const Task::Callback &callback, const Task::Tag &tag);
+
+ // if task with the same tag exists, the task is not added and return false
+ virtual bool
+ addTask(TaskPtr task, bool reset = true);
+
+ // delete task by task->tag, regardless of whether it's invoked or not
+ virtual void
+ deleteTask(TaskPtr task);
+
+ // delete task by tag, regardless of whether it's invoked or not
+ // if no task is found, no effect
+ virtual void
+ deleteTask(const Task::Tag &tag);
+
+ // delete tasks by matcher, regardless of whether it's invoked or not
+ // this is flexiable in that you can use any form of criteria in finding tasks to delete
+ // but keep in mind this is a linear scan
+
+ // if no task is found, no effect
+ virtual void
+ deleteTask(const Task::TaskMatcher &matcher);
+
+ // task must already have been added to the scheduler, otherwise this method has no effect
+ // this is usually used by PeriodicTask
+ virtual void
+ rescheduleTask(const Task::Tag &tag);
+
+ // if the task is not pending, it will be added to the schedule queue
+ // if the task is pending, the delay is changed to the passed in delay
+ // e.g. if at second 0 task A with delay 5 is originally going to run at second 5 and
+ // rescheduleTask(A) is called at second 4, A will be reschedule to run
+ // at second 9
+ virtual void
+ rescheduleTask(TaskPtr task);
+
+ virtual void
+ rescheduleTaskAt (const Task::Tag &tag, double time);
+
+ virtual void
+ rescheduleTaskAt (TaskPtr task, double time);
+
+ void
+ execute(Executor::Job);
+
+ void
+ eventLoop();
+
+ event_base *
+ base() { return m_base; }
+
+ // used in test
+ int
+ size();
+
+protected:
+ bool
+ addToMap(TaskPtr task);
+
+protected:
+ typedef std::map<Task::Tag, TaskPtr> TaskMap;
+ typedef std::map<Task::Tag, TaskPtr>::iterator TaskMapIt;
+ typedef boost::recursive_mutex Mutex;
+ typedef boost::unique_lock<Mutex> ScopedLock;
+
+ TaskMap m_taskMap;
+ Mutex m_mutex;
+ volatile bool m_running;
+ event_base *m_base;
+ event *m_ev;
+ boost::thread m_thread;
+ Executor m_executor;
+};
+
+struct SchedulerException : virtual boost::exception, virtual std::exception { };
+
+#endif // SCHEDULER_H
diff --git a/scheduler/simple-interval-generator.h b/scheduler/simple-interval-generator.h
new file mode 100644
index 0000000..c7a9e77
--- /dev/null
+++ b/scheduler/simple-interval-generator.h
@@ -0,0 +1,31 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef SIMPLE_INTERVAL_GENERATOR_H
+#define SIMPLE_INTERVAL_GENERATOR_H
+
+#include "interval-generator.h"
+
+class SimpleIntervalGenerator : public IntervalGenerator
+{
+public:
+ SimpleIntervalGenerator(double interval) : m_interval (interval) {}
+ virtual ~SimpleIntervalGenerator() {}
+
+ virtual double
+ nextInterval() _OVERRIDE { return m_interval; }
+
+private:
+ double m_interval;
+};
+
+#endif // SIMPLE_INTERVAL_GENERATOR_H
diff --git a/scheduler/task.cc b/scheduler/task.cc
new file mode 100644
index 0000000..fa73490
--- /dev/null
+++ b/scheduler/task.cc
@@ -0,0 +1,74 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "task.h"
+#include "scheduler.h"
+
+static void
+eventCallback(evutil_socket_t fd, short what, void *arg)
+{
+ Task *task = static_cast<Task *>(arg);
+ task->execute();
+ task = NULL;
+}
+
+Task::Task(const Callback &callback, const Tag &tag, const SchedulerPtr &scheduler)
+ : m_callback(callback)
+ , m_tag(tag)
+ , m_scheduler(scheduler)
+ , m_invoked(false)
+ , m_event(NULL)
+ , m_tv(NULL)
+{
+ m_event = evtimer_new(scheduler->base(), eventCallback, this);
+ m_tv = new timeval;
+}
+
+Task::~Task()
+{
+ if (m_event != NULL)
+ {
+ event_free(m_event);
+ m_event = NULL;
+ }
+
+ if (m_tv != NULL)
+ {
+ delete m_tv;
+ m_tv = NULL;
+ }
+}
+
+void
+Task::setTv(double delay)
+{
+ // Alex: when using abs function, i would recommend use it with std:: prefix, otherwise
+ // the standard one may be used, which converts everything to INT, making a lot of problems
+ double intPart, fraction;
+ fraction = modf(std::abs(delay), &intPart);
+
+ m_tv->tv_sec = static_cast<int>(intPart);
+ m_tv->tv_usec = static_cast<int>((fraction * 1000000));
+}
+
+void
+Task::execute()
+{
+ // m_scheduler->execute(boost::bind(&Task::run, this));
+
+ // using a shared_ptr of this to ensure that when invoked from executor
+ // the task object still exists
+ // otherwise, it could be the case that the run() is to be executed, but before it
+ // could finish, the TaskPtr gets deleted from scheduler and the task object
+ // gets destroyed, causing crash
+ m_scheduler->execute(boost::bind(&Task::run, shared_from_this()));
+}
diff --git a/scheduler/task.h b/scheduler/task.h
new file mode 100644
index 0000000..bd14296
--- /dev/null
+++ b/scheduler/task.h
@@ -0,0 +1,94 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef TASK_H
+#define TASK_H
+
+#define _OVERRIDE
+#ifdef __GNUC__
+#if __GNUC_MAJOR >= 4 && __GNUC_MINOR__ >= 7
+ #undef _OVERRIDE
+ #define _OVERRIDE override
+#endif // __GNUC__ version
+#endif // __GNUC__
+
+#include <boost/function.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <sys/time.h>
+
+//////////////////////////////////////////////////
+// forward declarations
+class Task;
+typedef boost::shared_ptr<Task> TaskPtr;
+
+class Scheduler;
+typedef boost::shared_ptr<Scheduler> SchedulerPtr;
+
+struct event;
+//////////////////////////////////////////////////
+
+
+/**
+ * @brief Base class for a task
+ */
+class Task : public boost::enable_shared_from_this<Task>
+{
+public:
+ // callback of this task
+ typedef boost::function<void ()> Callback;
+ // tag identifies this task, should be unique
+ typedef std::string Tag;
+ // used to match tasks
+ typedef boost::function<bool (const TaskPtr &task)> TaskMatcher;
+
+ // Task is associated with Schedulers due to the requirement that libevent event is associated with an libevent event_base
+ Task(const Callback &callback, const Tag &tag, const SchedulerPtr &scheduler);
+ virtual ~Task();
+
+ virtual void
+ run() = 0;
+
+ Tag
+ tag() { return m_tag; }
+
+ event *
+ ev() { return m_event; }
+
+ timeval *
+ tv() { return m_tv; }
+
+ // Task needs to be resetted after the callback is invoked if it is to be schedule again; just for safety
+ // it's called by scheduler automatically when addTask or rescheduleTask is called;
+ // Tasks should do preparation work here (e.g. set up new delay, etc. )
+ virtual void
+ reset() = 0;
+
+ // set delay
+ // This overrides whatever delay kept in m_tv
+ void
+ setTv(double delay);
+
+ void
+ execute();
+
+protected:
+ Callback m_callback;
+ Tag m_tag;
+ SchedulerPtr m_scheduler;
+ bool m_invoked;
+ event *m_event;
+ timeval *m_tv;
+};
+
+
+#endif // TASK_H