Created
September 20, 2017 16:56
-
-
Save vinniefalco/04d6299c94c5a71f2808caeb742000de to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Copyright (c) 2017 Vinnie Falco (vinnie dot falco at gmail 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) | |
// | |
#include <beast/core/async_result.hpp> | |
#include <beast/core/bind_handler.hpp> | |
#include <beast/core/error.hpp> | |
#include <boost/asio/io_service.hpp> | |
#include <boost/optional.hpp> | |
#include <functional> | |
#include <list> | |
#include <thread> | |
/** Start an asynchronous operation in an synchronous context | |
*/ | |
class sync_io_service | |
{ | |
boost::asio::io_service ios_; | |
boost::optional<boost::asio::io_service::work> work_; | |
std::list<std::thread> workers_; | |
template<class SyncOp, class Handler> | |
class task | |
{ | |
SyncOp op_; | |
boost::asio::io_service& ios_; | |
Handler h_; | |
public: | |
template<class DeducedHandler> | |
task( | |
DeducedHandler&& handler, | |
boost::asio::io_service& ios, | |
SyncOp const& op) | |
: op_(op) | |
, ios_(ios) | |
, h_(std::forward<DeducedHandler>(handler)) | |
{ | |
} | |
void | |
operator() | |
{ | |
beast::error_code ec; | |
try | |
{ | |
ec = op_(); | |
} | |
catch(...) | |
{ | |
// Could use a different error code | |
ec = beast::errc::io_error; | |
} | |
ios_.post( | |
beast::bind_handler(std::move(h_), ec)); | |
} | |
}; | |
public: | |
/** Constructor | |
@param n_threads The number of worker threads to launch. | |
*/ | |
explicit | |
sync_io_service(std::size_t n_threads) | |
: work_(ios_) | |
{ | |
while(n_threads--) | |
workers_.emplace([&]{ ios_.run(); }); | |
} | |
/** Destructor | |
This function will not return until all pending work | |
has been completed. | |
*/ | |
~sync_io_service() | |
{ | |
work_ = boost::none; | |
for(auto& w : workers_) | |
w.join(); | |
} | |
/** Launch an operation | |
This function launches a synchronous operation in an | |
implementation-provided thread. The call always returns | |
immediately. The asynchronous operation will continue | |
until one of the following conditions is met: | |
@li The synchronous function exits with an error code. | |
@li The synchronous function exits via exception. In | |
this case the error code delivered to the completion | |
handler will be `beast::errc::io_error`. | |
@param sync_op The synchronous operation to perform. Copies | |
will be made of this object as needed. The equivalent | |
function signature must be: | |
@code | |
error_code sync_op(); | |
@endcode | |
The error returned from the synchronous operation function | |
will be delivered to the completion handler. | |
@param io_service The `io_service` upon which the handler | |
will be dispatched. | |
@param handler The handler to be called when the request | |
completes. Copies will be made of the handler as required. | |
The equivalent function signature of the handler must be: | |
@code void handler( | |
error_code const& error // result of operation | |
); @endcode | |
Regardless of whether the asynchronous operation completes | |
immediately or not, the handler will not be invoked from within | |
this function. Invocation of the handler will be performed in a | |
manner equivalent to using `boost::asio::io_service::post`. | |
*/ | |
template<class SyncOp, class Handler> | |
beast::async_return_type<Handler, void(error_code)> | |
async_run( | |
SyncOp const& sync_op, | |
boost::asio::io_service& ios, | |
Handler&& handler) | |
{ | |
beast::async_completion< | |
Handler, | |
void(error_code)> init{handler}; | |
ios_.post( | |
task< | |
SyncOp, | |
beast::handler_type<Handler, void(error_code)> | |
>{ | |
std::forward<Handler>(handler), | |
ios, | |
sync_op}); | |
return init.result.get(); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment