Hello, Dean,

Sorry for previous message, somehow it appears to be unreadable :(

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 */

------------------------------------------------------------------------------
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

Reply via email to