18 #ifndef PSTORE_OS_SHARED_MEMORY_HPP 19 #define PSTORE_OS_SHARED_MEMORY_HPP 29 # include <sys/mman.h> 30 # include <sys/stat.h> 51 template <
typename SpanType>
52 auto shm_name (std::string
const & name, SpanType arr) -> ::pstore::gsl::zstring {
53 using difference_type =
54 std::iterator_traits<std::string::const_iterator>::difference_type;
56 using udifference_type = std::make_unsigned<difference_type>::type;
58 static_assert (SpanType::extent >= 2,
59 "The posix_mutex_name span must be fixed size and able to hold " 60 "at least 2 characters");
61 auto out = arr.begin ();
64 auto name_begin = std::begin (name);
65 auto name_end = name_begin;
66 PSTORE_ASSERT (name.length () <=
static_cast<udifference_type
> (
67 std::numeric_limits<difference_type>::max ()));
68 auto const name_length =
static_cast<difference_type
> (name.length ());
69 std::advance (name_end, std::min (SpanType::extent - 2, name_length));
70 out = std::copy (name_begin, name_end, out);
75 template <std::
size_t N>
76 auto shm_name (std::string
const & name, std::array<char, N> & arr)
77 -> ::pstore::gsl::zstring {
79 static_assert (N <= std::numeric_limits<std::ptrdiff_t>::max (),
80 "array size must not exected ptrdiff_t max");
81 return shm_name (name, ::pstore::gsl::make_span (arr));
91 template <
typename Ty>
104 Ty & operator* () {
return *
get (); }
105 Ty
const & operator* ()
const {
return *
get (); }
106 Ty * operator-> () {
return get (); }
107 Ty
const * operator-> ()
const {
return get (); }
110 auto p = ptr_.get ();
111 return (p !=
nullptr) ? &p->contents :
nullptr;
113 Ty
const *
get ()
const {
114 auto p = ptr_.get ();
115 return (p !=
nullptr) ? &p->contents :
nullptr;
128 spin_lock (spin_lock
const &) =
delete;
129 spin_lock & operator= (spin_lock
const &) =
delete;
134 void lock () noexcept {
135 while (lock_->test_and_set (std::memory_order_acquire)) {
144 void unlock () noexcept {
145 lock_->clear (std::memory_order_release);
149 std::atomic_flag *
const lock_;
155 std::atomic_flag lock{
false};
160 std::atomic_flag init_done{
false};
164 static_assert (std::is_standard_layout<value_type>::value,
165 "value_type must be StandardLayout");
169 using os_file_handle = HANDLE;
171 using os_file_handle = int;
176 explicit file_mapping (gsl::czstring
const name)
177 : descriptor_ (open (name)) {}
178 ~file_mapping () noexcept;
180 os_file_handle
get () {
return descriptor_; }
183 static os_file_handle open (gsl::czstring name);
184 os_file_handle descriptor_;
187 using pointer_type = std::unique_ptr<value_type, void (*) (value_type *)>;
188 auto mmap (os_file_handle map_file) -> pointer_type;
190 static void unmap (value_type * p);
194 shm_name () =
default;
195 explicit shm_name (std::string
const & name);
196 shm_name (shm_name && rhs) noexcept =
default;
197 shm_name (shm_name
const & rhs) =
delete;
199 shm_name & operator= (shm_name
const & rhs) =
delete;
200 shm_name & operator= (shm_name && rhs) noexcept =
default;
202 gsl::czstring c_str ()
const noexcept {
return name_.c_str (); }
203 bool empty ()
const noexcept {
return name_.empty (); }
221 template <
typename Ty>
228 std::replace (name_.begin (), name_.end (),
'\\',
'/');
231 template <
typename Ty>
236 std::copy_n (std::begin (name), std::min (name.length (), len - 1),
237 std::back_inserter (name_));
247 template <
typename Ty>
250 , ptr_ (
nullptr, &unmap) {}
252 template <
typename Ty>
253 shared_memory<Ty>::shared_memory (std::string
const & name)
255 , ptr_ (
nullptr, &unmap) {
257 file_mapping mapping (name_.c_str ());
258 ptr_ = mmap (mapping.get ());
263 spin_lock sl (&ptr_->lock);
264 std::lock_guard<spin_lock> lock (sl);
266 if (!ptr_->init_done.test_and_set ()) {
267 static_assert (
sizeof (ptr_->contents) == sizeof (Ty),
268 "placement new buffer was not the expected size");
269 new (&ptr_->contents) Ty;
273 template <
typename Ty>
274 shared_memory<Ty>::shared_memory (
shared_memory && rhs) noexcept
275 : name_ (std::move (rhs.name_))
276 , ptr_ (std::move (rhs.ptr_)) {}
280 template <
typename Ty>
283 if (!name_.empty ()) {
284 ::shm_unlink (name_.c_str ());
291 template <
typename Ty>
294 name_ = std::move (rhs.name_);
295 ptr_ = std::move (rhs.ptr_);
304 template <
typename Ty>
306 if (::UnmapViewOfFile (p) == 0) {
307 auto const error = ::GetLastError ();
308 raise (win32_erc (error),
"UnmapViewOfFile");
314 template <
typename Ty>
316 auto mapped_ptr =
static_cast<value_type *
> (::MapViewOfFile (map_file, FILE_MAP_ALL_ACCESS,
320 if (mapped_ptr ==
nullptr) {
321 auto const error = ::GetLastError ();
322 raise (win32_erc (error),
"MapViewOfFile");
324 return {mapped_ptr, &unmap};
331 template <
typename Ty>
333 if (::munmap (p,
sizeof (Ty)) == -1) {
340 template <
typename Ty>
342 auto ptr =
static_cast<value_type *
> (
343 ::mmap (
nullptr,
sizeof (Ty), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
344 if (ptr == MAP_FAILED) {
347 return {ptr, &unmap};
361 template <
typename Ty>
363 ::CloseHandle (descriptor_);
364 descriptor_ =
nullptr;
369 template <
typename Ty>
372 HANDLE map_file = ::CreateFileMappingW (
373 INVALID_HANDLE_VALUE,
376 uint64_high4 (
sizeof (Ty)),
377 uint64_low4 (
sizeof (Ty)),
378 utf::win32::to16 (name).c_str ());
379 if (map_file ==
nullptr) {
380 std::ostringstream str;
381 char const * n =
"hello";
382 str <<
"Couldn't create a file mapping for " <<
pstore::quoted (n);
383 raise (win32_erc (::GetLastError ()), str.str ());
392 template <
typename Ty>
394 ::close (descriptor_);
400 template <
typename Ty>
402 int const fd = ::shm_open (name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
404 int const error = errno;
405 if (error == ENAMETOOLONG) {
406 std::ostringstream str;
407 str <<
"shared memory object name (" << name <<
") is too long";
417 if (::fstat (fd, &st) == -1) {
420 if (st.st_size < static_cast<off_t> (sizeof (Ty))) {
421 if (::ftruncate (fd,
sizeof (Ty)) == -1) {
430 #endif // PSTORE_OS_SHARED_MEMORY_HPP auto shm_name(std::string const &name, SpanType arr) -> ::pstore::gsl::zstring
Definition: shared_memory.hpp:52
Opens a shared memory object containing type Ty with the given name.
Definition: shared_memory.hpp:92
std::size_t get_pshmnamlen() noexcept
A function which returns the maximum length of a shared memory object name.
Definition: shared_memory.cpp:47
Convenience functions for breaking up a uint64_t value for use with Win32 API functions.
This class is a tiny wrapper that allows an errno value to be passed to std::make_error_code().
Definition: error.hpp:99
auto quoted(std::string const &str)
Wraps quotation marks around a string for presentation to the user.
Definition: quoted.hpp:38
Definition: nonpod2.cpp:40
Wrapping quotation marks around strings for output to the user.
Provides an pstore-specific error codes and a suitable error category for them.