mirror of
https://github.com/matrix-construct/construct
synced 2024-11-29 10:12:39 +01:00
ircd::ios: Split headers into directory; minor reorg.
ircd::ios: Move profile constexprs into namespace.
This commit is contained in:
parent
befe5ac750
commit
9ca664d231
9 changed files with 507 additions and 447 deletions
|
@ -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,
|
||||
|
|
|
@ -1,390 +0,0 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2018 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. 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<class function>
|
||||
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<class function> 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<void ()>);
|
||||
dispatch(descriptor &, synchronous_t, const std::function<void ()> &);
|
||||
dispatch(descriptor &, synchronous_t);
|
||||
dispatch(std::function<void ()>);
|
||||
dispatch(synchronous_t, const std::function<void ()> &);
|
||||
};
|
||||
|
||||
struct ircd::ios::defer
|
||||
{
|
||||
defer(descriptor &, std::function<void ()>);
|
||||
defer(descriptor &, synchronous_t, const std::function<void ()> &);
|
||||
defer(descriptor &, synchronous_t);
|
||||
defer(std::function<void ()>);
|
||||
defer(synchronous_t, const std::function<void ()> &);
|
||||
};
|
||||
|
||||
struct ircd::ios::post
|
||||
{
|
||||
post(descriptor &, std::function<void ()>);
|
||||
post(descriptor &, synchronous_t, const std::function<void ()> &);
|
||||
post(descriptor &, synchronous_t);
|
||||
post(std::function<void ()>);
|
||||
post(synchronous_t, const std::function<void ()> &);
|
||||
};
|
||||
|
||||
struct ircd::ios::descriptor
|
||||
:instance_list<descriptor>
|
||||
{
|
||||
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<struct stats> stats;
|
||||
void *(*allocator)(handler &, const size_t &);
|
||||
void (*deallocator)(handler &, void *const &, const size_t &);
|
||||
std::vector<std::array<uint64_t, 2>> 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<class function>
|
||||
struct ircd::ios::handle
|
||||
:handler
|
||||
{
|
||||
function f;
|
||||
|
||||
template<class... args>
|
||||
void operator()(args&&... a) const;
|
||||
|
||||
handle(ios::descriptor &, function) noexcept;
|
||||
};
|
||||
|
||||
// boost handlers
|
||||
namespace ircd::ios
|
||||
{
|
||||
template<class function>
|
||||
void asio_handler_deallocate(void *, size_t, handle<function> *);
|
||||
|
||||
template<class function>
|
||||
void *asio_handler_allocate(size_t, handle<function> *);
|
||||
|
||||
template<class function>
|
||||
bool asio_handler_is_continuation(handle<function> *);
|
||||
|
||||
template<class callable,
|
||||
class function>
|
||||
void asio_handler_invoke(callable &f, handle<function> *);
|
||||
}
|
||||
|
||||
template<class callable,
|
||||
class function>
|
||||
inline void
|
||||
ircd::ios::asio_handler_invoke(callable &f,
|
||||
handle<function> *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<class function>
|
||||
inline bool
|
||||
ircd::ios::asio_handler_is_continuation(handle<function> *const h)
|
||||
{
|
||||
return handler::continuation(h);
|
||||
}
|
||||
|
||||
template<class function>
|
||||
inline void *
|
||||
__attribute__((malloc, returns_nonnull, warn_unused_result, alloc_size(1)))
|
||||
ircd::ios::asio_handler_allocate(size_t size,
|
||||
handle<function> *const h)
|
||||
{
|
||||
return handler::allocate(h, size);
|
||||
}
|
||||
|
||||
template<class function>
|
||||
inline void
|
||||
ircd::ios::asio_handler_deallocate(void *const ptr,
|
||||
size_t size,
|
||||
handle<function> *const h)
|
||||
{
|
||||
handler::deallocate(h, ptr, size);
|
||||
}
|
||||
|
||||
//
|
||||
// ircd::ios::handle
|
||||
//
|
||||
|
||||
template<class function>
|
||||
inline
|
||||
ircd::ios::handle<function>::handle(ios::descriptor &d,
|
||||
function f)
|
||||
noexcept
|
||||
:handler{&d, prof::cycles()}
|
||||
,f(std::move(f))
|
||||
{
|
||||
handler::enqueue(this);
|
||||
}
|
||||
|
||||
template<class function>
|
||||
template<class... args>
|
||||
inline void
|
||||
ircd::ios::handle<function>::operator()(args&&... a)
|
||||
const
|
||||
{
|
||||
assert(descriptor && descriptor->stats);
|
||||
assert(descriptor->stats->queued > 0);
|
||||
descriptor->stats->queued--;
|
||||
f(std::forward<args>(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;
|
||||
}
|
81
include/ircd/ios/asio.h
Normal file
81
include/ircd/ios/asio.h
Normal file
|
@ -0,0 +1,81 @@
|
|||
// The Construct
|
||||
//
|
||||
// Copyright (C) The Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2020 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. 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<class function>
|
||||
void asio_handler_invoke(function&, ...);
|
||||
}
|
||||
|
||||
namespace ircd::ios
|
||||
{
|
||||
template<class function>
|
||||
void asio_handler_deallocate(void *, size_t, handle<function> *);
|
||||
|
||||
template<class function>
|
||||
void *asio_handler_allocate(size_t, handle<function> *);
|
||||
|
||||
template<class function>
|
||||
bool asio_handler_is_continuation(handle<function> *);
|
||||
|
||||
template<class callable,
|
||||
class function>
|
||||
void asio_handler_invoke(callable &f, handle<function> *);
|
||||
}
|
||||
|
||||
template<class callable,
|
||||
class function>
|
||||
inline void
|
||||
ircd::ios::asio_handler_invoke(callable &f,
|
||||
handle<function> *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<class function>
|
||||
inline bool
|
||||
ircd::ios::asio_handler_is_continuation(handle<function> *const h)
|
||||
{
|
||||
return handler::continuation(h);
|
||||
}
|
||||
|
||||
template<class function>
|
||||
inline void *
|
||||
__attribute__((malloc, returns_nonnull, warn_unused_result, alloc_size(1)))
|
||||
ircd::ios::asio_handler_allocate(size_t size,
|
||||
handle<function> *const h)
|
||||
{
|
||||
return handler::allocate(h, size);
|
||||
}
|
||||
|
||||
template<class function>
|
||||
inline void
|
||||
ircd::ios::asio_handler_deallocate(void *const ptr,
|
||||
size_t size,
|
||||
handle<function> *const h)
|
||||
{
|
||||
handler::deallocate(h, ptr, size);
|
||||
}
|
97
include/ircd/ios/descriptor.h
Normal file
97
include/ircd/ios/descriptor.h
Normal file
|
@ -0,0 +1,97 @@
|
|||
// The Construct
|
||||
//
|
||||
// Copyright (C) The Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2020 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. 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<descriptor>
|
||||
{
|
||||
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<struct stats> stats;
|
||||
void *(*allocator)(handler &, const size_t &);
|
||||
void (*deallocator)(handler &, void *const &, const size_t &);
|
||||
std::vector<std::array<uint64_t, 2>> 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;
|
||||
}
|
55
include/ircd/ios/dispatch.h
Normal file
55
include/ircd/ios/dispatch.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
// The Construct
|
||||
//
|
||||
// Copyright (C) The Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2020 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. 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<void ()>);
|
||||
dispatch(descriptor &, synchronous_t, const std::function<void ()> &);
|
||||
dispatch(descriptor &, synchronous_t);
|
||||
dispatch(std::function<void ()>);
|
||||
dispatch(synchronous_t, const std::function<void ()> &);
|
||||
};
|
||||
|
||||
struct ircd::ios::defer
|
||||
{
|
||||
defer(descriptor &, std::function<void ()>);
|
||||
defer(descriptor &, synchronous_t, const std::function<void ()> &);
|
||||
defer(descriptor &, synchronous_t);
|
||||
defer(std::function<void ()>);
|
||||
defer(synchronous_t, const std::function<void ()> &);
|
||||
};
|
||||
|
||||
struct ircd::ios::post
|
||||
{
|
||||
post(descriptor &, std::function<void ()>);
|
||||
post(descriptor &, synchronous_t, const std::function<void ()> &);
|
||||
post(descriptor &, synchronous_t);
|
||||
post(std::function<void ()>);
|
||||
post(synchronous_t, const std::function<void ()> &);
|
||||
};
|
160
include/ircd/ios/handler.h
Normal file
160
include/ircd/ios/handler.h
Normal file
|
@ -0,0 +1,160 @@
|
|||
// The Construct
|
||||
//
|
||||
// Copyright (C) The Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2020 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. 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<class function>
|
||||
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<class function>
|
||||
struct ircd::ios::handle
|
||||
:handler
|
||||
{
|
||||
function f;
|
||||
|
||||
template<class... args>
|
||||
void operator()(args&&... a) const;
|
||||
|
||||
handle(ios::descriptor &, function) noexcept;
|
||||
};
|
||||
|
||||
//
|
||||
// ircd::ios::handle
|
||||
//
|
||||
|
||||
template<class function>
|
||||
inline
|
||||
ircd::ios::handle<function>::handle(ios::descriptor &d,
|
||||
function f)
|
||||
noexcept
|
||||
:handler{&d, prof::cycles()}
|
||||
,f(std::move(f))
|
||||
{
|
||||
handler::enqueue(this);
|
||||
}
|
||||
|
||||
template<class function>
|
||||
template<class... args>
|
||||
inline void
|
||||
ircd::ios::handle<function>::operator()(args&&... a)
|
||||
const
|
||||
{
|
||||
assert(descriptor && descriptor->stats);
|
||||
assert(descriptor->stats->queued > 0);
|
||||
descriptor->stats->queued--;
|
||||
f(std::forward<args>(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);
|
||||
}
|
60
include/ircd/ios/ios.h
Normal file
60
include/ircd/ios/ios.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
// The Construct
|
||||
//
|
||||
// Copyright (C) The Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2020 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. 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;
|
||||
}
|
|
@ -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"
|
||||
|
|
107
ircd/ios.cc
107
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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue