mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-07 01:06:45 +08:00
add: [ipc] shared_memory object
This commit is contained in:
parent
af654d5769
commit
d55d9f549f
@ -37,6 +37,37 @@ LIBIMP_EXPORT std::size_t shm_size(shm_t) noexcept;
|
|||||||
|
|
||||||
/// @brief Gets the name of the shared memory file based on the shared memory handle.
|
/// @brief Gets the name of the shared memory file based on the shared memory handle.
|
||||||
/// @return empty string on failure.
|
/// @return empty string on failure.
|
||||||
LIBIMP_EXPORT std::string shm_file(shm_t) noexcept;
|
LIBIMP_EXPORT std::string shm_name(shm_t) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The shared memory object.
|
||||||
|
*/
|
||||||
|
class LIBIMP_EXPORT shared_memory {
|
||||||
|
shm_t shm_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit shared_memory() noexcept;
|
||||||
|
~shared_memory() noexcept;
|
||||||
|
|
||||||
|
shared_memory(shared_memory &&other) noexcept;
|
||||||
|
shared_memory &operator=(shared_memory &&rhs) & noexcept;
|
||||||
|
void swap(shared_memory &other) noexcept;
|
||||||
|
|
||||||
|
explicit shared_memory(std::string name,
|
||||||
|
std::size_t size = 0,
|
||||||
|
mode::type = mode::create | mode::open) noexcept;
|
||||||
|
|
||||||
|
bool open(std::string name, std::size_t size, mode::type) noexcept;
|
||||||
|
void close() noexcept;
|
||||||
|
bool valid() const noexcept;
|
||||||
|
|
||||||
|
void *get() const noexcept;
|
||||||
|
void *operator*() const noexcept;
|
||||||
|
template <typename T>
|
||||||
|
T *as() { return static_cast<T *>(get()); }
|
||||||
|
|
||||||
|
std::size_t size() const noexcept;
|
||||||
|
std::string name() const noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
LIBIPC_NAMESPACE_END_
|
LIBIPC_NAMESPACE_END_
|
||||||
|
|||||||
@ -67,7 +67,7 @@ result<shm_t> shm_open(std::string name, std::size_t size, mode::type type) noex
|
|||||||
S_IRGRP | S_IWGRP |
|
S_IRGRP | S_IWGRP |
|
||||||
S_IROTH | S_IWOTH);
|
S_IROTH | S_IWOTH);
|
||||||
if (fd == posix::failed) {
|
if (fd == posix::failed) {
|
||||||
log.error("shm_open fails. error = {}", sys::error_msg(sys::error_code()));
|
log.error("shm_open fails. error = {}", sys::error());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,14 +75,14 @@ result<shm_t> shm_open(std::string name, std::size_t size, mode::type type) noex
|
|||||||
/// @brief Try to get the size of this fd
|
/// @brief Try to get the size of this fd
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (::fstat(fd, &st) == posix::failed) {
|
if (::fstat(fd, &st) == posix::failed) {
|
||||||
log.error("fstat fails. error = {}", sys::error_msg(sys::error_code()));
|
log.error("fstat fails. error = {}", sys::error());
|
||||||
::shm_unlink(name.c_str());
|
::shm_unlink(name.c_str());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
size = static_cast<std::size_t>(st.st_size);
|
size = static_cast<std::size_t>(st.st_size);
|
||||||
/// @brief Truncate this fd to a specified length
|
/// @brief Truncate this fd to a specified length
|
||||||
} else if (::ftruncate(fd, size) != 0) {
|
} else if (::ftruncate(fd, size) != 0) {
|
||||||
log.error("ftruncate fails. error = {}", sys::error_msg(sys::error_code()));
|
log.error("ftruncate fails. error = {}", sys::error());
|
||||||
::shm_unlink(name.c_str());
|
::shm_unlink(name.c_str());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -90,7 +90,7 @@ result<shm_t> shm_open(std::string name, std::size_t size, mode::type type) noex
|
|||||||
/// @brief Creates a new mapping in the virtual address space of the calling process.
|
/// @brief Creates a new mapping in the virtual address space of the calling process.
|
||||||
void *mem = ::mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
void *mem = ::mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||||
if (mem == MAP_FAILED) {
|
if (mem == MAP_FAILED) {
|
||||||
log.error("mmap fails. error = {}", sys::error_msg(sys::error_code()));
|
log.error("mmap fails. error = {}", sys::error());
|
||||||
::shm_unlink(name.c_str());
|
::shm_unlink(name.c_str());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -114,7 +114,7 @@ result_code shm_close(shm_t h) noexcept {
|
|||||||
}
|
}
|
||||||
if (::munmap(shm->memp, shm->f_sz) == posix::failed) {
|
if (::munmap(shm->memp, shm->f_sz) == posix::failed) {
|
||||||
auto ec = sys::error_code();
|
auto ec = sys::error_code();
|
||||||
log.error("munmap fails. error = {}", sys::error_msg(ec));
|
log.error("munmap fails. error = {}", sys::error(ec));
|
||||||
return ec;
|
return ec;
|
||||||
}
|
}
|
||||||
/// @brief no unlink the file.
|
/// @brief no unlink the file.
|
||||||
|
|||||||
@ -30,11 +30,11 @@ inline LPSECURITY_ATTRIBUTES get_sa() {
|
|||||||
using namespace ::LIBIMP_;
|
using namespace ::LIBIMP_;
|
||||||
log::gripper log {"get_sa"};
|
log::gripper log {"get_sa"};
|
||||||
if (!::InitializeSecurityDescriptor(&sd_, SECURITY_DESCRIPTOR_REVISION)) {
|
if (!::InitializeSecurityDescriptor(&sd_, SECURITY_DESCRIPTOR_REVISION)) {
|
||||||
log.error("InitializeSecurityDescriptor fails. error = {}", sys::error_msg(sys::error_code()));
|
log.error("InitializeSecurityDescriptor fails. error = {}", sys::error());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!::SetSecurityDescriptorDacl(&sd_, TRUE, NULL, FALSE)) {
|
if (!::SetSecurityDescriptorDacl(&sd_, TRUE, NULL, FALSE)) {
|
||||||
log.error("SetSecurityDescriptorDacl fails. error = {}", sys::error_msg(sys::error_code()));
|
log.error("SetSecurityDescriptorDacl fails. error = {}", sys::error());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sa_.nLength = sizeof(SECURITY_ATTRIBUTES);
|
sa_.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||||
|
|||||||
@ -40,18 +40,21 @@ void mmap_close(HANDLE h) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!::CloseHandle(h)) {
|
if (!::CloseHandle(h)) {
|
||||||
log.error("CloseHandle fails. error = {}", sys::error_msg(sys::error_code()));
|
log.error("CloseHandle fails. error = {}", sys::error());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Creates or opens a file mapping object for a specified file.
|
* @brief Creates or opens a file mapping object for a specified file.
|
||||||
|
*
|
||||||
* @see https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-openfilemappinga
|
* @see https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-openfilemappinga
|
||||||
* https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createfilemappinga
|
* https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createfilemappinga
|
||||||
|
*
|
||||||
* @param file Specifies the name of the file mapping object
|
* @param file Specifies the name of the file mapping object
|
||||||
* @param size Specifies the size required to create a file mapping object.
|
* @param size Specifies the size required to create a file mapping object.
|
||||||
* This size is ignored when opening an existing file mapping object
|
* This size is ignored when opening an existing file mapping object
|
||||||
* @param type Combinable open modes, create | open
|
* @param type Combinable open modes, create | open
|
||||||
|
*
|
||||||
* @return File mapping object HANDLE, NULL on error
|
* @return File mapping object HANDLE, NULL on error
|
||||||
*/
|
*/
|
||||||
HANDLE mmap_open(std::string const &file, std::size_t size, mode::type type) noexcept {
|
HANDLE mmap_open(std::string const &file, std::size_t size, mode::type type) noexcept {
|
||||||
@ -65,26 +68,42 @@ HANDLE mmap_open(std::string const &file, std::size_t size, mode::type type) noe
|
|||||||
log.error("file name is empty. (TCHAR conversion failed)");
|
log.error("file name is empty. (TCHAR conversion failed)");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Opens a named file mapping object.
|
/// @brief Opens a named file mapping object.
|
||||||
if (type == mode::open) {
|
auto try_open = [&]() -> HANDLE {
|
||||||
HANDLE h = ::OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, t_name.c_str());
|
HANDLE h = ::OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, t_name.c_str());
|
||||||
if (h == NULL) {
|
if (h == NULL) {
|
||||||
log.error("OpenFileMapping fails. error = {}", sys::error_msg(sys::error_code()));
|
log.error("OpenFileMapping fails. error = {}", sys::error());
|
||||||
}
|
}
|
||||||
return h;
|
return h;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief Creates or opens a named or unnamed file mapping object for a specified file.
|
||||||
|
auto try_create = [&]() -> HANDLE {
|
||||||
|
HANDLE h = ::CreateFileMapping(INVALID_HANDLE_VALUE, detail::get_sa(), PAGE_READWRITE | SEC_COMMIT,
|
||||||
|
/// @remark dwMaximumSizeHigh always 0 here.
|
||||||
|
0, static_cast<DWORD>(size), t_name.c_str());
|
||||||
|
if (h == NULL) {
|
||||||
|
log.error("CreateFileMapping fails. error = {}", sys::error());
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (type == mode::open) {
|
||||||
|
return try_open();
|
||||||
|
} else if ((type == (mode::create | mode::open)) && (size == 0)) {
|
||||||
|
/// @remark CreateFileMapping may returns ERROR_INVALID_PARAMETER when dwMaximumSizeLow is zero.
|
||||||
|
/// @see CreateFileMapping (Windows CE 5.0)
|
||||||
|
/// https://learn.microsoft.com/en-us/previous-versions/windows/embedded/aa517331(v=msdn.10)
|
||||||
|
return try_open();
|
||||||
} else if (!(type & mode::create)) {
|
} else if (!(type & mode::create)) {
|
||||||
log.error("mode type is invalid. type = {}", type);
|
log.error("mode type is invalid. type = {}", type);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
/// @brief Creates or opens a named or unnamed file mapping object for a specified file.
|
HANDLE h = try_create();
|
||||||
HANDLE h = ::CreateFileMapping(INVALID_HANDLE_VALUE, detail::get_sa(), PAGE_READWRITE | SEC_COMMIT,
|
/// @remark If the object exists before the function call, the function returns a handle to the existing object
|
||||||
0, static_cast<DWORD>(size), t_name.c_str());
|
/// (with its current size, not the specified size), and GetLastError returns ERROR_ALREADY_EXISTS.
|
||||||
if (h == NULL) {
|
|
||||||
log.error("CreateFileMapping fails. error = {}", sys::error_msg(sys::error_code()));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
// If the object exists before the function call, the function returns a handle to the existing object
|
|
||||||
// (with its current size, not the specified size), and GetLastError returns ERROR_ALREADY_EXISTS.
|
|
||||||
if ((type == mode::create) && (::GetLastError() == ERROR_ALREADY_EXISTS)) {
|
if ((type == mode::create) && (::GetLastError() == ERROR_ALREADY_EXISTS)) {
|
||||||
mmap_close(h);
|
mmap_close(h);
|
||||||
log.info("the file being created already exists. file = {}, type = {}", file, type);
|
log.info("the file being created already exists. file = {}, type = {}", file, type);
|
||||||
@ -105,7 +124,7 @@ LPVOID mmap_memof(HANDLE h) {
|
|||||||
}
|
}
|
||||||
LPVOID mem = ::MapViewOfFile(h, FILE_MAP_ALL_ACCESS, 0, 0, 0);
|
LPVOID mem = ::MapViewOfFile(h, FILE_MAP_ALL_ACCESS, 0, 0, 0);
|
||||||
if (h == NULL) {
|
if (h == NULL) {
|
||||||
log.error("MapViewOfFile fails. error = {}", sys::error_msg(sys::error_code()));
|
log.error("MapViewOfFile fails. error = {}", sys::error());
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return mem;
|
return mem;
|
||||||
@ -123,7 +142,7 @@ SIZE_T mmap_sizeof(LPCVOID mem) {
|
|||||||
}
|
}
|
||||||
MEMORY_BASIC_INFORMATION mem_info {};
|
MEMORY_BASIC_INFORMATION mem_info {};
|
||||||
if (::VirtualQuery(mem, &mem_info, sizeof(mem_info)) == 0) {
|
if (::VirtualQuery(mem, &mem_info, sizeof(mem_info)) == 0) {
|
||||||
log.error("VirtualQuery fails. error = {}", sys::error_msg(sys::error_code()));
|
log.error("VirtualQuery fails. error = {}", sys::error());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return mem_info.RegionSize;
|
return mem_info.RegionSize;
|
||||||
@ -144,7 +163,7 @@ void mmap_release(HANDLE h, LPCVOID mem) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!::UnmapViewOfFile(mem)) {
|
if (!::UnmapViewOfFile(mem)) {
|
||||||
log.warning("UnmapViewOfFile fails. error = {}", sys::error_msg(sys::error_code()));
|
log.warning("UnmapViewOfFile fails. error = {}", sys::error());
|
||||||
}
|
}
|
||||||
mmap_close(h);
|
mmap_close(h);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
|
|
||||||
|
#include <utility> // std::exchange, std::swap (since C++11)
|
||||||
|
|
||||||
#include "libimp/log.h"
|
#include "libimp/log.h"
|
||||||
|
|
||||||
#include "libimp/detect_plat.h"
|
#include "libimp/detect_plat.h"
|
||||||
@ -10,6 +12,8 @@
|
|||||||
|
|
||||||
LIBIPC_NAMESPACE_BEG_
|
LIBIPC_NAMESPACE_BEG_
|
||||||
|
|
||||||
|
/// @brief C style shared memory access interface implementation.
|
||||||
|
|
||||||
void *shm_get(shm_t h) noexcept {
|
void *shm_get(shm_t h) noexcept {
|
||||||
LIBIMP_LOG_();
|
LIBIMP_LOG_();
|
||||||
if (h == nullptr) {
|
if (h == nullptr) {
|
||||||
@ -30,7 +34,7 @@ std::size_t shm_size(shm_t h) noexcept {
|
|||||||
return shm->f_sz;
|
return shm->f_sz;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string shm_file(shm_t h) noexcept {
|
std::string shm_name(shm_t h) noexcept {
|
||||||
LIBIMP_LOG_();
|
LIBIMP_LOG_();
|
||||||
if (h == nullptr) {
|
if (h == nullptr) {
|
||||||
log.error("shm handle is null.");
|
log.error("shm handle is null.");
|
||||||
@ -40,4 +44,63 @@ std::string shm_file(shm_t h) noexcept {
|
|||||||
return shm->file;
|
return shm->file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief The shared memory object.
|
||||||
|
|
||||||
|
shared_memory::shared_memory() noexcept
|
||||||
|
: shm_(nullptr) {}
|
||||||
|
|
||||||
|
shared_memory::~shared_memory() noexcept {
|
||||||
|
this->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_memory::shared_memory(shared_memory &&other) noexcept
|
||||||
|
: shm_(std::exchange(other.shm_, nullptr)) {}
|
||||||
|
|
||||||
|
shared_memory &shared_memory::operator=(shared_memory &&rhs) & noexcept {
|
||||||
|
this->shm_ = std::exchange(rhs.shm_, nullptr);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void shared_memory::swap(shared_memory &other) noexcept {
|
||||||
|
std::swap(this->shm_, other.shm_);
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_memory::shared_memory(std::string name, std::size_t size, mode::type type) noexcept
|
||||||
|
: shared_memory() {
|
||||||
|
open(std::move(name), size, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool shared_memory::open(std::string name, std::size_t size, mode::type type) noexcept {
|
||||||
|
this->close();
|
||||||
|
auto ret = shm_open(std::move(name), size, type);
|
||||||
|
if (!ret) return false;
|
||||||
|
shm_ = *ret;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void shared_memory::close() noexcept {
|
||||||
|
if (!valid()) return;
|
||||||
|
shm_close(std::exchange(shm_, nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool shared_memory::valid() const noexcept {
|
||||||
|
return this->shm_ != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *shared_memory::get() const noexcept {
|
||||||
|
return shm_get(shm_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *shared_memory::operator*() const noexcept {
|
||||||
|
return this->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t shared_memory::size() const noexcept {
|
||||||
|
return shm_size(shm_);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string shared_memory::name() const noexcept {
|
||||||
|
return shm_name(shm_);
|
||||||
|
}
|
||||||
|
|
||||||
LIBIPC_NAMESPACE_END_
|
LIBIPC_NAMESPACE_END_
|
||||||
|
|||||||
@ -15,16 +15,63 @@ TEST(shm, create_close) {
|
|||||||
EXPECT_NE(pt1, nullptr);
|
EXPECT_NE(pt1, nullptr);
|
||||||
*(int *)pt1 = 0;
|
*(int *)pt1 = 0;
|
||||||
|
|
||||||
auto shm2 = ipc::shm_open(ipc::shm_file(*shm1), 0, ipc::mode::open);
|
auto shm2 = ipc::shm_open(ipc::shm_name(*shm1), 0, ipc::mode::create | ipc::mode::open);
|
||||||
EXPECT_TRUE(shm2);
|
EXPECT_TRUE(shm2);
|
||||||
|
auto shm3 = ipc::shm_open(ipc::shm_name(*shm1), 128, ipc::mode::open);
|
||||||
|
EXPECT_TRUE(shm3);
|
||||||
|
auto shm4 = ipc::shm_open(ipc::shm_name(*shm1), 256, ipc::mode::create | ipc::mode::open);
|
||||||
|
EXPECT_TRUE(shm4);
|
||||||
EXPECT_EQ(ipc::shm_size(*shm1), ipc::shm_size(*shm2));
|
EXPECT_EQ(ipc::shm_size(*shm1), ipc::shm_size(*shm2));
|
||||||
|
EXPECT_EQ(ipc::shm_size(*shm1), ipc::shm_size(*shm3));
|
||||||
|
EXPECT_EQ(ipc::shm_size(*shm1), ipc::shm_size(*shm4));
|
||||||
auto pt2 = ipc::shm_get(*shm1);
|
auto pt2 = ipc::shm_get(*shm1);
|
||||||
EXPECT_NE(pt2, nullptr);
|
EXPECT_NE(pt2, nullptr);
|
||||||
EXPECT_EQ(*(int *)pt2, 0);
|
EXPECT_EQ(*(int *)pt2, 0);
|
||||||
*(int *)pt1 = 1234;
|
*(int *)pt1 = 1234;
|
||||||
EXPECT_EQ(*(int *)pt2, 1234);
|
EXPECT_EQ(*(int *)pt2, 1234);
|
||||||
|
|
||||||
|
EXPECT_TRUE(ipc::shm_close(*shm4));
|
||||||
|
EXPECT_TRUE(ipc::shm_close(*shm3));
|
||||||
EXPECT_TRUE(ipc::shm_close(*shm2));
|
EXPECT_TRUE(ipc::shm_close(*shm2));
|
||||||
EXPECT_TRUE(ipc::shm_close(*shm1));
|
EXPECT_TRUE(ipc::shm_close(*shm1));
|
||||||
EXPECT_FALSE(ipc::shm_close(nullptr));
|
EXPECT_FALSE(ipc::shm_close(nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(shm, shared_memory) {
|
||||||
|
ipc::shared_memory shm;
|
||||||
|
EXPECT_FALSE(shm.valid());
|
||||||
|
EXPECT_EQ(shm.size(), 0);
|
||||||
|
EXPECT_EQ(shm.name(), "");
|
||||||
|
EXPECT_EQ(shm.get() , nullptr);
|
||||||
|
EXPECT_EQ(*shm , nullptr);
|
||||||
|
EXPECT_EQ(shm.as<int>(), nullptr);
|
||||||
|
shm.close();
|
||||||
|
|
||||||
|
EXPECT_TRUE(shm.open("hello-ipc-shared-memory", 2048, ipc::mode::create | ipc::mode::open));
|
||||||
|
EXPECT_TRUE(shm.valid());
|
||||||
|
EXPECT_TRUE(shm.size() >= 2048);
|
||||||
|
EXPECT_EQ(shm.name(), "hello-ipc-shared-memory");
|
||||||
|
EXPECT_NE(shm.get() , nullptr);
|
||||||
|
EXPECT_NE(*shm , nullptr);
|
||||||
|
EXPECT_NE(shm.as<int>(), nullptr);
|
||||||
|
*shm.as<int>() = 4321;
|
||||||
|
|
||||||
|
auto shm_r = ipc::shm_open(shm.name());
|
||||||
|
ASSERT_TRUE(shm_r);
|
||||||
|
EXPECT_EQ(*static_cast<int *>(ipc::shm_get(*shm_r)), 4321);
|
||||||
|
|
||||||
|
shm = ipc::shared_memory("hello-ipc-shared-memory-2", 512);
|
||||||
|
EXPECT_TRUE(shm.valid());
|
||||||
|
EXPECT_TRUE(shm.size() >= 512);
|
||||||
|
EXPECT_EQ(shm.name(), "hello-ipc-shared-memory-2");
|
||||||
|
EXPECT_NE(shm.get() , nullptr);
|
||||||
|
EXPECT_NE(*shm , nullptr);
|
||||||
|
EXPECT_NE(shm.as<int>(), nullptr);
|
||||||
|
|
||||||
|
*static_cast<int *>(ipc::shm_get(*shm_r)) = 1234;
|
||||||
|
*shm.as<int>() = 4444;
|
||||||
|
EXPECT_EQ(*static_cast<int *>(ipc::shm_get(*shm_r)), 1234);
|
||||||
|
EXPECT_EQ(*shm.as<int>(), 4444);
|
||||||
|
|
||||||
|
EXPECT_TRUE(ipc::shm_close(*shm_r));
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user