PLCnext API Documentation 26.0.1.58
SharedMemory.hpp
1#pragma once
3#include "Arp/System/Core/TypeName.hxx"
4#include "Arp/System/Commons/Logging.h"
5#include "Arp/System/Commons/Threading/Thread.hpp"
6#include "Arp/System/Commons/Exceptions/InvalidOperationException.hpp"
7#include "boost/interprocess/managed_shared_memory.hpp"
8#include <array>
9#include <algorithm>
10#include <new> // using displacement new
11
12namespace Arp { namespace System { namespace Commons { namespace Ipc
13{
14
16class SharedMemory : private Loggable<SharedMemory>
17{
18public: // usings
19 using SharedMemoryImpl = boost::interprocess::managed_shared_memory;
20 using SegmentManager = SharedMemoryImpl::segment_manager;
21 using SharedMemoryPermission = boost::interprocess::permissions;
22
24 template <class T>
25 using Ptr = boost::interprocess::offset_ptr<T>;
26
27public: // construction/destruction
28 explicit SharedMemory(const char* name);
29 SharedMemory(const char* name, size_t memorySize);
30 SharedMemory(const SharedMemory& arg) = delete;
31 SharedMemory(SharedMemory&& arg)noexcept = delete;
32 SharedMemory& operator=(const SharedMemory& arg) = delete;
33 SharedMemory& operator=(SharedMemory&& arg)noexcept = delete;
34 ~SharedMemory(void);
35
36public: // operations
37 void Dispose(void);
38
39public: // properties
40 bool IsOwner(void)const;
41 size_t GetSize(void)const;
42 const String& GetName(void)const;
43
44public: // operations
45 byte* Allocate(size_t size);
46 void Deallocate(byte* pMemory);
47 size_t GetFreeMemory(void)const;
48 void ZeroFreeMemory(void);
49 bool AllMemoryDeallocated(void);
50 bool CheckSanity(void);
51
52public: // template operations
53 template<class T>
54 Ptr<T> Get(const char* name);
55
56 template<class T, typename ...TArgs>
57 Ptr<T> GetOrConstruct(const char* name, TArgs&& ... args);
58
59 template<class T, typename ...TArgs>
60 Ptr<T> Construct(const char* name, TArgs&& ... args);
61
62 template<class T>
63 void Destroy(const char* name);
64
65 template<class T, typename ...TArgs>
66 Ptr<T> ConstructUnnamed(TArgs&& ... args);
67
68 template<class T>
70
71protected: // fields
72 SharedMemoryImpl sharedMemoryImpl;
73
74private: // methods
75 void Create(void);
76 bool TryCreate(void);
77 void Open(void);
78 bool TryOpen(void);
79 void Remove(void);
80 bool TryRemove(void);
81
82private: // fields
83 String memoryName;
84 size_t memorySize = 0;
85
86private: // nested class
87 template<class T> class AlignmentProxy
88 {
89 public: // construction/destruction
90 template<typename ...Args>
91 explicit AlignmentProxy(Args&& ... args);
92 AlignmentProxy(const AlignmentProxy& arg) = delete;
93 AlignmentProxy(AlignmentProxy&& arg)noexcept = delete;
94 AlignmentProxy& operator=(const AlignmentProxy& arg) = delete;
95 AlignmentProxy& operator=(AlignmentProxy&& arg)noexcept = delete;
96 ~AlignmentProxy(void);
97
98 public: // operations
99 T* GetAlignedObjectPtr(void);
100
101 private: // fields
102 static constexpr size_t alignment = static_cast<size_t>(std::max(static_cast<int>(alignof(T)) - static_cast<int>(alignof(void*)), 0));
103 static constexpr size_t alignedSize = sizeof(T) + alignment;
104 std::array<byte, alignedSize> buffer{};
105 };
106};
107
109// inline methods of class SharedMemory
110
113template<class T>
115{
116 SharedMemory::Ptr<AlignmentProxy<T>> proxyPtr = sharedMemoryImpl.find<AlignmentProxy<T>>(name).first;
117 if (!proxyPtr)
118 {
119 return nullptr;
120 }
121 // else
122 return proxyPtr.get()->GetAlignedObjectPtr();
123}
124
129template<class T, typename ...TArgs>
130inline SharedMemory::Ptr<T> SharedMemory::GetOrConstruct(const char* name, TArgs&& ... args)
131{
132 Ptr<T> result = Get<T>(name);
133 if (!result)
134 {
135 return Construct<T>(name, std::forward<TArgs>(args)...);
136 }
137 return result;
138}
139
144template<class T, typename ...TArgs>
145inline SharedMemory::Ptr<T> SharedMemory::Construct(const char* name, TArgs&& ... args)
146{
147 return this->sharedMemoryImpl.construct<AlignmentProxy<T>>(name)(std::forward<TArgs>(args)...)->GetAlignedObjectPtr();
148}
149
152template<class T>
153inline void SharedMemory::Destroy(const char* name)
154{
155 SharedMemory::Ptr<AlignmentProxy<T>> proxyPtr = sharedMemoryImpl.find<AlignmentProxy<T>>(name).first;
156
157 if (proxyPtr != nullptr)
158 {
159 // free memory
160 this->sharedMemoryImpl.destroy<AlignmentProxy<T>>(name);
161 }
162}
163
167template<class T, typename ...TArgs>
169{
170 // allocate memory
171 void* pResult = this->sharedMemoryImpl.allocate(sizeof(T));
172 // call ctor using placement new operator with allocated memory pointer
173 return new (pResult) T(std::forward<TArgs>(args)...);
174}
175
178template<class T>
180{
181 if (ptr != nullptr)
182 {
183 // call dtor of object explicitly
184 ptr->~T();
185 // free memory
186 this->sharedMemoryImpl.deallocate(ptr.get());
187 }
188}
189
191// inline methods of class SharedMemory::AlignmentProxy<T>
192
193template<class T>
194template<typename ...Args>
195inline SharedMemory::AlignmentProxy<T>::AlignmentProxy(Args&& ... args)
196{
197 new (this->GetAlignedObjectPtr()) T(std::forward<Args>(args)...);
198}
199
200template<class T>
201inline SharedMemory::AlignmentProxy<T>::~AlignmentProxy()
202{
203 this->GetAlignedObjectPtr()->~T();
204}
205
206template<class T>
207inline T* SharedMemory::AlignmentProxy<T>::GetAlignedObjectPtr()
208{
209 size_t alignedSpace = alignedSize;
210 void* pBuffer = buffer.data();
211
212 void* pResult = std::align(alignof(T), sizeof(T), pBuffer, alignedSpace);
213 if (pResult == nullptr)
214 {
215 // aligning failed
216 throw InvalidOperationException::Create("Could not construct shared memory object due to failing alignment.");
217 }
218 // else
219 return reinterpret_cast<T*>(pResult);
220};
221
222}}}} // end of namespace Arp::System::Commons::Ipc
static InvalidOperationException Create(const String &message)
Creates an InvalidOperationException using an additional message.
Definition: InvalidOperationException.cpp:96
This class represents the Arp String. The implementation is based on std::string.
Definition: String.hpp:39
Derive from this class to inherit logging functionality.
Definition: Loggable.hxx:28
API to manage and manipulate memory shared between several processes
Definition: SharedMemory.hpp:17
void DestroyUnnamed(SharedMemory::Ptr< T > ptr)
Deallocates the unnamed object in the shared memory, also calling the objects destructor.
Definition: SharedMemory.hpp:179
byte * Allocate(size_t size)
Tries to allocate size amount of bytes in the memory.
Definition: SharedMemory.cpp:178
bool IsOwner(void) const
Determines if this instance is the woner of the shared memory, i.e. ths shared memory was created by ...
Definition: SharedMemory.cpp:156
void ZeroFreeMemory(void)
Writes zero in all bytes not yet allocated.
Definition: SharedMemory.cpp:207
Ptr< T > Get(const char *name)
Tries to find a previously allocated named object.
Definition: SharedMemory.hpp:114
SharedMemoryImpl sharedMemoryImpl
Actual implementation of the shared memory functionality.
Definition: SharedMemory.hpp:72
boost::interprocess::offset_ptr< T > Ptr
Returned pointer types are shared memory based offset pointer.
Definition: SharedMemory.hpp:25
void Deallocate(byte *pMemory)
Marks the memory pointed to by pMemory available for new allocation requests.
Definition: SharedMemory.cpp:185
bool AllMemoryDeallocated(void)
Checks if all memory has been deallocated.
Definition: SharedMemory.cpp:214
SharedMemory(const char *name)
Opens an existing shared memory.
Definition: SharedMemory.cpp:17
size_t GetSize(void) const
Returns the capacity of the shared memory in bytes.
Definition: SharedMemory.cpp:170
void Destroy(const char *name)
Deallocates the object in the shared memory, also calling the objects destructor.
Definition: SharedMemory.hpp:153
size_t GetFreeMemory(void) const
Obtain the number of free bytes in the shared memory.
Definition: SharedMemory.cpp:201
const String & GetName(void) const
Returns the name of the memory object.
Definition: SharedMemory.cpp:163
~SharedMemory(void)
Deallocates the memory for this management object but not the memory shared between processes.
Definition: SharedMemory.cpp:46
void Dispose(void)
Removes the shared memory from the system. if this instance owns it.
Definition: SharedMemory.cpp:191
Ptr< T > GetOrConstruct(const char *name, TArgs &&... args)
Tries to find object identified by name, creates a new one if the object does not exists yet.
Definition: SharedMemory.hpp:130
Ptr< T > Construct(const char *name, TArgs &&... args)
Creates a named object in the shared memory.
Definition: SharedMemory.hpp:145
Ptr< T > ConstructUnnamed(TArgs &&... args)
Creates an unnamed object in the shared memory.
Definition: SharedMemory.hpp:168
bool CheckSanity(void)
Performs a sanity check over the shared memory.
Definition: SharedMemory.cpp:221
Root namespace for the PLCnext API