join 1.0
lightweight network framework library
Loading...
Searching...
No Matches
memory.hpp
Go to the documentation of this file.
1
25#ifndef JOIN_CORE_MEMORY_HPP
26#define JOIN_CORE_MEMORY_HPP
27
28// libjoin.
29#include <join/error.hpp>
30#include <join/utils.hpp>
31
32// C++.
33#include <system_error>
34#include <stdexcept>
35#include <limits>
36
37// C.
38#include <sys/types.h>
39#include <sys/mman.h>
40#include <sys/stat.h>
41#include <unistd.h>
42#include <numaif.h>
43#include <numa.h>
44#include <fcntl.h>
45#include <cstdint>
46
47namespace join
48{
50 template <typename Backend, size_t Count, size_t... Sizes>
52
54 template <typename Backend, template <typename, typename> class SyncPolicy>
55 struct SyncBinding;
56 template <typename, typename>
57 struct Spsc;
58 template <typename, typename>
59 struct Mpsc;
60 template <typename, typename>
61 struct Mpmc;
62
70 inline int mbind (void* ptr, size_t size, int numa) noexcept
71 {
72 if (ptr == nullptr || numa < 0)
73 {
75 return -1;
76 }
77
78 unsigned long mask = (1UL << numa);
79 if (::mbind (ptr, size, MPOL_BIND, &mask, sizeof (mask) * 8, MPOL_MF_STRICT) == -1)
80 {
81 lastError = std::error_code (errno, std::generic_category ());
82 return -1;
83 }
84
85 return 0;
86 }
87
94 inline int mlock (void* ptr, size_t size) noexcept
95 {
96 if (ptr == nullptr)
97 {
99 return -1;
100 }
101
102 if (::mlock (ptr, size) == -1)
103 {
104 lastError = std::error_code (errno, std::generic_category ());
105 return -1;
106 }
107
108 return 0;
109 }
110
115 {
116 public:
117 template <size_t Count, size_t... Sizes>
118 using Allocator = BasicArena<LocalMem, Count, Sizes...>;
119
123
129 explicit LocalMem (uint64_t size)
130 {
131 long sc = sysconf (_SC_PAGESIZE);
132 uint64_t pageSize = (sc > 0) ? static_cast<uint64_t> (sc) : 4096;
133 _size = (size + pageSize - 1) & ~(pageSize - 1);
134
135 create ();
136 }
137
142 LocalMem (const LocalMem& other) = delete;
143
149 LocalMem& operator= (const LocalMem& other) = delete;
150
155 LocalMem (LocalMem&& other) noexcept
156 : _size (other._size)
157 , _ptr (other._ptr)
158 {
159 other._size = 0;
160 other._ptr = nullptr;
161 }
162
168 LocalMem& operator= (LocalMem&& other) noexcept
169 {
170 cleanup ();
171
172 _size = other._size;
173 _ptr = other._ptr;
174
175 other._size = 0;
176 other._ptr = nullptr;
177
178 return *this;
179 }
180
184 ~LocalMem () noexcept
185 {
186 cleanup ();
187 }
188
196 inline const void* get (uint64_t offset = 0) const
197 {
198 if (JOIN_UNLIKELY (_ptr == nullptr))
199 {
200 throw std::runtime_error ("memory not mapped");
201 }
202
203 if (JOIN_UNLIKELY (offset >= _size))
204 {
205 throw std::out_of_range ("offset out of bounds");
206 }
207
208 return static_cast<const char*> (_ptr) + offset;
209 }
210
218 inline void* get (uint64_t offset = 0)
219 {
220 if (JOIN_UNLIKELY (_ptr == nullptr))
221 {
222 throw std::runtime_error ("memory not mapped");
223 }
224
225 if (JOIN_UNLIKELY (offset >= _size))
226 {
227 throw std::out_of_range ("offset out of bounds");
228 }
229
230 return static_cast<char*> (_ptr) + offset;
231 }
232
238 int mbind (int numa) const noexcept
239 {
240 return join::mbind (_ptr, _size, numa);
241 }
242
247 int mlock () const noexcept
248 {
249 return join::mlock (_ptr, _size);
250 }
251
252 private:
257 void create ()
258 {
259 _ptr = ::mmap (nullptr, _size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0);
260 if ((_ptr == MAP_FAILED) && ((errno == ENOMEM) || (errno == EINVAL)))
261 {
262 // no hugepages available or no support.
263 _ptr = ::mmap (nullptr, _size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
264 }
265
266 if (_ptr == MAP_FAILED)
267 {
268 throw std::system_error (errno, std::generic_category (), "mmap failed");
269 }
270 }
271
275 void cleanup () noexcept
276 {
277 if ((_ptr != nullptr) && (_ptr != MAP_FAILED))
278 {
279 ::munlock (_ptr, _size);
280 ::munmap (_ptr, _size);
281 _ptr = nullptr;
282 }
283
284 _size = 0;
285 }
286
288 uint64_t _size = 0;
289
291 void* _ptr = nullptr;
292 };
293
297 class ShmMem
298 {
299 public:
300 template <size_t Count, size_t... Sizes>
301 using Allocator = BasicArena<ShmMem, Count, Sizes...>;
302
306
313 explicit ShmMem (uint64_t size, const std::string& name)
314 : _name (name)
315 {
316 long sc = sysconf (_SC_PAGESIZE);
317 uint64_t pageSize = (sc > 0) ? static_cast<uint64_t> (sc) : 4096;
318 _size = (size + pageSize - 1) & ~(pageSize - 1);
319
320 if (_size > static_cast<uint64_t> (std::numeric_limits<off_t>::max ()))
321 {
322 throw std::overflow_error ("size will overflow");
323 }
324
325 create ();
326 }
327
332 ShmMem (const ShmMem& other) = delete;
333
339 ShmMem& operator= (const ShmMem& other) = delete;
340
345 ShmMem (ShmMem&& other) noexcept
346 : _size (other._size)
347 , _name (std::move (other._name))
348 , _ptr (other._ptr)
349 , _fd (other._fd)
350 {
351 other._size = 0;
352 other._ptr = nullptr;
353 other._fd = -1;
354 }
355
361 ShmMem& operator= (ShmMem&& other) noexcept
362 {
363 cleanup ();
364
365 _size = other._size;
366 _name = std::move (other._name);
367 _ptr = other._ptr;
368 _fd = other._fd;
369
370 other._size = 0;
371 other._ptr = nullptr;
372 other._fd = -1;
373
374 return *this;
375 }
376
380 ~ShmMem () noexcept
381 {
382 cleanup ();
383 }
384
392 inline const void* get (uint64_t offset = 0) const
393 {
394 if (JOIN_UNLIKELY (_ptr == nullptr))
395 {
396 throw std::runtime_error ("memory not mapped");
397 }
398
399 if (JOIN_UNLIKELY (offset >= _size))
400 {
401 throw std::out_of_range ("offset out of bounds");
402 }
403
404 return static_cast<const char*> (_ptr) + offset;
405 }
406
414 inline void* get (uint64_t offset = 0)
415 {
416 if (JOIN_UNLIKELY (_ptr == nullptr))
417 {
418 throw std::runtime_error ("memory not mapped");
419 }
420
421 if (JOIN_UNLIKELY (offset >= _size))
422 {
423 throw std::out_of_range ("offset out of bounds");
424 }
425
426 return static_cast<char*> (_ptr) + offset;
427 }
428
434 int mbind (int numa) const noexcept
435 {
436 return join::mbind (_ptr, _size, numa);
437 }
438
443 int mlock () const noexcept
444 {
445 return join::mlock (_ptr, _size);
446 }
447
453 static int unlink (const std::string& name) noexcept
454 {
455 if (::shm_unlink (name.c_str ()) == -1)
456 {
457 if (errno == ENOENT)
458 {
459 return 0;
460 }
461 lastError = std::error_code (errno, std::generic_category ());
462 return -1;
463 }
464
465 return 0;
466 }
467
468 private:
473 void create ()
474 {
475 bool created = true;
476
477 _fd = ::shm_open (_name.c_str (), O_CREAT | O_RDWR | O_EXCL | O_CLOEXEC, 0644);
478 if ((_fd == -1) && (errno == EEXIST))
479 {
480 created = false;
481 _fd = ::shm_open (_name.c_str (), O_RDWR | O_CLOEXEC, 0644);
482 }
483
484 if (_fd == -1)
485 {
486 throw std::system_error (errno, std::generic_category (), "shm_open failed");
487 }
488
489 if (!created)
490 {
491 struct stat st;
492
493 if (fstat (_fd, &st) == -1)
494 {
495 int err = errno;
496 ::close (_fd);
497 throw std::system_error (err, std::generic_category (), "fstat failed");
498 }
499
500 if (static_cast<uint64_t> (st.st_size) != _size)
501 {
502 ::close (_fd);
503 throw std::runtime_error ("shared memory size mismatch");
504 }
505 }
506 else
507 {
508 if (::ftruncate (_fd, _size) == -1)
509 {
510 int err = errno;
511 ::close (_fd);
512 throw std::system_error (err, std::generic_category (), "ftruncate failed");
513 }
514 }
515
516 _ptr = ::mmap (nullptr, _size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_HUGETLB, _fd, 0);
517 if ((_ptr == MAP_FAILED) && ((errno == ENOMEM) || (errno == EINVAL)))
518 {
519 // no hugepages available or no support.
520 _ptr = ::mmap (nullptr, _size, PROT_READ | PROT_WRITE, MAP_SHARED, _fd, 0);
521 }
522
523 if (_ptr == MAP_FAILED)
524 {
525 int err = errno;
526 ::close (_fd);
527 throw std::system_error (err, std::generic_category (), "mmap failed");
528 }
529 }
530
534 void cleanup () noexcept
535 {
536 if ((_ptr != nullptr) && (_ptr != MAP_FAILED))
537 {
538 ::munlock (_ptr, _size);
539 ::munmap (_ptr, _size);
540 _ptr = nullptr;
541 }
542
543 if (_fd != -1)
544 {
545 ::close (_fd);
546 _fd = -1;
547 }
548
549 _name.clear ();
550 _size = 0;
551 }
552
554 uint64_t _size = 0;
555
557 std::string _name;
558
560 void* _ptr = nullptr;
561
563 int _fd = -1;
564 };
565}
566
567#endif
memory arena owning backend and managing one or more pools.
Definition memory.hpp:51
local anonymous memory provider.
Definition memory.hpp:115
LocalMem(uint64_t size)
allocates a local anonymous memory segment.
Definition memory.hpp:129
int mlock() const noexcept
lock memory in RAM.
Definition memory.hpp:247
int mbind(int numa) const noexcept
bind memory to a NUMA node.
Definition memory.hpp:238
const void * get(uint64_t offset=0) const
get a const pointer to the memory at a given offset.
Definition memory.hpp:196
LocalMem & operator=(const LocalMem &other)=delete
copy assignment operator.
void * get(uint64_t offset=0)
get a pointer to the memory at a given offset.
Definition memory.hpp:218
LocalMem(const LocalMem &other)=delete
copy constructor.
LocalMem(LocalMem &&other) noexcept
move constructor.
Definition memory.hpp:155
~LocalMem() noexcept
releases the mapped memory.
Definition memory.hpp:184
posix shared memory provider.
Definition memory.hpp:298
void * get(uint64_t offset=0)
get a pointer to the shared memory at a given offset.
Definition memory.hpp:414
ShmMem(const ShmMem &other)=delete
copy constructor.
ShmMem & operator=(const ShmMem &other)=delete
copy assignment operator.
int mbind(int numa) const noexcept
bind memory to a NUMA node.
Definition memory.hpp:434
static int unlink(const std::string &name) noexcept
destroy synchronization primitives and unlink the shared memory segment.
Definition memory.hpp:453
int mlock() const noexcept
lock memory in RAM.
Definition memory.hpp:443
ShmMem(ShmMem &&other) noexcept
move constructor.
Definition memory.hpp:345
~ShmMem() noexcept
unmaps the memory and closes the file descriptor.
Definition memory.hpp:380
ShmMem(uint64_t size, const std::string &name)
creates or opens a named shared memory segment.
Definition memory.hpp:313
const void * get(uint64_t offset=0) const
get a const pointer to the shared memory at a given offset.
Definition memory.hpp:392
Definition acceptor.hpp:32
int mlock(void *ptr, size_t size) noexcept
lock memory in RAM.
Definition memory.hpp:94
int mbind(void *ptr, size_t size, int numa) noexcept
bind memory to a NUMA node.
Definition memory.hpp:70
std::error_code make_error_code(join::Errc code) noexcept
Create an std::error_code object.
Definition error.cpp:150
const std::string _name
Definition semaphore_test.cpp:39
multiple producer multiple consumer ring buffer.
Definition queue.hpp:520
multiple producer single consumer ring buffer.
Definition queue.hpp:433
single producer single consumer ring buffer.
Definition queue.hpp:364
queue forward declarations.
Definition queue.hpp:586
#define JOIN_UNLIKELY(x)
Definition utils.hpp:47