OpenSDN source code
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  std::unique_lock<std::mutex> lock(timer_->mutex_);
22 
23  // cancelled task .. ignore
24  if (task_cancelled()) {
25  // Cancelled timer's task releases the ownership of the timer
26  lock.unlock();
27  timer_ = NULL;
28  return true;
29  }
30 
31  // Conditions to invoke user callback met. Fire it
32  timer_->SetState(Timer::Fired);
33  }
34 
35  bool restart = false;
36 
37  // TODO: Is this error needed by user?
38  if (ec_ && !timer_->error_handler_.empty()) {
39  timer_->error_handler_(timer_->name_,
40  std::string(ec_.category().name()),
41  ec_.message());
42  } else {
43  restart = timer_->handler_();
44  }
45 
46  OnTaskCancel();
47 
48  if (restart) {
49  timer_->Start(timer_->time_, timer_->handler_,
50  timer_->error_handler_);
51  } else if (timer_->delete_on_completion_) {
53  }
54  return true;
55  }
56 
57  // Task Cancelled/Destroyed when it was Fired.
58  void OnTaskCancel() {
59  if (!timer_) {
60  return;
61  }
62  std::scoped_lock lock(timer_->mutex_);
63 
64  if (timer_->timer_task_ != this) {
65  assert(!timer_->timer_task_);
66  }
67 
68  timer_->timer_task_ = NULL;
69  timer_->SetState(Timer::Init);
70  }
71 
72  virtual std::string Description() const {
73  return timer_->Description();
74  }
75 
76 private:
78  boost::system::error_code ec_;
80 };
81 
82 Timer::Timer(boost::asio::io_context &service, const std::string &name,
83  int task_id, int task_instance, bool delete_on_completion)
84  : impl_(new TimerImpl(service)),
85  name_(name),
86  handler_(NULL),
87  error_handler_(NULL),
88  state_(Init),
89  timer_task_(NULL),
90  time_(0),
91  task_id_(task_id),
92  task_instance_(task_instance),
93  seq_no_(0),
94  delete_on_completion_(delete_on_completion) {
95  refcount_ = 0;
96 }
97 
99  assert(state_ != Running && state_ != Fired);
100 }
101 
102 //
103 // Start a timer
104 //
105 // If the timer is already running, return silently
106 //
107 bool Timer::Start(int time, Handler handler, ErrorHandler error_handler) {
108  std::scoped_lock lock(mutex_);
109 
110  if (time < 0) {
111  return true;
112  }
113 
114  if (state_ == Running || state_ == Fired) {
115  return true;
116  }
117 
118  // Restart the timer
119  time_ = time;
120  handler_ = handler;
121  seq_no_++;
122  error_handler_ = error_handler;
123  boost::system::error_code ec;
124  impl_->expires_from_now(time, ec);
125  if (ec) {
126  return false;
127  }
128 
129  SetState(Running);
130  impl_->async_wait(
131  boost::bind(&Timer::StartTimerTask, this, TimerPtr(this),
132  time, seq_no_, boost::asio::placeholders::error));
133  return true;
134 }
135 
136 bool Timer::Reschedule(int time)
137 {
138  if (state_ != Fired)
139  return false;
140 
141  if (time < 0)
142  return false;
143 
144  time_ = time;
145  return true;
146 }
147 
148 // Cancel a running timer
150  std::scoped_lock lock(mutex_);
151 
152  // A fired timer cannot be cancelled
153  if (state_ == Fired) {
154  return false;
155  }
156 
157  // Cancel Task. If Task cancel succeeds, there will be no callback.
158  // Reset TaskRef if call succeeds.
159  if (timer_task_) {
162  assert(rc != TaskScheduler::FAILED);
163  timer_task_ = NULL;
164  }
165 
167  return true;
168 }
169 
170 // ASIO callback on timer expiry. Start a task to serve the timer
171 void Timer::StartTimerTask(TimerPtr reference, int time, uint32_t seq_no,
172  const boost::system::error_code &ec) {
173  std::scoped_lock lock(mutex_);
174 
175  if (state_ == Cancelled) {
176  return;
177  }
178 
179  // If timer was cancelled, no callback is invoked
180  if (ec && ec.value() == boost::asio::error::operation_aborted) {
181  return;
182  }
183 
184  // Timer could have fired for previous run. Validate the seq_no_
185  if (seq_no_ != seq_no) {
186  return;
187  }
188  // Start a task and add Task reference.
189  assert(timer_task_ == NULL);
190  timer_task_ = new TimerTask(reference, ec);
192 }
193 
194 //
195 // TimerManager class routines
196 //
198 std::mutex TimerManager::mutex_;
199 
201  boost::asio::io_context &service, const std::string &name,
202  int task_id, int task_instance, bool delete_on_completion) {
203  Timer *timer = new Timer(service, name, task_id, task_instance,
204  delete_on_completion);
205  AddTimer(timer);
206  return timer;
207 }
208 
210  std::scoped_lock lock(mutex_);
211  timer_ref_.insert(TimerPtr(timer));
212 
213  return;
214 }
215 
216 //
217 // Delete a timer object from the data base, by removing the intrusive
218 // reference. If any other objects has a reference to this timer such as
219 // boost::asio, the timer object deletion is automatically deferred
220 //
222  if (!timer || timer->fired()) return false;
223 
224  if (!timer->Cancel() && timer->IsDeleteOnCompletion())
225  return false;
226 
227  std::scoped_lock lock(mutex_);
228  timer_ref_.erase(TimerPtr(timer));
229 
230  return true;
231 }
232 
233 // Get timer's already elapsed time in milliseconds.
234 int64_t Timer::GetElapsedTime() const {
235  std::scoped_lock lock(mutex_);
236  int64_t elapsed;
237 
238 #if __cplusplus >= 201103L
239  elapsed = std::chrono::nanoseconds(impl_->expires_from_now()).count();
240 #else
241  elapsed = boost::chrono::nanoseconds(impl_->expires_from_now()).count();
242 #endif
243 
244  elapsed = time_ - elapsed / 1000000; // Convert nanoseconds to milliseconds.
245  if (elapsed < 0)
246  elapsed = 0;
247  return elapsed;
248 }
CancelReturnCode
Definition: task.h:331
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:642
static TaskScheduler * GetInstance()
Definition: task.cc:554
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:704
Task is a class to describe a computational task within OpenSDN control plane applications....
Definition: task.h:79
bool task_cancelled() const
Returns true if the task has been canceled.
Definition: task.h:150
static TimerSet timer_ref_
Definition: timer.h:226
static std::mutex mutex_
Definition: timer.h:225
std::set< TimerPtr, TimerPtrCmp > TimerSet
Definition: timer.h:222
static bool DeleteTimer(Timer *Timer)
Definition: timer.cc:221
static void AddTimer(Timer *Timer)
Definition: timer.cc:209
boost::intrusive_ptr< Timer > TimerPtr
Definition: timer.h:215
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:200
virtual std::string Description() const
Gives a description of the task.
Definition: timer.cc:72
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:58
TimerPtr timer_
Definition: timer.cc:77
DISALLOW_COPY_AND_ASSIGN(TimerTask)
TimerTask(TimerPtr timer, boost::system::error_code ec)
Definition: timer.cc:10
virtual ~TimerTask()
Definition: timer.cc:14
boost::system::error_code ec_
Definition: timer.cc:78
virtual bool Run()
Code to execute in a task. Returns true if task is completed. Return false to reschedule the task.
Definition: timer.cc:19
Definition: timer.h:57
@ Running
Definition: timer.h:143
@ Init
Definition: timer.h:142
@ Fired
Definition: timer.h:144
@ Cancelled
Definition: timer.h:145
bool IsDeleteOnCompletion() const
Definition: timer.h:113
int task_id_
Definition: timer.h:173
virtual ~Timer()
Definition: timer.cc:98
void SetState(TimerState s)
Definition: timer.h:153
bool Cancel()
Definition: timer.cc:149
int task_instance_
Definition: timer.h:174
Timer(boost::asio::io_context &service, const std::string &name, int task_id, int task_instance, bool delete_on_completion=false)
Definition: timer.cc:82
uint32_t seq_no_
Definition: timer.h:175
boost::scoped_ptr< TimerImpl > impl_
Definition: timer.h:165
std::mutex mutex_
Definition: timer.h:169
TimerState state_
Definition: timer.h:170
int64_t GetElapsedTime() const
Definition: timer.cc:234
ErrorHandler error_handler_
Definition: timer.h:168
bool Start(int time, Handler handler, ErrorHandler error_handler=NULL)
Definition: timer.cc:107
boost::intrusive_ptr< Timer > TimerPtr
Definition: timer.h:139
int time_
Definition: timer.h:172
TimerTask * timer_task_
Definition: timer.h:171
Handler handler_
Definition: timer.h:167
boost::function< bool(void)> Handler
Definition: timer.h:60
void StartTimerTask(TimerPtr reference, int time, uint32_t seq_no, const boost::system::error_code &ec)
Definition: timer.cc:171
bool Reschedule(int time)
Definition: timer.cc:136
boost::function< void(std::string, std::string, std::string)> ErrorHandler
Definition: timer.h:65
std::atomic< int > refcount_
Definition: timer.h:177
bool fired() const
Definition: timer.h:94
int time() const
Definition: timer.h:99