Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:28:45

0001 //
0002 // detail/timer_queue.hpp
0003 // ~~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
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 // defined(_MSC_VER) && (_MSC_VER >= 1200)
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   // The time type.
0041   typedef typename Time_Traits::time_type time_type;
0042 
0043   // The duration type.
0044   typedef typename Time_Traits::duration_type duration_type;
0045 
0046   // Per-timer data.
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     // The operations waiting on the timer.
0060     op_queue<wait_op> op_queue_;
0061 
0062     // The index of the timer in the heap.
0063     std::size_t heap_index_;
0064 
0065     // Pointers to adjacent timers in a linked list.
0066     per_timer_data* next_;
0067     per_timer_data* prev_;
0068   };
0069 
0070   // Constructor.
0071   timer_queue()
0072     : timers_(),
0073       heap_()
0074   {
0075   }
0076 
0077   // Add a new timer to the queue. Returns true if this is the timer that is
0078   // earliest in the queue, in which case the reactor's event demultiplexing
0079   // function call may need to be interrupted and restarted.
0080   bool enqueue_timer(const time_type& time, per_timer_data& timer, wait_op* op)
0081   {
0082     // Enqueue the timer object.
0083     if (timer.prev_ == 0 && &timer != timers_)
0084     {
0085       if (this->is_positive_infinity(time))
0086       {
0087         // No heap entry is required for timers that never expire.
0088         timer.heap_index_ = (std::numeric_limits<std::size_t>::max)();
0089       }
0090       else
0091       {
0092         // Put the new timer at the correct position in the heap. This is done
0093         // first since push_back() can throw due to allocation failure.
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       // Insert the new timer into the linked list of active timers.
0101       timer.next_ = timers_;
0102       timer.prev_ = 0;
0103       if (timers_)
0104         timers_->prev_ = &timer;
0105       timers_ = &timer;
0106     }
0107 
0108     // Enqueue the individual timer operation.
0109     timer.op_queue_.push(op);
0110 
0111     // Interrupt reactor only if newly added timer is first to expire.
0112     return timer.heap_index_ == 0 && timer.op_queue_.front() == op;
0113   }
0114 
0115   // Whether there are no timers in the queue.
0116   virtual bool empty() const
0117   {
0118     return timers_ == 0;
0119   }
0120 
0121   // Get the time for the timer that is earliest in the queue.
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   // Get the time for the timer that is earliest in the queue.
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   // Dequeue all timers not later than the current time.
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   // Dequeue all timers.
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   // Cancel and dequeue operations for the given timer.
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   // Cancel and dequeue a specific operation for the given timer.
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   // Move operations from one timer to another, empty timer.
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_ = &target;
0235 
0236     if (timers_ == &source)
0237       timers_ = &target;
0238     if (source.prev_)
0239       source.prev_->next_ = &target;
0240     if (source.next_)
0241       source.next_->prev_= &target;
0242     target.next_ = source.next_;
0243     target.prev_ = source.prev_;
0244     source.next_ = 0;
0245     source.prev_ = 0;
0246   }
0247 
0248 private:
0249   // Move the item at the given index up the heap to its correct position.
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   // Move the item at the given index down the heap to its correct position.
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   // Swap two entries in the heap.
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   // Remove a timer from the heap and list of timers.
0291   void remove_timer(per_timer_data& timer)
0292   {
0293     // Remove the timer from the heap.
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     // Remove the timer from the linked list of active timers.
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   // Determine if the specified absolute time is positive infinity.
0327   template <typename Time_Type>
0328   static bool is_positive_infinity(const Time_Type&)
0329   {
0330     return false;
0331   }
0332 
0333   // Determine if the specified absolute time is positive infinity.
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   // Helper function to convert a duration into milliseconds.
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   // Helper function to convert a duration into microseconds.
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   // The head of a linked list of all active timers.
0370   per_timer_data* timers_;
0371 
0372   struct heap_entry
0373   {
0374     // The time when the timer should fire.
0375     time_type time_;
0376 
0377     // The associated timer with enqueued operations.
0378     per_timer_data* timer_;
0379   };
0380 
0381   // The heap of timers, with the earliest timer at the front.
0382   std::vector<heap_entry> heap_;
0383 };
0384 
0385 } // namespace detail
0386 } // namespace asio
0387 } // namespace boost
0388 
0389 #include <boost/asio/detail/pop_options.hpp>
0390 
0391 #endif // BOOST_ASIO_DETAIL_TIMER_QUEUE_HPP