shm: Ref counting for unmanaged regions in a dedicated segment

This commit is contained in:
Alexey Rybalchenko
2023-09-19 10:21:00 +02:00
parent cacf69d5f6
commit 1a0ab3a4e2
7 changed files with 159 additions and 85 deletions

View File

@@ -59,8 +59,9 @@ struct UnmanagedRegion
, fRemoveOnDestruction(cfg.removeOnDestruction)
, fLinger(cfg.linger)
, fStopAcks(false)
, fName("fmq_" + shmId + "_rg_" + std::to_string(cfg.id.value()))
, fQueueName("fmq_" + shmId + "_rgq_" + std::to_string(cfg.id.value()))
, fName(MakeShmName(shmId, "rg", cfg.id.value()))
, fQueueName(MakeShmName(shmId, "rgq", cfg.id.value()))
, fRefCountSegmentName(MakeShmName(shmId, "rrc", cfg.id.value()))
, fShmemObject()
, fFile(nullptr)
, fFileMapping()
@@ -186,6 +187,19 @@ struct UnmanagedRegion
bool RemoveOnDestruction() { return fRemoveOnDestruction; }
RefCount& MakeRefCount(uint16_t initialCount = 1)
{
RefCount* refCount = fRefCountPool->allocate(1).get();
new (refCount) RefCount(initialCount);
return *refCount;
}
void RemoveRefCount(RefCount& refCount)
{
refCount.~RefCount();
fRefCountPool->deallocate(&refCount, 1);
}
~UnmanagedRegion()
{
LOG(debug) << "~UnmanagedRegion(): " << fName << " (" << (fControlling ? "controller" : "viewer") << ")";
@@ -208,6 +222,11 @@ struct UnmanagedRegion
if (Monitor::RemoveFileMapping(fName.c_str())) {
LOG(trace) << "File mapping '" << fName << "' destroyed.";
}
if (fRefCountSegment) {
if (Monitor::RemoveObject(fRefCountSegmentName)) {
LOG(trace) << "Ref Count Segment '" << fRefCountSegmentName << "' destroyed.";
}
}
} else {
LOG(debug) << "Skipping removal of " << fName << " unmanaged region, because RegionConfig::removeOnDestruction is false";
}
@@ -235,6 +254,7 @@ struct UnmanagedRegion
std::atomic<bool> fStopAcks;
std::string fName;
std::string fQueueName;
std::string fRefCountSegmentName;
boost::interprocess::shared_memory_object fShmemObject;
FILE* fFile;
boost::interprocess::file_mapping fFileMapping;
@@ -245,12 +265,18 @@ struct UnmanagedRegion
std::vector<RegionBlock> fBlocksToFree;
const std::size_t fAckBunchSize = 256;
std::unique_ptr<boost::interprocess::message_queue> fQueue;
std::unique_ptr<boost::interprocess::managed_shared_memory> fRefCountSegment;
std::unique_ptr<RefCountPool> fRefCountPool;
std::thread fAcksReceiver;
std::thread fAcksSender;
RegionCallback fCallback;
RegionBulkCallback fBulkCallback;
static std::string MakeSegmentName(const std::string& shmId, std::string_view segment, int regionIndex) {
return tools::ToString("fmq_", shmId, "_", segment, "_", regionIndex);
}
static RegionConfig makeRegionConfig(uint16_t id)
{
RegionConfig regionCfg;
@@ -275,7 +301,7 @@ struct UnmanagedRegion
throw TransportError(tools::ToString("Unmanaged Region with id ", cfg.id.value(), " has already been registered. Only unique IDs per session are allowed."));
}
shmRegions->emplace(cfg.id.value(), RegionInfo(cfg.path.c_str(), cfg.creationFlags, cfg.userFlags, cfg.size, alloc));
shmRegions->emplace(cfg.id.value(), RegionInfo(cfg.path.c_str(), cfg.creationFlags, cfg.userFlags, cfg.size, cfg.rcSegmentSize, alloc));
(eventCounter->fCount)++;
}
@@ -294,6 +320,29 @@ struct UnmanagedRegion
}
}
void InitializeRefCountSegment(uint64_t size)
{
using namespace boost::interprocess;
if (!fRefCountSegment) {
fRefCountSegment = std::make_unique<managed_shared_memory>(open_or_create, fRefCountSegmentName.c_str(), size);
LOG(trace) << "shmem: initialized ref count segment: " << fRefCountSegmentName;
fRefCountPool = std::make_unique<RefCountPool>(fRefCountSegment->get_segment_manager());
}
}
RefCount* GetRefCountAddressFromHandle(const boost::interprocess::managed_shared_memory::handle_t handle)
{
if (fRefCountPool) {
return reinterpret_cast<RefCount*>(fRefCountSegment->get_address_from_handle(handle));
}
return nullptr;
};
boost::interprocess::managed_shared_memory::handle_t HandleFromAddress(const void* ptr)
{
return fRefCountSegment->get_handle_from_address(ptr);
}
void StartAckSender()
{
if (!fAcksSender.joinable()) {