0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-10-31 19:08:59 +01:00
construct/include/ircd/ios/handler.h

168 lines
4 KiB
C++

// 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 &);
}
/// Non-template base class for ios::handle; templated derivations of this
/// class comprise the function object we're submitting to boost::asio.
struct ircd::ios::handler
{
static thread_local handler *current;
static thread_local uint64_t epoch;
static void enqueue(handler *) noexcept;
static void *allocate(handler *, const size_t);
static void deallocate(handler *, void *, const size_t) noexcept;
static bool continuation(handler *) noexcept;
static void enter(handler *) noexcept;
static void leave(handler *) noexcept;
static bool fault(handler *) noexcept;
ios::descriptor *descriptor {nullptr};
uint64_t ts {0}; // last tsc sample; for profiling each phase
};
/// Our function object type template. These should be rvalue-constructed in a
/// callback argument to a boost::asio call. A reference to an ios::descriptor
/// must be provided.
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
//
/// Construction of the handle is considered the enquement. Construct in the
/// callback argument to a boost::asio call; provide a reference to the
/// appropriate callsite descriptor.
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] ------[%15lu] q:%-4lu",
descriptor.id,
trunc(descriptor.name, 30),
uint64_t(stats.calls),
0UL,
uint64_t(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);
}