32#include <flow/util/basic_blob.hpp>
33#include <flow/util/stat/stat_set.hpp>
34#include <flow/util/util.hpp>
35#include <boost/interprocess/indexes/flat_map_index.hpp>
223 public flow::log::Log_context,
224 private boost::noncopyable
278 using Blob = flow::util::Blob_sans_log_context;
281 using Mem_algo = ::ipc::bipc::rbtree_best_fit<::ipc::bipc::mutex_family>;
441 template<
typename Handle_name_func>
579 template<
typename T,
typename... Ctor_args>
580 Handle<T>
construct(Ctor_args&&... ctor_args);
909 template<
typename Mode_tag>
910 explicit Pool_arena(Mode_tag mode_tag, flow::log::Logger* logger_ptr,
const Shared_name& pool_name,
size_t pool_sz,
1048 <= (
arena_size() - (
reinterpret_cast<uintptr_t
>(obj)
1049 -
reinterpret_cast<uintptr_t
>(
m_pool->address())));
1052template<
typename T,
typename... Ctor_args>
1057 using Atomic_owner_ct =
typename Shm_handle::Atomic_owner_ct;
1058 using flow::util::stat::fetch_add;
1059 using flow::util::stat::update_hi_wmark;
1061 using boost::shared_ptr;
1063 static_assert(
alignof(Shm_handle) <= flow::util::max_align_sz(),
1064 "allocate() guarantees only std::max_align_t alignment; over-aligned T is not supported.");
1073 const auto handle_state =
static_cast<Shm_handle*
>(
allocate(
sizeof(Shm_handle)));
1076 flow::util::construct_at(&handle_state->m_atomic_owner_ct, 1);
1092 if constexpr(std::is_trivially_destructible_v<Value>)
1094 flow::util::construct_at(&handle_state->m_obj, std::forward<Ctor_args>(ctor_args)...);
1099 flow::util::construct_at(&handle_state->m_obj, std::forward<Ctor_args>(ctor_args)...);
1106 (handle_state->m_atomic_owner_ct).~Atomic_owner_ct();
1107 deallocate(
static_cast<void*
>(handle_state));
1115 update_hi_wmark(&live_obj_stats.m_live_objects_hi_wmark,
1116 fetch_add(&live_obj_stats.m_live_objects, 1) + 1);
1127 [
this](Shm_handle* handle_state)
1128 { handle_deleter_impl<Value>(handle_state,
true); }},
1129 &handle_state->m_obj};
1138 using flow::util::buffers_dump_string;
1139 using flow::util::stat::fetch_add;
1147 const auto handle_state =
reinterpret_cast<Shm_handle*
>(handle.get());
1148 const auto new_owner_ct = handle_state->
m_atomic_owner_ct.fetch_add(1, std::memory_order_relaxed) + 1;
1168 const ptrdiff_t offset_from_pool_base =
reinterpret_cast<uintptr_t
>(handle_state)
1169 -
reinterpret_cast<uintptr_t
>(
m_pool->address());
1171 Blob serialization{
sizeof(offset_from_pool_base)};
1172 *(
reinterpret_cast<ptrdiff_t*
>(serialization.data())) = offset_from_pool_base;
1174 FLOW_LOG_TRACE(
"SHM-classic pool [" << *
this <<
"]: Serializing SHM outer handle [" << handle <<
"] before "
1175 "IPC-transmission: Owning process-count incremented to [" << new_owner_ct <<
"] "
1176 "(may change concurrently). "
1177 "Handle points to SHM-offset [" << offset_from_pool_base <<
"] (serialized). Serialized contents are "
1178 "[\n" << buffers_dump_string(serialization.const_buffer(),
" ") <<
"].");
1187 return serialization;
1195 using flow::util::buffers_dump_string;
1196 using flow::util::stat::fetch_add;
1197 using flow::util::stat::update_hi_wmark;
1198 using boost::shared_ptr;
1207 ptrdiff_t offset_from_pool_base;
1208 if (serialization.size() !=
sizeof(offset_from_pool_base))
1211 FLOW_LOG_WARNING(
"SHM-classic pool [" << *
this <<
"]: In attempt to deserialize SHM outer handle "
1212 "(type [" <<
typeid(Value).name() <<
"]) "
1213 "after IPC-receipt detected incorrect size [" << serialization.size() <<
"] of the serialized "
1214 "SHM-handle blob (expected: [" <<
sizeof(offset_from_pool_base) <<
"]). Borrow op fails. "
1215 "Was there a bug in transmitting the blob returned by opposing lend_object()?");
1223 memcpy(&offset_from_pool_base, serialization.const_data(),
sizeof(offset_from_pool_base));
1225 const auto handle_state
1226 =
reinterpret_cast<Shm_handle*
>
1227 (
reinterpret_cast<uintptr_t
>(
m_pool->address()) + offset_from_pool_base);
1234 FLOW_LOG_WARNING(
"SHM-classic pool [" << *
this <<
"]: In attempt to deserialize SHM outer handle "
1235 "[" <<
static_cast<const void*
>(handle_state) <<
"] "
1236 "(value+metadata size [" <<
sizeof(Shm_handle) <<
"], type [" <<
typeid(Value).name() <<
"]) "
1237 "after IPC-receipt detected that the value+metadata buffer is not wholly contained in "
1238 "our pool. Borrow op fails. "
1239 "Was there a bug in transmitting the blob returned by opposing lend_object()?");
1244 FLOW_LOG_TRACE(
"SHM-classic pool [" << *
this <<
"]: Deserialized SHM outer handle "
1245 "[" <<
static_cast<const void*
>(handle_state) <<
"] "
1246 "(type [" <<
typeid(Value).name() <<
"]) after IPC-receipt: "
1247 "Owner-count is at [" << handle_state->m_atomic_owner_ct <<
"] "
1248 "(may change concurrently; but includes us at least hence must be 1+); "
1249 "constructing PID = [" << handle_state->m_cting_process_id <<
"]; "
1251 "Handle points to SHM-offset [" << offset_from_pool_base <<
"] (deserialized). Serialized "
1252 "contents are [\n" << buffers_dump_string(serialization.const_buffer(),
" ") <<
"].");
1266 [
this](Shm_handle* handle_state)
1267 { handle_deleter_impl<Value>(handle_state,
false); }},
1268 &handle_state->m_obj};
1276 using flow::util::stat::fetch_add;
1277 using flow::util::stat::fetch_sub;
1312 const auto prev_owner_ct = handle_state->
m_atomic_owner_ct.fetch_sub(1, std::memory_order_release);
1313 assert((prev_owner_ct != 0) &&
"How was owner_ct=0, yet handle was still alive? Bug?");
1315 FLOW_LOG_TRACE(
"SHM-classic pool [" << *
this <<
"]: Return SHM outer handle [" << handle_state <<
"] "
1316 "(type [" <<
typeid(Value).name() <<
"]) "
1317 "because, for a given owner, a Handle is being destroyed due to shared_ptr ref-count reaching 0: "
1318 "Owner-count decremented to [" << (prev_owner_ct - 1) <<
"] (may change concurrently "
1319 "unless 0). If it is 0 now, shall invoke dtor and SHM-dealloc now. "
1323 enum { S_NONE, S_OWN_PID, S_OTHER_PID } destroy_type;
1324 if (prev_owner_ct == 1)
1326 std::atomic_thread_fence(std::memory_order_acquire);
1329 if constexpr(!std::is_trivially_destructible_v<Value>)
1337 (handle_state->
m_obj).~Value();
1342 deallocate(
static_cast<void*
>(handle_state));
1346 destroy_type = S_NONE;
1354 const auto update_stats = [&](
auto* obj_stats)
1356 fetch_add(&obj_stats->m_disposer_count, 1);
1357 fetch_sub(&obj_stats->m_live_handle_groups, 1);
1360 if (constructing_else_borrowing)
1363 fetch_add(&shared_arena_obj_stats.m_construct_disposer_count, 1);
1368 fetch_add(&shared_arena_obj_stats.m_borrow_disposer_count, 1);
1371 if (destroy_type != S_NONE)
1383 fetch_add(&shared_arena_obj_stats.m_destroy_count, 1);
1385 if (destroy_type == S_OTHER_PID)
1388 fetch_add(&shared_arena_obj_stats.m_non_owner_destroy_count, 1);
1394template<
typename Handle_name_func>
Similar to bipc's basic_managed_shared_memory, except that if a ctor created the SHM-pool in the file...
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.
::ipc::bipc::rbtree_best_fit<::ipc::bipc::mutex_family > Mem_algo
The boost.interprocess memory-algorithm used by the pools we set up.
void handle_deleter_impl(Handle_in_shm< T > *handle_state, bool constructing_else_borrowing)
Identical deleter for Handle returned by both construct() and borrow_object(); invoked when a given p...
bool commit(Error_code *err_code=nullptr)
Commits (takes RAM for) every page of the pool not yet committed, so that subsequent use of the pool ...
const stat::Arena_stats * arena_stats() const
Cumulative stats relevant to one SHM-classic arena – in this case single SHM-pool in shared memory,...
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={}, Error_code *err_code=nullptr)
Construct Pool_arena accessor object to non-existing named SHM pool, creating it first.
std::optional< Pool > m_pool
Attached SHM pool. If ctor fails in non-throwing fashion then this remains null. Immutable after ctor...
Arena_metadata * m_arena_metadata
Created or acquired in ctor, pointer to in-m_pool (in-SHM) metadata singleton; see Arena_metadata doc...
stat::Local_stats m_local_stats
Per-*this (not per-arena-in-SHM) stats being accumulated, from multiple threads sans sharding.
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...
const util::process_id_t m_own_process_id
Process ID captured in ctor, at least for perf. Used for and in relation to Handle_in_shm::m_cting_pr...
size_t arena_stat_free_size() const
How much of arena_size() is currently available for allocations; that is, not currently used by curre...
boost::shared_ptr< T > Handle
Outer handle to a SHM-stored object; really a regular-looking shared_ptr but with custom deleter that...
void init_arena_metadata(bool read_only)
Helper of ctors: with the assumption that m_pool is ready, sets up m_arena_metadata if possible.
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.
size_t arena_size() const
Arena (in this case, arena=pool) size in bytes as configured at arena/pool creation; never changes.
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 arena_stats_reset()
Resets arena_stats().
const stat::Local_stats & local_stats() const
Cumulative stats relevant to *this Pool_arena object – a Pool_arena – and excluding those in arena_st...
void * allocate(size_t n)
Allocates buffer of specified size, in bytes, in the accessed pool; returns locally-dereferenceable a...
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...
stat::Arena_info_dump Info_dump
Alias for a stats/info bundle type.
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 close_shm_object_handle()
Closes the pool's OS handle (FD) that *this keeps open only to enable commit(), returning that resour...
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 local_stats_reset()
Resets local_stats().
void info_dump(Info_dump *target_info_dump) const
Fills-out the stats/info contents of the given stat::Arena_info_dump: a printable bundling of all sta...
RAII-style class operating a stack-like notion of the given thread's currently active SHM-aware Arena...
Stateless allocator usable with STL-compliant containers to store (or merely read) them directly in S...
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.
::pid_t process_id_t
Syntactic-sugary type for POSIX process ID (integer).
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...
util::process_id_t m_cting_process_id
Process ID of the process that performed the Pool_arena::construct() that resulted in *this Handle_in...
std::atomic< uint32_t > Atomic_owner_ct
Atomically accessed count of each time the following events occurs for a given Handle_in_shm in the b...
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.
Printable (with knobs in contained util::stat::Info_dump_format) bundling of stats/info pertaining to...
Cumulative stats relevant to one SHM-classic arena – in this case single SHM-pool in shared memory,...
shm::stat::Live_obj_stats m_live_obj
Sub-struct with individual stats; see type's doc header.
shm::stat::Shared_arena_obj_stats m_obj
Sub-struct with individual stats; see type's doc header.
Cumulative stats relevant to a given SHM-classic arena object – a Pool_arena – and excluding those in...
shm::stat::Borrower_obj_stats m_borrower_obj
Sub-struct with individual stats; see type's doc header.
shm::stat::Owner_obj_stats m_owner_obj
Sub-struct with individual stats; see type's doc header.
shm::stat::Lender_obj_stats m_lender_obj
Sub-struct with individual stats; see type's doc header.
std::atomic< int64_t > m_live_handle_groups_hi_wmark
Max of m_live_handle_groups observed so far.
std::atomic< uint64_t > m_borrow_count
Count of the arena-or-session's .borrow_object<T>() calls by user.
std::atomic< int64_t > m_live_handle_groups
Gauge: How many groups counted in m_borrow_count have not yet had their disposer execute (as counted ...
std::atomic< uint64_t > m_lend_count
Count of .lend_object(obj) calls, where shared_ptr<T> obj was obtained as arena.construct<T>(....
std::atomic< uint64_t > m_live_objects
Gauge: Count of first-class – arena.construct()ed – objects that have not yet been destroyed (via GC)...
std::atomic< uint64_t > m_construct_count
Count of the arena object's .construct<T>() calls by user.
std::atomic< uint64_t > m_non_owner_destroy_count
Number of times the arena object has destroyed a first-class (construct()ed) object stored in the und...
std::atomic< uint64_t > m_destroy_count
Number of times the arena object has destroyed a first-class (construct()ed) object stored in the und...
std::atomic< int64_t > m_live_handle_groups_hi_wmark
Max of m_live_handle_groups observed so far.
std::atomic< int64_t > m_live_handle_groups
Gauge: How many groups counted in m_construct_count have not yet had their disposer execute (as count...
std::atomic< uint64_t > m_construct_count
Similar to Owner_obj_stats::m_construct_count but applies to all arena.construct()s executed w/r/t th...
std::atomic< uint64_t > m_lend_count
Similar to Lender_obj_stats::m_lend_count but applies to all arena.lend_object()s executed w/r/t the ...
std::atomic< uint64_t > m_borrow_count
Similar to Borrower_obj_stats::m_borrow_count but applies to all arena.borrow_object()s executed w/r/...