blob: ee6a124d0ffe815172af5286ce5d3e161a21a108 [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"
25
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -080026#include <utility>
Alexander Afanasyeve41e7d22013-01-19 15:13:47 -080027#include <boost/make_shared.hpp>
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -080028
29using namespace std;
Alexander Afanasyeve41e7d22013-01-19 15:13:47 -080030using namespace boost;
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -080031
32#define EVLOOP_NO_EXIT_ON_EMPTY 0x04
33
34// IntervalGeneratorPtr
35// IntervalGenerator:: Null;
36
37void errorCallback(int err)
38{
39 cout << "Fatal error: " << err << endl;
40}
41
42Scheduler::Scheduler()
43 : m_running(false)
44{
45 event_set_fatal_callback(errorCallback);
46 evthread_use_pthreads();
47 m_base = event_base_new();
48}
49
50Scheduler::~Scheduler()
51{
52 event_base_free(m_base);
53}
54
55void
56Scheduler::eventLoop()
57{
58 while(true)
59 {
60 if (event_base_loop(m_base, EVLOOP_NO_EXIT_ON_EMPTY) < 0)
61 {
62 cout << "scheduler loop break error" << endl;
63 }
Alexander Afanasyev34edd4d2013-01-17 17:55:45 -080064
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -080065 {
Alexander Afanasyev34edd4d2013-01-17 17:55:45 -080066 ReadLock lock(m_mutex);
67 if (!m_running)
68 {
69 cout << "scheduler loop break normal" << endl;
70 break;
71 }
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -080072 }
73 }
74}
75
76void
77Scheduler::start()
78{
79 WriteLock lock(m_mutex);
80 if (!m_running)
81 {
82 m_thread = boost::thread(&Scheduler::eventLoop, this);
83 m_running = true;
84 }
85}
86
87void
88Scheduler::shutdown()
89{
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -080090 {
Zhenkai Zhua3c71bb2013-01-18 09:59:24 -080091 WriteLock lock(m_mutex);
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -080092 m_running = false;
93 }
Zhenkai Zhua3c71bb2013-01-18 09:59:24 -080094
95 event_base_loopbreak(m_base);
96 m_thread.join();
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -080097}
98
Alexander Afanasyeve41e7d22013-01-19 15:13:47 -080099TaskPtr
100Scheduler::scheduleOneTimeTask (SchedulerPtr scheduler, double delay,
101 const Task::Callback &callback, const Task::Tag &tag)
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -0800102{
Alexander Afanasyeve41e7d22013-01-19 15:13:47 -0800103 TaskPtr task = make_shared<OneTimeTask> (callback, tag, scheduler, delay);
104 if (scheduler->addTask (task))
105 return task;
106 else
107 return TaskPtr ();
108}
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -0800109
Alexander Afanasyeve41e7d22013-01-19 15:13:47 -0800110TaskPtr
111Scheduler::schedulePeriodicTask (SchedulerPtr scheduler, IntervalGeneratorPtr delayGenerator,
112 const Task::Callback &callback, const Task::Tag &tag)
113{
114 TaskPtr task = make_shared<PeriodicTask> (callback, tag, scheduler, delayGenerator);
115
116 if (scheduler->addTask (task))
117 return task;
118 else
119 return TaskPtr ();
120}
121
122bool
123Scheduler::addTask(TaskPtr newTask)
124{
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -0800125 if (addToMap(newTask))
126 {
127 newTask->reset();
128 int res = evtimer_add(newTask->ev(), newTask->tv());
129 if (res < 0)
130 {
Alexander Afanasyeve41e7d22013-01-19 15:13:47 -0800131 cout << "evtimer_add failed for " << newTask->tag() << endl;
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -0800132 }
133 return true;
134 }
135 else
136 {
Alexander Afanasyeve41e7d22013-01-19 15:13:47 -0800137 cout << "fail to add task: " << newTask->tag() << endl;
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -0800138 }
139
140 return false;
141}
142
Alexander Afanasyevfb4c43f2013-01-18 17:43:25 -0800143void
Alexander Afanasyev997ba632013-01-18 17:40:23 -0800144Scheduler::deleteTask(TaskPtr task)
145{
146 deleteTask (task->tag ());
147}
148
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -0800149void
Zhenkai Zhu66ddb232013-01-18 17:53:52 -0800150Scheduler::rescheduleTask(const TaskPtr &task)
151{
152 ReadLock lock(m_mutex);
Zhenkai Zhud2ca3922013-01-18 17:58:48 -0800153 TaskMapIt it = m_taskMap.find(task->tag());
Zhenkai Zhu66ddb232013-01-18 17:53:52 -0800154 if (it != m_taskMap.end())
155 {
156 TaskPtr task = it->second;
157 task->reset();
158 int res = evtimer_add(task->ev(), task->tv());
159 if (res < 0)
160 {
161 cout << "evtimer_add failed for " << task->tag() << endl;
162 }
163 }
164 else
165 {
166 addTask(task);
167 }
168}
169
170void
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -0800171Scheduler::rescheduleTask(const Task::Tag &tag)
172{
173 ReadLock lock(m_mutex);
174 TaskMapIt it = m_taskMap.find(tag);
175 if (it != m_taskMap.end())
176 {
177 TaskPtr task = it->second;
178 task->reset();
179 int res = evtimer_add(task->ev(), task->tv());
180 if (res < 0)
181 {
182 cout << "evtimer_add failed for " << task->tag() << endl;
183 }
184 }
185}
186
187bool
188Scheduler::addToMap(const TaskPtr &task)
189{
190 WriteLock lock(m_mutex);
191 if (m_taskMap.find(task->tag()) == m_taskMap.end())
192 {
193 m_taskMap.insert(make_pair(task->tag(), task));
194 return true;
195 }
196 return false;
197}
198
199void
200Scheduler::deleteTask(const Task::Tag &tag)
201{
202 WriteLock lock(m_mutex);
203 TaskMapIt it = m_taskMap.find(tag);
204 if (it != m_taskMap.end())
205 {
206 TaskPtr task = it->second;
207 evtimer_del(task->ev());
208 m_taskMap.erase(it);
209 }
210}
211
212void
213Scheduler::deleteTask(const Task::TaskMatcher &matcher)
214{
215 WriteLock lock(m_mutex);
216 TaskMapIt it = m_taskMap.begin();
217 while(it != m_taskMap.end())
218 {
219 TaskPtr task = it->second;
220 if (matcher(task))
221 {
222 evtimer_del(task->ev());
223 // Use post increment; map.erase invalidate the iterator that is beening erased,
224 // but does not invalidate other iterators. This seems to be the convention to
225 // erase something from C++ STL map while traversing.
226 m_taskMap.erase(it++);
227 }
228 else
229 {
230 ++it;
231 }
232 }
233}
234
235int
236Scheduler::size()
237{
238 ReadLock lock(m_mutex);
239 return m_taskMap.size();
240}