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
136 explicit LocalMem (uint64_t size)
137 {
138 long sc = sysconf (_SC_PAGESIZE);
139 uint64_t pageSize = (sc > 0) ? static_cast<uint64_t> (sc) : _defaultPageSize;
140 _size = (size + pageSize - 1) & ~(pageSize - 1);
141
142 create ();
143 }
144
149 LocalMem (const LocalMem& other) = delete;
150
156 LocalMem& operator= (const LocalMem& other) = delete;
157
162 LocalMem (LocalMem&& other) noexcept
163 : _size (other._size)
164 , _ptr (other._ptr)
165 {
166 other._size = 0;
167 other._ptr = nullptr;
168 }
169
175 LocalMem& operator= (LocalMem&& other) noexcept
176 {
177 cleanup ();
178
179 _size = other._size;
180 _ptr = other._ptr;
181
182 other._size = 0;
183 other._ptr = nullptr;
184
185 return *this;
186 }
187
191 ~LocalMem () noexcept
192 {
193 cleanup ();
194 }
195
203 const void* get (uint64_t offset = 0) const
204 {
205 if (JOIN_UNLIKELY (_ptr == nullptr))
206 {
207 throw std::runtime_error ("memory not mapped");
208 }
209
210 if (JOIN_UNLIKELY (offset >= _size))
211 {
212 throw std::out_of_range ("offset out of bounds");
213 }
214
215 return static_cast<const char*> (_ptr) + offset;
216 }
217
225 void* get (uint64_t offset = 0)
226 {
227 if (JOIN_UNLIKELY (_ptr == nullptr))
228 {
229 throw std::runtime_error ("memory not mapped");
230 }
231
232 if (JOIN_UNLIKELY (offset >= _size))
233 {
234 throw std::out_of_range ("offset out of bounds");
235 }
236
237 return static_cast<char*> (_ptr) + offset;
238 }
239
240#ifdef JOIN_HAS_NUMA
246 int mbind (int numa) const noexcept
247 {
248 return join::mbind (_ptr, _size, numa);
249 }
250#endif
251
256 int mlock () const noexcept
257 {
258 return join::mlock (_ptr, _size);
259 }
260
261 private:
266 void create ()
267 {
268 _ptr = ::mmap (nullptr, _size, PROT_READ | PROT_WRITE,
269 MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE | MAP_HUGETLB, -1, 0);
270 if ((_ptr == MAP_FAILED) && ((errno == ENOMEM) || (errno == EINVAL)))
271 {
272 // no hugepages available or no support.
273 _ptr =
274 ::mmap (nullptr, _size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0);
275 }
276
277 if (_ptr == MAP_FAILED)
278 {
279 throw std::system_error (errno, std::generic_category (), "mmap failed");
280 }
281 }
282
286 void cleanup () noexcept
287 {
288 if ((_ptr != nullptr) && (_ptr != MAP_FAILED))
289 {
290 ::munlock (_ptr, _size);
291 ::munmap (_ptr, _size);
292 _ptr = nullptr;
293 }
294
295 _size = 0;
296 }
297
299 static constexpr uint64_t _defaultPageSize = 4096;
300
302 uint64_t _size = 0;
303
305 void* _ptr = nullptr;
306 };
307
311 class ShmMem
312 {
313 public:
314 template <size_t Count, size_t... Sizes>
315 using Allocator = BasicArena<ShmMem, Count, Sizes...>;
316
320
327 explicit ShmMem (uint64_t size, const std::string& name)
328 : _name (name)
329 {
330 long sc = sysconf (_SC_PAGESIZE);
331 uint64_t pageSize = (sc > 0) ? static_cast<uint64_t> (sc) : _defaultPageSize;
332 _size = (size + pageSize - 1) & ~(pageSize - 1);
333
334 if (_size > static_cast<uint64_t> (std::numeric_limits<off_t>::max ()))
335 {
336 throw std::overflow_error ("size will overflow");
337 }
338
339 create ();
340 }
341
346 ShmMem (const ShmMem& other) = delete;
347
353 ShmMem& operator= (const ShmMem& other) = delete;
354
359 ShmMem (ShmMem&& other) noexcept
360 : _size (other._size)
361 , _name (std::move (other._name))
362 , _ptr (other._ptr)
363 , _fd (other._fd)
364 {
365 other._size = 0;
366 other._ptr = nullptr;
367 other._fd = -1;
368 }
369
375 ShmMem& operator= (ShmMem&& other) noexcept
376 {
377 cleanup ();
378
379 _size = other._size;
380 _name = std::move (other._name);
381 _ptr = other._ptr;
382 _fd = other._fd;
383
384 other._size = 0;
385 other._ptr = nullptr;
386 other._fd = -1;
387
388 return *this;
389 }
390
394 ~ShmMem () noexcept
395 {
396 cleanup ();
397 }
398
406 const void* get (uint64_t offset = 0) const
407 {
408 if (JOIN_UNLIKELY (_ptr == nullptr))
409 {
410 throw std::runtime_error ("memory not mapped");
411 }
412
413 if (JOIN_UNLIKELY (offset >= _size))
414 {
415 throw std::out_of_range ("offset out of bounds");
416 }
417
418 return static_cast<const char*> (_ptr) + offset;
419 }
420
428 void* get (uint64_t offset = 0)
429 {
430 if (JOIN_UNLIKELY (_ptr == nullptr))
431 {
432 throw std::runtime_error ("memory not mapped");
433 }
434
435 if (JOIN_UNLIKELY (offset >= _size))
436 {
437 throw std::out_of_range ("offset out of bounds");
438 }
439
440 return static_cast<char*> (_ptr) + offset;
441 }
442
443#ifdef JOIN_HAS_NUMA
449 int mbind (int numa) const noexcept
450 {
451 return join::mbind (_ptr, _size, numa);
452 }
453#endif
454
459 int mlock () const noexcept
460 {
461 return join::mlock (_ptr, _size);
462 }
463
469 static int unlink (const std::string& name) noexcept
470 {
471 if (::shm_unlink (name.c_str ()) == -1)
472 {
473 if (errno == ENOENT)
474 {
475 return 0;
476 }
477 lastError = std::error_code (errno, std::generic_category ());
478 return -1;
479 }
480
481 return 0;
482 }
483
484 private:
489 void create ()
490 {
491 bool created = true;
492
493 _fd = ::shm_open (_name.c_str (), O_CREAT | O_RDWR | O_EXCL | O_CLOEXEC, 0644);
494 if ((_fd == -1) && (errno == EEXIST))
495 {
496 created = false;
497 _fd = ::shm_open (_name.c_str (), O_RDWR | O_CLOEXEC, 0644);
498 }
499
500 if (_fd == -1)
501 {
502 throw std::system_error (errno, std::generic_category (), "shm_open failed");
503 }
504
505 if (!created)
506 {
507 struct stat st;
508
509 if (fstat (_fd, &st) == -1)
510 {
511 int err = errno;
512 ::close (_fd);
513 throw std::system_error (err, std::generic_category (), "fstat failed");
514 }
515
516 if (static_cast<uint64_t> (st.st_size) != _size)
517 {
518 ::close (_fd);
519 throw std::runtime_error ("shared memory size mismatch");
520 }
521 }
522 else
523 {
524 if (::ftruncate (_fd, _size) == -1)
525 {
526 int err = errno;
527 ::close (_fd);
528 throw std::system_error (err, std::generic_category (), "ftruncate failed");
529 }
530 }
531
532 _ptr = ::mmap (nullptr, _size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_HUGETLB, _fd, 0);
533 if ((_ptr == MAP_FAILED) && ((errno == ENOMEM) || (errno == EINVAL)))
534 {
535 // no hugepages available or no support.
536 _ptr = ::mmap (nullptr, _size, PROT_READ | PROT_WRITE, MAP_SHARED, _fd, 0);
537 }
538
539 if (_ptr == MAP_FAILED)
540 {
541 int err = errno;
542 ::close (_fd);
543 throw std::system_error (err, std::generic_category (), "mmap failed");
544 }
545 }
546
550 void cleanup () noexcept
551 {
552 if ((_ptr != nullptr) && (_ptr != MAP_FAILED))
553 {
554 ::munlock (_ptr, _size);
555 ::munmap (_ptr, _size);
556 _ptr = nullptr;
557 }
558
559 if (_fd != -1)
560 {
561 ::close (_fd);
562 _fd = -1;
563 }
564
565 _name.clear ();
566 _size = 0;
567 }
568
570 static constexpr uint64_t _defaultPageSize = 4096;
571
573 uint64_t _size = 0;
574
576 std::string _name;
577
579 void* _ptr = nullptr;
580
582 int _fd = -1;
583 };
584}
585
586#endif
memory arena owning backend and managing one or more pools.
Definition memory.hpp:53
local anonymous memory provider.
Definition memory.hpp:122
LocalMem(uint64_t size)
allocates a local anonymous memory segment.
Definition memory.hpp:136
int mlock() const noexcept
lock memory in RAM.
Definition memory.hpp:256
const void * get(uint64_t offset=0) const
get a const pointer to the memory at a given offset.
Definition memory.hpp:203
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:225
LocalMem(const LocalMem &other)=delete
copy constructor.
LocalMem(LocalMem &&other) noexcept
move constructor.
Definition memory.hpp:162
~LocalMem() noexcept
releases the mapped memory.
Definition memory.hpp:191
posix shared memory provider.
Definition memory.hpp:312
void * get(uint64_t offset=0)
get a pointer to the shared memory at a given offset.
Definition memory.hpp:428
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:469
int mlock() const noexcept
lock memory in RAM.
Definition memory.hpp:459
ShmMem(ShmMem &&other) noexcept
move constructor.
Definition memory.hpp:359
~ShmMem() noexcept
unmaps the memory and closes the file descriptor.
Definition memory.hpp:394
ShmMem(uint64_t size, const std::string &name)
creates or opens a named shared memory segment.
Definition memory.hpp:327
const void * get(uint64_t offset=0) const
get a const pointer to the shared memory at a given offset.
Definition memory.hpp:406
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:150
const std::string _name
Definition semaphore_test.cpp:39
multiple producer multiple consumer ring buffer.
Definition queue.hpp:882
multiple producer single consumer ring buffer.
Definition queue.hpp:682
single producer single consumer ring buffer.
Definition queue.hpp:502
queue forward declarations.
Definition queue.hpp:1083
#define JOIN_UNLIKELY(x)
Definition utils.hpp:47