311 lines
7.3 KiB
C++
311 lines
7.3 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);
|
||
|
|
}
|
||
|
|
|
||
|
|
// 导出函数实现
|
||
|
|
VRSHAREMEM_EXPORT IVrShareMem* CreateShareMemInstance()
|
||
|
|
{
|
||
|
|
return new VrShareMem();
|
||
|
|
}
|
||
|
|
|
||
|
|
VRSHAREMEM_EXPORT void DestroyShareMemInstance(IVrShareMem* instance)
|
||
|
|
{
|
||
|
|
delete instance;
|
||
|
|
}
|