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, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0);
269 if ((_ptr == MAP_FAILED) && ((errno == ENOMEM) || (errno == EINVAL)))
270 {
271 // no hugepages available or no support.
272 _ptr = ::mmap (nullptr, _size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
273 }
274
275 if (_ptr == MAP_FAILED)
276 {
277 throw std::system_error (errno, std::generic_category (), "mmap failed");
278 }
279 }
280
284 void cleanup () noexcept
285 {
286 if ((_ptr != nullptr) && (_ptr != MAP_FAILED))
287 {
288 ::munlock (_ptr, _size);
289 ::munmap (_ptr, _size);
290 _ptr = nullptr;
291 }
292
293 _size = 0;
294 }
295
297 static constexpr uint64_t _defaultPageSize = 4096;
298
300 uint64_t _size = 0;
301
303 void* _ptr = nullptr;
304 };
305
309 class ShmMem
310 {
311 public:
312 template <size_t Count, size_t... Sizes>
313 using Allocator = BasicArena<ShmMem, Count, Sizes...>;
314
318
325 explicit ShmMem (uint64_t size, const std::string& name)
326 : _name (name)
327 {
328 long sc = sysconf (_SC_PAGESIZE);
329 uint64_t pageSize = (sc > 0) ? static_cast<uint64_t> (sc) : _defaultPageSize;
330 _size = (size + pageSize - 1) & ~(pageSize - 1);
331
332 if (_size > static_cast<uint64_t> (std::numeric_limits<off_t>::max ()))
333 {
334 throw std::overflow_error ("size will overflow");
335 }
336
337 create ();
338 }
339
344 ShmMem (const ShmMem& other) = delete;
345
351 ShmMem& operator= (const ShmMem& other) = delete;
352
357 ShmMem (ShmMem&& other) noexcept
358 : _size (other._size)
359 , _name (std::move (other._name))
360 , _ptr (other._ptr)
361 , _fd (other._fd)
362 {
363 other._size = 0;
364 other._ptr = nullptr;
365 other._fd = -1;
366 }
367
373 ShmMem& operator= (ShmMem&& other) noexcept
374 {
375 cleanup ();
376
377 _size = other._size;
378 _name = std::move (other._name);
379 _ptr = other._ptr;
380 _fd = other._fd;
381
382 other._size = 0;
383 other._ptr = nullptr;
384 other._fd = -1;
385
386 return *this;
387 }
388
392 ~ShmMem () noexcept
393 {
394 cleanup ();
395 }
396
404 const void* get (uint64_t offset = 0) const
405 {
406 if (JOIN_UNLIKELY (_ptr == nullptr))
407 {
408 throw std::runtime_error ("memory not mapped");
409 }
410
411 if (JOIN_UNLIKELY (offset >= _size))
412 {
413 throw std::out_of_range ("offset out of bounds");
414 }
415
416 return static_cast<const char*> (_ptr) + offset;
417 }
418
426 void* get (uint64_t offset = 0)
427 {
428 if (JOIN_UNLIKELY (_ptr == nullptr))
429 {
430 throw std::runtime_error ("memory not mapped");
431 }
432
433 if (JOIN_UNLIKELY (offset >= _size))
434 {
435 throw std::out_of_range ("offset out of bounds");
436 }
437
438 return static_cast<char*> (_ptr) + offset;
439 }
440
441#ifdef JOIN_HAS_NUMA
447 int mbind (int numa) const noexcept
448 {
449 return join::mbind (_ptr, _size, numa);
450 }
451#endif
452
457 int mlock () const noexcept
458 {
459 return join::mlock (_ptr, _size);
460 }
461
467 static int unlink (const std::string& name) noexcept
468 {
469 if (::shm_unlink (name.c_str ()) == -1)
470 {
471 if (errno == ENOENT)
472 {
473 return 0;
474 }
475 lastError = std::error_code (errno, std::generic_category ());
476 return -1;
477 }
478
479 return 0;
480 }
481
482 private:
487 void create ()
488 {
489 bool created = true;
490
491 _fd = ::shm_open (_name.c_str (), O_CREAT | O_RDWR | O_EXCL | O_CLOEXEC, 0644);
492 if ((_fd == -1) && (errno == EEXIST))
493 {
494 created = false;
495 _fd = ::shm_open (_name.c_str (), O_RDWR | O_CLOEXEC, 0644);
496 }
497
498 if (_fd == -1)
499 {
500 throw std::system_error (errno, std::generic_category (), "shm_open failed");
501 }
502
503 if (!created)
504 {
505 struct stat st;
506
507 if (fstat (_fd, &st) == -1)
508 {
509 int err = errno;
510 ::close (_fd);
511 throw std::system_error (err, std::generic_category (), "fstat failed");
512 }
513
514 if (static_cast<uint64_t> (st.st_size) != _size)
515 {
516 ::close (_fd);
517 throw std::runtime_error ("shared memory size mismatch");
518 }
519 }
520 else
521 {
522 if (::ftruncate (_fd, _size) == -1)
523 {
524 int err = errno;
525 ::close (_fd);
526 throw std::system_error (err, std::generic_category (), "ftruncate failed");
527 }
528 }
529
530 _ptr = ::mmap (nullptr, _size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_HUGETLB, _fd, 0);
531 if ((_ptr == MAP_FAILED) && ((errno == ENOMEM) || (errno == EINVAL)))
532 {
533 // no hugepages available or no support.
534 _ptr = ::mmap (nullptr, _size, PROT_READ | PROT_WRITE, MAP_SHARED, _fd, 0);
535 }
536
537 if (_ptr == MAP_FAILED)
538 {
539 int err = errno;
540 ::close (_fd);
541 throw std::system_error (err, std::generic_category (), "mmap failed");
542 }
543 }
544
548 void cleanup () noexcept
549 {
550 if ((_ptr != nullptr) && (_ptr != MAP_FAILED))
551 {
552 ::munlock (_ptr, _size);
553 ::munmap (_ptr, _size);
554 _ptr = nullptr;
555 }
556
557 if (_fd != -1)
558 {
559 ::close (_fd);
560 _fd = -1;
561 }
562
563 _name.clear ();
564 _size = 0;
565 }
566
568 static constexpr uint64_t _defaultPageSize = 4096;
569
571 uint64_t _size = 0;
572
574 std::string _name;
575
577 void* _ptr = nullptr;
578
580 int _fd = -1;
581 };
582}
583
584#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:310
void * get(uint64_t offset=0)
get a pointer to the shared memory at a given offset.
Definition memory.hpp:426
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:467
int mlock() const noexcept
lock memory in RAM.
Definition memory.hpp:457
ShmMem(ShmMem &&other) noexcept
move constructor.
Definition memory.hpp:357
~ShmMem() noexcept
unmaps the memory and closes the file descriptor.
Definition memory.hpp:392
ShmMem(uint64_t size, const std::string &name)
creates or opens a named shared memory segment.
Definition memory.hpp:325
const void * get(uint64_t offset=0) const
get a const pointer to the shared memory at a given offset.
Definition memory.hpp:404
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:838
multiple producer single consumer ring buffer.
Definition queue.hpp:654
single producer single consumer ring buffer.
Definition queue.hpp:508
queue forward declarations.
Definition queue.hpp:982
#define JOIN_UNLIKELY(x)
Definition utils.hpp:47