PLCnext API Documentation  21.0.0.35466
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 #ifdef ARP_PLATFORM_LINUX
16  #include <pthread.h>
17 #endif
18 
19 namespace Arp { namespace System { namespace Commons { namespace Ipc
20 {
21 
22 // This class uses CRTP (Curiously recurring template pattern) to implement an own SharedData singleton
23 // for each derived class.
24 // For CRTP see: https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
25 template<class Derived>
26 class SharedData : public SharedMemory, public AppDomainSingleton<Derived>
27 {
28 public: // typedefs
29  typedef SharedMemory Base;
30  typedef Derived DerivedType;
32  typedef boost::interprocess::managed_shared_memory SharedMemory;
33  typedef SharedMemory::segment_manager SegmentManager;
34  typedef boost::interprocess::permissions SharedMemoryPermission;
35 
37  template <class T>
38  using Ptr = boost::interprocess::offset_ptr<T>;
39 
40  template <class T>
41  using ConstPtr = boost::interprocess::offset_ptr<const T>;
42 
43 protected: // construction/destruction
44  SharedData(void); // opens an existing instance, throws if not exist
45  SharedData(size_t memorySize); // creates an non-existing instance, throws if yet exists
46  ~SharedData(void) = default;
47 
48 public: // static operations
49  ARP_CXX_SYMBOL_EXPORT
50  static void CreateInstance(size_t memorySize);
51  static void OpenInstance(void);
52  static void CloseInstance(bool removeMemory = false);
53  static void Remove(void);
54 
55  //TODO(OR): remove this
56  // wait til shared data instance created and open it
57  static void WaitInstance(const char* waitMessage, uint32 timeout = -1);
58 
59 private: // deleted copying/assignment
60  SharedData(const SharedData& arg) = delete;
61  SharedData& operator=(const SharedData& arg) = delete;
62 
63 public: // nested type Allocator
64  template <class T>
65  class Allocator : public boost::interprocess::allocator<T, SegmentManager>
66  {
67  public: // typedef
68  typedef boost::interprocess::allocator<T, SegmentManager> AllocatorBase;
69 
70  public: // construction
71  Allocator(void);
72 
73  public: // meta-programming
74  template<class T2>
75  struct rebind
76  {
77  typedef Allocator<T2> other;
78  };
79  };
80 
81 public: // nested type Mutex
82 #ifdef ARP_PLATFORM_LINUX
83  class Mutex
84  {
85  public: // construction
86  Mutex(void)
87  {
88  pthread_mutexattr_t attr;
89  pthread_mutexattr_init(&attr);
90 
91  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT);
92  pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
93  pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
94 
95  pthread_mutex_init(&this->mutex, &attr);
96 
97  pthread_mutexattr_destroy(&attr);
98  }
99  ~Mutex(void)
100  {
101  pthread_mutex_destroy(&this->mutex);
102  }
103 
104  public: // Operations
105  void Lock(void)
106  {
107  pthread_mutex_lock(&this->mutex);
108  }
109  void Unlock(void)
110  {
111  pthread_mutex_unlock(&this->mutex);
112  }
113 
114  private: // fields
115  pthread_mutex_t mutex;
116  };
117 #else
118  class Mutex
119  {
120  public: // construction
121  Mutex(void) = default;
122  ~Mutex(void) = default;
123 
124  public: // Operations
125  void Lock(void)
126  {
127  this->mutex.lock();
128  }
129  void Unlock(void)
130  {
131  this->mutex.unlock();
132  }
133 
134  private: // fields
135  boost::interprocess::interprocess_mutex mutex;
136  };
137 #endif
138 
139  class NullMutex
140  {
141  public: // construction
142  NullMutex(void) = default;
143  ~NullMutex(void) = default;
144 
145  public: // Operations
146  void Lock(void) {}
147  void Unlock(void) {}
148  };
149 
150 public: // nested type ScopedLock
151  template <class TMutex>
153  {
154  public: // construction
155  ScopedLock(TMutex& mutex): pMutex(&mutex)
156  {
157  this->pMutex->Lock();
158  }
159  ~ScopedLock(void)
160  {
161  if (this->pMutex)
162  {
163  this->pMutex->Unlock();
164  }
165  }
166 
167  private: // fields
168  TMutex* pMutex;
169  };
170 
171 public: // typedefs on nested types
172  // typedef shared string type
173  typedef boost::interprocess::basic_string<char, std::char_traits<char>, Allocator<char>> String;
174  // typedef shared vector type
175  template <class T>
176  using vector = boost::interprocess::vector<T, Allocator<T>>;
177  // typedef shared list type
178  template <class T>
179  using list = boost::interprocess::list<T, Allocator<T>>;
180  // typedef shared map type
181  template <class TKey, class TValue, class TCompare = std::less<TKey>>
182  using map = boost::interprocess::map<TKey, TValue, TCompare, Allocator<std::pair<const TKey, TValue>>>;
183  // typedef shared set type
184  template <class TKey, class TCompare = std::less<TKey>>
185  using set = boost::interprocess::set<TKey, TCompare, Allocator<TKey>>;
186 
187  // declare Allocator as friend of this class
188  template<class T> friend class Allocator;
189 };
190 
192 // inline methods of class SharedData<Derived>
193 template<class Derived>
195  : Base(TypeName<DerivedType>().GetSafeName())
196 {
197 }
198 
199 template<class Derived>
200 inline SharedData<Derived>::SharedData(size_t memorySize)
201  : Base(TypeName<DerivedType>().GetSafeName(), memorySize)
202 {
203 }
204 
205 template<class Derived>
206 void SharedData<Derived>::CreateInstance(size_t memorySize)
207 {
208  SingletonBase::CreateInstance(memorySize);
209 }
210 
211 // open an existing one
212 template<class Derived>
214 {
215  SingletonBase::CreateInstance(); // using open version when default ctor is called
216 }
217 
218 //TODO(OR): remove this
219 template<class Derived>
220 void SharedData<Derived>::WaitInstance(const char* waitMessage, uint32 /* timeout */)
221 {
223  {
224  return; // TODO: throw exception, double creation not allowed?
225  }
226  // else
227  bool instanceExists = false;
228  do
229  {
230  try
231  {
232  OpenInstance();
233  instanceExists = true;
234  }
235  catch (...)
236  {
237  Log::Debug(waitMessage);
239  }
240  // TODO: timeout handling
241  } while (!instanceExists);
242 }
243 
244 template<class Derived>
245 void SharedData<Derived>::CloseInstance(bool removeMemory)
246 {
248  {
249  return;
250  }
251  // else
252  if (removeMemory && !SingletonBase::GetInstance().GetName().IsEmpty())
253  {
254  SingletonBase::GetInstance().Remove();
255  }
257 }
258 
259 template<class Derived>
261 {
262  (void)boost::interprocess::shared_memory_object::remove(TypeName<DerivedType>().GetSafeName());
263 }
264 
266 // inline methods of nested class SharedData<Derived>::Allocator<T>
267 template<class Derived>
268 template<class T>
270  : AllocatorBase(SharedData::GetInstance().sharedMemoryImpl.get_segment_manager())
271 {
272 }
273 
274 }}}} // 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:26
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
Definition: SharedData.hxx:118
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