00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #ifndef ASIO_DETAIL_TIMER_QUEUE_HPP
00012 #define ASIO_DETAIL_TIMER_QUEUE_HPP
00013
00014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
00015 # pragma once
00016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
00017
00018 #include "asio/detail/push_options.hpp"
00019
00020 #include "asio/detail/push_options.hpp"
00021 #include <cstddef>
00022 #include <functional>
00023 #include <limits>
00024 #include <memory>
00025 #include <vector>
00026 #include <boost/config.hpp>
00027 #include "asio/detail/pop_options.hpp"
00028
00029 #include "asio/error.hpp"
00030 #include "asio/detail/hash_map.hpp"
00031 #include "asio/detail/noncopyable.hpp"
00032 #include "asio/detail/timer_queue_base.hpp"
00033
00034 namespace asio {
00035 namespace detail {
00036
00037 template <typename Time_Traits>
00038 class timer_queue
00039 : public timer_queue_base
00040 {
00041 public:
00042
00043 typedef typename Time_Traits::time_type time_type;
00044
00045
00046 typedef typename Time_Traits::duration_type duration_type;
00047
00048
00049 timer_queue()
00050 : timers_(),
00051 heap_()
00052 {
00053 }
00054
00055
00056
00057
00058 template <typename Handler>
00059 bool enqueue_timer(const time_type& time, Handler handler, void* token)
00060 {
00061
00062
00063 heap_.reserve(heap_.size() + 1);
00064
00065
00066 std::auto_ptr<timer<Handler> > new_timer(
00067 new timer<Handler>(time, handler, token));
00068
00069
00070 typedef typename hash_map<void*, timer_base*>::iterator iterator;
00071 typedef typename hash_map<void*, timer_base*>::value_type value_type;
00072 std::pair<iterator, bool> result =
00073 timers_.insert(value_type(token, new_timer.get()));
00074 if (!result.second)
00075 {
00076 result.first->second->prev_ = new_timer.get();
00077 new_timer->next_ = result.first->second;
00078 result.first->second = new_timer.get();
00079 }
00080
00081
00082 new_timer->heap_index_ = heap_.size();
00083 heap_.push_back(new_timer.get());
00084 up_heap(heap_.size() - 1);
00085 bool is_first = (heap_[0] == new_timer.get());
00086
00087
00088 new_timer.release();
00089
00090 return is_first;
00091 }
00092
00093
00094 virtual bool empty() const
00095 {
00096 return heap_.empty();
00097 }
00098
00099
00100 virtual boost::posix_time::time_duration wait_duration() const
00101 {
00102 return Time_Traits::to_posix_duration(
00103 Time_Traits::subtract(heap_[0]->time_, Time_Traits::now()));
00104 }
00105
00106
00107 virtual void dispatch_timers()
00108 {
00109 const time_type now = Time_Traits::now();
00110 while (!heap_.empty() && !Time_Traits::less_than(now, heap_[0]->time_))
00111 {
00112 timer_base* t = heap_[0];
00113 remove_timer(t);
00114 t->invoke(asio::error_code());
00115 }
00116 }
00117
00118
00119
00120 std::size_t cancel_timer(void* timer_token)
00121 {
00122 std::size_t num_cancelled = 0;
00123 typedef typename hash_map<void*, timer_base*>::iterator iterator;
00124 iterator it = timers_.find(timer_token);
00125 if (it != timers_.end())
00126 {
00127 timer_base* t = it->second;
00128 while (t)
00129 {
00130 timer_base* next = t->next_;
00131 remove_timer(t);
00132 t->invoke(asio::error::operation_aborted);
00133 t = next;
00134 ++num_cancelled;
00135 }
00136 }
00137 return num_cancelled;
00138 }
00139
00140
00141 virtual void destroy_timers()
00142 {
00143 typename hash_map<void*, timer_base*>::iterator i = timers_.begin();
00144 typename hash_map<void*, timer_base*>::iterator end = timers_.end();
00145 while (i != end)
00146 {
00147 timer_base* t = i->second;
00148 typename hash_map<void*, timer_base*>::iterator old_i = i++;
00149 timers_.erase(old_i);
00150 t->destroy();
00151 }
00152 heap_.clear();
00153 timers_.clear();
00154 }
00155
00156 private:
00157
00158
00159 class timer_base
00160 {
00161 public:
00162
00163 void invoke(const asio::error_code& result)
00164 {
00165 invoke_func_(this, result);
00166 }
00167
00168
00169 void destroy()
00170 {
00171 destroy_func_(this);
00172 }
00173
00174 protected:
00175 typedef void (*invoke_func_type)(timer_base*,
00176 const asio::error_code&);
00177 typedef void (*destroy_func_type)(timer_base*);
00178
00179
00180 timer_base(invoke_func_type invoke_func, destroy_func_type destroy_func,
00181 const time_type& time, void* token)
00182 : invoke_func_(invoke_func),
00183 destroy_func_(destroy_func),
00184 time_(time),
00185 token_(token),
00186 next_(0),
00187 prev_(0),
00188 heap_index_(
00189 std::numeric_limits<size_t>::max BOOST_PREVENT_MACRO_SUBSTITUTION())
00190 {
00191 }
00192
00193
00194 ~timer_base()
00195 {
00196 }
00197
00198 private:
00199 friend class timer_queue<Time_Traits>;
00200
00201
00202 invoke_func_type invoke_func_;
00203
00204
00205 destroy_func_type destroy_func_;
00206
00207
00208 time_type time_;
00209
00210
00211 void* token_;
00212
00213
00214 timer_base* next_;
00215
00216
00217 timer_base* prev_;
00218
00219
00220 size_t heap_index_;
00221 };
00222
00223
00224 template <typename Handler>
00225 class timer
00226 : public timer_base
00227 {
00228 public:
00229
00230 timer(const time_type& time, Handler handler, void* token)
00231 : timer_base(&timer<Handler>::invoke_handler,
00232 &timer<Handler>::destroy_handler, time, token),
00233 handler_(handler)
00234 {
00235 }
00236
00237
00238 static void invoke_handler(timer_base* base,
00239 const asio::error_code& result)
00240 {
00241 std::auto_ptr<timer<Handler> > t(static_cast<timer<Handler>*>(base));
00242 t->handler_(result);
00243 }
00244
00245
00246 static void destroy_handler(timer_base* base)
00247 {
00248 delete static_cast<timer<Handler>*>(base);
00249 }
00250
00251 private:
00252 Handler handler_;
00253 };
00254
00255
00256 void up_heap(size_t index)
00257 {
00258 size_t parent = (index - 1) / 2;
00259 while (index > 0
00260 && Time_Traits::less_than(heap_[index]->time_, heap_[parent]->time_))
00261 {
00262 swap_heap(index, parent);
00263 index = parent;
00264 parent = (index - 1) / 2;
00265 }
00266 }
00267
00268
00269 void down_heap(size_t index)
00270 {
00271 size_t child = index * 2 + 1;
00272 while (child < heap_.size())
00273 {
00274 size_t min_child = (child + 1 == heap_.size()
00275 || Time_Traits::less_than(
00276 heap_[child]->time_, heap_[child + 1]->time_))
00277 ? child : child + 1;
00278 if (Time_Traits::less_than(heap_[index]->time_, heap_[min_child]->time_))
00279 break;
00280 swap_heap(index, min_child);
00281 index = min_child;
00282 child = index * 2 + 1;
00283 }
00284 }
00285
00286
00287 void swap_heap(size_t index1, size_t index2)
00288 {
00289 timer_base* tmp = heap_[index1];
00290 heap_[index1] = heap_[index2];
00291 heap_[index2] = tmp;
00292 heap_[index1]->heap_index_ = index1;
00293 heap_[index2]->heap_index_ = index2;
00294 }
00295
00296
00297 void remove_timer(timer_base* t)
00298 {
00299
00300 size_t index = t->heap_index_;
00301 if (!heap_.empty() && index < heap_.size())
00302 {
00303 if (index == heap_.size() - 1)
00304 {
00305 heap_.pop_back();
00306 }
00307 else
00308 {
00309 swap_heap(index, heap_.size() - 1);
00310 heap_.pop_back();
00311 size_t parent = (index - 1) / 2;
00312 if (index > 0 && Time_Traits::less_than(t->time_, heap_[parent]->time_))
00313 up_heap(index);
00314 else
00315 down_heap(index);
00316 }
00317 }
00318
00319
00320 typedef typename hash_map<void*, timer_base*>::iterator iterator;
00321 iterator it = timers_.find(t->token_);
00322 if (it != timers_.end())
00323 {
00324 if (it->second == t)
00325 it->second = t->next_;
00326 if (t->prev_)
00327 t->prev_->next_ = t->next_;
00328 if (t->next_)
00329 t->next_->prev_ = t->prev_;
00330 if (it->second == 0)
00331 timers_.erase(it);
00332 }
00333 }
00334
00335
00336 hash_map<void*, timer_base*> timers_;
00337
00338
00339 std::vector<timer_base*> heap_;
00340 };
00341
00342 }
00343 }
00344
00345 #include "asio/detail/pop_options.hpp"
00346
00347 #endif // ASIO_DETAIL_TIMER_QUEUE_HPP