blob: 28060759b9ff98c6ecc3efbff0657ea2d414043c [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"
23#include <utility>
24
25using namespace std;
26
27#define EVLOOP_NO_EXIT_ON_EMPTY 0x04
28
29// IntervalGeneratorPtr
30// IntervalGenerator:: Null;
31
32void errorCallback(int err)
33{
34 cout << "Fatal error: " << err << endl;
35}
36
37Scheduler::Scheduler()
38 : m_running(false)
39{
40 event_set_fatal_callback(errorCallback);
41 evthread_use_pthreads();
42 m_base = event_base_new();
43}
44
45Scheduler::~Scheduler()
46{
47 event_base_free(m_base);
48}
49
50void
51Scheduler::eventLoop()
52{
53 while(true)
54 {
55 if (event_base_loop(m_base, EVLOOP_NO_EXIT_ON_EMPTY) < 0)
56 {
57 cout << "scheduler loop break error" << endl;
58 }
Alexander Afanasyev34edd4d2013-01-17 17:55:45 -080059
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -080060 {
Alexander Afanasyev34edd4d2013-01-17 17:55:45 -080061 ReadLock lock(m_mutex);
62 if (!m_running)
63 {
64 cout << "scheduler loop break normal" << endl;
65 break;
66 }
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -080067 }
68 }
69}
70
71void
72Scheduler::start()
73{
74 WriteLock lock(m_mutex);
75 if (!m_running)
76 {
77 m_thread = boost::thread(&Scheduler::eventLoop, this);
78 m_running = true;
79 }
80}
81
82void
83Scheduler::shutdown()
84{
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -080085 {
Zhenkai Zhua3c71bb2013-01-18 09:59:24 -080086 WriteLock lock(m_mutex);
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -080087 m_running = false;
88 }
Zhenkai Zhua3c71bb2013-01-18 09:59:24 -080089
90 event_base_loopbreak(m_base);
91 m_thread.join();
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -080092}
93
94bool
95Scheduler::addTask(const TaskPtr &task)
96{
97 TaskPtr newTask = task;
98
99 if (addToMap(newTask))
100 {
101 newTask->reset();
102 int res = evtimer_add(newTask->ev(), newTask->tv());
103 if (res < 0)
104 {
105 cout << "evtimer_add failed for " << task->tag() << endl;
106 }
107 return true;
108 }
109 else
110 {
111 cout << "fail to add task: " << task->tag() << endl;
112 }
113
114 return false;
115}
116
Alexander Afanasyevfb4c43f2013-01-18 17:43:25 -0800117void
Alexander Afanasyev997ba632013-01-18 17:40:23 -0800118Scheduler::deleteTask(TaskPtr task)
119{
120 deleteTask (task->tag ());
121}
122
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -0800123void
Zhenkai Zhu66ddb232013-01-18 17:53:52 -0800124Scheduler::rescheduleTask(const TaskPtr &task)
125{
126 ReadLock lock(m_mutex);
Zhenkai Zhud2ca3922013-01-18 17:58:48 -0800127 TaskMapIt it = m_taskMap.find(task->tag());
Zhenkai Zhu66ddb232013-01-18 17:53:52 -0800128 if (it != m_taskMap.end())
129 {
130 TaskPtr task = it->second;
131 task->reset();
132 int res = evtimer_add(task->ev(), task->tv());
133 if (res < 0)
134 {
135 cout << "evtimer_add failed for " << task->tag() << endl;
136 }
137 }
138 else
139 {
140 addTask(task);
141 }
142}
143
144void
Alexander Afanasyev1b0e0082013-01-17 16:48:26 -0800145Scheduler::rescheduleTask(const Task::Tag &tag)
146{
147 ReadLock lock(m_mutex);
148 TaskMapIt it = m_taskMap.find(tag);
149 if (it != m_taskMap.end())
150 {
151 TaskPtr task = it->second;
152 task->reset();
153 int res = evtimer_add(task->ev(), task->tv());
154 if (res < 0)
155 {
156 cout << "evtimer_add failed for " << task->tag() << endl;
157 }
158 }
159}
160
161bool
162Scheduler::addToMap(const TaskPtr &task)
163{
164 WriteLock lock(m_mutex);
165 if (m_taskMap.find(task->tag()) == m_taskMap.end())
166 {
167 m_taskMap.insert(make_pair(task->tag(), task));
168 return true;
169 }
170 return false;
171}
172
173void
174Scheduler::deleteTask(const Task::Tag &tag)
175{
176 WriteLock lock(m_mutex);
177 TaskMapIt it = m_taskMap.find(tag);
178 if (it != m_taskMap.end())
179 {
180 TaskPtr task = it->second;
181 evtimer_del(task->ev());
182 m_taskMap.erase(it);
183 }
184}
185
186void
187Scheduler::deleteTask(const Task::TaskMatcher &matcher)
188{
189 WriteLock lock(m_mutex);
190 TaskMapIt it = m_taskMap.begin();
191 while(it != m_taskMap.end())
192 {
193 TaskPtr task = it->second;
194 if (matcher(task))
195 {
196 evtimer_del(task->ev());
197 // Use post increment; map.erase invalidate the iterator that is beening erased,
198 // but does not invalidate other iterators. This seems to be the convention to
199 // erase something from C++ STL map while traversing.
200 m_taskMap.erase(it++);
201 }
202 else
203 {
204 ++it;
205 }
206 }
207}
208
209int
210Scheduler::size()
211{
212 ReadLock lock(m_mutex);
213 return m_taskMap.size();
214}