0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-06-02 10:08:56 +02:00

ircd: Make asio header; comments; add special continuation for yielding to asio.

This commit is contained in:
Jason Volk 2017-09-20 19:31:54 -07:00
parent a9ac3f9956
commit 7f548cee1c
15 changed files with 150 additions and 50 deletions

View file

@ -20,7 +20,7 @@
*/
#include <ircd/ircd.h>
#include <boost/asio.hpp>
#include <ircd/asio.h>
#include "lgetopt.h"
#include "charybdis.h"
@ -62,11 +62,11 @@ lgetopt opts[] =
{ nullptr, nullptr, lgetopt::STRING, nullptr },
};
boost::asio::io_service *ios
std::unique_ptr<boost::asio::io_service> ios
{
// Having trouble with static destruction in clang so this
// has to become still-reachable
new boost::asio::io_service
std::make_unique<boost::asio::io_service>()
};
boost::asio::signal_set sigs

View file

@ -23,7 +23,7 @@
// charybdis.cc
//
extern boost::asio::io_service *ios;
extern std::unique_ptr<boost::asio::io_service> ios;
//
// console.cc

View file

@ -20,8 +20,7 @@
*/
#include <ircd/ircd.h>
#include <boost/asio.hpp>
#include <ircd/ctx/continuation.h>
#include <ircd/asio.h>
#include <ircd/m.h>
#include "charybdis.h"
@ -163,7 +162,7 @@ try
// so the output of the command (if log messages) can be seen.
{
const log::console_quiet quiet(false);
boost::asio::async_read_until(in, buf, '\n', yield_context{continuation{}});
boost::asio::async_read_until(in, buf, '\n', yield_context{to_asio{}});
}
std::getline(is, line);

54
include/ircd/asio.h Normal file
View file

