25#include <flow/util/basic_blob.hpp>
26#include <boost/interprocess/managed_shared_memory.hpp>
27#include <boost/interprocess/indexes/null_index.hpp>
152 public flow::log::Log_context,
153 private boost::noncopyable
195 using Blob = flow::util::Blob_sans_log_context;
344 template<
typename Handle_name_func>
424 template<
typename T,
typename... Ctor_args>
425 Handle<T>
construct(Ctor_args&&... ctor_args);
512 using Pool = ::ipc::bipc::basic_managed_shared_memory<char,
513 ::ipc::bipc::rbtree_best_fit<::ipc::bipc::mutex_family>,
514 ::ipc::bipc::null_index>;
575 template<
typename Mode_tag>
576 explicit Pool_arena(Mode_tag mode_tag, flow::log::Logger* logger_ptr,
const Shared_name& pool_name,
size_t pool_sz,
593 template<
typename T,
typename... Ctor_args>
594 static void construct_at(T* obj, Ctor_args&&... ctor_args);
673 <= (
m_pool->get_size() - (
reinterpret_cast<uintptr_t
>(obj)
674 -
reinterpret_cast<uintptr_t
>(
m_pool->get_address())));
677template<
typename T,
typename... Ctor_args>
682 using boost::shared_ptr;
690 const auto handle_state =
static_cast<Shm_handle*
>(
allocate(
sizeof(Shm_handle)));
696 construct_at(&handle_state->m_obj, std::forward<Ctor_args>(ctor_args)...);
701 [
this](Shm_handle* handle_state)
702 { handle_deleter_impl<Value>(handle_state); }},
703 &handle_state->m_obj};
712 using flow::util::buffers_dump_string;
720 const auto handle_state =
reinterpret_cast<Shm_handle*
>(handle.get());
723 const ptrdiff_t offset_from_pool_base =
reinterpret_cast<uintptr_t
>(handle_state)
724 -
reinterpret_cast<uintptr_t
>(
m_pool->get_address());
726 Blob serialization{
sizeof(offset_from_pool_base)};
727 *(
reinterpret_cast<ptrdiff_t*
>(serialization.data())) = offset_from_pool_base;
729 FLOW_LOG_TRACE(
"SHM-classic pool [" << *
this <<
"]: Serializing SHM outer handle [" << handle <<
"] before "
730 "IPC-transmission: Owning process-count incremented to [" << new_owner_ct <<
"] "
731 "(may change concurrently). "
732 "Handle points to SHM-offset [" << offset_from_pool_base <<
"] (serialized). Serialized contents are "
733 "[" << buffers_dump_string(serialization.const_buffer(),
" ") <<
"].");
735 return serialization;
743 using flow::util::buffers_dump_string;
744 using boost::shared_ptr;
753 ptrdiff_t offset_from_pool_base;
754 if (serialization.size() !=
sizeof(offset_from_pool_base))
757 FLOW_LOG_WARNING(
"SHM-classic pool [" << *
this <<
"]: In attempt to deserialize SHM outer handle "
758 "(type [" <<
typeid(Value).name() <<
"]) "
759 "after IPC-receipt detected incorrect size [" << serialization.size() <<
"] of the serialized "
760 "SHM-handle blob (expected: [" <<
sizeof(offset_from_pool_base) <<
"]). Borrow op fails. "
761 "Was there a bug in transmitting the blob returned by opposing lend_object()?");
769 memcpy(&offset_from_pool_base, serialization.const_data(),
sizeof(offset_from_pool_base));
771 const auto handle_state
772 =
reinterpret_cast<Shm_handle*
>
773 (
reinterpret_cast<uintptr_t
>(
m_pool->get_address()) + offset_from_pool_base);
780 FLOW_LOG_WARNING(
"SHM-classic pool [" << *
this <<
"]: In attempt to deserialize SHM outer handle "
781 "[" <<
static_cast<const void*
>(handle_state) <<
"] "
782 "(value+metadata size [" <<
sizeof(Shm_handle) <<
"], type [" <<
typeid(Value).name() <<
"]) "
783 "after IPC-receipt detected that the value+metadata buffer is not wholly contained in "
784 "our pool. Borrow op fails. "
785 "Was there a bug in transmitting the blob returned by opposing lend_object()?");
790 FLOW_LOG_TRACE(
"SHM-classic pool [" << *
this <<
"]: Deserialized SHM outer handle "
791 "[" <<
static_cast<const void*
>(handle_state) <<
"] "
792 "(type [" <<
typeid(Value).name() <<
"]) after IPC-receipt: "
793 "Owner-count is at [" << handle_state->m_atomic_owner_ct <<
"] "
794 "(may change concurrently; but includes us at least hence must be 1+). "
795 "Handle points to SHM-offset [" << offset_from_pool_base <<
"] (deserialized). Serialized "
796 "contents are [" << buffers_dump_string(serialization.const_buffer(),
" ") <<
"].");
801 [
this](Shm_handle* handle_state)
802 { handle_deleter_impl<Value>(handle_state); }},
803 &handle_state->m_obj};
814 assert((prev_owner_ct != 0) &&
"How was owner_ct=0, yet handle was still alive? Bug?");
816 FLOW_LOG_TRACE(
"SHM-classic pool [" << *
this <<
"]: Return SHM outer handle [" << handle_state <<
"] "
817 "(type [" <<
typeid(Value).name() <<
"]) "
818 "because, for a given owner, a Handle is being destroyed due to shared_ptr ref-count reaching 0: "
819 "Owner-count decremented to [" << (prev_owner_ct - 1) <<
"] (may change concurrently "
820 "unless 0). If it is 0 now, shall invoke dtor and SHM-dealloc now.");
821 if (prev_owner_ct == 1)
831 (handle_state->
m_obj).~Value();
840template<
typename T,
typename... Ctor_args>
846 ::new (
const_cast<void*
>
847 (
static_cast<void const volatile *
>
849 Value(std::forward<Ctor_args>(ctor_args)...);
852template<
typename Handle_name_func>
A SHM-classic interface around a single SHM pool with allocation-algorithm services by boost....
::ipc::bipc::offset_ptr< T > Pointer
SHM-storable fancy-pointer.
static void construct_at(T *obj, Ctor_args &&... ctor_args)
std::construct_at() equivalent; unavailable until C++20, so here it is.
std::optional< Pool > m_pool
Attached SHM pool. If ctor fails in non-throwing fashion then this remains null. Immutable after ctor...
bool deallocate(void *buf_not_null) noexcept
Undoes effects of local allocate() that returned buf_not_null; or another-process's allocate() that r...
bool is_obj_in_arena(const T *obj) const
Returns true if and only if all sizeof(T) bytes at address obj are within the bounds of the pool acce...
::ipc::bipc::basic_managed_shared_memory< char, ::ipc::bipc::rbtree_best_fit<::ipc::bipc::mutex_family >, ::ipc::bipc::null_index > Pool
The SHM pool type one instance of which is managed by *this.
boost::shared_ptr< T > Handle
Outer handle to a SHM-stored object; really a regular-looking shared_ptr but with custom deleter that...
const Shared_name m_pool_name
SHM pool name as set immutably at construction.
flow::util::Blob_sans_log_context Blob
Alias for a light-weight blob.
Pool_arena(flow::log::Logger *logger_ptr, const Shared_name &pool_name, util::Create_only mode_tag, size_t pool_sz, const util::Permissions &perms=util::Permissions{}, Error_code *err_code=nullptr)
Construct Pool_arena accessor object to non-existing named SHM pool, creating it first.
bool is_addr_in_arena(const void *p) const
Returns true if and only if the byte at p is within the bounds of the pool accessed by *this.
static void remove_persistent(flow::log::Logger *logger_ptr, const Shared_name &name, Error_code *err_code=nullptr)
Removes the named SHM pool object.
void * allocate(size_t n)
Allocates buffer of specified size, in bytes, in the accessed pool; returns locally-derefernceable ad...
static void for_each_persistent(const Handle_name_func &handle_name_func)
Lists all named SHM pool objects currently persisting, invoking the given handler synchronously on ea...
Handle< T > construct(Ctor_args &&... ctor_args)
Constructs an object of given type with given ctor args, having allocated space directly in attached ...
~Pool_arena()
Destroys Pool_arena accessor object.
Blob lend_object(const Handle< T > &handle)
Adds an owner process to the owner count of the given construct()-created handle, and returns an opaq...
bool is_handle_in_arena(const Handle< T > &handle) const
Returns true if and only if handle came from either this->construct<T>() or this->borrow_object<T>().
Handle< T > borrow_object(const Blob &serialization)
Completes the cross-process operation begun by lend_object() that returned serialization; to be invok...
void handle_deleter_impl(Handle_in_shm< T > *handle_state)
Identical deleter for Handle returned by both construct() and borrow_object(); invoked when a given p...
RAII-style class operating a stack-like notion of a the given thread's currently active SHM-aware Are...
String-wrapping abstraction representing a name uniquely distinguishing a kernel-persistent entity fr...
ipc::shm sub-module with the SHM-classic SHM-provider. See ipc::shm doc header for introduction.
util::Shared_name Shared_name
Short-hand for util::Shared_name; used in particular for SHM pool names at least.
bipc::permissions Permissions
Short-hand for Unix (POSIX) permissions class.
bipc::open_only_t Open_only
Tag type indicating an ideally-atomic open-if-exists-else-fail operation.
void for_each_persistent_shm_pool(const Handle_name_func &handle_name_func)
Equivalent to shm::classic::Pool_arena::for_each_persistent().
bipc::open_or_create_t Open_or_create
Tag type indicating an atomic open-if-exists-else-create operation.
bipc::create_only_t Create_only
Tag type indicating a create-unless-exists-else-fail operation.
boost::asio::const_buffer Blob_const
Short-hand for an immutable blob somewhere in memory, stored as exactly a void const * and a size_t.
flow::Error_code Error_code
Short-hand for flow::Error_code which is very common.
The data structure stored in SHM corresponding to an original construct()-returned Handle; exactly on...
Atomic_owner_ct m_atomic_owner_ct
See Atomic_owner_ct doc header. This value is 1+; once it reaches 0 *this is destroyed in SHM.
T m_obj
The constructed object; Handle::get() returns &m_obj.
std::atomic< unsigned int > Atomic_owner_ct
Atomically accessed count of each time the following events occurs for a given Handle_in_shm in the b...