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#ifdef JOIN_HAS_NUMA
43#include <numaif.h>
44#include <numa.h>
45#endif
46#include <fcntl.h>
47#include <cstdint>
48
49namespace join
50{
52 template <typename Backend, size_t Count, size_t... Sizes>
54
56 template <typename Backend, template <typename, typename> class SyncPolicy>
57 struct SyncBinding;
58
59 template <typename, typename>
60 struct Spsc;
61
62 template <typename, typename>
63 struct Mpsc;
64
65 template <typename, typename>
66 struct Mpmc;
67
68#ifdef JOIN_HAS_NUMA
76 inline int mbind (void* ptr, size_t size, int numa) noexcept
77 {
78 if (ptr == nullptr || numa < 0 || numa > (static_cast<int> (sizeof (unsigned long) * 8) - 1))
79 {
81 return -1;
82 }
83
84 unsigned long mask = (1UL << numa);
85 if (::mbind (ptr, size, MPOL_BIND, &mask, sizeof (mask) * 8, MPOL_MF_STRICT) == -1)
86 {
87 lastError = std::error_code (errno, std::generic_category ());
88 return -1;
89 }
90
91 return 0;
92 }
93#endif
94
101 inline int mlock (void* ptr, size_t size) noexcept
102 {
103 if (ptr == nullptr)
104 {
106 return -1;
107 }
108
109 if (::mlock (ptr, size) == -1)
110 {
111 lastError = std::error_code (errno, std::generic_category ());
112 return -1;
113 }
114
115 return 0;
116 }
117
122 {
123 public:
124 template <size_t Count, size_t... Sizes>
125 using Allocator = BasicArena<LocalMem, Count, Sizes...>;
126
130
134 LocalMem () noexcept = default;
135
141 explicit LocalMem (uint64_t size)
142 {
143 long sc = sysconf (_SC_PAGESIZE);
144 uint64_t pageSize = (sc > 0) ? static_cast<uint64_t> (sc) : _defaultPageSize;
145 _size = (size + pageSize - 1) & ~(pageSize - 1);
146
147 create ();
148 }
149
154 LocalMem (const LocalMem& other) = delete;
155
161 LocalMem& operator= (const LocalMem& other) = delete;
162
167 LocalMem (LocalMem&& other) noexcept
168 : _size (other._size)
169 , _ptr (other._ptr)
170 {
171 other._size = 0;
172 other._ptr = nullptr;
173 }
174
180 LocalMem& operator= (LocalMem&& other) noexcept
181 {
182 cleanup ();
183
184 _size = other._size;
185 _ptr = other._ptr;
186
187 other._size = 0;
188 other._ptr = nullptr;
189
190 return *this;
191 }
192
196 ~LocalMem () noexcept
197 {
198 cleanup ();
199 }
200
205 bool mapped () const noexcept
206 {
207 return _ptr != nullptr;
208 }
209
217 const void* get (uint64_t offset = 0) const
218 {
219 if (JOIN_UNLIKELY (_ptr == nullptr))
220 {
221 throw std::runtime_error ("memory not mapped");
222 }
223
224 if (JOIN_UNLIKELY (offset >= _size))
225 {
226 throw std::out_of_range ("offset out of bounds");
227 }
228
229 return static_cast<const char*> (_ptr) + offset;
230 }
231
239 void* get (uint64_t offset = 0)
240 {
241 if (JOIN_UNLIKELY (_ptr == nullptr))
242 {
243 throw std::runtime_error ("memory not mapped");
244 }
245
246 if (JOIN_UNLIKELY (offset >= _size))
247 {
248 throw std::out_of_range ("offset out of bounds");
249 }
250
251 return static_cast<char*> (_ptr) + offset;
252 }
253
254#ifdef JOIN_HAS_NUMA
260 int mbind (int numa) const noexcept
261 {
262 return join::mbind (_ptr, _size, numa);
263 }
264#endif
265
270 int mlock () const noexcept
271 {
272 return join::mlock (_ptr, _size);
273 }
274
275 private:
280 void create ()
281 {
282 _ptr = ::mmap (nullptr, _size, PROT_READ | PROT_WRITE,
283 MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE | MAP_HUGETLB, -1, 0);
284 if ((_ptr == MAP_FAILED) && ((errno == ENOMEM) || (errno == EINVAL)))
285 {
286 // no hugepages available or no support.
287 _ptr =
288 ::mmap (nullptr, _size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0);
289 }
290
291 if (_ptr == MAP_FAILED)
292 {
293 throw std::system_error (errno, std::generic_category (), "mmap failed");
294 }
295 }
296
300 void cleanup () noexcept
301 {
302 if ((_ptr != nullptr) && (_ptr != MAP_FAILED))
303 {
304 ::munlock (_ptr, _size);
305 ::munmap (_ptr, _size);
306 _ptr = nullptr;
307 }
308
309 _size = 0;
310 }
311
313 static constexpr uint64_t _defaultPageSize = 4096;
314
316 uint64_t _size = 0;
317
319 void* _ptr = nullptr;
320 };
321
325 class ShmMem
326 {
327 public:
328 template <size_t Count, size_t... Sizes>
329 using Allocator = BasicArena<ShmMem, Count, Sizes...>;
330
334
341 explicit ShmMem (uint64_t size, const std::string& name)
342 : _name (name)
343 {
344 long sc = sysconf (_SC_PAGESIZE);
345 uint64_t pageSize = (sc > 0) ? static_cast<uint64_t> (sc) : _defaultPageSize;
346 _size = (size + pageSize - 1) & ~(pageSize - 1);
347
348 if (_size > static_cast<uint64_t> (std::numeric_limits<off_t>::max ()))
349 {
350 throw std::overflow_error ("size will overflow");
351 }
352
353 create ();
354 }
355
360 ShmMem (const ShmMem& other) = delete;
361
367 ShmMem& operator= (const ShmMem& other) = delete;
368
373 ShmMem (ShmMem&& other) noexcept
374 : _size (other._size)
375 , _name (std::move (other._name))
376 , _ptr (other._ptr)
377 , _fd (other._fd)
378 {
379 other._size = 0;
380 other._ptr = nullptr;
381 other._fd = -1;
382 }
383
389 ShmMem& operator= (ShmMem&& other) noexcept
390 {
391 cleanup ();
392
393 _size = other._size;
394 _name = std::move (other._name);
395 _ptr = other._ptr;
396 _fd = other._fd;
397
398 other._size = 0;
399 other._ptr = nullptr;
400 other._fd = -1;
401
402 return *this;
403 }
404
408 ~ShmMem () noexcept
409 {
410 cleanup ();
411 }
412
417 bool mapped () const noexcept
418 {
419 return _ptr != nullptr;
420 }
421
429 const void* get (uint64_t offset = 0) const
430 {
431 if (JOIN_UNLIKELY (_ptr == nullptr))
432 {
433 throw std::runtime_error ("memory not mapped");
434 }
435
436 if (JOIN_UNLIKELY (offset >= _size))
437 {
438 throw std::out_of_range ("offset out of bounds");
439 }
440
441 return static_cast<const char*> (_ptr) + offset;
442 }
443
451 void* get (uint64_t offset = 0)
452 {
453 if (JOIN_UNLIKELY (_ptr == nullptr))
454 {
455 throw std::runtime_error ("memory not mapped");
456 }
457
458 if (JOIN_UNLIKELY (offset >= _size))
459 {
460 throw std::out_of_range ("offset out of bounds");
461 }
462
463 return static_cast<char*> (_ptr) + offset;
464 }
465
466#ifdef JOIN_HAS_NUMA
472 int mbind (int numa) const noexcept
473 {
474 return join::mbind (_ptr, _size, numa);
475 }
476#endif
477
482 int mlock () const noexcept
483 {
484 return join::mlock (_ptr, _size);
485 }
486
492 static int unlink (const std::string& name) noexcept
493 {
494 if (::shm_unlink (name.c_str ()) == -1)
495 {
496 if (errno == ENOENT)
497 {
498 return 0;
499 }
500 lastError = std::error_code (errno, std::generic_category ());
501 return -1;
502 }
503
504 return 0;
505 }
506
507 private:
512 void create ()
513 {
514 bool created = true;
515
516 _fd = ::shm_open (_name.c_str (), O_CREAT | O_RDWR | O_EXCL | O_CLOEXEC, 0644);
517 if ((_fd == -1) && (errno == EEXIST))
518 {
519 created = false;
520 _fd = ::shm_open (_name.c_str (), O_RDWR | O_CLOEXEC, 0644);
521 }
522
523 if (_fd == -1)
524 {
525 throw std::system_error (errno, std::generic_category (), "shm_open failed");
526 }
527
528 if (!created)
529 {
530 struct stat st;
531
532 if (fstat (_fd, &st) == -1)
533 {
534 int err = errno;
535 ::close (_fd);
536 throw std::system_error (err, std::generic_category (), "fstat failed");
537 }
538
539 if (static_cast<uint64_t> (st.st_size) != _size)
540 {
541 ::close (_fd);
542 throw std::runtime_error ("shared memory size mismatch");
543 }
544 }
545 else
546 {
547 if (::ftruncate (_fd, _size) == -1)
548 {
549 int err = errno;
550 ::close (_fd);
551 throw std::system_error (err, std::generic_category (), "ftruncate failed");
552 }
553 }
554
555 _ptr = ::mmap (nullptr, _size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_HUGETLB, _fd, 0);
556 if ((_ptr == MAP_FAILED) && ((errno == ENOMEM) || (errno == EINVAL)))
557 {
558 // no hugepages available or no support.
559 _ptr = ::mmap (nullptr, _size, PROT_READ | PROT_WRITE, MAP_SHARED, _fd, 0);
560 }
561
562 if (_ptr == MAP_FAILED)
563 {
564 int err = errno;
565 ::close (_fd);
566 throw std::system_error (err, std::generic_category (), "mmap failed");
567 }
568 }
569
573 void cleanup () noexcept
574 {
575 if ((_ptr != nullptr) && (_ptr != MAP_FAILED))
576 {
577 ::munlock (_ptr, _size);
578 ::munmap (_ptr, _size);
579 _ptr = nullptr;
580 }
581
582 if (_fd != -1)
583 {
584 ::close (_fd);
585 _fd = -1;
586 }
587
588 _name.clear ();
589 _size = 0;
590 }
591
593 static constexpr uint64_t _defaultPageSize = 4096;
594
596 uint64_t _size = 0;
597
599 std::string _name;
600
602 void* _ptr = nullptr;
603
605 int _fd = -1;
606 };
607}
608
609#endif
memory arena owning backend and managing one or more pools.
Definition memory.hpp:53
local anonymous memory provider.
Definition memory.hpp:122
int mlock() const noexcept
lock memory in RAM.
Definition memory.hpp:270
const void * get(uint64_t offset=0) const
get a const pointer to the memory at a given offset.
Definition memory.hpp:217
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:239
LocalMem(const LocalMem &other)=delete
copy constructor.
LocalMem() noexcept=default
default constructor.
LocalMem(LocalMem &&other) noexcept
move constructor.
Definition memory.hpp:167
bool mapped() const noexcept
check if the memory is mapped.
Definition memory.hpp:205
~LocalMem() noexcept
releases the mapped memory.
Definition memory.hpp:196
posix shared memory provider.
Definition memory.hpp:326
bool mapped() const noexcept
check if the shared memory is mapped.
Definition memory.hpp:417
void * get(uint64_t offset=0)
get a pointer to the shared memory at a given offset.
Definition memory.hpp:451
ShmMem(const ShmMem &other)=delete
copy constructor.
ShmMem & operator=(const ShmMem &other)=delete
copy assignment operator.
static int unlink(const std::string &name) noexcept
destroy synchronization primitives and unlink the shared memory segment.
Definition memory.hpp:492
int mlock() const noexcept
lock memory in RAM.
Definition memory.hpp:482
ShmMem(ShmMem &&other) noexcept
move constructor.
Definition memory.hpp:373
~ShmMem() noexcept
unmaps the memory and closes the file descriptor.
Definition memory.hpp:408
ShmMem(uint64_t size, const std::string &name)
creates or opens a named shared memory segment.
Definition memory.hpp:341
const void * get(uint64_t offset=0) const
get a const pointer to the shared memory at a given offset.
Definition memory.hpp:429
Definition acceptor.hpp:32
int mlock(void *ptr, size_t size) noexcept
lock memory in RAM.
Definition memory.hpp:101
std::error_code make_error_code(join::Errc code) noexcept
Create an std::error_code object.
Definition error.cpp:195
const std::string _name
Definition shared_futex_test.cpp:45
multiple producer multiple consumer ring buffer.
Definition queue.hpp:857
multiple producer single consumer ring buffer.
Definition queue.hpp:664
single producer single consumer ring buffer.
Definition queue.hpp:483
queue forward declarations.
Definition queue.hpp:1051
#define JOIN_UNLIKELY(x)
Definition utils.hpp:46