mirror of
https://github.com/FairRootGroup/FairMQ.git
synced 2025-10-13 16:46:47 +00:00
shm: Ref counting for unmanaged regions in a dedicated segment
This commit is contained in:
parent
cacf69d5f6
commit
1a0ab3a4e2
|
@ -134,6 +134,7 @@ struct RegionConfig
|
||||||
int creationFlags = 0; /// flags passed to the underlying transport on region creation
|
int creationFlags = 0; /// flags passed to the underlying transport on region creation
|
||||||
int64_t userFlags = 0; /// custom flags that have no effect on the transport, but can be retrieved from the region by the user
|
int64_t userFlags = 0; /// custom flags that have no effect on the transport, but can be retrieved from the region by the user
|
||||||
uint64_t size = 0; /// region size
|
uint64_t size = 0; /// region size
|
||||||
|
uint64_t rcSegmentSize = 10000000; /// region size
|
||||||
std::string path = ""; /// file path, if the region is backed by a file
|
std::string path = ""; /// file path, if the region is backed by a file
|
||||||
std::optional<uint16_t> id = std::nullopt; /// region id
|
std::optional<uint16_t> id = std::nullopt; /// region id
|
||||||
uint32_t linger = 100; /// delay in ms before region destruction to collect outstanding events
|
uint32_t linger = 100; /// delay in ms before region destruction to collect outstanding events
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <functional> // std::equal_to
|
#include <functional> // std::equal_to
|
||||||
|
|
||||||
#include <boost/functional/hash.hpp>
|
#include <boost/functional/hash.hpp>
|
||||||
|
#include <boost/interprocess/allocators/adaptive_pool.hpp>
|
||||||
#include <boost/interprocess/allocators/allocator.hpp>
|
#include <boost/interprocess/allocators/allocator.hpp>
|
||||||
#include <boost/interprocess/containers/map.hpp>
|
#include <boost/interprocess/containers/map.hpp>
|
||||||
#include <boost/interprocess/containers/string.hpp>
|
#include <boost/interprocess/containers/string.hpp>
|
||||||
|
@ -25,6 +26,8 @@
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <fairmq/tools/Strings.h>
|
||||||
|
|
||||||
namespace fair::mq::shmem
|
namespace fair::mq::shmem
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -41,6 +44,31 @@ using RBTreeBestFitSegment = boost::interprocess::basic_managed_shared_memory<ch
|
||||||
boost::interprocess::null_index>;
|
boost::interprocess::null_index>;
|
||||||
// boost::interprocess::iset_index>;
|
// boost::interprocess::iset_index>;
|
||||||
|
|
||||||
|
inline std::string MakeShmName(const std::string& shmId, const std::string& type, int index) {
|
||||||
|
return std::string("fmq_" + shmId + "_" + type + "_" + std::to_string(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RefCount
|
||||||
|
{
|
||||||
|
explicit RefCount(uint16_t c)
|
||||||
|
: count(c)
|
||||||
|
{}
|
||||||
|
|
||||||
|
uint16_t Get() { return count.load(); }
|
||||||
|
uint16_t Increment() { return count.fetch_add(1); }
|
||||||
|
uint16_t Decrement() { return count.fetch_sub(1); }
|
||||||
|
|
||||||
|
std::atomic<uint16_t> count;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Number of nodes allocated at once when the allocator runs out of nodes.
|
||||||
|
static constexpr size_t numNodesPerBlock = 4096;
|
||||||
|
// Maximum number of totally free blocks that the adaptive node pool will hold.
|
||||||
|
// The rest of the totally free blocks will be deallocated with the segment manager.
|
||||||
|
static constexpr size_t maxFreeBlocks = 2;
|
||||||
|
|
||||||
|
using RefCountPool = boost::interprocess::adaptive_pool<RefCount, boost::interprocess::managed_shared_memory::segment_manager, numNodesPerBlock, maxFreeBlocks>;
|
||||||
|
|
||||||
using SegmentManager = boost::interprocess::managed_shared_memory::segment_manager;
|
using SegmentManager = boost::interprocess::managed_shared_memory::segment_manager;
|
||||||
using VoidAlloc = boost::interprocess::allocator<void, SegmentManager>;
|
using VoidAlloc = boost::interprocess::allocator<void, SegmentManager>;
|
||||||
using CharAlloc = boost::interprocess::allocator<char, SegmentManager>;
|
using CharAlloc = boost::interprocess::allocator<char, SegmentManager>;
|
||||||
|
@ -121,6 +149,17 @@ struct ShmHeader
|
||||||
static void Destruct(char* ptr) { RefCountPtr(ptr).~atomic(); }
|
static void Destruct(char* ptr) { RefCountPtr(ptr).~atomic(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct MetaHeader
|
||||||
|
{
|
||||||
|
size_t fSize; // size of the shm buffer
|
||||||
|
size_t fHint; // user-defined value, given by the user on message creation and returned to the user on "buffer no longer needed"-callbacks
|
||||||
|
boost::interprocess::managed_shared_memory::handle_t fHandle; // handle to shm buffer, convertible to shm buffer ptr
|
||||||
|
mutable boost::interprocess::managed_shared_memory::handle_t fShared; // handle to the buffer storing the ref count for shared buffers
|
||||||
|
uint16_t fRegionId; // id of the unmanaged region
|
||||||
|
mutable uint16_t fSegmentId; // id of the managed segment
|
||||||
|
bool fManaged; // true = managed segment, false = unmanaged region
|
||||||
|
};
|
||||||
|
|
||||||
enum class AllocationAlgorithm : int
|
enum class AllocationAlgorithm : int
|
||||||
{
|
{
|
||||||
rbtree_best_fit,
|
rbtree_best_fit,
|
||||||
|
@ -129,26 +168,30 @@ enum class AllocationAlgorithm : int
|
||||||
|
|
||||||
struct RegionInfo
|
struct RegionInfo
|
||||||
{
|
{
|
||||||
RegionInfo(const VoidAlloc& alloc)
|
static constexpr uint64_t DefaultRcSegmentSize = 10000000;
|
||||||
: fPath("", alloc)
|
|
||||||
, fCreationFlags(0)
|
|
||||||
, fUserFlags(0)
|
|
||||||
, fSize(0)
|
|
||||||
, fDestroyed(false)
|
|
||||||
{}
|
|
||||||
|
|
||||||
RegionInfo(const char* path, int flags, uint64_t userFlags, uint64_t size, const VoidAlloc& alloc)
|
RegionInfo(const char* path, int flags, uint64_t userFlags, uint64_t size, uint64_t rcSegmentSize, const VoidAlloc& alloc)
|
||||||
: fPath(path, alloc)
|
: fPath(path, alloc)
|
||||||
, fCreationFlags(flags)
|
, fCreationFlags(flags)
|
||||||
, fUserFlags(userFlags)
|
, fUserFlags(userFlags)
|
||||||
, fSize(size)
|
, fSize(size)
|
||||||
|
, fRCSegmentSize(rcSegmentSize)
|
||||||
, fDestroyed(false)
|
, fDestroyed(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
RegionInfo(const VoidAlloc& alloc)
|
||||||
|
: RegionInfo("", 0, 0, 0, DefaultRcSegmentSize, alloc)
|
||||||
|
{}
|
||||||
|
|
||||||
|
RegionInfo(const char* path, int flags, uint64_t userFlags, uint64_t size, const VoidAlloc& alloc)
|
||||||
|
: RegionInfo(path, flags, userFlags, size, DefaultRcSegmentSize, alloc)
|
||||||
|
{}
|
||||||
|
|
||||||
Str fPath;
|
Str fPath;
|
||||||
int fCreationFlags;
|
int fCreationFlags;
|
||||||
uint64_t fUserFlags;
|
uint64_t fUserFlags;
|
||||||
uint64_t fSize;
|
uint64_t fSize;
|
||||||
|
uint64_t fRCSegmentSize;
|
||||||
bool fDestroyed;
|
bool fDestroyed;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -216,17 +259,6 @@ struct RegionCounter
|
||||||
std::atomic<uint16_t> fCount;
|
std::atomic<uint16_t> fCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MetaHeader
|
|
||||||
{
|
|
||||||
size_t fSize;
|
|
||||||
size_t fHint;
|
|
||||||
boost::interprocess::managed_shared_memory::handle_t fHandle;
|
|
||||||
mutable boost::interprocess::managed_shared_memory::handle_t fShared;
|
|
||||||
uint16_t fRegionId;
|
|
||||||
mutable uint16_t fSegmentId;
|
|
||||||
bool fManaged;
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef FAIRMQ_DEBUG_MODE
|
#ifdef FAIRMQ_DEBUG_MODE
|
||||||
struct MsgCounter
|
struct MsgCounter
|
||||||
{
|
{
|
||||||
|
@ -310,29 +342,6 @@ struct SegmentBufferShrink
|
||||||
mutable char* local_ptr;
|
mutable char* local_ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
// struct SegmentWrapper
|
|
||||||
// {
|
|
||||||
// SegmentWrapper(boost::variant<RBTreeBestFitSegment, SimpleSeqFitSegment>&& _segment)
|
|
||||||
// : segment(std::move(_segment))
|
|
||||||
// , refCountPool(nullptr)
|
|
||||||
// {}
|
|
||||||
|
|
||||||
// void InitRefCountPoolSSF()
|
|
||||||
// {
|
|
||||||
// refCountPool = std::make_unique<boost::variant<RefCountPoolRBT, RefCountPoolSSF>>(
|
|
||||||
// RefCountPoolSSF(boost::get<SimpleSeqFitSegment>(segment).get_segment_manager()));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// void InitRefCountPoolRBT()
|
|
||||||
// {
|
|
||||||
// refCountPool = std::make_unique<boost::variant<RefCountPoolRBT, RefCountPoolSSF>>(
|
|
||||||
// RefCountPoolRBT(boost::get<RBTreeBestFitSegment>(segment).get_segment_manager()));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// boost::variant<SimpleSeqFitSegment, RBTreeBestFitSegment> segment;
|
|
||||||
// std::unique_ptr<boost::variant<RefCountPoolRBT, RefCountPoolSSF>> refCountPool;
|
|
||||||
// };
|
|
||||||
|
|
||||||
} // namespace fair::mq::shmem
|
} // namespace fair::mq::shmem
|
||||||
|
|
||||||
#endif /* FAIR_MQ_SHMEM_COMMON_H_ */
|
#endif /* FAIR_MQ_SHMEM_COMMON_H_ */
|
||||||
|
|
|
@ -323,6 +323,7 @@ class Manager
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint16_t id = cfg.id.value();
|
const uint16_t id = cfg.id.value();
|
||||||
|
const uint64_t rcSegmentSize = cfg.rcSegmentSize;
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(fLocalRegionsMtx);
|
std::lock_guard<std::mutex> lock(fLocalRegionsMtx);
|
||||||
|
|
||||||
|
@ -347,6 +348,7 @@ class Manager
|
||||||
// start ack receiver only if a callback has been provided.
|
// start ack receiver only if a callback has been provided.
|
||||||
if (callback || bulkCallback) {
|
if (callback || bulkCallback) {
|
||||||
region->SetCallbacks(callback, bulkCallback);
|
region->SetCallbacks(callback, bulkCallback);
|
||||||
|
region->InitializeRefCountSegment(rcSegmentSize);
|
||||||
region->InitializeQueues();
|
region->InitializeQueues();
|
||||||
region->StartAckSender();
|
region->StartAckSender();
|
||||||
region->StartAckReceiver();
|
region->StartAckReceiver();
|
||||||
|
@ -398,6 +400,7 @@ class Manager
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
RegionConfig cfg;
|
RegionConfig cfg;
|
||||||
|
const uint64_t rcSegmentSize = cfg.rcSegmentSize;
|
||||||
// get region info
|
// get region info
|
||||||
{
|
{
|
||||||
boost::interprocess::scoped_lock<boost::interprocess::interprocess_mutex> shmLock(*fShmMtx);
|
boost::interprocess::scoped_lock<boost::interprocess::interprocess_mutex> shmLock(*fShmMtx);
|
||||||
|
@ -409,6 +412,7 @@ class Manager
|
||||||
// LOG(debug) << "Located remote region with id '" << id << "', path: '" << cfg.path << "', flags: '" << cfg.creationFlags << "'";
|
// LOG(debug) << "Located remote region with id '" << id << "', path: '" << cfg.path << "', flags: '" << cfg.creationFlags << "'";
|
||||||
|
|
||||||
auto r = fRegions.emplace(id, std::make_unique<UnmanagedRegion>(fShmId, 0, false, std::move(cfg)));
|
auto r = fRegions.emplace(id, std::make_unique<UnmanagedRegion>(fShmId, 0, false, std::move(cfg)));
|
||||||
|
r.first->second->InitializeRefCountSegment(rcSegmentSize);
|
||||||
r.first->second->InitializeQueues();
|
r.first->second->InitializeQueues();
|
||||||
r.first->second->StartAckSender();
|
r.first->second->StartAckSender();
|
||||||
return r.first->second.get();
|
return r.first->second.get();
|
||||||
|
@ -499,8 +503,10 @@ class Manager
|
||||||
if (it != fRegions.end()) {
|
if (it != fRegions.end()) {
|
||||||
region = it->second.get();
|
region = it->second.get();
|
||||||
} else {
|
} else {
|
||||||
|
const uint64_t rcSegmentSize = cfgIt->second.rcSegmentSize;
|
||||||
auto r = fRegions.emplace(cfgIt->first, std::make_unique<UnmanagedRegion>(fShmId, 0, false, cfgIt->second));
|
auto r = fRegions.emplace(cfgIt->first, std::make_unique<UnmanagedRegion>(fShmId, 0, false, cfgIt->second));
|
||||||
region = r.first->second.get();
|
region = r.first->second.get();
|
||||||
|
region->InitializeRefCountSegment(rcSegmentSize);
|
||||||
region->InitializeQueues();
|
region->InitializeQueues();
|
||||||
region->StartAckSender();
|
region->StartAckSender();
|
||||||
}
|
}
|
||||||
|
|
|
@ -262,52 +262,50 @@ class Message final : public fair::mq::Message
|
||||||
if (fMeta.fManaged) { // managed segment
|
if (fMeta.fManaged) { // managed segment
|
||||||
fManager.GetSegment(fMeta.fSegmentId);
|
fManager.GetSegment(fMeta.fSegmentId);
|
||||||
return ShmHeader::RefCount(fManager.GetAddressFromHandle(fMeta.fHandle, fMeta.fSegmentId));
|
return ShmHeader::RefCount(fManager.GetAddressFromHandle(fMeta.fHandle, fMeta.fSegmentId));
|
||||||
} else { // unmanaged region
|
|
||||||
if (fMeta.fShared < 0) { // UR msg is not yet shared
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
fManager.GetSegment(fMeta.fSegmentId);
|
|
||||||
return ShmHeader::RefCount(fManager.GetAddressFromHandle(fMeta.fShared, fMeta.fSegmentId));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (fMeta.fShared < 0) { // UR msg is not yet shared
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
fRegionPtr = fManager.GetRegionFromCache(fMeta.fRegionId);
|
||||||
|
if (!fRegionPtr) {
|
||||||
|
throw TransportError(tools::ToString("Cannot get unmanaged region with id ", fMeta.fRegionId));
|
||||||
|
}
|
||||||
|
return fRegionPtr->GetRefCountAddressFromHandle(fMeta.fShared)->Get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Copy(const fair::mq::Message& other) override
|
void Copy(const fair::mq::Message& other) override
|
||||||
{
|
{
|
||||||
const Message& otherMsg = static_cast<const Message&>(other);
|
const Message& otherMsg = static_cast<const Message&>(other);
|
||||||
|
// if the other message is not initialized, close this one too and return
|
||||||
if (otherMsg.fMeta.fHandle < 0) {
|
if (otherMsg.fMeta.fHandle < 0) {
|
||||||
// if the other message is not initialized, close this one too and return
|
|
||||||
CloseMessage();
|
CloseMessage();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if this msg is already initialized, close it first
|
||||||
if (fMeta.fHandle >= 0) {
|
if (fMeta.fHandle >= 0) {
|
||||||
// if this msg is already initialized, close it first
|
|
||||||
CloseMessage();
|
CloseMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (otherMsg.fMeta.fManaged) { // managed segment
|
// increment ref count
|
||||||
fMeta = otherMsg.fMeta;
|
if (otherMsg.fMeta.fManaged) { // msg in managed segment
|
||||||
fManager.GetSegment(fMeta.fSegmentId);
|
fManager.GetSegment(otherMsg.fMeta.fSegmentId);
|
||||||
ShmHeader::IncrementRefCount(fManager.GetAddressFromHandle(fMeta.fHandle, fMeta.fSegmentId));
|
ShmHeader::IncrementRefCount(fManager.GetAddressFromHandle(otherMsg.fMeta.fHandle, otherMsg.fMeta.fSegmentId));
|
||||||
} else { // unmanaged region
|
} else { // msg in unmanaged region
|
||||||
if (otherMsg.fMeta.fShared < 0) { // if UR msg is not yet shared
|
fRegionPtr = fManager.GetRegionFromCache(otherMsg.fMeta.fRegionId);
|
||||||
// TODO: minimize the size to 0 and don't create extra space for user buffer alignment
|
if (!fRegionPtr) {
|
||||||
char* ptr = fManager.Allocate(2, 0);
|
throw TransportError(tools::ToString("Cannot get unmanaged region with id ", otherMsg.fMeta.fRegionId));
|
||||||
// point the fShared in the unmanaged region message to the refCount holder
|
}
|
||||||
otherMsg.fMeta.fShared = fManager.GetHandleFromAddress(ptr, fMeta.fSegmentId);
|
if (otherMsg.fMeta.fShared < 0) {
|
||||||
// the message needs to be able to locate in which segment the refCount is stored
|
// UR msg not yet shared, create the reference counting object with count 2
|
||||||
otherMsg.fMeta.fSegmentId = fMeta.fSegmentId;
|
otherMsg.fMeta.fShared = fRegionPtr->HandleFromAddress(&(fRegionPtr->MakeRefCount(2)));
|
||||||
// point this message to the same content as the unmanaged region message
|
} else {
|
||||||
fMeta = otherMsg.fMeta;
|
fRegionPtr->GetRefCountAddressFromHandle(otherMsg.fMeta.fShared)->Increment();
|
||||||
// increment the refCount
|
|
||||||
ShmHeader::IncrementRefCount(ptr);
|
|
||||||
} else { // if the UR msg is already shared
|
|
||||||
fMeta = otherMsg.fMeta;
|
|
||||||
fManager.GetSegment(fMeta.fSegmentId);
|
|
||||||
ShmHeader::IncrementRefCount(fManager.GetAddressFromHandle(fMeta.fShared, fMeta.fSegmentId));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// copy meta data
|
||||||
|
fMeta = otherMsg.fMeta;
|
||||||
}
|
}
|
||||||
|
|
||||||
~Message() override { CloseMessage(); }
|
~Message() override { CloseMessage(); }
|
||||||
|
@ -344,12 +342,13 @@ class Message final : public fair::mq::Message
|
||||||
}
|
}
|
||||||
} else { // unmanaged region
|
} else { // unmanaged region
|
||||||
if (fMeta.fShared >= 0) {
|
if (fMeta.fShared >= 0) {
|
||||||
// make sure segment is initialized in this transport
|
fRegionPtr = fManager.GetRegionFromCache(fMeta.fRegionId);
|
||||||
fManager.GetSegment(fMeta.fSegmentId);
|
if (!fRegionPtr) {
|
||||||
// release unmanaged region block if ref count is one
|
throw TransportError(tools::ToString("Cannot get unmanaged region with id ", fMeta.fRegionId));
|
||||||
uint16_t refCount = ShmHeader::DecrementRefCount(fManager.GetAddressFromHandle(fMeta.fShared, fMeta.fSegmentId));
|
}
|
||||||
|
uint16_t refCount = fRegionPtr->GetRefCountAddressFromHandle(fMeta.fShared)->Decrement();
|
||||||
if (refCount == 1) {
|
if (refCount == 1) {
|
||||||
fManager.Deallocate(fMeta.fShared, fMeta.fSegmentId);
|
fRegionPtr->RemoveRefCount(*(fRegionPtr->GetRefCountAddressFromHandle(fMeta.fShared)));
|
||||||
ReleaseUnmanagedRegionBlock();
|
ReleaseUnmanagedRegionBlock();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -235,8 +235,8 @@ bool Monitor::PrintShm(const ShmId& shmId)
|
||||||
<< ", managed segments:\n";
|
<< ", managed segments:\n";
|
||||||
|
|
||||||
for (const auto& s : segments) {
|
for (const auto& s : segments) {
|
||||||
size_t free = std::visit([](auto& s){ return s.get_free_memory(); }, s.second);
|
size_t free = std::visit([](auto& seg){ return seg.get_free_memory(); }, s.second);
|
||||||
size_t total = std::visit([](auto& s){ return s.get_size(); }, s.second);
|
size_t total = std::visit([](auto& seg){ return seg.get_size(); }, s.second);
|
||||||
size_t used = total - free;
|
size_t used = total - free;
|
||||||
|
|
||||||
std::string msgCount;
|
std::string msgCount;
|
||||||
|
@ -268,12 +268,19 @@ bool Monitor::PrintShm(const ShmId& shmId)
|
||||||
|
|
||||||
if (shmRegions && !shmRegions->empty()) {
|
if (shmRegions && !shmRegions->empty()) {
|
||||||
ss << "\n unmanaged regions:";
|
ss << "\n unmanaged regions:";
|
||||||
for (const auto& r : *shmRegions) {
|
for (const auto& [id, info] : *shmRegions) {
|
||||||
ss << "\n [" << r.first << "]: " << (r.second.fDestroyed ? "destroyed" : "alive");
|
ss << "\n [" << id << "]: " << (info.fDestroyed ? "destroyed" : "alive");
|
||||||
ss << ", size: " << r.second.fSize;
|
ss << ", size: " << info.fSize;
|
||||||
|
|
||||||
|
try {
|
||||||
|
managed_shared_memory rcCountSegment(open_read_only, std::string("fmq_" + shmId.shmId + "_rrc_" + to_string(id)).c_str());
|
||||||
|
ss << ", rcCountSegment size: " << rcCountSegment.get_size();
|
||||||
|
} catch (bie&) {
|
||||||
|
ss << ", rcCountSegment: not found";
|
||||||
|
}
|
||||||
|
|
||||||
// try {
|
// try {
|
||||||
// boost::interprocess::message_queue q(open_only, std::string("fmq_" + std::string(shmId) + "_rgq_" + to_string(r.first)).c_str());
|
// boost::interprocess::message_queue q(open_only, std::string("fmq_" + std::string(shmId) + "_rgq_" + to_string(id)).c_str());
|
||||||
// ss << ", ack queue: " << q.get_num_msg() << " messages";
|
// ss << ", ack queue: " << q.get_num_msg() << " messages";
|
||||||
// } catch (bie&) {
|
// } catch (bie&) {
|
||||||
// ss << ", ack queue: not found";
|
// ss << ", ack queue: not found";
|
||||||
|
@ -679,6 +686,7 @@ std::vector<std::pair<std::string, bool>> Monitor::Cleanup(const ShmId& shmIdT,
|
||||||
result.emplace_back(Remove<bipc::shared_memory_object>("fmq_" + shmId + "_rg_" + to_string(id), verbose));
|
result.emplace_back(Remove<bipc::shared_memory_object>("fmq_" + shmId + "_rg_" + to_string(id), verbose));
|
||||||
}
|
}
|
||||||
result.emplace_back(Remove<bipc::message_queue>("fmq_" + shmId + "_rgq_" + to_string(id), verbose));
|
result.emplace_back(Remove<bipc::message_queue>("fmq_" + shmId + "_rgq_" + to_string(id), verbose));
|
||||||
|
result.emplace_back(Remove<bipc::shared_memory_object>("fmq_" + shmId + "_rrc_" + to_string(id), verbose));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -780,6 +788,7 @@ void Monitor::ResetContent(const ShmId& shmIdT, bool verbose /* = true */)
|
||||||
for (const auto& region : *shmRegions) {
|
for (const auto& region : *shmRegions) {
|
||||||
uint16_t id = region.first;
|
uint16_t id = region.first;
|
||||||
Remove<bipc::message_queue>("fmq_" + shmId + "_rgq_" + to_string(id), verbose);
|
Remove<bipc::message_queue>("fmq_" + shmId + "_rgq_" + to_string(id), verbose);
|
||||||
|
Remove<bipc::shared_memory_object>("fmq_" + shmId + "_rrc_" + to_string(id), verbose);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (bie& e) {
|
} catch (bie& e) {
|
||||||
|
|
|
@ -16,6 +16,7 @@ FairMQ Shared Memory currently uses the following names to register shared memor
|
||||||
| `fmq_<shmId>_mng` | management segment (management data) | one of the devices | devices |
|
| `fmq_<shmId>_mng` | management segment (management data) | one of the devices | devices |
|
||||||
| `fmq_<shmId>_rg_<index>` | unmanaged region(s) | one of the devices | devices with unmanaged regions |
|
| `fmq_<shmId>_rg_<index>` | unmanaged region(s) | one of the devices | devices with unmanaged regions |
|
||||||
| `fmq_<shmId>_rgq_<index>` | unmanaged region queue(s) | one of the devices | devices with unmanaged regions |
|
| `fmq_<shmId>_rgq_<index>` | unmanaged region queue(s) | one of the devices | devices with unmanaged regions |
|
||||||
|
| `fmq_<shmId>_rrc_<index>` | unmanaged region reference count pool(s) | one of the devices | devices with unmanaged regions |
|
||||||
| `fmq_<shmId>_ms` | shmmonitor status | shmmonitor | devices, shmmonitor |
|
| `fmq_<shmId>_ms` | shmmonitor status | shmmonitor | devices, shmmonitor |
|
||||||
|
|
||||||
The shmId is generated out of session id and user id.
|
The shmId is generated out of session id and user id.
|
||||||
|
|
|
@ -59,8 +59,9 @@ struct UnmanagedRegion
|
||||||
, fRemoveOnDestruction(cfg.removeOnDestruction)
|
, fRemoveOnDestruction(cfg.removeOnDestruction)
|
||||||
, fLinger(cfg.linger)
|
, fLinger(cfg.linger)
|
||||||
, fStopAcks(false)
|
, fStopAcks(false)
|
||||||
, fName("fmq_" + shmId + "_rg_" + std::to_string(cfg.id.value()))
|
, fName(MakeShmName(shmId, "rg", cfg.id.value()))
|
||||||
, fQueueName("fmq_" + shmId + "_rgq_" + std::to_string(cfg.id.value()))
|
, fQueueName(MakeShmName(shmId, "rgq", cfg.id.value()))
|
||||||
|
, fRefCountSegmentName(MakeShmName(shmId, "rrc", cfg.id.value()))
|
||||||
, fShmemObject()
|
, fShmemObject()
|
||||||
, fFile(nullptr)
|
, fFile(nullptr)
|
||||||
, fFileMapping()
|
, fFileMapping()
|
||||||
|
@ -186,6 +187,19 @@ struct UnmanagedRegion
|
||||||
|
|
||||||
bool RemoveOnDestruction() { return fRemoveOnDestruction; }
|
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()
|
~UnmanagedRegion()
|
||||||
{
|
{
|
||||||
LOG(debug) << "~UnmanagedRegion(): " << fName << " (" << (fControlling ? "controller" : "viewer") << ")";
|
LOG(debug) << "~UnmanagedRegion(): " << fName << " (" << (fControlling ? "controller" : "viewer") << ")";
|
||||||
|
@ -208,6 +222,11 @@ struct UnmanagedRegion
|
||||||
if (Monitor::RemoveFileMapping(fName.c_str())) {
|
if (Monitor::RemoveFileMapping(fName.c_str())) {
|
||||||
LOG(trace) << "File mapping '" << fName << "' destroyed.";
|
LOG(trace) << "File mapping '" << fName << "' destroyed.";
|
||||||
}
|
}
|
||||||
|
if (fRefCountSegment) {
|
||||||
|
if (Monitor::RemoveObject(fRefCountSegmentName)) {
|
||||||
|
LOG(trace) << "Ref Count Segment '" << fRefCountSegmentName << "' destroyed.";
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG(debug) << "Skipping removal of " << fName << " unmanaged region, because RegionConfig::removeOnDestruction is false";
|
LOG(debug) << "Skipping removal of " << fName << " unmanaged region, because RegionConfig::removeOnDestruction is false";
|
||||||
}
|
}
|
||||||
|
@ -235,6 +254,7 @@ struct UnmanagedRegion
|
||||||
std::atomic<bool> fStopAcks;
|
std::atomic<bool> fStopAcks;
|
||||||
std::string fName;
|
std::string fName;
|
||||||
std::string fQueueName;
|
std::string fQueueName;
|
||||||
|
std::string fRefCountSegmentName;
|
||||||
boost::interprocess::shared_memory_object fShmemObject;
|
boost::interprocess::shared_memory_object fShmemObject;
|
||||||
FILE* fFile;
|
FILE* fFile;
|
||||||
boost::interprocess::file_mapping fFileMapping;
|
boost::interprocess::file_mapping fFileMapping;
|
||||||
|
@ -245,12 +265,18 @@ struct UnmanagedRegion
|
||||||
std::vector<RegionBlock> fBlocksToFree;
|
std::vector<RegionBlock> fBlocksToFree;
|
||||||
const std::size_t fAckBunchSize = 256;
|
const std::size_t fAckBunchSize = 256;
|
||||||
std::unique_ptr<boost::interprocess::message_queue> fQueue;
|
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 fAcksReceiver;
|
||||||
std::thread fAcksSender;
|
std::thread fAcksSender;
|
||||||
RegionCallback fCallback;
|
RegionCallback fCallback;
|
||||||
RegionBulkCallback fBulkCallback;
|
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)
|
static RegionConfig makeRegionConfig(uint16_t id)
|
||||||
{
|
{
|
||||||
RegionConfig regionCfg;
|
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."));
|
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)++;
|
(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()
|
void StartAckSender()
|
||||||
{
|
{
|
||||||
if (!fAcksSender.joinable()) {
|
if (!fAcksSender.joinable()) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user