OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
timer.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 #include "base/timer.h"
6 #include "base/timer_impl.h"
7 
8 class Timer::TimerTask : public Task {
9 public:
10  TimerTask(TimerPtr timer, boost::system::error_code ec)
11  : Task(timer->task_id_, timer->task_instance_), timer_(timer), ec_(ec) {
12  }
13 
14  virtual ~TimerTask() {
15  }
16 
17  // Invokes user callback.
18  // Timer could have been cancelled or delete when task was enqueued
19  virtual bool Run() {
20  {
21  tbb::mutex::scoped_lock lock(timer_->mutex_);
22 
23  // cancelled task .. ignore
24  if (task_cancelled()) {
25  // Cancelled timer's task releases the ownership of the timer
26 
27  lock.release();
28  timer_ = NULL;
29  return true;
30  }
31 
32  // Conditions to invoke user callback met. Fire it
33  timer_->SetState(Timer::Fired);
34  }
35 
36  bool restart = false;
37 
38  // TODO: Is this error needed by user?
39  if (ec_ && !timer_->error_handler_.empty()) {
40  timer_->error_handler_(timer_->name_,
41  std::string(ec_.category().name()),
42  ec_.message());
43  } else {
44  restart = timer_->handler_();
45  }
46 
47  OnTaskCancel();
48 
49  if (restart) {
50  timer_->Start(timer_->time_, timer_->handler_,
51  timer_->error_handler_);
52  } else if (timer_->delete_on_completion_) {
54  }
55  return true;
56  }
57 
58  // Task Cancelled/Destroyed when it was Fired.
59  void OnTaskCancel() {
60  if (!timer_) {
61  return;
62  }
63  tbb::mutex::scoped_lock lock(timer_->mutex_);
64 
65  if (timer_->timer_task_ != this) {
66  assert(!timer_->timer_task_);
67  }
68 
69  timer_->timer_task_ = NULL;
70  timer_->SetState(Timer::Init);
71  }
72 
73  virtual std::string Description() const {
74  return timer_->Description();
75  }
76 
77 private:
79  boost::system::error_code ec_;
81 };
82 
83 Timer::Timer(boost::asio::io_context &service, const std::string &name,
84  int task_id, int task_instance, bool delete_on_completion)
85  : impl_(new TimerImpl(service)),
86  name_(name),
87  handler_(NULL),
88  error_handler_(NULL),
89  state_(Init),
90  timer_task_(NULL),
91  time_(0),
92  task_id_(task_id),
93  task_instance_(task_instance),
94  seq_no_(0),
95  delete_on_completion_(delete_on_completion) {
96  refcount_ = 0;
97 }
98 
100  assert(state_ != Running && state_ != Fired);
101 }
102 
103 //
104 // Start a timer
105 //
106 // If the timer is already running, return silently
107 //
108 bool Timer::Start(int time, Handler handler, ErrorHandler error_handler) {
109  tbb::mutex::scoped_lock lock(mutex_);
110 
111  if (time < 0) {
112  return true;
113  }
114 
115  if (state_ == Running || state_ == Fired) {
116  return true;
117  }
118 
119  // Restart the timer
120  time_ = time;
121  handler_ = handler;
122  seq_no_++;
123  error_handler_ = error_handler;
124  boost::system::error_code ec;
125  impl_->expires_from_now(time, ec);
126  if (ec) {
127  return false;
128  }
129 
130  SetState(Running);
131  impl_->async_wait(
132  boost::bind(&Timer::StartTimerTask, this, TimerPtr(this),
133  time, seq_no_, boost::asio::placeholders::error));
134  return true;
135 }
136 
137 bool Timer::Reschedule(int time)
138 {
139  if (state_ != Fired)
140  return false;
141 
142  if (time < 0)
143  return false;
144 
145  time_ = time;
146  return true;
147 }
148 
149 // Cancel a running timer
151  tbb::mutex::scoped_lock lock(mutex_);
152 
153  // A fired timer cannot be cancelled
154  if (state_ == Fired) {
155  return false;
156  }
157 
158  // Cancel Task. If Task cancel succeeds, there will be no callback.
159  // Reset TaskRef if call succeeds.
160  if (timer_task_) {
163  assert(rc != TaskScheduler::FAILED);
164  timer_task_ = NULL;
165  }
166 
168  return true;
169 }
170 
171 // ASIO callback on timer expiry. Start a task to serve the timer
172 void Timer::StartTimerTask(TimerPtr reference, int time, uint32_t seq_no,
173  const boost::system::error_code &ec) {
174  tbb::mutex::scoped_lock lock(mutex_);
175 
176  if (state_ == Cancelled) {
177  return;
178  }
179 
180  // If timer was cancelled, no callback is invoked
181  if (ec && ec.value() == boost::asio::error::operation_aborted) {
182  return;
183  }
184 
185  // Timer could have fired for previous run. Validate the seq_no_
186  if (seq_no_ != seq_no) {
187  return;
188  }
189  // Start a task and add Task reference.
190  assert(timer_task_ == NULL);
191  timer_task_ = new TimerTask(reference, ec);
193 }
194 
195 //
196 // TimerManager class routines
197 //
199 tbb::mutex TimerManager::mutex_;
200 
202  boost::asio::io_context &service, const std::string &name,
203  int task_id, int task_instance, bool delete_on_completion) {
204  Timer *timer = new Timer(service, name, task_id, task_instance,
205  delete_on_completion);
206  AddTimer(timer);
207  return timer;
208 }
209 
211  tbb::mutex::scoped_lock lock(mutex_);
212  timer_ref_.insert(TimerPtr(timer));
213 
214  return;
215 }
216 
217 //
218 // Delete a timer object from the data base, by removing the intrusive
219 // reference. If any other objects has a reference to this timer such as
220 // boost::asio, the timer object deletion is automatically deferred
221 //
223  if (!timer || timer->fired()) return false;
224 
225  if (!timer->Cancel() && timer->IsDeleteOnCompletion())
226  return false;
227 
228  tbb::mutex::scoped_lock lock(mutex_);
229  timer_ref_.erase(TimerPtr(timer));
230 
231  return true;
232 }
233 
234 // Get timer's already elapsed time in milliseconds.
235 int64_t Timer::GetElapsedTime() const {
236  tbb::mutex::scoped_lock lock(mutex_);
237  int64_t elapsed;
238 
239 #if __cplusplus >= 201103L
240  elapsed = std::chrono::nanoseconds(impl_->expires_from_now()).count();
241 #else
242  elapsed = boost::chrono::nanoseconds(impl_->expires_from_now()).count();
243 #endif
244 
245  elapsed = time_ - elapsed / 1000000; // Convert nanoseconds to milliseconds.
246  if (elapsed < 0)
247  elapsed = 0;
248  return elapsed;
249 }
int task_id_
The code path executed by the task.
Definition: task.h:149
tbb::atomic< int > refcount_
Definition: timer.h:174
boost::intrusive_ptr< Timer > TimerPtr
Definition: timer.h:136
void OnTaskCancel()
Called on task exit, if it is marked for cancellation. If the user wants to do any cleanup on task ca...
Definition: timer.cc:59
CancelReturnCode
Definition: task.h:205
std::set< TimerPtr, TimerPtrCmp > TimerSet
Definition: timer.h:219
virtual ~Timer()
Definition: timer.cc:99
Handler handler_
Definition: timer.h:164
TimerTask(TimerPtr timer, boost::system::error_code ec)
Definition: timer.cc:10
boost::function< bool(void)> Handler
Definition: timer.h:57
uint32_t seq_no_
Definition: timer.h:172
bool IsDeleteOnCompletion() const
Definition: timer.h:110
boost::system::error_code ec_
Definition: timer.cc:79
TimerTask * timer_task_
Definition: timer.h:168
CancelReturnCode Cancel(Task *task)
Cancels a Task that can be in RUN/WAIT state. The caller needs to ensure that the task exists when Ca...
Definition: task.cc:699
tbb::mutex mutex_
Definition: timer.h:166
boost::scoped_ptr< TimerImpl > impl_
Definition: timer.h:162
virtual bool Run()
Code to execute. Returns true if task is completed. Return false to reschedule the task...
Definition: timer.cc:19
bool fired() const
Definition: timer.h:91
ErrorHandler error_handler_
Definition: timer.h:165
bool task_cancelled() const
Definition: task.h:127
static TaskScheduler * GetInstance()
Definition: task.cc:547
void Enqueue(Task *task)
Enqueues a task for running. Starts task if all policy rules are met else puts task in waitq...
Definition: task.cc:636
void SetState(TimerState s)
Definition: timer.h:150
int time_
Definition: timer.h:169
Timer(boost::asio::io_context &service, const std::string &name, int task_id, int task_instance, bool delete_on_completion=false)
Definition: timer.cc:83
DISALLOW_COPY_AND_ASSIGN(TimerTask)
TimerPtr timer_
Definition: timer.cc:78
static Timer * CreateTimer(boost::asio::io_context &service, const std::string &name, int task_id=Timer::GetTimerTaskId(), int task_instance=Timer::GetTimerInstanceId(), bool delete_on_completion=false)
Definition: timer.cc:201
static tbb::mutex mutex_
Definition: timer.h:222
bool Cancel()
Definition: timer.cc:150
boost::intrusive_ptr< Timer > TimerPtr
Definition: timer.h:212
virtual std::string Description() const
Definition: timer.cc:73
boost::function< void(std::string, std::string, std::string)> ErrorHandler
Definition: timer.h:62
virtual ~TimerTask()
Definition: timer.cc:14
bool Start(int time, Handler handler, ErrorHandler error_handler=NULL)
Definition: timer.cc:108
static TimerSet timer_ref_
Definition: timer.h:223
TimerState state_
Definition: timer.h:167
int task_instance_
The dataset id within a code path.
Definition: task.h:152
bool Reschedule(int time)
Definition: timer.cc:137
Definition: timer.h:54
int64_t GetElapsedTime() const
Definition: timer.cc:235
Task is a wrapper over tbb::task to support policies.
Definition: task.h:86
int time() const
Definition: timer.h:96
static bool DeleteTimer(Timer *Timer)
Definition: timer.cc:222
static void AddTimer(Timer *Timer)
Definition: timer.cc:210
void StartTimerTask(TimerPtr reference, int time, uint32_t seq_no, const boost::system::error_code &ec)
Definition: timer.cc:172