Hello, Dean, Here is my implementation of async_connection::write_vec(). Before any pull requests I want you to check it to see if you like the idea.
First of all, current write_impl() introduces race on user data. If execution flow falls in one of conditions when we need to wait for headers being sent than we schedule an operation and return control to user _without_ copying the data. The actual copying will occur after continue_write(). Being not hardcore-templating-guru I don't know how to make specific write() overload with ConstBufferSequence model as a first argument (because it overlaps with <Range, Callback>) so I introduced write_vec interface. BTW, I think it is a good idea to explicitly specify that write() makes a copy of supplied data and rename it to write_copy() (see to_lower_copy, to_upper_copy, etc. in boost::algorithm) To maximise core reuse, write_impl now only prepares buffers and passes them to write_vec_impl. Tested both write and write_vec on 'master' with valgrind on linux/amd64: no memory leaks, no memory corruption. Patch provided applies cleanly to master and 0.9-devel. -- Best regards, Oleg Malashenko.
diff --git a/boost/network/protocol/http/server/async_connection.hpp b/boost/network/protocol/http/server/async_connection.hpp
index 8ff34b7..23e1372 100644
--- a/boost/network/protocol/http/server/async_connection.hpp
+++ b/boost/network/protocol/http/server/async_connection.hpp
@@ -212,10 +212,15 @@ namespace boost { namespace network { namespace http {
void write(Range const & range, Callback const & callback) {
lock_guard lock(headers_mutex);
if (error_encountered) boost::throw_exception(boost::system::system_error(*error_encountered));
- boost::function<void(boost::system::error_code)> f = callback;
write_impl(boost::make_iterator_range(range), callback);
}
+ template <class ConstBufferSeq, class Callback>
+ void write_vec(ConstBufferSeq const & seq, Callback const & callback)
+ {
+ write_vec_impl(seq, callback, shared_array_list(), shared_buffers());
+ }
+
private:
typedef boost::array<char, BOOST_NETWORK_HTTP_SERVER_CONNECTION_BUFFER_SIZE> buffer_type;
@@ -510,15 +515,6 @@ namespace boost { namespace network { namespace http {
void do_nothing() {}
- template <class Range>
- void continue_write(Range range, boost::function<void(boost::system::error_code)> callback) {
- thread_pool().post(
- boost::bind(
- &async_connection<Tag,Handler>::write_impl<Range>
- , async_connection<Tag,Handler>::shared_from_this()
- , range, callback));
- }
-
template <class Callback>
void write_first_line(Callback callback) {
lock_guard lock(headers_mutex);
@@ -603,27 +599,6 @@ namespace boost { namespace network { namespace http {
template <class Range>
void write_impl(Range range, boost::function<void(boost::system::error_code)> callback) {
- lock_guard lock(headers_mutex);
- boost::function<void(boost::system::error_code)> callback_function =
- callback;
-
- if (!headers_already_sent && !headers_in_progress) {
- write_headers_only(
- boost::bind(
- &async_connection<Tag,Handler>::continue_write<Range>
- , async_connection<Tag,Handler>::shared_from_this()
- , range, callback_function
- ));
- return;
- } else if (headers_in_progress && !headers_already_sent) {
- pending_actions.push_back(
- boost::bind(
- &async_connection<Tag,Handler>::continue_write<Range>
- , async_connection<Tag,Handler>::shared_from_this()
- , range, callback_function));
- return;
- }
-
// linearize the whole range into a vector
// of fixed-sized buffers, then schedule an asynchronous
// write of these buffers -- make sure they are live
@@ -670,25 +645,47 @@ namespace boost { namespace network { namespace http {
}
if (!buffers->empty()) {
- boost::function<void(boost::system::error_code const &)> f = callback;
- asio::async_write(
- socket_
- , *buffers
- , strand.wrap(
- boost::bind(
- &async_connection<Tag,Handler>::handle_write
- , async_connection<Tag,Handler>::shared_from_this()
- , f
- , temporaries
- , buffers // keep these alive until the handler is called!
- , boost::asio::placeholders::error
- , boost::asio::placeholders::bytes_transferred
- )
- )
- );
+ write_vec_impl(*buffers, callback, temporaries, buffers);
}
}
+ template <class ConstBufferSeq, class Callback>
+ void write_vec_impl(ConstBufferSeq const & seq
+ ,Callback const & callback
+ ,shared_array_list temporaries
+ ,shared_buffers buffers)
+ {
+ lock_guard lock(headers_mutex);
+ if (error_encountered)
+ boost::throw_exception(boost::system::system_error(*error_encountered));
+
+ boost::function<void()> continuation = boost::bind(
+ &async_connection<Tag,Handler>::write_vec_impl<ConstBufferSeq, Callback>
+ ,async_connection<Tag,Handler>::shared_from_this()
+ ,seq, callback, temporaries, buffers
+ );
+
+ if (!headers_already_sent && !headers_in_progress) {
+ write_headers_only(continuation);
+ return;
+ } else if (headers_in_progress && !headers_already_sent) {
+ pending_actions.push_back(continuation);
+ return;
+ }
+
+ asio::async_write(
+ socket_
+ ,seq
+ ,boost::bind(
+ &async_connection<Tag,Handler>::handle_write
+ ,async_connection<Tag,Handler>::shared_from_this()
+ ,callback
+ ,temporaries
+ ,buffers
+ ,asio::placeholders::error
+ ,asio::placeholders::bytes_transferred)
+ );
+ }
};
} /* http */
signature.asc
Description: OpenPGP digital signature
------------------------------------------------------------------------------ Protect Your Site and Customers from Malware Attacks Learn about various malware tactics and how to avoid them. Understand malware threats, the impact they can have on your business, and how you can protect your company and customers by using code signing. http://p.sf.net/sfu/oracle-sfdevnl
_______________________________________________ Cpp-netlib-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/cpp-netlib-devel
