2
// reactor_op_queue.hpp
3
// ~~~~~~~~~~~~~~~~~~~~
5
// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
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)
11
#ifndef ASIO_DETAIL_REACTOR_OP_QUEUE_HPP
12
#define ASIO_DETAIL_REACTOR_OP_QUEUE_HPP
14
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
16
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
18
#include "asio/detail/push_options.hpp"
20
#include "asio/detail/push_options.hpp"
22
#include "asio/detail/pop_options.hpp"
24
#include "asio/error.hpp"
25
#include "asio/detail/hash_map.hpp"
26
#include "asio/detail/noncopyable.hpp"
31
template <typename Descriptor>
32
class reactor_op_queue
39
cancelled_operations_(0),
40
cleanup_operations_(0)
44
// Add a new operation to the queue. Returns true if this is the only
45
// operation for the given descriptor, in which case the reactor's event
46
// demultiplexing function call may need to be interrupted and restarted.
47
template <typename Handler>
48
bool enqueue_operation(Descriptor descriptor, Handler handler)
50
op_base* new_op = new op<Handler>(descriptor, handler);
52
typedef typename operation_map::iterator iterator;
53
typedef typename operation_map::value_type value_type;
54
std::pair<iterator, bool> entry =
55
operations_.insert(value_type(descriptor, new_op));
59
op_base* current_op = entry.first->second;
60
while (current_op->next_)
61
current_op = current_op->next_;
62
current_op->next_ = new_op;
67
// Cancel all operations associated with the descriptor. Any operations
68
// pending for the descriptor will be notified that they have been cancelled
69
// next time dispatch_cancellations is called. Returns true if any operations
70
// were cancelled, in which case the reactor's event demultiplexing function
71
// may need to be interrupted and restarted.
72
bool cancel_operations(Descriptor descriptor)
74
typename operation_map::iterator i = operations_.find(descriptor);
75
if (i != operations_.end())
77
op_base* last_op = i->second;
78
while (last_op->next_)
79
last_op = last_op->next_;
80
last_op->next_ = cancelled_operations_;
81
cancelled_operations_ = i->second;
89
// Whether there are no operations in the queue.
92
return operations_.empty();
95
// Determine whether there are any operations associated with the descriptor.
96
bool has_operation(Descriptor descriptor) const
98
return operations_.find(descriptor) != operations_.end();
101
// Dispatch the first operation corresponding to the descriptor. Returns true
102
// if there are more operations queued for the descriptor.
103
bool dispatch_operation(Descriptor descriptor,
104
const asio::error_code& result)
106
typename operation_map::iterator i = operations_.find(descriptor);
107
if (i != operations_.end())
109
op_base* this_op = i->second;
110
i->second = this_op->next_;
111
this_op->next_ = cleanup_operations_;
112
cleanup_operations_ = this_op;
113
bool done = this_op->invoke(result);
116
// Operation has finished.
123
operations_.erase(i);
129
// Operation wants to be called again. Leave it at the front of the
130
// queue for this descriptor, and remove from the cleanup list.
131
cleanup_operations_ = this_op->next_;
132
this_op->next_ = i->second;
140
// Dispatch all operations corresponding to the descriptor.
141
void dispatch_all_operations(Descriptor descriptor,
142
const asio::error_code& result)
144
typename operation_map::iterator i = operations_.find(descriptor);
145
if (i != operations_.end())
149
op_base* this_op = i->second;
150
i->second = this_op->next_;
151
this_op->next_ = cleanup_operations_;
152
cleanup_operations_ = this_op;
153
bool done = this_op->invoke(result);
156
// Operation has not finished yet, so leave at front of queue, and
157
// remove from the cleanup list.
158
cleanup_operations_ = this_op->next_;
159
this_op->next_ = i->second;
164
operations_.erase(i);
168
// Fill a descriptor set with the descriptors corresponding to each active
170
template <typename Descriptor_Set>
171
void get_descriptors(Descriptor_Set& descriptors)
173
typename operation_map::iterator i = operations_.begin();
174
while (i != operations_.end())
176
Descriptor descriptor = i->first;
178
if (!descriptors.set(descriptor))
180
asio::error_code ec(error::fd_set_failure);
181
dispatch_all_operations(descriptor, ec);
186
// Dispatch the operations corresponding to the ready file descriptors
187
// contained in the given descriptor set.
188
template <typename Descriptor_Set>
189
void dispatch_descriptors(const Descriptor_Set& descriptors,
190
const asio::error_code& result)
192
typename operation_map::iterator i = operations_.begin();
193
while (i != operations_.end())
195
typename operation_map::iterator op_iter = i++;
196
if (descriptors.is_set(op_iter->first))
198
op_base* this_op = op_iter->second;
199
op_iter->second = this_op->next_;
200
this_op->next_ = cleanup_operations_;
201
cleanup_operations_ = this_op;
202
bool done = this_op->invoke(result);
205
if (!op_iter->second)
206
operations_.erase(op_iter);
210
// Operation has not finished yet, so leave at front of queue, and
211
// remove from the cleanup list.
212
cleanup_operations_ = this_op->next_;
213
this_op->next_ = op_iter->second;
214
op_iter->second = this_op;
220
// Dispatch any pending cancels for operations.
221
void dispatch_cancellations()
223
while (cancelled_operations_)
225
op_base* this_op = cancelled_operations_;
226
cancelled_operations_ = this_op->next_;
227
this_op->next_ = cleanup_operations_;
228
cleanup_operations_ = this_op;
229
this_op->invoke(asio::error::operation_aborted);
233
// Destroy operations that are waiting to be cleaned up.
234
void cleanup_operations()
236
while (cleanup_operations_)
238
op_base* next_op = cleanup_operations_->next_;
239
cleanup_operations_->next_ = 0;
240
cleanup_operations_->destroy();
241
cleanup_operations_ = next_op;
245
// Destroy all operations owned by the queue.
246
void destroy_operations()
248
while (cancelled_operations_)
250
op_base* next_op = cancelled_operations_->next_;
251
cancelled_operations_->next_ = 0;
252
cancelled_operations_->destroy();
253
cancelled_operations_ = next_op;
256
while (cleanup_operations_)
258
op_base* next_op = cleanup_operations_->next_;
259
cleanup_operations_->next_ = 0;
260
cleanup_operations_->destroy();
261
cleanup_operations_ = next_op;
264
typename operation_map::iterator i = operations_.begin();
265
while (i != operations_.end())
267
typename operation_map::iterator op_iter = i++;
268
op_base* curr_op = op_iter->second;
269
operations_.erase(op_iter);
272
op_base* next_op = curr_op->next_;
281
// Base class for reactor operations. A function pointer is used instead of
282
// virtual functions to avoid the associated overhead.
286
// Get the descriptor associated with the operation.
287
Descriptor descriptor() const
292
// Perform the operation.
293
bool invoke(const asio::error_code& result)
295
return invoke_func_(this, result);
298
// Destroy the operation.
301
return destroy_func_(this);
305
typedef bool (*invoke_func_type)(op_base*,
306
const asio::error_code&);
307
typedef void (*destroy_func_type)(op_base*);
309
// Construct an operation for the given descriptor.
310
op_base(invoke_func_type invoke_func,
311
destroy_func_type destroy_func, Descriptor descriptor)
312
: invoke_func_(invoke_func),
313
destroy_func_(destroy_func),
314
descriptor_(descriptor),
319
// Prevent deletion through this type.
325
friend class reactor_op_queue<Descriptor>;
327
// The function to be called to dispatch the handler.
328
invoke_func_type invoke_func_;
330
// The function to be called to delete the handler.
331
destroy_func_type destroy_func_;
333
// The descriptor associated with the operation.
334
Descriptor descriptor_;
336
// The next operation for the same file descriptor.
340
// Adaptor class template for using handlers in operations.
341
template <typename Handler>
347
op(Descriptor descriptor, Handler handler)
348
: op_base(&op<Handler>::invoke_handler,
349
&op<Handler>::destroy_handler, descriptor),
354
// Invoke the handler.
355
static bool invoke_handler(op_base* base,
356
const asio::error_code& result)
358
return static_cast<op<Handler>*>(base)->handler_(result);
361
// Delete the handler.
362
static void destroy_handler(op_base* base)
364
delete static_cast<op<Handler>*>(base);
371
// The type for a map of operations.
372
typedef hash_map<Descriptor, op_base*> operation_map;
374
// The operations that are currently executing asynchronously.
375
operation_map operations_;
377
// The list of operations that have been cancelled.
378
op_base* cancelled_operations_;
380
// The list of operations to be destroyed.
381
op_base* cleanup_operations_;
384
} // namespace detail
387
#include "asio/detail/pop_options.hpp"
389
#endif // ASIO_DETAIL_REACTOR_OP_QUEUE_HPP