GrabBag/Module/ShareMem/Src/VrShareMem.cpp

312 lines
7.5 KiB
C++

#ifndef VRSHAREMEM_LIBRARY
#define VRSHAREMEM_LIBRARY
#endif
#include "VrShareMem.h"
#include "VrError.h"
#include <cstring>
#include <iostream>
#ifdef _WIN32
#include <sstream>
#else
#include <errno.h>
#include <sys/types.h>
#endif
VrShareMem::VrShareMem()
: m_size(0)
, m_mappedAddress(nullptr)
, m_created(false)
{
#ifdef _WIN32
m_hMapFile = nullptr;
#else
m_fd = -1;
#endif
}
VrShareMem::~VrShareMem()
{
Close();
}
int VrShareMem::CreateOrOpen(const std::string& name, size_t size, bool create)
{
if (name.empty() || size == 0) {
return ERR_CODE(SHAREMEM_ERR_PARAM); // 参数错误
}
// 先关闭已有的
Close();
m_name = name;
m_size = size;
m_created = create;
std::string platformName = GetPlatformName(name);
#ifdef _WIN32
if (create) {
// 创建新的共享内存
m_hMapFile = CreateFileMappingA(
INVALID_HANDLE_VALUE, // 使用页面文件
nullptr, // 默认安全性
PAGE_READWRITE, // 读写访问
0, // 高32位大小
static_cast<DWORD>(size), // 低32位大小
platformName.c_str() // 对象名称
);
if (m_hMapFile == nullptr) {
return ERR_CODE(SHAREMEM_ERR_CREATE); // 创建失败
}
// 检查是否已存在
if (GetLastError() == ERROR_ALREADY_EXISTS && create) {
CloseHandle(m_hMapFile);
m_hMapFile = nullptr;
return ERR_CODE(SHAREMEM_ERR_ALREADY_EXIST); // 已存在
}
} else {
// 打开已存在的共享内存
m_hMapFile = OpenFileMappingA(
FILE_MAP_ALL_ACCESS, // 读写访问
FALSE, // 不继承句柄
platformName.c_str() // 对象名称
);
if (m_hMapFile == nullptr) {
return ERR_CODE(SHAREMEM_ERR_NOT_EXIST); // 打开失败
}
}
#else
// Linux 实现
if (create) {
// 创建新的共享内存
m_fd = shm_open(platformName.c_str(), O_CREAT | O_EXCL | O_RDWR, 0666);
if (m_fd == -1) {
if (errno == EEXIST) {
return ERR_CODE(SHAREMEM_ERR_ALREADY_EXIST); // 已存在
}
return ERR_CODE(SHAREMEM_ERR_CREATE); // 创建失败
}
// 设置大小
if (ftruncate(m_fd, size) == -1) {
close(m_fd);
shm_unlink(platformName.c_str());
m_fd = -1;
return ERR_CODE(SHAREMEM_ERR_SIZE); // 设置大小失败
}
} else {
// 打开已存在的共享内存
m_fd = shm_open(platformName.c_str(), O_RDWR, 0666);
if (m_fd == -1) {
return ERR_CODE(SHAREMEM_ERR_NOT_EXIST); // 打开失败
}
// 获取实际大小
struct stat st;
if (fstat(m_fd, &st) == -1) {
close(m_fd);
m_fd = -1;
return ERR_CODE(SHAREMEM_ERR_INFO); // 获取信息失败
}
m_size = st.st_size;
}
#endif
return SUCCESS; // 成功
}
void* VrShareMem::MapView()
{
if (!IsValid()) {
return nullptr;
}
if (m_mappedAddress != nullptr) {
return m_mappedAddress; // 已经映射
}
#ifdef _WIN32
m_mappedAddress = MapViewOfFile(
m_hMapFile, // 文件映射对象句柄
FILE_MAP_ALL_ACCESS, // 读写访问
0, // 高32位偏移
0, // 低32位偏移
m_size // 映射大小
);
#else
m_mappedAddress = mmap(
nullptr, // 系统选择地址
m_size, // 映射大小
PROT_READ | PROT_WRITE, // 读写权限
MAP_SHARED, // 共享映射
m_fd, // 文件描述符
0 // 偏移量
);
if (m_mappedAddress == MAP_FAILED) {
m_mappedAddress = nullptr;
}
#endif
return m_mappedAddress;
}
int VrShareMem::UnmapView()
{
if (m_mappedAddress == nullptr) {
return SUCCESS; // 已经取消映射
}
#ifdef _WIN32
if (!UnmapViewOfFile(m_mappedAddress)) {
return ERR_CODE(APP_ERR_EXEC); // 取消映射失败
}
#else
if (munmap(m_mappedAddress, m_size) == -1) {
return ERR_CODE(APP_ERR_EXEC); // 取消映射失败
}
#endif
m_mappedAddress = nullptr;
return SUCCESS;
}
int VrShareMem::Close()
{
// 取消映射
UnmapView();
#ifdef _WIN32
if (m_hMapFile != nullptr) {
CloseHandle(m_hMapFile);
m_hMapFile = nullptr;
}
#else
if (m_fd != -1) {
close(m_fd);
// 如果是创建者,删除共享内存
if (m_created) {
std::string platformName = GetPlatformName(m_name);
shm_unlink(platformName.c_str());
}
m_fd = -1;
}
#endif
m_size = 0;
m_name.clear();
m_created = false;
return SUCCESS;
}
size_t VrShareMem::GetSize() const
{
return m_size;
}
void* VrShareMem::GetMappedAddress() const
{
return m_mappedAddress;
}
bool VrShareMem::IsValid() const
{
#ifdef _WIN32
return m_hMapFile != nullptr;
#else
return m_fd != -1;
#endif
}
int VrShareMem::WriteData(size_t offset, const void* data, size_t size)
{
if (!CheckBounds(offset, size) || data == nullptr) {
return ERR_CODE(SHAREMEM_ERR_PARAM);
}
if (m_mappedAddress == nullptr) {
return ERR_CODE(SHAREMEM_ERR_NOT_MAPPED); // 未映射
}
std::lock_guard<std::timed_mutex> lock(m_mutex);
char* dest = static_cast<char*>(m_mappedAddress) + offset;
std::memcpy(dest, data, size);
return static_cast<int>(size);
}
int VrShareMem::ReadData(size_t offset, void* buffer, size_t size)
{
if (!CheckBounds(offset, size) || buffer == nullptr) {
return ERR_CODE(SHAREMEM_ERR_PARAM);
}
if (m_mappedAddress == nullptr) {
return ERR_CODE(SHAREMEM_ERR_NOT_MAPPED); // 未映射
}
std::lock_guard<std::timed_mutex> lock(m_mutex);
const char* src = static_cast<const char*>(m_mappedAddress) + offset;
std::memcpy(buffer, src, size);
return static_cast<int>(size);
}
int VrShareMem::Lock(int timeout)
{
if (timeout == -1) {
// 无限等待
m_mutex.lock();
return SUCCESS;
} else {
// 有超时的锁定
auto timeoutDuration = std::chrono::milliseconds(timeout);
if (m_mutex.try_lock_for(timeoutDuration)) {
return SUCCESS; // 成功
} else {
return ERR_CODE(SHAREMEM_ERR_TIMEOUT); // 超时
}
}
}
int VrShareMem::Unlock()
{
m_mutex.unlock();
return SUCCESS;
}
std::string VrShareMem::GetPlatformName(const std::string& name) const
{
#ifdef _WIN32
// Windows 文件映射对象名称
return "Global\\VrShareMem_" + name;
#else
// POSIX 共享内存名称,必须以 / 开头
return "/VrShareMem_" + name;
#endif
}
bool VrShareMem::CheckBounds(size_t offset, size_t size) const
{
return (offset < m_size) && (offset + size <= m_size);
}
// 导出函数实现
IVrShareMem* CreateShareMemInstance()
{
return new VrShareMem();
}
void DestroyShareMemInstance(IVrShareMem* instance)
{
delete instance;
}