Line data Source code
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 76591 : TimerTask(TimerPtr timer, boost::system::error_code ec)
11 76591 : : Task(timer->task_id_, timer->task_instance_), timer_(timer), ec_(ec) {
12 76591 : }
13 :
14 153182 : virtual ~TimerTask() {
15 153182 : }
16 :
17 : // Invokes user callback.
18 : // Timer could have been cancelled or delete when task was enqueued
19 76373 : virtual bool Run() {
20 : {
21 76373 : std::unique_lock<std::mutex> lock(timer_->mutex_);
22 :
23 : // cancelled task .. ignore
24 76410 : if (task_cancelled()) {
25 : // Cancelled timer's task releases the ownership of the timer
26 1 : lock.unlock();
27 1 : timer_ = NULL;
28 1 : return true;
29 : }
30 :
31 : // Conditions to invoke user callback met. Fire it
32 76363 : timer_->SetState(Timer::Fired);
33 76373 : }
34 :
35 76409 : bool restart = false;
36 :
37 : // TODO: Is this error needed by user?
38 76409 : if (ec_ && !timer_->error_handler_.empty()) {
39 0 : timer_->error_handler_(timer_->name_,
40 0 : std::string(ec_.category().name()),
41 0 : ec_.message());
42 : } else {
43 76398 : restart = timer_->handler_();
44 : }
45 :
46 76436 : OnTaskCancel();
47 :
48 76421 : if (restart) {
49 69080 : timer_->Start(timer_->time_, timer_->handler_,
50 34559 : timer_->error_handler_);
51 41854 : } else if (timer_->delete_on_completion_) {
52 163 : TimerManager::DeleteTimer(timer_.get());
53 : }
54 76465 : return true;
55 : }
56 :
57 : // Task Cancelled/Destroyed when it was Fired.
58 76435 : void OnTaskCancel() {
59 76435 : if (!timer_) {
60 1 : return;
61 : }
62 76426 : std::scoped_lock lock(timer_->mutex_);
63 :
64 76392 : if (timer_->timer_task_ != this) {
65 0 : assert(!timer_->timer_task_);
66 : }
67 :
68 76364 : timer_->timer_task_ = NULL;
69 76353 : timer_->SetState(Timer::Init);
70 76322 : }
71 :
72 0 : virtual std::string Description() const {
73 0 : return timer_->Description();
74 : }
75 :
76 : private:
77 : TimerPtr timer_;
78 : boost::system::error_code ec_;
79 : DISALLOW_COPY_AND_ASSIGN(TimerTask);
80 : };
81 :
82 397797 : Timer::Timer(boost::asio::io_context &service, const std::string &name,
83 397797 : int task_id, int task_instance, bool delete_on_completion)
84 397798 : : impl_(new TimerImpl(service)),
85 397795 : name_(name),
86 397794 : handler_(NULL),
87 397793 : error_handler_(NULL),
88 397794 : state_(Init),
89 397794 : timer_task_(NULL),
90 397794 : time_(0),
91 397794 : task_id_(task_id),
92 397794 : task_instance_(task_instance),
93 397794 : seq_no_(0),
94 795591 : delete_on_completion_(delete_on_completion) {
95 397794 : refcount_ = 0;
96 397798 : }
97 :
98 792764 : Timer::~Timer() {
99 396382 : assert(state_ != Running && state_ != Fired);
100 792764 : }
101 :
102 : //
103 : // Start a timer
104 : //
105 : // If the timer is already running, return silently
106 : //
107 5144763 : bool Timer::Start(int time, Handler handler, ErrorHandler error_handler) {
108 5144763 : std::scoped_lock lock(mutex_);
109 :
110 5145042 : if (time < 0) {
111 138 : return true;
112 : }
113 :
114 5144904 : if (state_ == Running || state_ == Fired) {
115 183408 : return true;
116 : }
117 :
118 : // Restart the timer
119 4961496 : time_ = time;
120 4961496 : handler_ = handler;
121 4960767 : seq_no_++;
122 4960767 : error_handler_ = error_handler;
123 4960565 : boost::system::error_code ec;
124 4960565 : impl_->expires_from_now(time, ec);
125 4961492 : if (ec) {
126 0 : return false;
127 : }
128 :
129 4961478 : SetState(Running);
130 9922937 : impl_->async_wait(
131 9923003 : boost::bind(&Timer::StartTimerTask, this, TimerPtr(this),
132 : time, seq_no_, boost::asio::placeholders::error));
133 4961592 : return true;
134 5145138 : }
135 :
136 11588 : bool Timer::Reschedule(int time)
137 : {
138 11588 : if (state_ != Fired)
139 183 : return false;
140 :
141 11405 : if (time < 0)
142 0 : return false;
143 :
144 11405 : time_ = time;
145 11405 : return true;
146 : }
147 :
148 : // Cancel a running timer
149 5975065 : bool Timer::Cancel() {
150 5975065 : std::scoped_lock lock(mutex_);
151 :
152 : // A fired timer cannot be cancelled
153 5975184 : if (state_ == Fired) {
154 4601 : return false;
155 : }
156 :
157 : // Cancel Task. If Task cancel succeeds, there will be no callback.
158 : // Reset TaskRef if call succeeds.
159 5970583 : if (timer_task_) {
160 : TaskScheduler::CancelReturnCode rc =
161 126 : TaskScheduler::GetInstance()->Cancel(timer_task_);
162 126 : assert(rc != TaskScheduler::FAILED);
163 126 : timer_task_ = NULL;
164 : }
165 :
166 5970583 : SetState(Cancelled);
167 5970506 : return true;
168 5975107 : }
169 :
170 : // ASIO callback on timer expiry. Start a task to serve the timer
171 4878612 : void Timer::StartTimerTask(TimerPtr reference, int time, uint32_t seq_no,
172 : const boost::system::error_code &ec) {
173 4878612 : std::scoped_lock lock(mutex_);
174 :
175 4878613 : if (state_ == Cancelled) {
176 26470 : return;
177 : }
178 :
179 : // If timer was cancelled, no callback is invoked
180 4852143 : if (ec && ec.value() == boost::asio::error::operation_aborted) {
181 4775549 : return;
182 : }
183 :
184 : // Timer could have fired for previous run. Validate the seq_no_
185 76593 : if (seq_no_ != seq_no) {
186 2 : return;
187 : }
188 : // Start a task and add Task reference.
189 76591 : assert(timer_task_ == NULL);
190 76591 : timer_task_ = new TimerTask(reference, ec);
191 76591 : TaskScheduler::GetInstance()->Enqueue(timer_task_);
192 4878612 : }
193 :
194 : //
195 : // TimerManager class routines
196 : //
197 : TimerManager::TimerSet TimerManager::timer_ref_;
198 : std::mutex TimerManager::mutex_;
199 :
200 397796 : Timer *TimerManager::CreateTimer(
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 397796 : delete_on_completion);
205 397796 : AddTimer(timer);
206 397799 : return timer;
207 : }
208 :
209 397796 : void TimerManager::AddTimer(Timer *timer) {
210 397796 : std::scoped_lock lock(mutex_);
211 397799 : timer_ref_.insert(TimerPtr(timer));
212 :
213 795598 : return;
214 397799 : }
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 : //
221 392434 : bool TimerManager::DeleteTimer(Timer *timer) {
222 392434 : if (!timer || timer->fired()) return false;
223 :
224 380430 : if (!timer->Cancel() && timer->IsDeleteOnCompletion())
225 0 : return false;
226 :
227 380430 : std::scoped_lock lock(mutex_);
228 380430 : timer_ref_.erase(TimerPtr(timer));
229 :
230 380430 : return true;
231 380430 : }
232 :
233 : // Get timer's already elapsed time in milliseconds.
234 752 : int64_t Timer::GetElapsedTime() const {
235 752 : std::scoped_lock lock(mutex_);
236 : int64_t elapsed;
237 :
238 : #if __cplusplus >= 201103L
239 752 : 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 752 : elapsed = time_ - elapsed / 1000000; // Convert nanoseconds to milliseconds.
245 752 : if (elapsed < 0)
246 0 : elapsed = 0;
247 752 : return elapsed;
248 752 : }
|