hmbdc
simplify-high-performance-messaging-programming
Allocators.hpp
1 #include "hmbdc/Copyright.hpp"
2 #pragma once
3 
4 #include "hmbdc/Compile.hpp"
5 #include "hmbdc/Exception.hpp"
6 
7 #include <boost/align/align.hpp>
8 #include <boost/interprocess/sync/file_lock.hpp>
9 
10 #include <stdexcept>
11 #include <string>
12 #include <iostream>
13 #include <utility>
14 #include <mutex>
15 
16 #include <sys/mman.h>
17 #include <fcntl.h> /* For O_* constants */
18 #include <malloc.h>
19 
20 #include <sys/mman.h>
21 #include <sys/stat.h> /* For mode constants */
22 
23 namespace hmbdc { namespace os {
24 
25 /**
26  * @brief helping allocating object and its aggregated objects in a continouse memory
27  * @details the class working with this cannot have significant dtor (dtor that does more than
28  * just freeing memory)
29  */
31  enum {
32  fromHeap = false,
33  };
35  : cur_(NULL)
36  , size_(0)
37  , runCtor_(false)
38  {}
39 
40  BasePtrAllocator(void* base, size_t size, bool runCtor /* = true */)
41  : cur_((char*)base)
42  , size_(size)
43  , runCtor_(runCtor)
44  {}
45 
46  BasePtrAllocator(BasePtrAllocator const&) = delete;
47  BasePtrAllocator& operator = (BasePtrAllocator const&) = delete;
48  virtual ~BasePtrAllocator(){}
49 
50  template <typename T, typename ...Args>
51  T* allocate(size_t alignment, Args&&... args) {
52  auto cur = boost::alignment::align(alignment, sizeof(T), cur_, size_);
53  cur_ = ((char*)cur) + sizeof(T);
54  T *res;
55  if (runCtor_) {
56  res = ::new (cur)T(std::forward<Args>(args)...);
57  msync(cur, sizeof(T), MS_SYNC);
58  } else {
59  res = static_cast<T*>(cur);
60  }
61  return res;
62  }
63 
64  void * memalign(size_t alignment, size_t size) {
65  auto res = boost::alignment::align(alignment, size, cur_, size_);
66  cur_ = ((char*)cur_) + size_;
67  return res;
68  }
69 
70  template <typename T> void unallocate(T* ptr){
71  if (runCtor_) {
72  ptr->~T();
73  }
74  }
75  void free(void*){}
76 
77 protected:
78  void set(void* base, size_t size, bool runCtor = true) {
79  cur_= base;
80  size_ = size;
81  runCtor_ = runCtor;
82  }
83 
84 private:
85  void* cur_;
86  size_t size_;
87  bool runCtor_;
88 };
89 
90 /**
91  * @brief helping allocating object and its aggregated objects in a continouse shared memory
92  * @details the class working with this cannot have significant dtor (dtor that does more than
93  * just freeing memory)
94  */
97  ShmBasePtrAllocator(char const* name, size_t offset, size_t len
98  , bool& tryOwn);
100 
101  template <typename T, typename ...Args>
102  T* allocate(size_t alignment, Args&&... args) {
103  std::lock_guard<decltype(lock_)> g(lock_);
104  auto res = BasePtrAllocator::allocate<T>(alignment
105  , std::forward<Args>(args)...);
106  return res;
107  }
108 
109  auto& fileLock() {
110  return lock_;
111  }
112 
113 private:
114  std::string name_;
115  size_t len_;
116  void* addr_;
117  bool own_;
118  boost::interprocess::file_lock lock_;
119 };
120 
121 /**
122  * @brief similar to ShmBasePtrAllocator but using dev memory
123  * @details typically PCIe BAR
124  */
127  DevMemBasePtrAllocator(char const* devName, size_t offset, size_t len
128  , bool own);
130 
131  template <typename T, typename ...Args>
132  T* allocate(size_t alignment, Args&&... args) {
133  std::lock_guard<decltype(lock_)> g(lock_);
134  return BasePtrAllocator::allocate<T>(alignment
135  , std::forward<Args>(args)...);
136  }
137 
138  auto& fileLock() {
139  return lock_;
140  }
141 
142 private:
143  size_t len_;
144  void* addr_;
145  bool own_;
146  boost::interprocess::file_lock lock_;
147  int fd_ = -1;
148 };
149 
150 /**
151  * @brief the default vanilla allocate
152  */
154  enum {
155  fromHeap = true,
156  };
157  template <typename ...NoUses>
158  DefaultAllocator(NoUses&& ...){}
159 
160  template <typename T, typename ...Args>
161  T* allocate(size_t alignment, Args&&... args) {
162  // return new T(std::forward<Args>(args)...);
163  auto space = memalign(alignment, sizeof(T));
164  return new (space) T(std::forward<Args>(args)...);
165  }
166 
167  void* memalign(size_t alignment, size_t size) {
168  auto res = ::memalign(alignment, size);
169  if (!res) {
170  throw std::bad_alloc();
171  }
172  return res;
173  }
174 
175  template <typename T>
176  void
177  unallocate(T* ptr){
178  ptr->~T();
179  this->free(ptr);
180  // delete ptr;
181  }
182  void free(void* ptr){
183  ::free(ptr);
184  }
185  static DefaultAllocator& instance() {
186  static DefaultAllocator ins;
187  return ins;
188  }
189 };
190 
191 inline
192 ShmBasePtrAllocator::
193 ShmBasePtrAllocator(char const* name, size_t offset, size_t len, bool& tryOwn)
195 , len_(len)
196 , addr_(NULL)
197 , own_(false) {
198  using namespace std;
199  if (name[0] != '/') {
200  name_ = string("/") + name;
201  } else {
202  name_ = name;
203  }
204 
205  string devName = string("/dev/shm") + name_;
206  int oflags = O_RDWR;
207  if (tryOwn) {
208  oflags |= O_CREAT | O_EXCL;
209  }
210 
211  int fd = shm_open(name, oflags, 0660);
212  if (fd < 0 && tryOwn) {
213  oflags = O_RDWR;
214  fd = shm_open(name, oflags, 0660);
215  tryOwn = false;
216  }
217  if (fd >= 0) {
218  if (tryOwn) {
219  own_ = true;
220  if (ftruncate(fd, len)) {
221  HMBDC_THROW(std::runtime_error,
222  "error when sizing ipc transport errno=" << errno);
223 
224  }
225  }
226  struct stat st;
227  stat(devName.c_str(), &st);
228  if (len != (size_t)st.st_size) {
229  HMBDC_THROW(std::runtime_error, "file not expected size - unmatch?");
230  }
231  void* base = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED
232  , fd, offset);
233  if (base != MAP_FAILED) {
234  set(base, len, own_);
235  addr_ = base;
236  lock_ = boost::interprocess::file_lock(devName.c_str());
237  close(fd);
238  return;
239  }
240  }
241 
242  HMBDC_THROW(std::runtime_error
243  , "error when creating file errno=" << errno);
244 }
245 
246 inline
247 ShmBasePtrAllocator::
248 ~ShmBasePtrAllocator() {
249  munmap(addr_, len_);
250  if (own_) {
251  shm_unlink(name_.c_str());
252  }
253 }
254 
255 inline
256 DevMemBasePtrAllocator::
257 DevMemBasePtrAllocator(char const* devName, size_t offset, size_t len, bool own)
258 : BasePtrAllocator()
259 , len_(len)
260 , addr_(NULL)
261 , own_(false) {
262  if (offset % getpagesize() || len_ % getpagesize()) {
263  HMBDC_THROW(std::out_of_range, "address not at page boundary devName="
264  << devName << "@" << offset << ':' << len_);
265  }
266  int oflags = O_RDWR | O_SYNC;
267  fd_ = open(devName, oflags);
268  addr_ = (uint32_t*)mmap(NULL, len_, PROT_READ | PROT_WRITE, MAP_SHARED
269  , fd_, offset);
270  if (addr_ == MAP_FAILED) {
271  HMBDC_THROW(std::runtime_error
272  , "cannot map RegRange " << devName << '@' << offset << ':' << len_);
273  }
274  own_ = own;
275  set(addr_, len, own_);
276  lock_ = boost::interprocess::file_lock(devName);
277 }
278 
279 inline
280 DevMemBasePtrAllocator::
281 ~DevMemBasePtrAllocator() {
282  munmap(addr_, len_);
283  close(fd_);
284 }
285 
286 }}
287 
Definition: TypedString.hpp:84
the default vanilla allocate
Definition: Allocators.hpp:153
similar to ShmBasePtrAllocator but using dev memory
Definition: Allocators.hpp:125
helping allocating object and its aggregated objects in a continouse memory
Definition: Allocators.hpp:30
helping allocating object and its aggregated objects in a continouse shared memory ...
Definition: Allocators.hpp:95
Definition: Base.hpp:12