You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
202 lines
5.7 KiB
202 lines
5.7 KiB
// |
|
// detail/reactor_op_queue.hpp |
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
// |
|
// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) |
|
// |
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying |
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
|
// |
|
|
|
#ifndef BOOST_ASIO_DETAIL_REACTOR_OP_QUEUE_HPP |
|
#define BOOST_ASIO_DETAIL_REACTOR_OP_QUEUE_HPP |
|
|
|
#if defined(_MSC_VER) && (_MSC_VER >= 1200) |
|
# pragma once |
|
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) |
|
|
|
#include <boost/asio/detail/config.hpp> |
|
#include <boost/asio/detail/hash_map.hpp> |
|
#include <boost/asio/detail/noncopyable.hpp> |
|
#include <boost/asio/detail/op_queue.hpp> |
|
#include <boost/asio/detail/reactor_op.hpp> |
|
#include <boost/asio/error.hpp> |
|
|
|
#include <boost/asio/detail/push_options.hpp> |
|
|
|
namespace boost { |
|
namespace asio { |
|
namespace detail { |
|
|
|
template <typename Descriptor> |
|
class reactor_op_queue |
|
: private noncopyable |
|
{ |
|
public: |
|
// Constructor. |
|
reactor_op_queue() |
|
: operations_() |
|
{ |
|
} |
|
|
|
// Add a new operation to the queue. Returns true if this is the only |
|
// operation for the given descriptor, in which case the reactor's event |
|
// demultiplexing function call may need to be interrupted and restarted. |
|
bool enqueue_operation(Descriptor descriptor, reactor_op* op) |
|
{ |
|
typedef typename operations_map::iterator iterator; |
|
typedef typename operations_map::value_type value_type; |
|
std::pair<iterator, bool> entry = |
|
operations_.insert(value_type(descriptor, operations())); |
|
entry.first->second.op_queue_.push(op); |
|
return entry.second; |
|
} |
|
|
|
// Cancel all operations associated with the descriptor. Any operations |
|
// pending for the descriptor will be notified that they have been cancelled |
|
// next time perform_cancellations is called. Returns true if any operations |
|
// were cancelled, in which case the reactor's event demultiplexing function |
|
// may need to be interrupted and restarted. |
|
bool cancel_operations(Descriptor descriptor, op_queue<operation>& ops, |
|
const boost::system::error_code& ec = |
|
boost::asio::error::operation_aborted) |
|
{ |
|
typename operations_map::iterator i = operations_.find(descriptor); |
|
if (i != operations_.end()) |
|
{ |
|
while (reactor_op* op = i->second.op_queue_.front()) |
|
{ |
|
op->ec_ = ec; |
|
i->second.op_queue_.pop(); |
|
ops.push(op); |
|
} |
|
operations_.erase(i); |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
// Whether there are no operations in the queue. |
|
bool empty() const |
|
{ |
|
return operations_.empty(); |
|
} |
|
|
|
// Determine whether there are any operations associated with the descriptor. |
|
bool has_operation(Descriptor descriptor) const |
|
{ |
|
return operations_.find(descriptor) != operations_.end(); |
|
} |
|
|
|
// Perform the operations corresponding to the descriptor. Returns true if |
|
// there are still unfinished operations queued for the descriptor. |
|
bool perform_operations(Descriptor descriptor, op_queue<operation>& ops) |
|
{ |
|
typename operations_map::iterator i = operations_.find(descriptor); |
|
if (i != operations_.end()) |
|
{ |
|
while (reactor_op* op = i->second.op_queue_.front()) |
|
{ |
|
if (op->perform()) |
|
{ |
|
i->second.op_queue_.pop(); |
|
ops.push(op); |
|
} |
|
else |
|
{ |
|
return true; |
|
} |
|
} |
|
operations_.erase(i); |
|
} |
|
return false; |
|
} |
|
|
|
// Fill a descriptor set with the descriptors corresponding to each active |
|
// operation. The op_queue is used only when descriptors fail to be added to |
|
// the descriptor set. |
|
template <typename Descriptor_Set> |
|
void get_descriptors(Descriptor_Set& descriptors, op_queue<operation>& ops) |
|
{ |
|
typename operations_map::iterator i = operations_.begin(); |
|
while (i != operations_.end()) |
|
{ |
|
Descriptor descriptor = i->first; |
|
++i; |
|
if (!descriptors.set(descriptor)) |
|
{ |
|
boost::system::error_code ec(error::fd_set_failure); |
|
cancel_operations(descriptor, ops, ec); |
|
} |
|
} |
|
} |
|
|
|
// Perform the operations corresponding to the ready file descriptors |
|
// contained in the given descriptor set. |
|
template <typename Descriptor_Set> |
|
void perform_operations_for_descriptors( |
|
const Descriptor_Set& descriptors, op_queue<operation>& ops) |
|
{ |
|
typename operations_map::iterator i = operations_.begin(); |
|
while (i != operations_.end()) |
|
{ |
|
typename operations_map::iterator op_iter = i++; |
|
if (descriptors.is_set(op_iter->first)) |
|
{ |
|
while (reactor_op* op = op_iter->second.op_queue_.front()) |
|
{ |
|
if (op->perform()) |
|
{ |
|
op_iter->second.op_queue_.pop(); |
|
ops.push(op); |
|
} |
|
else |
|
{ |
|
break; |
|
} |
|
} |
|
|
|
if (op_iter->second.op_queue_.empty()) |
|
operations_.erase(op_iter); |
|
} |
|
} |
|
} |
|
|
|
// Get all operations owned by the queue. |
|
void get_all_operations(op_queue<operation>& ops) |
|
{ |
|
typename operations_map::iterator i = operations_.begin(); |
|
while (i != operations_.end()) |
|
{ |
|
typename operations_map::iterator op_iter = i++; |
|
ops.push(op_iter->second.op_queue_); |
|
operations_.erase(op_iter); |
|
} |
|
} |
|
|
|
private: |
|
struct operations |
|
{ |
|
operations() {} |
|
operations(const operations&) {} |
|
void operator=(const operations&) {} |
|
|
|
// The operations waiting on the desccriptor. |
|
op_queue<reactor_op> op_queue_; |
|
}; |
|
|
|
// The type for a map of operations. |
|
typedef hash_map<Descriptor, operations> operations_map; |
|
|
|
// The operations that are currently executing asynchronously. |
|
operations_map operations_; |
|
}; |
|
|
|
} // namespace detail |
|
} // namespace asio |
|
} // namespace boost |
|
|
|
#include <boost/asio/detail/pop_options.hpp> |
|
|
|
#endif // BOOST_ASIO_DETAIL_REACTOR_OP_QUEUE_HPP
|
|
|