File indexing completed on 2025-01-18 09:28:45
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_ASIO_DETAIL_TIMER_QUEUE_HPP
0012 #define BOOST_ASIO_DETAIL_TIMER_QUEUE_HPP
0013
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif
0017
0018 #include <boost/asio/detail/config.hpp>
0019 #include <cstddef>
0020 #include <vector>
0021 #include <boost/asio/detail/cstdint.hpp>
0022 #include <boost/asio/detail/date_time_fwd.hpp>
0023 #include <boost/asio/detail/limits.hpp>
0024 #include <boost/asio/detail/op_queue.hpp>
0025 #include <boost/asio/detail/timer_queue_base.hpp>
0026 #include <boost/asio/detail/wait_op.hpp>
0027 #include <boost/asio/error.hpp>
0028
0029 #include <boost/asio/detail/push_options.hpp>
0030
0031 namespace boost {
0032 namespace asio {
0033 namespace detail {
0034
0035 template <typename Time_Traits>
0036 class timer_queue
0037 : public timer_queue_base
0038 {
0039 public:
0040
0041 typedef typename Time_Traits::time_type time_type;
0042
0043
0044 typedef typename Time_Traits::duration_type duration_type;
0045
0046
0047 class per_timer_data
0048 {
0049 public:
0050 per_timer_data() :
0051 heap_index_((std::numeric_limits<std::size_t>::max)()),
0052 next_(0), prev_(0)
0053 {
0054 }
0055
0056 private:
0057 friend class timer_queue;
0058
0059
0060 op_queue<wait_op> op_queue_;
0061
0062
0063 std::size_t heap_index_;
0064
0065
0066 per_timer_data* next_;
0067 per_timer_data* prev_;
0068 };
0069
0070
0071 timer_queue()
0072 : timers_(),
0073 heap_()
0074 {
0075 }
0076
0077
0078
0079
0080 bool enqueue_timer(const time_type& time, per_timer_data& timer, wait_op* op)
0081 {
0082
0083 if (timer.prev_ == 0 && &timer != timers_)
0084 {
0085 if (this->is_positive_infinity(time))
0086 {
0087
0088 timer.heap_index_ = (std::numeric_limits<std::size_t>::max)();
0089 }
0090 else
0091 {
0092
0093
0094 timer.heap_index_ = heap_.size();
0095 heap_entry entry = { time, &timer };
0096 heap_.push_back(entry);
0097 up_heap(heap_.size() - 1);
0098 }
0099
0100
0101 timer.next_ = timers_;
0102 timer.prev_ = 0;
0103 if (timers_)
0104 timers_->prev_ = &timer;
0105 timers_ = &timer;
0106 }
0107
0108
0109 timer.op_queue_.push(op);
0110
0111
0112 return timer.heap_index_ == 0 && timer.op_queue_.front() == op;
0113 }
0114
0115
0116 virtual bool empty() const
0117 {
0118 return timers_ == 0;
0119 }
0120
0121
0122 virtual long wait_duration_msec(long max_duration) const
0123 {
0124 if (heap_.empty())
0125 return max_duration;
0126
0127 return this->to_msec(
0128 Time_Traits::to_posix_duration(
0129 Time_Traits::subtract(heap_[0].time_, Time_Traits::now())),
0130 max_duration);
0131 }
0132
0133
0134 virtual long wait_duration_usec(long max_duration) const
0135 {
0136 if (heap_.empty())
0137 return max_duration;
0138
0139 return this->to_usec(
0140 Time_Traits::to_posix_duration(
0141 Time_Traits::subtract(heap_[0].time_, Time_Traits::now())),
0142 max_duration);
0143 }
0144
0145
0146 virtual void get_ready_timers(op_queue<operation>& ops)
0147 {
0148 if (!heap_.empty())
0149 {
0150 const time_type now = Time_Traits::now();
0151 while (!heap_.empty() && !Time_Traits::less_than(now, heap_[0].time_))
0152 {
0153 per_timer_data* timer = heap_[0].timer_;
0154 while (wait_op* op = timer->op_queue_.front())
0155 {
0156 timer->op_queue_.pop();
0157 op->ec_ = boost::system::error_code();
0158 ops.push(op);
0159 }
0160 remove_timer(*timer);
0161 }
0162 }
0163 }
0164
0165
0166 virtual void get_all_timers(op_queue<operation>& ops)
0167 {
0168 while (timers_)
0169 {
0170 per_timer_data* timer = timers_;
0171 timers_ = timers_->next_;
0172 ops.push(timer->op_queue_);
0173 timer->next_ = 0;
0174 timer->prev_ = 0;
0175 }
0176
0177 heap_.clear();
0178 }
0179
0180
0181 std::size_t cancel_timer(per_timer_data& timer, op_queue<operation>& ops,
0182 std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)())
0183 {
0184 std::size_t num_cancelled = 0;
0185 if (timer.prev_ != 0 || &timer == timers_)
0186 {
0187 while (wait_op* op = (num_cancelled != max_cancelled)
0188 ? timer.op_queue_.front() : 0)
0189 {
0190 op->ec_ = boost::asio::error::operation_aborted;
0191 timer.op_queue_.pop();
0192 ops.push(op);
0193 ++num_cancelled;
0194 }
0195 if (timer.op_queue_.empty())
0196 remove_timer(timer);
0197 }
0198 return num_cancelled;
0199 }
0200
0201
0202 void cancel_timer_by_key(per_timer_data* timer,
0203 op_queue<operation>& ops, void* cancellation_key)
0204 {
0205 if (timer->prev_ != 0 || timer == timers_)
0206 {
0207 op_queue<wait_op> other_ops;
0208 while (wait_op* op = timer->op_queue_.front())
0209 {
0210 timer->op_queue_.pop();
0211 if (op->cancellation_key_ == cancellation_key)
0212 {
0213 op->ec_ = boost::asio::error::operation_aborted;
0214 ops.push(op);
0215 }
0216 else
0217 other_ops.push(op);
0218 }
0219 timer->op_queue_.push(other_ops);
0220 if (timer->op_queue_.empty())
0221 remove_timer(*timer);
0222 }
0223 }
0224
0225
0226 void move_timer(per_timer_data& target, per_timer_data& source)
0227 {
0228 target.op_queue_.push(source.op_queue_);
0229
0230 target.heap_index_ = source.heap_index_;
0231 source.heap_index_ = (std::numeric_limits<std::size_t>::max)();
0232
0233 if (target.heap_index_ < heap_.size())
0234 heap_[target.heap_index_].timer_ = ⌖
0235
0236 if (timers_ == &source)
0237 timers_ = ⌖
0238 if (source.prev_)
0239 source.prev_->next_ = ⌖
0240 if (source.next_)
0241 source.next_->prev_= ⌖
0242 target.next_ = source.next_;
0243 target.prev_ = source.prev_;
0244 source.next_ = 0;
0245 source.prev_ = 0;
0246 }
0247
0248 private:
0249
0250 void up_heap(std::size_t index)
0251 {
0252 while (index > 0)
0253 {
0254 std::size_t parent = (index - 1) / 2;
0255 if (!Time_Traits::less_than(heap_[index].time_, heap_[parent].time_))
0256 break;
0257 swap_heap(index, parent);
0258 index = parent;
0259 }
0260 }
0261
0262
0263 void down_heap(std::size_t index)
0264 {
0265 std::size_t child = index * 2 + 1;
0266 while (child < heap_.size())
0267 {
0268 std::size_t min_child = (child + 1 == heap_.size()
0269 || Time_Traits::less_than(
0270 heap_[child].time_, heap_[child + 1].time_))
0271 ? child : child + 1;
0272 if (Time_Traits::less_than(heap_[index].time_, heap_[min_child].time_))
0273 break;
0274 swap_heap(index, min_child);
0275 index = min_child;
0276 child = index * 2 + 1;
0277 }
0278 }
0279
0280
0281 void swap_heap(std::size_t index1, std::size_t index2)
0282 {
0283 heap_entry tmp = heap_[index1];
0284 heap_[index1] = heap_[index2];
0285 heap_[index2] = tmp;
0286 heap_[index1].timer_->heap_index_ = index1;
0287 heap_[index2].timer_->heap_index_ = index2;
0288 }
0289
0290
0291 void remove_timer(per_timer_data& timer)
0292 {
0293
0294 std::size_t index = timer.heap_index_;
0295 if (!heap_.empty() && index < heap_.size())
0296 {
0297 if (index == heap_.size() - 1)
0298 {
0299 timer.heap_index_ = (std::numeric_limits<std::size_t>::max)();
0300 heap_.pop_back();
0301 }
0302 else
0303 {
0304 swap_heap(index, heap_.size() - 1);
0305 timer.heap_index_ = (std::numeric_limits<std::size_t>::max)();
0306 heap_.pop_back();
0307 if (index > 0 && Time_Traits::less_than(
0308 heap_[index].time_, heap_[(index - 1) / 2].time_))
0309 up_heap(index);
0310 else
0311 down_heap(index);
0312 }
0313 }
0314
0315
0316 if (timers_ == &timer)
0317 timers_ = timer.next_;
0318 if (timer.prev_)
0319 timer.prev_->next_ = timer.next_;
0320 if (timer.next_)
0321 timer.next_->prev_= timer.prev_;
0322 timer.next_ = 0;
0323 timer.prev_ = 0;
0324 }
0325
0326
0327 template <typename Time_Type>
0328 static bool is_positive_infinity(const Time_Type&)
0329 {
0330 return false;
0331 }
0332
0333
0334 template <typename T, typename TimeSystem>
0335 static bool is_positive_infinity(
0336 const boost::date_time::base_time<T, TimeSystem>& time)
0337 {
0338 return time.is_pos_infinity();
0339 }
0340
0341
0342 template <typename Duration>
0343 long to_msec(const Duration& d, long max_duration) const
0344 {
0345 if (d.ticks() <= 0)
0346 return 0;
0347 int64_t msec = d.total_milliseconds();
0348 if (msec == 0)
0349 return 1;
0350 if (msec > max_duration)
0351 return max_duration;
0352 return static_cast<long>(msec);
0353 }
0354
0355
0356 template <typename Duration>
0357 long to_usec(const Duration& d, long max_duration) const
0358 {
0359 if (d.ticks() <= 0)
0360 return 0;
0361 int64_t usec = d.total_microseconds();
0362 if (usec == 0)
0363 return 1;
0364 if (usec > max_duration)
0365 return max_duration;
0366 return static_cast<long>(usec);
0367 }
0368
0369
0370 per_timer_data* timers_;
0371
0372 struct heap_entry
0373 {
0374
0375 time_type time_;
0376
0377
0378 per_timer_data* timer_;
0379 };
0380
0381
0382 std::vector<heap_entry> heap_;
0383 };
0384
0385 }
0386 }
0387 }
0388
0389 #include <boost/asio/detail/pop_options.hpp>
0390
0391 #endif