#include "SharedMemory.h" #include "sls_detector_exceptions.h" #include "ansi.h" #include "logger.h" #include #include // printf #include // errno #include // strerror #include #include // O_CREAT, O_TRUNC.. #include // fstat #include // shared memory #include #include "stdlib.h" #define SHM_MULTI_PREFIX "/slsDetectorPackage_multi_" #define SHM_SLS_PREFIX "_sls_" #define SHM_ENV_NAME "SLSDETNAME" SharedMemory::SharedMemory(int multiId, int slsId): fd(-1), shmSize(0) { name = ConstructSharedMemoryName(multiId, slsId); } SharedMemory::~SharedMemory(){ if (fd >= 0) close(fd); } bool SharedMemory::IsExisting() { bool ret = true; int tempfd = shm_open(name.c_str(), O_RDWR, 0); if ((tempfd < 0) && (errno == ENOENT)) { ret = false; } close(tempfd); return ret; } std::string SharedMemory::GetName() { return name; } void* SharedMemory::CreateSharedMemory(size_t sz){ // create fd = shm_open(name.c_str(), O_CREAT | O_TRUNC | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR); if (fd < 0) { FILE_LOG(logERROR) << "Create shared memory " << name << " failed: " << strerror(errno); throw SharedMemoryException(); } // resize if (ftruncate(fd, sz) < 0) { FILE_LOG(logERROR) << "Create shared memory " << name << " failed at ftruncate: " << strerror(errno); close(fd); RemoveSharedMemory(); throw SharedMemoryException(); } // map void* addr = MapSharedMemory(sz); FILE_LOG(logINFO) << "Shared memory created " << name; return addr; } void* SharedMemory::OpenSharedMemory(size_t sz){ // open fd = shm_open(name.c_str(), O_RDWR, 0); if (fd < 0) { FILE_LOG(logERROR) << "Open existing shared memory " << name << " failed: " << strerror(errno); throw SharedMemoryException(); } return MapSharedMemory(sz); } void SharedMemory::UnmapSharedMemory(void* addr) { if (munmap(addr, shmSize) < 0) { FILE_LOG(logERROR) << "Unmapping shared memory " << name << " failed: " << strerror(errno); close(fd); throw SharedMemoryException(); } } void SharedMemory::RemoveSharedMemory() { if (shm_unlink(name.c_str()) < 0) { // silent exit if shm did not exist anyway if (errno == ENOENT) return; FILE_LOG(logERROR) << "Free Shared Memory " << name << " Failed: " << strerror(errno); throw SharedMemoryException(); } FILE_LOG(logINFO) << "Shared memory deleted " << name; } void* SharedMemory::MapSharedMemory(size_t sz) { void* addr = mmap(nullptr, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (addr == MAP_FAILED) { FILE_LOG(logERROR) << "Mapping shared memory " << name << " failed: " << strerror(errno); close(fd); throw SharedMemoryException(); } shmSize = sz; close(fd); return addr; } std::string SharedMemory::ConstructSharedMemoryName(int multiId, int slsId) { // using environment path std::string sEnvPath = ""; char* envpath = getenv(SHM_ENV_NAME); if (envpath != nullptr) { sEnvPath.assign(envpath); sEnvPath.insert(0,"_"); } std::stringstream ss; if (slsId < 0) ss << SHM_MULTI_PREFIX << multiId << sEnvPath; else ss << SHM_MULTI_PREFIX << multiId << SHM_SLS_PREFIX << slsId << sEnvPath; std::string temp = ss.str(); if (temp.length() > NAME_MAX) { FILE_LOG(logERROR) << "Shared memory initialization failed. " << temp << " has " << temp.length() << " characters. \n" "Maximum is " << NAME_MAX << ". Change the environment variable " << SHM_ENV_NAME; throw SharedMemoryException(); } return temp; } int SharedMemory::VerifySizeMatch(size_t expectedSize) { struct stat sb; // could not fstat if (fstat(fd, &sb) < 0) { FILE_LOG(logERROR) << "Could not verify existing shared memory " << name << " size match " "(could not fstat): " << strerror(errno); close(fd); throw SharedMemoryException(); } //size does not match long unsigned int sz = (long unsigned int)sb.st_size; if (sz != expectedSize) { FILE_LOG(logERROR) << "Existing shared memory " << name << " size does not match"; FILE_LOG(logDEBUG1) << "Expected " << expectedSize << ", found " << sz; throw SharedMemoryException(); return 1; } return 0; }