@ -0,0 +1,54 @@
/*
* charybdis: standing on the shoulders of giant build times
*
* Copyright (C) 2017 Charybdis Development Team
* Copyright (C) 2017 Jason Volk <jason@zemos.net>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice is present in all copies.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#define HAVE_IRCD_ASIO_H
///
/// Boost library
///
/// It is better to add a boost header which we have omitted here rather than
/// in your definition file, and then #include <ircd/asio.h>. This is because
/// we can compose a precompiled header for your definition file much easier
/// this way.
///
/// Note that there is no precompile for this header right now, only the
/// standard headers. That still significantly improves compile times of these
/// boost headers for the time being...
///
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/io_service.hpp>
///
/// The following IRCd headers are not included in the main stdinc.h list of
/// includes because they require boost directly or symbols which we cannot
/// forward declare. You should include this in your definition file if you
/// need these low-level interfaces.
///
#include <ircd/ctx/continuation.h>
#include <ircd/socket.h>

View file

@ -22,6 +22,15 @@
#pragma once
#define HAVE_IRCD_BUFFER_H
// Forward declarations from boost::asio because it is not included here. IRCd
// buffers are not based directly on the boost ones but are easily converted
// when passing our buffer to an asio function.
namespace boost::asio
{
struct const_buffer;
struct mutable_buffer;
}
/// Lightweight buffer interface compatible with boost::asio IO buffers and vectors
///
/// A const_buffer is a pair of iterators like `const char *` meant for sending

View file

@ -42,6 +42,10 @@
/// Several low-level functions are exposed for library creators. This file is usually
/// included when boost/asio.hpp is also included and calls are actually made into boost.
///
/// boost::asio is not included from here. To access that include boost in a
/// definition file with #include <ircd/asio.h>. That include contains some
/// devices we use to yield a context to asio.
///
namespace ircd::ctx
{
IRCD_EXCEPTION(ircd::error, error)

View file

@ -22,25 +22,37 @@
#pragma once
#define HAVE_IRCD_CTX_CONTINUATION_H
#include <boost/asio/spawn.hpp>
/// This file is not included with the IRCd standard include stack because
/// it requires symbols we can't forward declare without boost headers. It
/// is part of the <ircd/asio.h> stack which can be included in your
/// definition file if necessary.
namespace ircd::ctx
{
using yield_context = boost::asio::yield_context;
struct continuation;
struct to_asio;
}
namespace ircd
{
using ctx::yield_context;
using ctx::continuation;
using ctx::to_asio;
}
/// This object is placed on the top of the stack when the context is yielding (INTERNAL USE).
/// This object must be placed on the stack when the context is yielding (INTERNAL)
///
/// The continuation constructor is the last thing executed before a context yields.
/// The continuation destructor is the first thing executed when a context continues.
/// The continuation constructor is the last thing executed before a context
/// yields. The continuation destructor is the first thing executed when a
/// context continues. This is not placed by a normal user wishing to context
/// switch, only a low-level library creator actually implementing the context
/// switch itself. The placement of this object must be correct. Generally,
/// we construct the `continuation` as an argument to `yield_context` as such
/// `yield_context{continuation{}}`. This ensures the continuation destructor
/// executes before control continues beyond the yield_context call itself and
/// ties this sequence together neatly.
///
struct ircd::ctx::continuation
{
@ -52,3 +64,18 @@ struct ircd::ctx::continuation
continuation(ctx *const &self = ircd::ctx::current);
~continuation() noexcept;
};
/// This type of continuation should be used when yielding a context to a
/// boost::asio handler so we can have specific control over that type of
/// context switch in possible contrast or extension of the regular
/// continuation behavior.
///
/// The statement `yield_context{to_asio{}}` can be passed to any boost::asio
/// callback handler. Those handlers have overloads to accept this, many of
/// which are not documented.
///
struct ircd::ctx::to_asio
:ircd::ctx::continuation
{
using continuation::continuation;
};

View file

@ -22,10 +22,12 @@
#pragma once
#define HAVE_IRCD_CLIENT_SOCKET_H
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/asio/steady_timer.hpp>
#include "ctx/continuation.h"
/// This file is not included with the IRCd standard include stack because
/// it requires symbols we can't forward declare without boost headers. It
/// is part of the <ircd/asio.h> stack which can be included in your
/// definition file if you need low level access to this socket API. The
/// client.h still offers higher level access to sockets without requiring
/// boost headers; please check that for satisfaction before including this.
namespace ircd
{
@ -185,7 +187,7 @@ ircd::socket::write(const iov &bufs)
{
return io(*this, out, [&]
{
return async_write(ssl, bufs, asio::transfer_all(), yield_context{continuation{}});
return async_write(ssl, bufs, asio::transfer_all(), yield_context{to_asio{}});
});
}
@ -196,7 +198,7 @@ ircd::socket::write(const iov &bufs,
{
return io(*this, out, [&]
{
return async_write(ssl, bufs, asio::transfer_all(), yield_context{continuation{}}[ec]);
return async_write(ssl, bufs, asio::transfer_all(), yield_context{to_asio{}}[ec]);
});
}
@ -206,7 +208,7 @@ ircd::socket::write_some(const iov &bufs)
{
return io(*this, out, [&]
{
return ssl.async_write_some(bufs, yield_context{continuation{}});
return ssl.async_write_some(bufs, yield_context{to_asio{}});
});
}
@ -217,7 +219,7 @@ ircd::socket::write_some(const iov &bufs,
{
return io(*this, out, [&]
{
return ssl.async_write_some(bufs, yield_context{continuation{}}[ec]);
return ssl.async_write_some(bufs, yield_context{to_asio{}}[ec]);
});
}
@ -227,7 +229,7 @@ ircd::socket::read(const iov &bufs)
{
return io(*this, in, [&]
{
const size_t ret(async_read(ssl, bufs, yield_context{continuation{}}));
const size_t ret(async_read(ssl, bufs, yield_context{to_asio{}}));
if(unlikely(!ret))
throw boost::system::system_error(boost::asio::error::eof);
@ -243,7 +245,7 @@ ircd::socket::read(const iov &bufs,
{
return io(*this, in, [&]
{
return async_read(ssl, bufs, yield_context{continuation{}}[ec]);
return async_read(ssl, bufs, yield_context{to_asio{}}[ec]);
});
}
@ -253,7 +255,7 @@ ircd::socket::read_some(const iov &bufs)
{
return io(*this, in, [&]
{
const size_t ret(ssl.async_read_some(bufs, yield_context{continuation{}}));
const size_t ret(ssl.async_read_some(bufs, yield_context{to_asio{}}));
if(unlikely(!ret))
throw boost::system::system_error(boost::asio::error::eof);
@ -269,6 +271,6 @@ ircd::socket::read_some(const iov &bufs,
{
return io(*this, in, [&]
{
return ssl.async_read_some(bufs, yield_context{continuation{}}[ec]);
return ssl.async_read_some(bufs, yield_context{to_asio{}}[ec]);
});
}

View file

@ -21,6 +21,13 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#define HAVE_IRCD_SPIRIT_H
/// This file is not part of the IRCd standard include list (stdinc.h) because
/// it involves extremely expensive boost headers for creating formal spirit
/// grammars. Include this in a definition file which defines such grammars.
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/fusion/include/std_pair.hpp>

View file

@ -40,8 +40,8 @@
// by doing things this way and C++ std headers have very little namespace
// pollution and risk of conflicts.
//
// * If any project header file requires standard library symbols we list it
// here, not in our header files.
// * If any project header file requires standard library symbols we try to
// list it here, not in our header files.
//
// * Rare one-off's #includes isolated to a specific .cc file may not always be
// listed here but can be.
@ -51,6 +51,8 @@
// we require a symbol in our API to them.
//
#define HAVE_IRCD_STDINC_H
// Generated by ./configure
#include "config.h"
@ -155,12 +157,11 @@ namespace boost
/// Forward declarations for boost::asio because it is not included here.
///
/// Boost headers are not exposed to our users unless explicitly included by a
/// definition file.
/// definition file. Other libircd headers may extend this namespace with more
/// forward declarations.
namespace boost::asio
{
struct io_service; // Allow a reference to an ios to be passed to ircd
struct const_buffer; // ircd/buffer.h
struct mutable_buffer; // ircd/buffer.h
}
///////////////////////////////////////////////////////////////////////////////

View file

@ -25,7 +25,7 @@
* USA
*/
#include <ircd/socket.h>
#include <ircd/asio.h>
namespace ircd {
@ -43,11 +43,6 @@ const auto request_timeout
300s
};
// Instance of socket::init is constructed and destructed manually to be in sync
// with client::init. This is placed here so ircd::main() doesn't have to see
// ircd/socket.h and do it there. It should be empty during static destruction.
std::unique_ptr<socket::init> socket_init;
// The pool of request contexts. When a client makes a request it does so by acquiring
// a stack from this pool. The request handling and response logic can then be written
// in a synchronous manner as if each connection had its own thread.
@ -76,18 +71,20 @@ template<class... args> std::shared_ptr<client> make_client(args&&...);
ircd::client::init::init()
{
assert(!socket_init);
socket_init = std::make_unique<socket::init>();
request.add(1);
request.add(2);
}
ircd::client::init::~init()
noexcept
{
log::debug("Interrupting %zu requests; dropping %zu requests; disconnecting %zu clients.",
request.active(),
request.pending(),
client::clients.size());
request.interrupt();
disconnect_all();
request.join();
socket_init.reset(nullptr);
}
ircd::string_view

