libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
shared_mem.cpp
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 "shared_mem.hpp"
20 
21 namespace jmmcg { namespace LIBJMMCG_VER_NAMESPACE {
22 
23 template<class>
25  static inline constexpr std::int64_t value=-1;
26 };
27 
28 shared_mem::handle_t
29 shared_mem::open_fd(std::string const &name, oflags_type oflags, mode_type mode) noexcept(false) {
30  if (name.empty()) {
31  info::function fun(__LINE__, __PRETTY_FUNCTION__, typeid(open_fd), info::function::argument(_T("std::string const &name"), name));
32  fun.add_args(
33  info::function::argument(_T("oflags_type oflags"), oflags),
34  info::function::argument(_T("mode_type mode"), mode)
35  );
36  throw exception_type(_T("Shared-memory segment must have a non-empty name."), std::move(fun), JMMCG_REVISION_HDR(_T(LIBJMMCG_VERSION_NUMBER)));
37  } else {
38  return JMMCG_SYSCALL_WRAPPER("Failed to open shared-memory segment.", _T(LIBJMMCG_VERSION_NUMBER), ::shm_open, name.c_str(), oflags, mode);
39  }
40 }
41 
42 void *
43 shared_mem::map_fd(handle_t fd, std::size_t length, protection_type prot) noexcept(false) {
44  if (length<=0) {
45  info::function fun(__LINE__, __PRETTY_FUNCTION__, typeid(map_fd), info::function::argument(_T("handle_t fd"), fd));
46  fun.add_args(
47  info::function::argument(_T("std::size_t length"), length),
48  info::function::argument(_T("protection_type prot"), prot)
49  );
50  throw exception_type(_T("Shared-memory segment must have a length greater than zero."), std::move(fun), JMMCG_REVISION_HDR(_T(LIBJMMCG_VERSION_NUMBER)));
51  } else {
52  assert(fd>0);
53  void * const addr=JMMCG_SYSCALL_WRAPPER_FC(failure_code_mmap, "Failed to map the shared-memory segment.", _T(LIBJMMCG_VERSION_NUMBER), ::mmap, nullptr, length, prot, MAP_SHARED_VALIDATE|MAP_LOCKED, fd, 0);
54  assert(addr);
55  return addr;
56  }
57 }
58 
59 shared_mem::shared_mem(std::string const &name, std::size_t length, oflags_type oflags, mode_type mode, protection_type prot) noexcept(false)
60 : name_(name), length_(length), fd(open_fd(name_, oflags, mode)), addr_(map_fd(fd, length, prot)) {
61  JMMCG_SYSCALL_WRAPPER("Failed to resize the shared-memory segment to the requested size.", _T(LIBJMMCG_VERSION_NUMBER), ::ftruncate, fd, length_);
62 }
63 
64 shared_mem::~shared_mem() noexcept(true) {
65  try {
66  JMMCG_SYSCALL_WRAPPER("Failed to unmap region.", _T(LIBJMMCG_VERSION_NUMBER), ::munmap, addr_, length_);
67  } catch (std::exception const &ex) {
68  JMMCG_TRACE(ex.what());
69  }
70  try {
71  JMMCG_SYSCALL_WRAPPER("Failed unlink the named region.", _T(LIBJMMCG_VERSION_NUMBER), ::shm_unlink, name_.c_str());
72  } catch (std::exception const &ex) {
73 // TODO: This seems to fail sometimes, so just ignore it... JMMCG_TRACE(ex.what());
74  }
75 }
76 
77 void
78 shared_mem::sync(void *addr, std::size_t length, sync_flags_t sync_flags) noexcept(false) {
79  if (length>length_) {
80  info::function fun(__LINE__, __PRETTY_FUNCTION__, typeid(this), info::function::argument(_T("void *addr"), addr));
81  fun.add_args(
82  info::function::argument(_T("std::size_t length"), length),
83  info::function::argument(_T("sync_flags_t sync_flags"), sync_flags),
84  info::function::argument(_T("std::size_t length_"), length_)
85  );
86  throw exception_type(_T("Requested size larger than configured size."), std::move(fun), JMMCG_REVISION_HDR(_T(LIBJMMCG_VERSION_NUMBER)));
87  }
88  if (addr<addr_) {
89  info::function fun(__LINE__, __PRETTY_FUNCTION__, typeid(this), info::function::argument(_T("void *addr"), addr));
90  fun.add_args(
91  info::function::argument(_T("std::size_t length"), length),
92  info::function::argument(_T("sync_flags_t sync_flags"), sync_flags),
93  info::function::argument(_T("void *addr_"), addr_)
94  );
95  throw exception_type(_T("Requested address less than mapped address."), std::move(fun), JMMCG_REVISION_HDR(_T(LIBJMMCG_VERSION_NUMBER)));
96  }
97  if ((reinterpret_cast<std::uint8_t const *>(addr)+length)>(reinterpret_cast<std::uint8_t const *>(addr_)+length_)) {
98  info::function fun(__LINE__, __PRETTY_FUNCTION__, typeid(this), info::function::argument(_T("void *addr"), addr));
99  fun.add_args(
100  info::function::argument(_T("std::size_t length"), length),
101  info::function::argument(_T("sync_flags_t sync_flags"), sync_flags),
102  info::function::argument(_T("std::size_t length_"), length_),
103  info::function::argument(_T("void *addr_"), addr_)
104  );
105  throw exception_type(_T("Requested address plus length less than mapped address ."), std::move(fun), JMMCG_REVISION_HDR(_T(LIBJMMCG_VERSION_NUMBER)));
106  }
107  JMMCG_SYSCALL_WRAPPER("Unable sync the portion of the mapped memory.", _T(LIBJMMCG_VERSION_NUMBER), ::msync, addr, length, sync_flags);
108 }
109 
110 } }