blob: 236d5e882b23a3bd88863b09e0a3d16d05f1c2c0 [file] [log] [blame]
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -08001/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
2/*
3 * Copyright (c) 2013 University of California, Los Angeles
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
19 * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
20 */
21
22#include "scheduler.h"
Alexander Afanasyeve41e7d22013-01-19 15:13:47 -080023#include "one-time-task.h"
24#include "periodic-task.h"
Alexander Afanasyevfc720362013-01-24 21:49:48 -080025#include "logging.h"
Alexander Afanasyeve41e7d22013-01-19 15:13:47 -080026
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -080027#include <utility>
Alexander Afanasyeve41e7d22013-01-19 15:13:47 -080028#include <boost/make_shared.hpp>
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -080029
Alexander Afanasyevfc720362013-01-24 21:49:48 -080030INIT_LOGGER ("Scheduler");
31
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -080032using namespace std;
Alexander Afanasyeve41e7d22013-01-19 15:13:47 -080033using namespace boost;
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -080034
35#define EVLOOP_NO_EXIT_ON_EMPTY 0x04
36
37// IntervalGeneratorPtr
38// IntervalGenerator:: Null;
39
40void errorCallback(int err)
41{
Alexander Afanasyevfc720362013-01-24 21:49:48 -080042 _LOG_ERROR ("Fatal error: " << err);
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -080043}
44
45Scheduler::Scheduler()
46 : m_running(false)
47{
48 event_set_fatal_callback(errorCallback);
49 evthread_use_pthreads();
50 m_base = event_base_new();
51}
52
53Scheduler::~Scheduler()
54{
Alexander Afanasyevfc720362013-01-24 21:49:48 -080055 shutdown ();
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -080056 event_base_free(m_base);
57}
58
59void
60Scheduler::eventLoop()
61{
62 while(true)
63 {
64 if (event_base_loop(m_base, EVLOOP_NO_EXIT_ON_EMPTY) < 0)
65 {
Alexander Afanasyevfc720362013-01-24 21:49:48 -080066 _LOG_DEBUG ("scheduler loop break error");
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -080067 }
Alexander Afanasyevfc720362013-01-24 21:49:48 -080068
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -080069 {
Alexander Afanasyevfc720362013-01-24 21:49:48 -080070 ScopedLock lock(m_mutex);
Alexander Afanasyev34edd4d2013-01-17 17:55:45 -080071 if (!m_running)
72 {
Alexander Afanasyevfc720362013-01-24 21:49:48 -080073 _LOG_DEBUG ("scheduler loop break normal");
Alexander Afanasyev34edd4d2013-01-17 17:55:45 -080074 break;
75 }
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -080076 }
77 }
78}
79
80void
81Scheduler::start()
82{
Alexander Afanasyevfc720362013-01-24 21:49:48 -080083 ScopedLock lock(m_mutex);
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -080084 if (!m_running)
85 {
86 m_thread = boost::thread(&Scheduler::eventLoop, this);
87 m_running = true;
88 }
89}
90
91void
92Scheduler::shutdown()
93{
Alexander Afanasyevfc720362013-01-24 21:49:48 -080094 bool breakAndWait = false;
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -080095 {
Alexander Afanasyevfc720362013-01-24 21:49:48 -080096 ScopedLock lock (m_mutex);
97 if (m_running)
98 {
99 m_running = false;
100 breakAndWait = true;
101 }
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -0800102 }
Alexander Afanasyevfc720362013-01-24 21:49:48 -0800103
104 if (breakAndWait)
105 {
106 event_base_loopbreak(m_base);
107 m_thread.join();
108 }
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -0800109}
110
Alexander Afanasyeve41e7d22013-01-19 15:13:47 -0800111TaskPtr
112Scheduler::scheduleOneTimeTask (SchedulerPtr scheduler, double delay,
113 const Task::Callback &callback, const Task::Tag &tag)
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -0800114{
Alexander Afanasyeve41e7d22013-01-19 15:13:47 -0800115 TaskPtr task = make_shared<OneTimeTask> (callback, tag, scheduler, delay);
116 if (scheduler->addTask (task))
117 return task;
118 else
119 return TaskPtr ();
120}
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -0800121
Alexander Afanasyeve41e7d22013-01-19 15:13:47 -0800122TaskPtr
123Scheduler::schedulePeriodicTask (SchedulerPtr scheduler, IntervalGeneratorPtr delayGenerator,
124 const Task::Callback &callback, const Task::Tag &tag)
125{
126 TaskPtr task = make_shared<PeriodicTask> (callback, tag, scheduler, delayGenerator);
127
128 if (scheduler->addTask (task))
129 return task;
130 else
131 return TaskPtr ();
132}
133
134bool
135Scheduler::addTask(TaskPtr newTask)
136{
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -0800137 if (addToMap(newTask))
138 {
139 newTask->reset();
140 int res = evtimer_add(newTask->ev(), newTask->tv());
141 if (res < 0)
142 {
Alexander Afanasyevfc720362013-01-24 21:49:48 -0800143 _LOG_ERROR ("evtimer_add failed for " << newTask->tag());
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -0800144 }
145 return true;
146 }
147 else
148 {
Alexander Afanasyevfc720362013-01-24 21:49:48 -0800149 _LOG_ERROR ("fail to add task: " << newTask->tag());
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -0800150 }
151
152 return false;
153}
154
Alexander Afanasyevfb4c43f2013-01-18 17:43:25 -0800155void
Alexander Afanasyev997ba632013-01-18 17:40:23 -0800156Scheduler::deleteTask(TaskPtr task)
157{
158 deleteTask (task->tag ());
159}
160
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -0800161void
Zhenkai Zhu66ddb232013-01-18 17:53:52 -0800162Scheduler::rescheduleTask(const TaskPtr &task)
163{
Alexander Afanasyevfc720362013-01-24 21:49:48 -0800164 ScopedLock lock(m_mutex);
Zhenkai Zhud2ca3922013-01-18 17:58:48 -0800165 TaskMapIt it = m_taskMap.find(task->tag());
Zhenkai Zhu66ddb232013-01-18 17:53:52 -0800166 if (it != m_taskMap.end())
167 {
168 TaskPtr task = it->second;
169 task->reset();
170 int res = evtimer_add(task->ev(), task->tv());
171 if (res < 0)
172 {
Alexander Afanasyevfc720362013-01-24 21:49:48 -0800173 _LOG_ERROR ("evtimer_add failed for " << task->tag());
Zhenkai Zhu66ddb232013-01-18 17:53:52 -0800174 }
175 }
176 else
177 {
178 addTask(task);
179 }
180}
181
182void
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -0800183Scheduler::rescheduleTask(const Task::Tag &tag)
184{
Alexander Afanasyevfc720362013-01-24 21:49:48 -0800185 ScopedLock lock(m_mutex);
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -0800186 TaskMapIt it = m_taskMap.find(tag);
187 if (it != m_taskMap.end())
188 {
189 TaskPtr task = it->second;
190 task->reset();
191 int res = evtimer_add(task->ev(), task->tv());
192 if (res < 0)
193 {
194 cout << "evtimer_add failed for " << task->tag() << endl;
195 }
196 }
197}
198
199bool
200Scheduler::addToMap(const TaskPtr &task)
201{
Alexander Afanasyevfc720362013-01-24 21:49:48 -0800202 ScopedLock lock(m_mutex);
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -0800203 if (m_taskMap.find(task->tag()) == m_taskMap.end())
204 {
205 m_taskMap.insert(make_pair(task->tag(), task));
206 return true;
207 }
208 return false;
209}
210
211void
212Scheduler::deleteTask(const Task::Tag &tag)
213{
Alexander Afanasyevfc720362013-01-24 21:49:48 -0800214 ScopedLock lock(m_mutex);
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -0800215 TaskMapIt it = m_taskMap.find(tag);
216 if (it != m_taskMap.end())
217 {
218 TaskPtr task = it->second;
219 evtimer_del(task->ev());
220 m_taskMap.erase(it);
221 }
222}
223
224void
225Scheduler::deleteTask(const Task::TaskMatcher &matcher)
226{
Alexander Afanasyevfc720362013-01-24 21:49:48 -0800227 ScopedLock lock(m_mutex);
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -0800228 TaskMapIt it = m_taskMap.begin();
229 while(it != m_taskMap.end())
230 {
231 TaskPtr task = it->second;
232 if (matcher(task))
233 {
234 evtimer_del(task->ev());
235 // Use post increment; map.erase invalidate the iterator that is beening erased,
236 // but does not invalidate other iterators. This seems to be the convention to
237 // erase something from C++ STL map while traversing.
238 m_taskMap.erase(it++);
239 }
240 else
241 {
242 ++it;
243 }
244 }
245}
246
247int
248Scheduler::size()
249{
Alexander Afanasyevfc720362013-01-24 21:49:48 -0800250 ScopedLock lock(m_mutex);
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -0800251 return m_taskMap.size();
252}