diff --git a/construct/construct.cc b/construct/construct.cc index 04f84a934..9b2ebe7dd 100644 --- a/construct/construct.cc +++ b/construct/construct.cc @@ -351,7 +351,7 @@ noexcept try { ios.run_one(); - if constexpr(ircd::ios::profile_logging) + if constexpr(ircd::ios::profile::logging) ircd::log::logf { ircd::ios::log, ircd::log::DEBUG, diff --git a/include/ircd/ios.h b/include/ircd/ios.h deleted file mode 100644 index a6892ecb1..000000000 --- a/include/ircd/ios.h +++ /dev/null @@ -1,390 +0,0 @@ -// Matrix Construct -// -// Copyright (C) Matrix Construct Developers, Authors & Contributors -// Copyright (C) 2016-2018 Jason Volk -// -// 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. The -// full license for this software is available in the LICENSE file. - -#pragma once -#define HAVE_IRCD_IOS_H - -// Boost headers are not exposed to our users unless explicitly included by a -// definition file. Other libircd headers may extend this namespace with more -// forward declarations. - -/// Forward declarations for boost::asio because it is not included here. -namespace boost::asio -{ - struct executor; - struct io_context; - - template - void asio_handler_invoke(function&, ...); -} - -namespace ircd -{ - namespace asio = boost::asio; ///< Alias so that asio:: can be used. - - extern const info::versions boost_version_api, boost_version_abi; -} - -namespace ircd::ios -{ - struct handler; - struct descriptor; - template struct handle; - - IRCD_OVERLOAD(synchronous) - struct dispatch; - struct defer; - struct post; - - constexpr bool profile_history {false}; - constexpr bool profile_logging {false}; - - extern log::log log; - extern std::thread::id main_thread_id; - extern asio::executor user; - extern asio::executor main; - - const string_view &name(const descriptor &); - const string_view &name(const handler &); - - bool available() noexcept; - const uint64_t &epoch() noexcept; - - void forked_parent(); - void forked_child(); - void forking(); - void init(asio::executor &&); -} - -namespace ircd -{ - using ios::dispatch; - using ios::defer; - using ios::post; -} - -struct ircd::ios::dispatch -{ - dispatch(descriptor &, std::function); - dispatch(descriptor &, synchronous_t, const std::function &); - dispatch(descriptor &, synchronous_t); - dispatch(std::function); - dispatch(synchronous_t, const std::function &); -}; - -struct ircd::ios::defer -{ - defer(descriptor &, std::function); - defer(descriptor &, synchronous_t, const std::function &); - defer(descriptor &, synchronous_t); - defer(std::function); - defer(synchronous_t, const std::function &); -}; - -struct ircd::ios::post -{ - post(descriptor &, std::function); - post(descriptor &, synchronous_t, const std::function &); - post(descriptor &, synchronous_t); - post(std::function); - post(synchronous_t, const std::function &); -}; - -struct ircd::ios::descriptor -:instance_list -{ - struct stats; - - static uint64_t ids; - - static void *default_allocator(handler &, const size_t &); - static void default_deallocator(handler &, void *const &, const size_t &) noexcept; - - string_view name; - uint64_t id {++ids}; - std::unique_ptr stats; - void *(*allocator)(handler &, const size_t &); - void (*deallocator)(handler &, void *const &, const size_t &); - std::vector> history; // epoch, cycles - uint8_t history_pos {0}; - bool continuation {false}; - - descriptor(const string_view &name, - const decltype(allocator) & = default_allocator, - const decltype(deallocator) & = default_deallocator, - const bool &continuation = false) noexcept; - - descriptor(descriptor &&) = delete; - descriptor(const descriptor &) = delete; - ~descriptor() noexcept; -}; - -struct ircd::ios::descriptor::stats -{ - uint64_t queued {0}; - uint64_t calls {0}; - uint64_t faults {0}; - uint64_t allocs {0}; - uint64_t alloc_bytes{0}; - uint64_t frees {0}; - uint64_t free_bytes{0}; - uint64_t slice_total {0}; - uint64_t slice_last {0}; - uint64_t latency_total {0}; - uint64_t latency_last {0}; - - stats &operator+=(const stats &) &; - - stats(); - ~stats() noexcept; -}; - -struct ircd::ios::handler -{ - static thread_local handler *current; - static thread_local uint64_t epoch; - - static void enqueue(handler *const &) noexcept; - static void *allocate(handler *const &, const size_t &); - static void deallocate(handler *const &, void *const &, const size_t &) noexcept; - static bool continuation(handler *const &) noexcept; - static void enter(handler *const &) noexcept; - static void leave(handler *const &) noexcept; - static bool fault(handler *const &) noexcept; - - ios::descriptor *descriptor {nullptr}; - uint64_t ts {0}; // last tsc sample; for profiling each phase -}; - -template -struct ircd::ios::handle -:handler -{ - function f; - - template - void operator()(args&&... a) const; - - handle(ios::descriptor &, function) noexcept; -}; - -// boost handlers -namespace ircd::ios -{ - template - void asio_handler_deallocate(void *, size_t, handle *); - - template - void *asio_handler_allocate(size_t, handle *); - - template - bool asio_handler_is_continuation(handle *); - - template - void asio_handler_invoke(callable &f, handle *); -} - -template -inline void -ircd::ios::asio_handler_invoke(callable &f, - handle *const h) -try -{ - handler::enter(h); - boost::asio::asio_handler_invoke(f, &h); - handler::leave(h); -} -catch(...) -{ - if(handler::fault(h)) - handler::leave(h); - else - throw; -} - -template -inline bool -ircd::ios::asio_handler_is_continuation(handle *const h) -{ - return handler::continuation(h); -} - -template -inline void * -__attribute__((malloc, returns_nonnull, warn_unused_result, alloc_size(1))) -ircd::ios::asio_handler_allocate(size_t size, - handle *const h) -{ - return handler::allocate(h, size); -} - -template -inline void -ircd::ios::asio_handler_deallocate(void *const ptr, - size_t size, - handle *const h) -{ - handler::deallocate(h, ptr, size); -} - -// -// ircd::ios::handle -// - -template -inline -ircd::ios::handle::handle(ios::descriptor &d, - function f) -noexcept -:handler{&d, prof::cycles()} -,f(std::move(f)) -{ - handler::enqueue(this); -} - -template -template -inline void -ircd::ios::handle::operator()(args&&... a) -const -{ - assert(descriptor && descriptor->stats); - assert(descriptor->stats->queued > 0); - descriptor->stats->queued--; - f(std::forward(a)...); -} - -// -// ircd::ios::handler -// - -[[gnu::hot]] -inline void -ircd::ios::handler::deallocate(handler *const &handler, - void *const &ptr, - const size_t &size) -noexcept -{ - assert(handler && handler->descriptor); - auto &descriptor(*handler->descriptor); - - assert(descriptor.deallocator); - descriptor.deallocator(*handler, ptr, size); - - assert(descriptor.stats); - auto &stats(*descriptor.stats); - stats.free_bytes += size; - ++stats.frees; -} - -[[gnu::hot]] -inline void * -ircd::ios::handler::allocate(handler *const &handler, - const size_t &size) -{ - assert(handler && handler->descriptor); - auto &descriptor(*handler->descriptor); - - assert(descriptor.stats); - auto &stats(*descriptor.stats); - stats.alloc_bytes += size; - ++stats.allocs; - - assert(descriptor.allocator); - return descriptor.allocator(*handler, size); -} - -[[gnu::hot]] -inline void -ircd::ios::handler::enqueue(handler *const &handler) -noexcept -{ - assert(handler && handler->descriptor); - auto &descriptor(*handler->descriptor); - - assert(descriptor.stats); - auto &stats(*descriptor.stats); - ++stats.queued; - - if constexpr(profile_logging) - log::logf - { - log, log::level::DEBUG, - "QUEUE %5u %-30s [%11lu] ------[%9lu] q:%-4lu", - descriptor.id, - trunc(descriptor.name, 30), - stats.calls, - 0UL, - stats.queued, - }; -} - -[[gnu::hot]] -inline bool -ircd::ios::handler::continuation(handler *const &handler) -noexcept -{ - assert(handler && handler->descriptor); - auto &descriptor(*handler->descriptor); - return descriptor.continuation; -} - -// -// ios::descriptor -// - -[[gnu::hot]] -inline void -ircd::ios::descriptor::default_deallocator(handler &handler, - void *const &ptr, - const size_t &size) -noexcept -{ - #ifdef __clang__ - ::operator delete(ptr); - #else - ::operator delete(ptr, size); - #endif -} - -[[gnu::hot]] -inline void * -ircd::ios::descriptor::default_allocator(handler &handler, - const size_t &size) -{ - return ::operator new(size); -} - -// -// ircd::ios -// - -inline const ircd::string_view & -ircd::ios::name(const handler &handler) -{ - assert(handler.descriptor); - return name(*handler.descriptor); -} - -inline const ircd::string_view & -ircd::ios::name(const descriptor &descriptor) -{ - return descriptor.name; -} - -inline const uint64_t & -__attribute__((always_inline)) -ircd::ios::epoch() -noexcept -{ - return handler::epoch; -} diff --git a/include/ircd/ios/asio.h b/include/ircd/ios/asio.h new file mode 100644 index 000000000..38b41d162 --- /dev/null +++ b/include/ircd/ios/asio.h @@ -0,0 +1,81 @@ +// The Construct +// +// Copyright (C) The Construct Developers, Authors & Contributors +// Copyright (C) 2016-2020 Jason Volk +// +// 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. The +// full license for this software is available in the LICENSE file. + +#pragma once +#define HAVE_IRCD_IOS_ASIO_H + +/// Forward declarations for boost::asio because it is not included here. +namespace boost::asio +{ + struct io_context; + + template + void asio_handler_invoke(function&, ...); +} + +namespace ircd::ios +{ + template + void asio_handler_deallocate(void *, size_t, handle *); + + template + void *asio_handler_allocate(size_t, handle *); + + template + bool asio_handler_is_continuation(handle *); + + template + void asio_handler_invoke(callable &f, handle *); +} + +template +inline void +ircd::ios::asio_handler_invoke(callable &f, + handle *const h) +try +{ + handler::enter(h); + boost::asio::asio_handler_invoke(f, &h); + handler::leave(h); +} +catch(...) +{ + if(handler::fault(h)) + handler::leave(h); + else + throw; +} + +template +inline bool +ircd::ios::asio_handler_is_continuation(handle *const h) +{ + return handler::continuation(h); +} + +template +inline void * +__attribute__((malloc, returns_nonnull, warn_unused_result, alloc_size(1))) +ircd::ios::asio_handler_allocate(size_t size, + handle *const h) +{ + return handler::allocate(h, size); +} + +template +inline void +ircd::ios::asio_handler_deallocate(void *const ptr, + size_t size, + handle *const h) +{ + handler::deallocate(h, ptr, size); +} diff --git a/include/ircd/ios/descriptor.h b/include/ircd/ios/descriptor.h new file mode 100644 index 000000000..009224985 --- /dev/null +++ b/include/ircd/ios/descriptor.h @@ -0,0 +1,97 @@ +// The Construct +// +// Copyright (C) The Construct Developers, Authors & Contributors +// Copyright (C) 2016-2020 Jason Volk +// +// 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. The +// full license for this software is available in the LICENSE file. + +#pragma once +#define HAVE_IRCD_IOS_DESCRIPTOR_H + +namespace ircd::ios +{ + struct handler; + struct descriptor; + + const string_view &name(const descriptor &); +} + +struct ircd::ios::descriptor +:instance_list +{ + struct stats; + + static uint64_t ids; + + static void *default_allocator(handler &, const size_t &); + static void default_deallocator(handler &, void *const &, const size_t &) noexcept; + + string_view name; + uint64_t id {++ids}; + std::unique_ptr stats; + void *(*allocator)(handler &, const size_t &); + void (*deallocator)(handler &, void *const &, const size_t &); + std::vector> history; // epoch, cycles + uint8_t history_pos {0}; + bool continuation {false}; + + descriptor(const string_view &name, + const decltype(allocator) & = default_allocator, + const decltype(deallocator) & = default_deallocator, + const bool &continuation = false) noexcept; + + descriptor(descriptor &&) = delete; + descriptor(const descriptor &) = delete; + ~descriptor() noexcept; +}; + +struct ircd::ios::descriptor::stats +{ + uint64_t queued {0}; + uint64_t calls {0}; + uint64_t faults {0}; + uint64_t allocs {0}; + uint64_t alloc_bytes{0}; + uint64_t frees {0}; + uint64_t free_bytes{0}; + uint64_t slice_total {0}; + uint64_t slice_last {0}; + uint64_t latency_total {0}; + uint64_t latency_last {0}; + + stats &operator+=(const stats &) &; + + stats(); + ~stats() noexcept; +}; + +[[gnu::hot]] +inline void +ircd::ios::descriptor::default_deallocator(handler &handler, + void *const &ptr, + const size_t &size) +noexcept +{ + #ifdef __clang__ + ::operator delete(ptr); + #else + ::operator delete(ptr, size); + #endif +} + +[[gnu::hot]] +inline void * +ircd::ios::descriptor::default_allocator(handler &handler, + const size_t &size) +{ + return ::operator new(size); +} + +inline const ircd::string_view & +ircd::ios::name(const descriptor &descriptor) +{ + return descriptor.name; +} diff --git a/include/ircd/ios/dispatch.h b/include/ircd/ios/dispatch.h new file mode 100644 index 000000000..961202e70 --- /dev/null +++ b/include/ircd/ios/dispatch.h @@ -0,0 +1,55 @@ +// The Construct +// +// Copyright (C) The Construct Developers, Authors & Contributors +// Copyright (C) 2016-2020 Jason Volk +// +// 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. The +// full license for this software is available in the LICENSE file. + +#pragma once +#define HAVE_IRCD_IOS_DISPATCH_H + +namespace ircd::ios +{ + IRCD_OVERLOAD(synchronous) + + struct dispatch; + struct defer; + struct post; +} + +namespace ircd +{ + using ios::dispatch; + using ios::defer; + using ios::post; +} + +struct ircd::ios::dispatch +{ + dispatch(descriptor &, std::function); + dispatch(descriptor &, synchronous_t, const std::function &); + dispatch(descriptor &, synchronous_t); + dispatch(std::function); + dispatch(synchronous_t, const std::function &); +}; + +struct ircd::ios::defer +{ + defer(descriptor &, std::function); + defer(descriptor &, synchronous_t, const std::function &); + defer(descriptor &, synchronous_t); + defer(std::function); + defer(synchronous_t, const std::function &); +}; + +struct ircd::ios::post +{ + post(descriptor &, std::function); + post(descriptor &, synchronous_t, const std::function &); + post(descriptor &, synchronous_t); + post(std::function); + post(synchronous_t, const std::function &); +}; diff --git a/include/ircd/ios/handler.h b/include/ircd/ios/handler.h new file mode 100644 index 000000000..fc0e2f386 --- /dev/null +++ b/include/ircd/ios/handler.h @@ -0,0 +1,160 @@ +// The Construct +// +// Copyright (C) The Construct Developers, Authors & Contributors +// Copyright (C) 2016-2020 Jason Volk +// +// 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. The +// full license for this software is available in the LICENSE file. + +#pragma once +#define HAVE_IRCD_IOS_HANDLER_H + +namespace ircd::ios +{ + struct handler; + + template + struct handle; + + const string_view &name(const handler &); +} + +struct ircd::ios::handler +{ + static thread_local handler *current; + static thread_local uint64_t epoch; + + static void enqueue(handler *const &) noexcept; + static void *allocate(handler *const &, const size_t &); + static void deallocate(handler *const &, void *const &, const size_t &) noexcept; + static bool continuation(handler *const &) noexcept; + static void enter(handler *const &) noexcept; + static void leave(handler *const &) noexcept; + static bool fault(handler *const &) noexcept; + + ios::descriptor *descriptor {nullptr}; + uint64_t ts {0}; // last tsc sample; for profiling each phase +}; + +template +struct ircd::ios::handle +:handler +{ + function f; + + template + void operator()(args&&... a) const; + + handle(ios::descriptor &, function) noexcept; +}; + +// +// ircd::ios::handle +// + +template +inline +ircd::ios::handle::handle(ios::descriptor &d, + function f) +noexcept +:handler{&d, prof::cycles()} +,f(std::move(f)) +{ + handler::enqueue(this); +} + +template +template +inline void +ircd::ios::handle::operator()(args&&... a) +const +{ + assert(descriptor && descriptor->stats); + assert(descriptor->stats->queued > 0); + descriptor->stats->queued--; + f(std::forward(a)...); +} + +// +// ircd::ios::handler +// + +[[gnu::hot]] +inline void +ircd::ios::handler::deallocate(handler *const &handler, + void *const &ptr, + const size_t &size) +noexcept +{ + assert(handler && handler->descriptor); + auto &descriptor(*handler->descriptor); + + assert(descriptor.deallocator); + descriptor.deallocator(*handler, ptr, size); + + assert(descriptor.stats); + auto &stats(*descriptor.stats); + stats.free_bytes += size; + ++stats.frees; +} + +[[gnu::hot]] +inline void * +ircd::ios::handler::allocate(handler *const &handler, + const size_t &size) +{ + assert(handler && handler->descriptor); + auto &descriptor(*handler->descriptor); + + assert(descriptor.stats); + auto &stats(*descriptor.stats); + stats.alloc_bytes += size; + ++stats.allocs; + + assert(descriptor.allocator); + return descriptor.allocator(*handler, size); +} + +[[gnu::hot]] +inline void +ircd::ios::handler::enqueue(handler *const &handler) +noexcept +{ + assert(handler && handler->descriptor); + auto &descriptor(*handler->descriptor); + + assert(descriptor.stats); + auto &stats(*descriptor.stats); + ++stats.queued; + + if constexpr(profile::logging) + log::logf + { + log, log::level::DEBUG, + "QUEUE %5u %-30s [%11lu] ------[%9lu] q:%-4lu", + descriptor.id, + trunc(descriptor.name, 30), + stats.calls, + 0UL, + stats.queued, + }; +} + +[[gnu::hot]] +inline bool +ircd::ios::handler::continuation(handler *const &handler) +noexcept +{ + assert(handler && handler->descriptor); + auto &descriptor(*handler->descriptor); + return descriptor.continuation; +} + +inline const ircd::string_view & +ircd::ios::name(const handler &handler) +{ + assert(handler.descriptor); + return name(*handler.descriptor); +} diff --git a/include/ircd/ios/ios.h b/include/ircd/ios/ios.h new file mode 100644 index 000000000..2281754fe --- /dev/null +++ b/include/ircd/ios/ios.h @@ -0,0 +1,60 @@ +// The Construct +// +// Copyright (C) The Construct Developers, Authors & Contributors +// Copyright (C) 2016-2020 Jason Volk +// +// 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. The +// full license for this software is available in the LICENSE file. + +#pragma once +#define HAVE_IRCD_IOS_IOS_H + +/// Forward declarations for boost::asio because it is not included here. +namespace boost::asio +{ + struct executor; +} + +namespace ircd +{ + namespace asio = boost::asio; ///< Alias so that asio:: can be used. + + extern const info::versions boost_version_api, boost_version_abi; +} + +namespace ircd::ios +{ + extern log::log log; + extern asio::executor user, main; + extern std::thread::id main_thread_id; + + bool available() noexcept; + const uint64_t &epoch() noexcept; + + void forked_parent(); + void forked_child(); + void forking(); + + void init(asio::executor &&); +} + +namespace ircd::ios::profile +{ + constexpr bool history {false}; + constexpr bool logging {false}; +} + +#include "descriptor.h" +#include "handler.h" +#include "asio.h" +#include "dispatch.h" + +inline const uint64_t & +__attribute__((always_inline)) +ircd::ios::epoch() +noexcept +{ + return handler::epoch; +} diff --git a/include/ircd/ircd.h b/include/ircd/ircd.h index ff0ab9978..756988abc 100644 --- a/include/ircd/ircd.h +++ b/include/ircd/ircd.h @@ -93,7 +93,7 @@ #include "stats.h" #include "prof/prof.h" #include "fs/fs.h" -#include "ios.h" +#include "ios/ios.h" #include "ctx/ctx.h" #include "exec.h" #include "db/db.h" diff --git a/ircd/ios.cc b/ircd/ios.cc index bd5559195..fa91195f4 100644 --- a/ircd/ios.cc +++ b/ircd/ios.cc @@ -44,10 +44,6 @@ ircd::boost_version_abi "boost", info::versions::ABI //TODO: get this }; -// -// init -// - void ircd::ios::init(asio::executor &&user) { @@ -64,6 +60,43 @@ ircd::ios::init(asio::executor &&user) ios::main = ios::user; } +void +ircd::ios::forking() +{ + #if BOOST_VERSION >= 107000 + get().context().notify_fork(asio::execution_context::fork_prepare); + #else + get().notify_fork(asio::execution_context::fork_prepare); + #endif +} + +void +ircd::ios::forked_child() +{ + #if BOOST_VERSION >= 107000 + get().context().notify_fork(asio::execution_context::fork_child); + #else + get().notify_fork(asio::execution_context::fork_child); + #endif +} + +void +ircd::ios::forked_parent() +{ + #if BOOST_VERSION >= 107000 + get().context().notify_fork(asio::execution_context::fork_parent); + #else + get().notify_fork(asio::execution_context::fork_parent); + #endif +} + +bool +ircd::ios::available() +noexcept +{ + return bool(main); +} + // // descriptor // @@ -191,7 +224,7 @@ noexcept false }; - if constexpr(profile_logging) + if constexpr(profile::logging) log::logf { log, log::level::DEBUG, @@ -233,7 +266,7 @@ noexcept stats.slice_last = handler->ts - slice_start; stats.slice_total += stats.slice_last; - if constexpr(profile_history) + if constexpr(profile::history) { assert(descriptor.history_pos < descriptor.history.size()); descriptor.history[descriptor.history_pos][0] = handler::epoch; @@ -241,7 +274,7 @@ noexcept ++descriptor.history_pos; } - if constexpr(profile_logging) + if constexpr(profile::logging) log::logf { log, log::level::DEBUG, @@ -281,7 +314,7 @@ noexcept stats.latency_last = handler->ts - last_ts; stats.latency_total += stats.latency_last; - if constexpr(profile_logging) + if constexpr(profile::logging) log::logf { log, log::level::DEBUG, @@ -295,50 +328,14 @@ noexcept } // -// ios.h +// dispatch // namespace ircd::ios { - extern descriptor post_desc; - extern descriptor defer_desc; extern descriptor dispatch_desc; } -void -ircd::ios::forking() -{ - #if BOOST_VERSION >= 107000 - get().context().notify_fork(asio::execution_context::fork_prepare); - #else - get().notify_fork(asio::execution_context::fork_prepare); - #endif -} - -void -ircd::ios::forked_child() -{ - #if BOOST_VERSION >= 107000 - get().context().notify_fork(asio::execution_context::fork_child); - #else - get().notify_fork(asio::execution_context::fork_child); - #endif -} - -void -ircd::ios::forked_parent() -{ - #if BOOST_VERSION >= 107000 - get().context().notify_fork(asio::execution_context::fork_parent); - #else - get().notify_fork(asio::execution_context::fork_parent); - #endif -} - -// -// dispatch -// - decltype(ircd::ios::dispatch_desc) ircd::ios::dispatch_desc { @@ -405,13 +402,15 @@ ircd::ios::dispatch::dispatch(descriptor &descriptor, // defer // +namespace ircd::ios +{ + extern descriptor defer_desc; +} + decltype(ircd::ios::defer_desc) ircd::ios::defer_desc { "ircd::ios defer", - descriptor::default_allocator, - descriptor::default_deallocator, - true, // continuation }; [[gnu::hot]] @@ -474,6 +473,11 @@ ircd::ios::defer::defer(descriptor &descriptor, // post // +namespace ircd::ios +{ + extern descriptor post_desc; +} + decltype(ircd::ios::post_desc) ircd::ios::post_desc { @@ -535,10 +539,3 @@ ircd::ios::post::post(descriptor &descriptor, { boost::asio::post(get(), handle(descriptor, std::move(function))); } - -bool -ircd::ios::available() -noexcept -{ - return bool(main); -}