libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
shared_mem.hpp
Go to the documentation of this file.
1 /******************************************************************************
2 ** Copyright © 2019 by J.M.McGuiness, coder@hussar.me.uk
3 **
4 ** This library is free software; you can redistribute it and/or
5 ** modify it under the terms of the GNU Lesser General Public
6 ** License as published by the Free Software Foundation; either
7 ** version 2.1 of the License, or (at your option) any later version.
8 **
9 ** This library is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 ** Lesser General Public License for more details.
13 **
14 ** You should have received a copy of the GNU Lesser General Public
15 ** License along with this library; if not, write to the Free Software
16 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 
19 #include "core/exception.hpp"
20 #include "core/sizeof_void.hpp"
21 #include "core/syscall_wrapper.hpp"
22 
23 #include <sys/mman.h>
24 #include <sys/stat.h> /* For mode constants */
25 #include <fcntl.h>
26 
27 namespace jmmcg { namespace LIBJMMCG_VER_NAMESPACE {
28 
29 /// A class to wrap POSIX (inter-process) shared-memory.
30 class shared_mem {
31 public:
32  using exception_type=crt_exception<ppd::platform_api, ppd::heavyweight_threading>;
33  using handle_t=int;
34 
35  enum oflags_t : int {
36  oflags_read_only=O_RDONLY,
41  };
43  enum flags_t : int {
44  /// Requires kernel support and configuration.
45  /**
46  <a href="https://www.kernel.org/doc/html/latest/admin-guide/mm/hugetlbpage.html"/>
47  */
48  flags_use_hugetlb=MAP_HUGETLB
49  };
50  enum mode_type : mode_t {
51  mode_rwxrwxrwx=ACCESSPERMS,
52  mode_srwxrwxrwx=ALLPERMS,
53  mode_rwrwrw=DEFFILEMODE
54  };
55  enum protection_type : int {
57  protection_read_write=PROT_READ|PROT_WRITE,
58  protection_read_write_execte=PROT_READ|PROT_WRITE|PROT_EXEC
59  };
60  enum sync_flags_t : int {
62  req_update_wait=MS_SYNC
63  };
64 
65  shared_mem(std::string const &name, std::size_t length, oflags_type oflags=oflags_create_if_not_exists|oflags_read_write, mode_type mode=mode_rwrwrw, protection_type prot=protection_read_write) noexcept(false);
66  ~shared_mem() noexcept(true);
67 
68  template<
69  class T ///< If one wishes to obtain an anonymous pointer (a "void *"), suitable for placement-new, simply used "void" as the template-argument.
70  >
71  T *get() noexcept(false);
72  template<
73  class T ///< If one wishes to obtain an anonymous pointer (a "void *"), suitable for placement-new, simply used "void" as the template-argument.
74  >
75  T const *get() const noexcept(false);
76 
77  void sync(void *addr, std::size_t length, sync_flags_t sync_flags=schedule_updates_return_immed) noexcept(false);
78  template<class T>
79  void sync(T *addr, sync_flags_t sync_flags=schedule_updates_return_immed) noexcept(false);
80 
81 private:
82  const std::string name_;
83  const std::size_t length_;
84  handle_t fd;
85  void *addr_;
86 
87  static handle_t open_fd(std::string const &name, oflags_type oflags, mode_type mode) noexcept(false);
88  static void *map_fd(handle_t fd, std::size_t length, protection_type prot) noexcept(false);
89 };
90 
91 template<class T>
92 inline T *
93 shared_mem::get() noexcept(false) {
94  if (private_::give_void_a_size_of<T>::value<=length_) {
95  return reinterpret_cast<T *>(addr_);
96  } else {
97  info::function fun(__LINE__, __PRETTY_FUNCTION__, typeid(this), info::function::argument(_T("sizeof(T)"), private_::give_void_a_size_of<T>::value));
98  fun.add_arg(info::function::argument(_T("std::size_t length_"), length_));
99  throw exception_type(_T("Requested size too large."), std::move(fun), JMMCG_REVISION_HDR(_T(LIBJMMCG_VERSION_NUMBER)));
100  }
101 }
102 
103 template<class T>
104 inline T const *
105 shared_mem::get() const noexcept(false) {
106  if (private_::give_void_a_size_of<T>::value<=length_) {
107  return reinterpret_cast<T const *>(addr_);
108  } else {
109  info::function fun(__LINE__, __PRETTY_FUNCTION__, typeid(this), info::function::argument(_T("sizeof(T)"), private_::give_void_a_size_of<T>::value));
110  fun.add_arg(info::function::argument(_T("std::size_t length_"), length_));
111  throw exception_type(_T("Requested size too large."), std::move(fun), JMMCG_REVISION_HDR(_T(LIBJMMCG_VERSION_NUMBER)));
112  }
113 }
114 
115 template<class T>
116 inline void
117 shared_mem::sync(T *addr, sync_flags_t sync_flags) noexcept(false) {
118  constexpr std::size_t length=sizeof(T);
119  if (addr<addr_) {
120  info::function fun(__LINE__, __PRETTY_FUNCTION__, typeid(this), info::function::argument(_T("T *addr"), addr));
121  fun.add_args(
122  info::function::argument(_T("std::size_t length"), length),
123  info::function::argument(_T("sync_flags_t sync_flags"), sync_flags),
124  info::function::argument(_T("void *addr_"), addr_)
125  );
126  throw exception_type(_T("Requested address less than mapped address."), std::move(fun), JMMCG_REVISION_HDR(_T(LIBJMMCG_VERSION_NUMBER)));
127  }
128  if ((reinterpret_cast<std::uint8_t const *>(addr)+length)>(reinterpret_cast<std::uint8_t const *>(addr_)+length_)) {
129  info::function fun(__LINE__, __PRETTY_FUNCTION__, typeid(this), info::function::argument(_T("T *addr"), addr));
130  fun.add_args(
131  info::function::argument(_T("std::size_t length"), length),
132  info::function::argument(_T("sync_flags_t sync_flags"), sync_flags),
133  info::function::argument(_T("std::size_t length_"), length_),
134  info::function::argument(_T("void *addr_"), addr_)
135  );
136  throw exception_type(_T("Requested address plus length less than mapped address ."), std::move(fun), JMMCG_REVISION_HDR(_T(LIBJMMCG_VERSION_NUMBER)));
137  }
138  JMMCG_SYSCALL_WRAPPER("Unable sync the portion of the mapped memory.", _T(LIBJMMCG_VERSION_NUMBER), ::msync, addr, length, sync_flags);
139 }
140 
141 } }