PLCnext API Documentation  20.0.0.24462
SharedData.hxx
1 #pragma once
2 #include "Arp/System/Core/Arp.h"
3 #include "Arp/System/Core/TypeName.hxx"
4 #include "Arp/System/Core/AppDomainSingleton.hxx"
5 #include "Arp/System/Commons/Ipc/SharedMemory.hpp"
6 #include "Arp/System/Commons/Threading/Thread.hpp"
7 #include "boost/interprocess/containers/string.hpp"
8 #include "boost/interprocess/containers/vector.hpp"
9 #include "boost/interprocess/containers/list.hpp"
10 #include "boost/interprocess/containers/map.hpp"
11 #include "boost/interprocess/containers/set.hpp"
12 #include <algorithm> // using std::replace
13 #include <new> // using std::new(p)
14 
15 namespace Arp { namespace System { namespace Commons { namespace Ipc
16 {
17 
18 // This class uses CRTP (Curiously recurring template pattern) to implement an own SharedData singleton
19 // for each derived class.
20 // For CRTP see: https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
21 template<class Derived>
22 class SharedData : public SharedMemory, public AppDomainSingleton<Derived>
23 {
24 public: // typedefs
25  typedef SharedMemory Base;
26  typedef Derived DerivedType;
28  typedef boost::interprocess::managed_shared_memory SharedMemory;
29  typedef SharedMemory::segment_manager SegmentManager;
30  typedef boost::interprocess::permissions SharedMemoryPermission;
31 
33  template <class T>
34  using Ptr = boost::interprocess::offset_ptr<T>;
35 
36  template <class T>
37  using ConstPtr = boost::interprocess::offset_ptr<const T>;
38 
39 protected: // construction/destruction
40  SharedData(void); // opens an existing instance, throws if not exist
41  SharedData(size_t memorySize); // creates an non-existing instance, throws if yet exists
42  ~SharedData(void) = default;
43 
44 public: // static operations
45  ARP_CXX_SYMBOL_EXPORT
46  static void CreateInstance(size_t memorySize);
47  static void OpenInstance(void);
48  static void CloseInstance(bool removeMemory = false);
49  static void Remove(void);
50 
51  //TODO(OR): remove this
52  // wait til shared data instance created and open it
53  static void WaitInstance(const char* waitMessage, uint32 timeout = -1);
54 
55 private: // deleted copying/assignment
56  SharedData(const SharedData& arg) = delete;
57  SharedData& operator=(const SharedData& arg) = delete;
58 
59 public: // nested type Allocator
60  template <class T>
61  class Allocator : public boost::interprocess::allocator<T, SegmentManager>
62  {
63  public: // typedef
64  typedef boost::interprocess::allocator<T, SegmentManager> AllocatorBase;
65 
66  public: // construction
67  Allocator(void);
68 
69  public: // meta-programming
70  template<class T2>
71  struct rebind
72  {
73  typedef Allocator<T2> other;
74  };
75  };
76 
77 public: // nested type Mutex
78  class Mutex
79  {
80  private: // typedef
81  typedef boost::interprocess::interprocess_mutex SharedMutex;
82 
83  public: // construction
84  Mutex(void) = default;
85  ~Mutex(void) = default;
86 
87  public: // Operations
88  void Lock(void)
89  {
90  this->mutex.lock();
91  }
92  void Unlock(void)
93  {
94  this->mutex.unlock();
95  }
96 
97  private: // fields
98  SharedMutex mutex;
99  };
100 
101  class NullMutex
102  {
103  public: // construction
104  NullMutex(void) = default;
105  ~NullMutex(void) = default;
106 
107  public: // Operations
108  void Lock(void) {}
109  void Unlock(void) {}
110  };
111 
112 public: // nested type ScopedLock
113  template <class TMutex>
115  {
116  public: // construction
117  ScopedLock(TMutex& mutex): pMutex(&mutex)
118  {
119  this->pMutex->Lock();
120  }
121  ~ScopedLock(void)
122  {
123  if (this->pMutex)
124  {
125  this->pMutex->Unlock();
126  }
127  }
128 
129  private: // fields
130  TMutex* pMutex;
131  };
132 
133 public: // typedefs on nested types
134  // typedef shared string type
135  typedef boost::interprocess::basic_string<char, std::char_traits<char>, Allocator<char>> String;
136  // typedef shared vector type
137  template <class T>
138  using vector = boost::interprocess::vector<T, Allocator<T>>;
139  // typedef shared list type
140  template <class T>
141  using list = boost::interprocess::list<T, Allocator<T>>;
142  // typedef shared map type
143  template <class TKey, class TValue, class TCompare = std::less<TKey>>
144  using map = boost::interprocess::map<TKey, TValue, TCompare, Allocator<std::pair<const TKey, TValue>>>;
145  // typedef shared set type
146  template <class TKey, class TCompare = std::less<TKey>>
147  using set = boost::interprocess::set<TKey, TCompare, Allocator<TKey>>;
148 
149  // declare Allocator as friend of this class
150  template<class T> friend class Allocator;
151 };
152 
154 // inline methods of class SharedData<Derived>
155 template<class Derived>
157  : Base(TypeName<DerivedType>().GetSafeName())
158 {
159 }
160 
161 template<class Derived>
162 inline SharedData<Derived>::SharedData(size_t memorySize)
163  : Base(TypeName<DerivedType>().GetSafeName(), memorySize)
164 {
165 }
166 
167 template<class Derived>
168 void SharedData<Derived>::CreateInstance(size_t memorySize)
169 {
170  SingletonBase::CreateInstance(memorySize);
171 }
172 
173 // open an existing one
174 template<class Derived>
176 {
177  SingletonBase::CreateInstance(); // using open version when default ctor is called
178 }
179 
180 //TODO(OR): remove this
181 template<class Derived>
182 void SharedData<Derived>::WaitInstance(const char* waitMessage, uint32 /* timeout */)
183 {
185  {
186  return; // TODO: throw exception, double creation not allowed?
187  }
188  // else
189  bool instanceExists = false;
190  do
191  {
192  try
193  {
194  OpenInstance();
195  instanceExists = true;
196  }
197  catch (...)
198  {
199  Log::Debug(waitMessage);
201  }
202  // TODO: timeout handling
203  } while (!instanceExists);
204 }
205 
206 template<class Derived>
207 void SharedData<Derived>::CloseInstance(bool removeMemory)
208 {
210  {
211  return;
212  }
213  // else
214  if (removeMemory && !SingletonBase::GetInstance().GetName().IsEmpty())
215  {
216  SingletonBase::GetInstance().Remove();
217  }
219 }
220 
221 template<class Derived>
223 {
224  (void)boost::interprocess::shared_memory_object::remove(TypeName<DerivedType>().GetSafeName());
225 }
226 
228 // inline methods of nested class SharedData<Derived>::Allocator<T>
229 template<class Derived>
230 template<class T>
232  : AllocatorBase(SharedData::GetInstance().sharedMemoryImpl.get_segment_manager())
233 {
234 }
235 
236 }}}} // end of namespace Arp::System::Commons::Ipc
static Derived & CreateInstance(Args &&... args)
Creates this singleton instance.
Definition: AppDomainSingleton.hxx:74
This (meta programming) class provides the C++ typename of the as template argument passed type...
Definition: TypeName.hxx:55
Definition: SharedData.hxx:22
std::uint32_t uint32
The Arp unsigned integer type of 4 byte size.
Definition: PrimitiveTypes.hpp:35
static void Sleep(size_t milliseconds)
Suspends the execution of the calling thread.
static Derived & GetInstance(void)
Gets a reference of the singleton instance.
Definition: AppDomainSingleton.hxx:102
SharedMemoryImpl sharedMemoryImpl
Actual implementation of the shared memory functionality.
Definition: SharedMemory.hpp:142
Root namespace for the PLCnext API
This class implements the singleton pattern for singletons with process wide scope.
Definition: AppDomainSingleton.hxx:24
static void DisposeInstance(void)
Disposes this singleton instance.
Definition: AppDomainSingleton.hxx:119
System components used by the System, Device, Plc or Io domains.
String GetSafeName(void) const
Gets a safe name of the as template parameter given type.
Definition: TypeName.hxx:144
static bool IsCreated(void)
Determines if this singleton instance is created yet.
Definition: AppDomainSingleton.hxx:91
const Arp::String & GetName(void) const
Returns the name of the memory object.
Definition: SharedMemory.hpp:157