1 //
2 // detail/reactor_op_queue.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 //
10 
11 #ifndef ASIO_DETAIL_REACTOR_OP_QUEUE_HPP
12 #define ASIO_DETAIL_REACTOR_OP_QUEUE_HPP
13 
14 
15 #include "asio/detail/config.hpp"
16 #include "asio/detail/hash_map.hpp"
17 #include "asio/detail/noncopyable.hpp"
18 #include "asio/detail/op_queue.hpp"
19 #include "asio/detail/reactor_op.hpp"
20 #include "asio/error.hpp"
21 
22 #include "asio/detail/push_options.hpp"
23 
24 namespace asio {
25 namespace detail {
26 
27 template <typename Descriptor>
28 class reactor_op_queue
29   : private noncopyable
30 {
31 public:
32   typedef Descriptor key_type;
33 
34   struct mapped_type : op_queue<reactor_op>
35   {
mapped_typeasio::detail::reactor_op_queue::mapped_type36     mapped_type() {}
mapped_typeasio::detail::reactor_op_queue::mapped_type37     mapped_type(const mapped_type&) {}
operator =asio::detail::reactor_op_queue::mapped_type38     void operator=(const mapped_type&) {}
39   };
40 
41   typedef typename hash_map<key_type, mapped_type>::value_type value_type;
42   typedef typename hash_map<key_type, mapped_type>::iterator iterator;
43 
44   // Constructor.
reactor_op_queue()45   reactor_op_queue()
46     : operations_()
47   {
48   }
49 
50   // Obtain iterators to all registered descriptors.
begin()51   iterator begin() { return operations_.begin(); }
end()52   iterator end() { return operations_.end(); }
53 
54   // Add a new operation to the queue. Returns true if this is the only
55   // operation for the given descriptor, in which case the reactor's event
56   // demultiplexing function call may need to be interrupted and restarted.
enqueue_operation(Descriptor descriptor,reactor_op * op)57   bool enqueue_operation(Descriptor descriptor, reactor_op* op)
58   {
59     std::pair<iterator, bool> entry =
60       operations_.insert(value_type(descriptor, mapped_type()));
61     entry.first->second.push(op);
62     return entry.second;
63   }
64 
65   // Cancel all operations associated with the descriptor identified by the
66   // supplied iterator. Any operations pending for the descriptor will be
67   // cancelled. Returns true if any operations were cancelled, in which case
68   // the reactor's event demultiplexing function may need to be interrupted and
69   // restarted.
cancel_operations(iterator i,op_queue<operation> & ops,const asio::error_code & ec=asio::error::operation_aborted)70   bool cancel_operations(iterator i, op_queue<operation>& ops,
71       const asio::error_code& ec =
72         asio::error::operation_aborted)
73   {
74     if (i != operations_.end())
75     {
76       while (reactor_op* op = i->second.front())
77       {
78         op->ec_ = ec;
79         i->second.pop();
80         ops.push(op);
81       }
82       operations_.erase(i);
83       return true;
84     }
85 
86     return false;
87   }
88 
89   // Cancel all operations associated with the descriptor. Any operations
90   // pending for the descriptor will be cancelled. Returns true if any
91   // operations were cancelled, in which case the reactor's event
92   // demultiplexing function may need to be interrupted and restarted.
cancel_operations(Descriptor descriptor,op_queue<operation> & ops,const asio::error_code & ec=asio::error::operation_aborted)93   bool cancel_operations(Descriptor descriptor, op_queue<operation>& ops,
94       const asio::error_code& ec =
95         asio::error::operation_aborted)
96   {
97     return this->cancel_operations(operations_.find(descriptor), ops, ec);
98   }
99 
100   // Whether there are no operations in the queue.
empty() const101   bool empty() const
102   {
103     return operations_.empty();
104   }
105 
106   // Determine whether there are any operations associated with the descriptor.
has_operation(Descriptor descriptor) const107   bool has_operation(Descriptor descriptor) const
108   {
109     return operations_.find(descriptor) != operations_.end();
110   }
111 
112   // Perform the operations corresponding to the descriptor identified by the
113   // supplied iterator. Returns true if there are still unfinished operations
114   // queued for the descriptor.
perform_operations(iterator i,op_queue<operation> & ops)115   bool perform_operations(iterator i, op_queue<operation>& ops)
116   {
117     if (i != operations_.end())
118     {
119       while (reactor_op* op = i->second.front())
120       {
121         if (op->perform())
122         {
123           i->second.pop();
124           ops.push(op);
125         }
126         else
127         {
128           return true;
129         }
130       }
131       operations_.erase(i);
132     }
133     return false;
134   }
135 
136   // Perform the operations corresponding to the descriptor. Returns true if
137   // there are still unfinished operations queued for the descriptor.
perform_operations(Descriptor descriptor,op_queue<operation> & ops)138   bool perform_operations(Descriptor descriptor, op_queue<operation>& ops)
139   {
140     return this->perform_operations(operations_.find(descriptor), ops);
141   }
142 
143   // Get all operations owned by the queue.
get_all_operations(op_queue<operation> & ops)144   void get_all_operations(op_queue<operation>& ops)
145   {
146     iterator i = operations_.begin();
147     while (i != operations_.end())
148     {
149       iterator op_iter = i++;
150       ops.push(op_iter->second);
151       operations_.erase(op_iter);
152     }
153   }
154 
155 private:
156   // The operations that are currently executing asynchronously.
157   hash_map<key_type, mapped_type> operations_;
158 };
159 
160 } // namespace detail
161 } // namespace asio
162 
163 #include "asio/detail/pop_options.hpp"
164 
165 #endif // ASIO_DETAIL_REACTOR_OP_QUEUE_HPP
166