View file

@ -19,8 +19,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <boost/asio/steady_timer.hpp>
#include <ircd/ctx/continuation.h>
#include <ircd/asio.h>
///////////////////////////////////////////////////////////////////////////////
///
@ -159,7 +158,7 @@ ircd::ctx::ctx::wait()
return false;
boost::system::error_code ec;
alarm.async_wait(boost::asio::yield_context(continuation(this))[ec]);
alarm.async_wait(boost::asio::yield_context{to_asio{this}}[ec]);
assert(ec == errc::operation_canceled || ec == errc::success);
assert(current == this);

View file

@ -23,7 +23,8 @@
* USA
*/
#include <boost/asio/io_service.hpp>
#include <ircd/asio.h>
#include <ircd/m.h>
namespace ircd
{
@ -105,7 +106,8 @@ try
// itself if either are more appropriate.
ctx::ole::init _ole_; // Thread OffLoad Engine
client::init _client_; // Client/Socket Networking
socket::init _socket_; // Socket/Networking
client::init _client_; // Client related
db::init _db_; // RocksDB
js::init _js_; // SpiderMonkey
m::init _matrix_; // Matrix

View file

@ -19,7 +19,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <ircd/socket.h>
#include <ircd/asio.h>
namespace ircd {

View file

@ -19,8 +19,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <ircd/ctx/continuation.h>
#include <ircd/socket.h>
#include <ircd/asio.h>
///////////////////////////////////////////////////////////////////////////////
//
@ -89,7 +88,7 @@ ircd::socket::socket(const std::string &host,
{
assert(resolver);
const ip::tcp::resolver::query query(host, string(lex_cast(port)));
auto epit(resolver->async_resolve(query, yield_context{continuation{}}));
auto epit(resolver->async_resolve(query, yield_context{to_asio{}}));
static const ip::tcp::resolver::iterator end;
if(epit == end)
throw nxdomain("host '%s' not found", host.data());
@ -143,8 +142,8 @@ ircd::socket::connect(const ip::tcp::endpoint &ep,
const milliseconds &timeout)
{
const scope_timeout ts(*this, timeout);
sd.async_connect(ep, yield_context{continuation{}});
ssl.async_handshake(socket::handshake_type::client, yield_context{continuation{}});
sd.async_connect(ep, yield_context{to_asio{}});
ssl.async_handshake(socket::handshake_type::client, yield_context{to_asio{}});
}
void
@ -179,7 +178,7 @@ ircd::socket::disconnect(const dc &type)
case dc::SSL_NOTIFY_YIELD:
{
ssl.async_shutdown(yield_context{continuation{}});
ssl.async_shutdown(yield_context{to_asio{}});
sd.close();
break;
}