libutil++  1.9.3
 All Classes Functions Variables
TaskQueue.cpp
1 /*
2 ** libutil++
3 ** $Id: TaskQueue.cpp 1653 2016-02-28 19:54:59Z sella $
4 ** Copyright (c) 2011-2016 Digital Genesis, LLC. All Rights Reserved.
5 ** Released under the LGPL Version 2.1 License.
6 ** http://www.digitalgenesis.com
7 */
8 
9 static const char rcsid[] __attribute__((used)) = "$Id: TaskQueue.cpp 1653 2016-02-28 19:54:59Z sella $";
10 
11 #include "TaskQueue.h"
12 #include "CommonMacro.h"
13 #include "Time.h"
14 
15 #include <stdio.h>
16 #include <assert.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <sys/time.h>
20 
21 #include <algorithm>
22 
23 using namespace sella::util;
24 
25 class CompareTask {
26  public:
27  bool operator()(const Task::shared &t1, const Task::shared &t2) const {
28  if (UNLIKELY(t1 == NULL)) {
29  return true;
30  } else if (UNLIKELY(t2 == NULL)) {
31  return false;
32  }
33 
34  const timeval &tv1 = t1->getTimer();
35  const timeval &tv2 = t2->getTimer();
36 
37  if (UNLIKELY(timercmp(&tv1, &tv2, ==))) {
38  return t1->getPriority() < t2->getPriority();
39  } else if (!timerisset(&tv1)) {
40  return false;
41  } else if (!timerisset(&tv2)) {
42  return true;
43  } else if (timercmp(&tv1, &tv2, <)) {
44  return false;
45  }
46  return true;
47  }
48 };
49 
50 TaskQueue::TaskQueue(const size_t capacity) : libutilxx__log(::libutilxx__log) {
51  reserve(capacity);
52 }
53 
54 TaskQueue::TaskQueue(Log::shared log, const size_t capacity) : libutilxx__log(log) {
55  reserve(capacity);
56 }
57 
58 TaskQueue::~TaskQueue() { }
59 
60 size_t TaskQueue::size(void) const {
61  return heap.size();
62 }
63 
64 bool TaskQueue::empty(void) const {
65  return heap.empty();
66 }
67 
68 void TaskQueue::clear(void) {
69  heap.clear();
70 }
71 
72 Task::shared TaskQueue::top(void) const {
73  assert(!heap.empty());
74 
75  return heap.front();
76 }
77 
78 Task::shared TaskQueue::next(void) const {
79  if (empty()) {
80  return Task::shared_ptr();
81  }
82 
83  return heap.front();
84 }
85 
86 const timeval TaskQueue::getDelay(timeval fallback) const {
87  if (empty()) {
88  return fallback;
89  }
90 
91  return heap.front()->getDelay();
92 }
93 
94 uint64_t TaskQueue::getDelayMsec(uint64_t fallback, uint64_t maximum) const {
95  if (empty()) {
96  return fallback;
97  }
98 
99  uint64_t delay = heap.front()->getDelayMsec();
100 
101  if (maximum > 0 && delay > maximum) {
102  return maximum;
103  }
104 
105  return delay;
106 }
107 
108 uint64_t TaskQueue::getDelayUsec(uint64_t fallback, uint64_t maximum) const {
109  if (empty()) {
110  return fallback;
111  }
112 
113  uint64_t delay = heap.front()->getDelayUsec();
114 
115  if (maximum > 0 && delay > maximum) {
116  return maximum;
117  }
118 
119  return delay;
120 }
121 
122 void TaskQueue::push(Task::shared &task) {
123  assert(task.get() != NULL);
124 
125  heap.push_back(task);
126  push_heap(heap.begin(), heap.end(), CompareTask());
127 }
128 
129 void TaskQueue::push(Task::shared &task, const std::chrono::system_clock::duration &delay, int priority) {
130  assert(task.get() != NULL);
131 
132  task->setDelay(delay);
133  if (priority) task->setPriority(priority);
134 
135  push(task);
136 }
137 
138 void TaskQueue::push(Task::shared &task, const std::chrono::system_clock::time_point &time, int priority) {
139  assert(task.get() != NULL);
140 
141  task->setTimer(time);
142  if (priority) task->setPriority(priority);
143 
144  push(task);
145 }
146 
147 void TaskQueue::push(Task::shared &task, time_t sec, suseconds_t usec, int priority) {
148  assert(task.get() != NULL);
149 
150  task->setDelay(sec, usec);
151  if (priority) task->setPriority(priority);
152 
153  push(task);
154 }
155 
156 void TaskQueue::push(Task::shared &task, timeval &tv, int priority) {
157  assert(task.get() != NULL);
158 
159  task->setTimer(tv);
160  if (priority) task->setPriority(priority);
161 
162  push(task);
163 }
164 
165 bool TaskQueue::repush(Task::shared &task, const std::chrono::system_clock::duration &delay, int priority, bool strict) {
166  timeval tv = Time::chronototv(delay);
167 
168  return repush(task, tv, priority, strict);
169 }
170 
171 bool TaskQueue::repush(Task::shared &task, const std::chrono::system_clock::time_point &time, int priority, bool strict) {
172  timeval tv = Time::chronototv(time);
173 
174  return repush(task, tv, priority, strict);
175 }
176 
177 bool TaskQueue::repush(Task::shared &task, time_t sec, suseconds_t usec, int priority, bool strict) {
178  assert(task.get() != NULL);
179 
180  if (task.unique()) { /* A unique pointer won't be in the list. */
181  if (strict) {
182  return false;
183  }
184 
185  push(task, sec, usec, priority);
186 
187  return true;
188  }
189 
190  for (auto it = heap.cbegin(); it != heap.cend(); ++it) {
191  if (*it == task) {
192  (*it)->setDelay(sec, usec);
193  if (priority) (*it)->setPriority(priority);
194  make_heap(heap.begin(), heap.end(), CompareTask());
195 
196  return true;
197  }
198  }
199 
200  if (strict) {
201  return false;
202  }
203 
204  push(task, sec, usec, priority);
205 
206  return true;
207 }
208 
209 bool TaskQueue::repush(Task::shared &task, timeval &tv, int priority, bool strict) {
210  assert(task.get() != NULL);
211 
212  if (task.unique()) { /* A unique pointer won't be in the list. */
213  if (strict) {
214  return false;
215  }
216 
217  push(task, tv, priority);
218 
219  return true;
220  }
221 
222  for (auto it = heap.cbegin(); it != heap.cend(); ++it) {
223  if (*it == task) {
224  (*it)->setTimer(tv);
225  if (priority) (*it)->setPriority(priority);
226  make_heap(heap.begin(), heap.end(), CompareTask());
227 
228  return true;
229  }
230  }
231 
232  if (strict) {
233  return false;
234  }
235 
236  push(task, tv, priority);
237 
238  return true;
239 }
240 
241 void TaskQueue::pop(void) {
242  assert(!heap.empty());
243 
244  pop_heap(heap.begin(), heap.end(), CompareTask());
245  heap.pop_back();
246 }
247 
248 bool TaskQueue::erase(Task::shared &task, bool firstonly) {
249  bool found = false;
250 
251  if (task.unique()) { /* A unique pointer won't be in the list. */
252  return false;
253  }
254 
255  auto it = heap.begin();
256  while (it != heap.end()) {
257  if (*it == task) {
258  it = heap.erase(it);
259 
260  found = true;
261  if (firstonly) break;
262  } else {
263  ++it; /* Faster than it++. */
264  }
265  }
266 
267  make_heap(heap.begin(), heap.end(), CompareTask());
268 
269  return found;
270 }
271 
272 bool TaskQueue::erase(void *object) {
273  bool found = false;
274 
275  auto it = heap.begin();
276  while (it != heap.end()) {
277  if ((*it)->getObject() == object) {
278  it = heap.erase(it);
279 
280  found = true;
281  } else {
282  ++it; /* Faster than it++. */
283  }
284  }
285 
286  make_heap(heap.begin(), heap.end(), CompareTask());
287 
288  return found;
289 }
290 
291 size_t TaskQueue::capacity(void) const {
292  return heap.capacity();
293 }
294 
295 void TaskQueue::reserve(size_t capacity) {
296  heap.reserve(capacity);
297 }
298 
299 void TaskQueue::setLog(Log::shared log) {
300  this->libutilxx__log = log;
301 }
302 
303 bool TaskQueue::isReady(void) const {
304  if (empty()) {
305  return false;
306  }
307 
308  return heap.front()->isReady();
309 }
310 
311 void TaskQueue::print(void) const {
312  Task::shared task;
313  timeval now, timer, delay;
314 
315  if (libutilxx__log == NULL) {
316  return;
317  }
318 
319  gettimeofday(&now, NULL);
320  INFO("[TaskQueue Heap] - now %10lu.%06lu, %zd queued", now.tv_sec, now.tv_usec, heap.size());
321 
322  if (heap.empty()) {
323  INFO(" heap => empty");
324 
325  return;
326  }
327 
328  for (auto it = heap.begin(); it != heap.end(); ++it) {
329  timer = (*it)->getTimer();
330  if (timerisset(&timer)) {
331  /* The output comes out very wrong when timersub() is used. This output is odd, but accurate. */
332  delay.tv_sec = timer.tv_sec - now.tv_sec;
333  delay.tv_usec = timer.tv_usec - now.tv_usec;
334  if (delay.tv_sec > 0 && delay.tv_usec < 0) { /* Only preform the subtraction when tv_sec is > 0. */
335  --delay.tv_sec;
336  delay.tv_usec += 1000000;
337  }
338 
339  INFO(" heap => task(%10p) obj: %10p pri: %3d timer: %10lu.%06lu delay: %4d.%d", (*it).get(), (*it)->getObject(), (*it)->getPriority(), timer.tv_sec, timer.tv_usec, (signed) delay.tv_sec, (signed) delay.tv_usec);
340  } else {
341  INFO(" heap => task(%10p) obj: %10p pri: %3d timer: %10lu.%06lu delay: -inf", (*it).get(), (*it)->getObject(), (*it)->getPriority(), timer.tv_sec, timer.tv_usec);
342  }
343  }
344 }
345 
346 /*
347 ** vim: noet ts=3 sw=3
348 */