00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #ifndef ASIO_DETAIL_REACTOR_OP_QUEUE_HPP
00012 #define ASIO_DETAIL_REACTOR_OP_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 <memory>
00022 #include "asio/detail/pop_options.hpp"
00023
00024 #include "asio/error.hpp"
00025 #include "asio/detail/hash_map.hpp"
00026 #include "asio/detail/noncopyable.hpp"
00027
00028 namespace asio {
00029 namespace detail {
00030
00031 template <typename Descriptor>
00032 class reactor_op_queue
00033 : private noncopyable
00034 {
00035 public:
00036
00037 reactor_op_queue()
00038 : operations_(),
00039 cancelled_operations_(0),
00040 cleanup_operations_(0)
00041 {
00042 }
00043
00044
00045
00046
00047 template <typename Handler>
00048 bool enqueue_operation(Descriptor descriptor, Handler handler)
00049 {
00050 op_base* new_op = new op<Handler>(descriptor, handler);
00051
00052 typedef typename operation_map::iterator iterator;
00053 typedef typename operation_map::value_type value_type;
00054 std::pair<iterator, bool> entry =
00055 operations_.insert(value_type(descriptor, new_op));
00056 if (entry.second)
00057 return true;
00058
00059 op_base* current_op = entry.first->second;
00060 while (current_op->next_)
00061 current_op = current_op->next_;
00062 current_op->next_ = new_op;
00063
00064 return false;
00065 }
00066
00067
00068
00069
00070
00071
00072 bool cancel_operations(Descriptor descriptor)
00073 {
00074 typename operation_map::iterator i = operations_.find(descriptor);
00075 if (i != operations_.end())
00076 {
00077 op_base* last_op = i->second;
00078 while (last_op->next_)
00079 last_op = last_op->next_;
00080 last_op->next_ = cancelled_operations_;
00081 cancelled_operations_ = i->second;
00082 operations_.erase(i);
00083 return true;
00084 }
00085
00086 return false;
00087 }
00088
00089
00090 bool empty() const
00091 {
00092 return operations_.empty();
00093 }
00094
00095
00096 bool has_operation(Descriptor descriptor) const
00097 {
00098 return operations_.find(descriptor) != operations_.end();
00099 }
00100
00101
00102
00103 bool dispatch_operation(Descriptor descriptor,
00104 const asio::error_code& result)
00105 {
00106 typename operation_map::iterator i = operations_.find(descriptor);
00107 if (i != operations_.end())
00108 {
00109 op_base* this_op = i->second;
00110 i->second = this_op->next_;
00111 this_op->next_ = cleanup_operations_;
00112 cleanup_operations_ = this_op;
00113 bool done = this_op->invoke(result);
00114 if (done)
00115 {
00116
00117 if (i->second)
00118 {
00119 return true;
00120 }
00121 else
00122 {
00123 operations_.erase(i);
00124 return false;
00125 }
00126 }
00127 else
00128 {
00129
00130
00131 cleanup_operations_ = this_op->next_;
00132 this_op->next_ = i->second;
00133 i->second = this_op;
00134 return true;
00135 }
00136 }
00137 return false;
00138 }
00139
00140
00141 void dispatch_all_operations(Descriptor descriptor,
00142 const asio::error_code& result)
00143 {
00144 typename operation_map::iterator i = operations_.find(descriptor);
00145 if (i != operations_.end())
00146 {
00147 while (i->second)
00148 {
00149 op_base* this_op = i->second;
00150 i->second = this_op->next_;
00151 this_op->next_ = cleanup_operations_;
00152 cleanup_operations_ = this_op;
00153 bool done = this_op->invoke(result);
00154 if (!done)
00155 {
00156
00157
00158 cleanup_operations_ = this_op->next_;
00159 this_op->next_ = i->second;
00160 i->second = this_op;
00161 return;
00162 }
00163 }
00164 operations_.erase(i);
00165 }
00166 }
00167
00168
00169
00170 template <typename Descriptor_Set>
00171 void get_descriptors(Descriptor_Set& descriptors)
00172 {
00173 typename operation_map::iterator i = operations_.begin();
00174 while (i != operations_.end())
00175 {
00176 descriptors.set(i->first);
00177 ++i;
00178 }
00179 }
00180
00181
00182
00183 template <typename Descriptor_Set>
00184 void dispatch_descriptors(const Descriptor_Set& descriptors,
00185 const asio::error_code& result)
00186 {
00187 typename operation_map::iterator i = operations_.begin();
00188 while (i != operations_.end())
00189 {
00190 typename operation_map::iterator op_iter = i++;
00191 if (descriptors.is_set(op_iter->first))
00192 {
00193 op_base* this_op = op_iter->second;
00194 op_iter->second = this_op->next_;
00195 this_op->next_ = cleanup_operations_;
00196 cleanup_operations_ = this_op;
00197 bool done = this_op->invoke(result);
00198 if (done)
00199 {
00200 if (!op_iter->second)
00201 operations_.erase(op_iter);
00202 }
00203 else
00204 {
00205
00206
00207 cleanup_operations_ = this_op->next_;
00208 this_op->next_ = op_iter->second;
00209 op_iter->second = this_op;
00210 }
00211 }
00212 }
00213 }
00214
00215
00216 void dispatch_cancellations()
00217 {
00218 while (cancelled_operations_)
00219 {
00220 op_base* this_op = cancelled_operations_;
00221 cancelled_operations_ = this_op->next_;
00222 this_op->next_ = cleanup_operations_;
00223 cleanup_operations_ = this_op;
00224 this_op->invoke(asio::error::operation_aborted);
00225 }
00226 }
00227
00228
00229 void cleanup_operations()
00230 {
00231 while (cleanup_operations_)
00232 {
00233 op_base* next_op = cleanup_operations_->next_;
00234 cleanup_operations_->next_ = 0;
00235 cleanup_operations_->destroy();
00236 cleanup_operations_ = next_op;
00237 }
00238 }
00239
00240
00241 void destroy_operations()
00242 {
00243 while (cancelled_operations_)
00244 {
00245 op_base* next_op = cancelled_operations_->next_;
00246 cancelled_operations_->next_ = 0;
00247 cancelled_operations_->destroy();
00248 cancelled_operations_ = next_op;
00249 }
00250
00251 while (cleanup_operations_)
00252 {
00253 op_base* next_op = cleanup_operations_->next_;
00254 cleanup_operations_->next_ = 0;
00255 cleanup_operations_->destroy();
00256 cleanup_operations_ = next_op;
00257 }
00258
00259 typename operation_map::iterator i = operations_.begin();
00260 while (i != operations_.end())
00261 {
00262 typename operation_map::iterator op_iter = i++;
00263 op_base* curr_op = op_iter->second;
00264 operations_.erase(op_iter);
00265 while (curr_op)
00266 {
00267 op_base* next_op = curr_op->next_;
00268 curr_op->next_ = 0;
00269 curr_op->destroy();
00270 curr_op = next_op;
00271 }
00272 }
00273 }
00274
00275 private:
00276
00277
00278 class op_base
00279 {
00280 public:
00281
00282 Descriptor descriptor() const
00283 {
00284 return descriptor_;
00285 }
00286
00287
00288 bool invoke(const asio::error_code& result)
00289 {
00290 return invoke_func_(this, result);
00291 }
00292
00293
00294 void destroy()
00295 {
00296 return destroy_func_(this);
00297 }
00298
00299 protected:
00300 typedef bool (*invoke_func_type)(op_base*,
00301 const asio::error_code&);
00302 typedef void (*destroy_func_type)(op_base*);
00303
00304
00305 op_base(invoke_func_type invoke_func,
00306 destroy_func_type destroy_func, Descriptor descriptor)
00307 : invoke_func_(invoke_func),
00308 destroy_func_(destroy_func),
00309 descriptor_(descriptor),
00310 next_(0)
00311 {
00312 }
00313
00314
00315 ~op_base()
00316 {
00317 }
00318
00319 private:
00320 friend class reactor_op_queue<Descriptor>;
00321
00322
00323 invoke_func_type invoke_func_;
00324
00325
00326 destroy_func_type destroy_func_;
00327
00328
00329 Descriptor descriptor_;
00330
00331
00332 op_base* next_;
00333 };
00334
00335
00336 template <typename Handler>
00337 class op
00338 : public op_base
00339 {
00340 public:
00341
00342 op(Descriptor descriptor, Handler handler)
00343 : op_base(&op<Handler>::invoke_handler,
00344 &op<Handler>::destroy_handler, descriptor),
00345 handler_(handler)
00346 {
00347 }
00348
00349
00350 static bool invoke_handler(op_base* base,
00351 const asio::error_code& result)
00352 {
00353 return static_cast<op<Handler>*>(base)->handler_(result);
00354 }
00355
00356
00357 static void destroy_handler(op_base* base)
00358 {
00359 delete static_cast<op<Handler>*>(base);
00360 }
00361
00362 private:
00363 Handler handler_;
00364 };
00365
00366
00367 typedef hash_map<Descriptor, op_base*> operation_map;
00368
00369
00370 operation_map operations_;
00371
00372
00373 op_base* cancelled_operations_;
00374
00375
00376 op_base* cleanup_operations_;
00377 };
00378
00379 }
00380 }
00381
00382 #include "asio/detail/pop_options.hpp"
00383
00384 #endif // ASIO_DETAIL_REACTOR_OP_QUEUE_HPP