Files
pip/libs/main/io_devices/pisharedmemory.cpp
peri4 daab41e41e add options for fftw3 precisions
configureFromFullPathDevice for all devices now trim() components
2025-09-23 21:16:54 +03:00

286 lines
7.3 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
PIP - Platform Independent Primitives
File
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pisharedmemory.h"
#include "piincludes_p.h"
#include "piliterals.h"
#include "pipropertystorage.h"
#if defined(LINUX) || defined(MAC_OS)
# define SHM_POSIX
#endif
#ifdef WINDOWS
#endif
#if defined(QNX) || defined(ANDROID)
#endif
#ifdef MAC_OS
// # include <fcntl.h>
#endif
#ifdef SHM_POSIX
# include <fcntl.h>
# include <sys/mman.h>
# include <sys/stat.h>
#endif
//! \class PISharedMemory pisharedmemory.h
//! \details
//! \~english
//!
//!
//! \~russian
//! Разделяемая память используется как единое хранилище данных,
//! доступное различным процессам по имени. При первом открытии
//! объекта разделяемой памяти выделяется \a size() байт, по умолчанию
//! 65 Кб. Все процессы должны использовать один и тот же \a size()
//! во избежании ошибок.
//!
//! У объекта разделяемой памяти нету позиции чтения/записи,
//! каждый вызов \a read() или \a write() обращается
//! к началу памяти. Для работы с конкретным участком памяти
//! используются перегруженные методы с указанием "offset".
//!
REGISTER_DEVICE(PISharedMemory)
PRIVATE_DEFINITION_START(PISharedMemory)
PIByteArray name;
#ifdef WINDOWS
HANDLE map;
void * data;
#endif
#ifdef SHM_POSIX
void * data;
bool owner;
#endif
PRIVATE_DEFINITION_END(PISharedMemory)
PISharedMemory::PISharedMemory(): PIIODevice() {
initPrivate();
dsize = 64_KiB;
}
PISharedMemory::PISharedMemory(const PIString & shm_name, int size, PIIODevice::DeviceMode mode): PIIODevice(shm_name, mode) {
initPrivate();
dsize = size;
if (!shm_name.isEmpty()) open();
}
PISharedMemory::~PISharedMemory() {
stop();
close();
}
bool PISharedMemory::openDevice() {
close();
// piCoutObj << "try open" << path() << dsize;
#ifdef WINDOWS
PRIVATE->name = ("PIP_SHM_" + path()).toByteArray();
PRIVATE->name.push_back(0);
const char * nm = (const char *)PRIVATE->name.data();
PRIVATE->map = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, nm);
// piCoutObj << "open map =" << ullong(PRIVATE->map);
if (!PRIVATE->map) {
PRIVATE->map = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (DWORD)dsize, nm);
// piCoutObj << "create map =" << ullong(PRIVATE->map);
if (!PRIVATE->map) {
piCoutObj << "CreateFileMapping error," << errorString();
return false;
}
}
PRIVATE->data = MapViewOfFile(PRIVATE->map, FILE_MAP_ALL_ACCESS, 0, 0, dsize);
if (!PRIVATE->data) {
CloseHandle(PRIVATE->map);
piCoutObj << "MapViewOfFile error," << errorString();
return false;
}
// piCout << PRIVATE->map << PRIVATE->data;
#endif
#ifdef SHM_POSIX
PRIVATE->name = ("/pip_shm_" + path()).toByteArray();
PRIVATE->name.push_back(0);
int fd = shm_open((const char *)PRIVATE->name.data(), O_RDWR, 0777);
// piCoutObj << "try open" << PICoutManipulators::Hex << fd;
if (fd < 0) {
// piCoutObj << "shm_open error," << errorString();
fd = shm_open((const char *)PRIVATE->name.data(), O_RDWR | O_CREAT, 0777);
// piCoutObj << "try create" << PICoutManipulators::Hex << (m | O_CREAT) << fd;
if (fd < 0) {
piCoutObj << "shm_open error," << errorString();
return false;
}
PRIVATE->owner = true;
// piCoutObj << "created" << fd;
}
if (fd >= 0) {
auto _r = ftruncate(fd, dsize);
NO_UNUSED(_r);
}
PRIVATE->data = mmap(0, dsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
::close(fd);
if (PRIVATE->data == MAP_FAILED) {
piCoutObj << "mmap error," << errorString();
return false;
}
// piCoutObj << "opened" << PRIVATE->data;
#endif
return true;
}
bool PISharedMemory::closeDevice() {
#ifdef WINDOWS
if (PRIVATE->data) UnmapViewOfFile(PRIVATE->data);
if (PRIVATE->map) CloseHandle(PRIVATE->map);
#endif
#ifdef SHM_POSIX
// piCoutObj << "close" << PIString(PRIVATE->name) << PRIVATE->data;
if (PRIVATE->data) munmap(PRIVATE->data, dsize);
if (PRIVATE->owner) {
// piCout << "unlink" << PIString(PRIVATE->name);
shm_unlink((const char *)PRIVATE->name.data());
}
// if (fd > 0)
#endif
initPrivate();
return true;
}
PIString PISharedMemory::constructFullPathDevice() const {
PIString ret;
ret += path() + ":" + PIString::fromNumber(dsize);
return ret;
}
void PISharedMemory::configureFromFullPathDevice(const PIString & full_path) {
initPrivate();
PIStringList pl = full_path.split(":");
for (int i = 0; i < pl.size_s(); ++i) {
PIString p(pl[i].trimmed());
switch (i) {
case 0: setPath(p); break;
case 1: dsize = p.toInt(); break;
}
}
}
PIPropertyStorage PISharedMemory::constructVariantDevice() const {
PIPropertyStorage ret;
ret.addProperty("path", path());
ret.addProperty("size", dsize);
return ret;
}
void PISharedMemory::configureFromVariantDevice(const PIPropertyStorage & d) {
setPath(d.propertyValueByName("path").toString());
setSize(d.propertyValueByName("size").toInt());
}
void PISharedMemory::initPrivate() {
#ifdef WINDOWS
PRIVATE->map = 0;
PRIVATE->data = 0;
#endif
#ifdef SHM_POSIX
PRIVATE->data = 0;
PRIVATE->owner = false;
#endif
}
PIByteArray PISharedMemory::readAll() {
if (dsize <= 0) return PIByteArray();
#ifdef WINDOWS
if (!PRIVATE->data) return PIByteArray();
#endif
#ifdef SHM_POSIX
if (!PRIVATE->data) return PIByteArray();
#endif
PIByteArray a(dsize);
read(a.data(), a.size_s());
return a;
}
llong PISharedMemory::size() const {
if (isClosed()) return -1;
return dsize;
}
void PISharedMemory::setSize(llong s) {
bool o = isOpened();
if (o) close();
dsize = s;
if (o) open();
}
int PISharedMemory::read(void * read_to, int max_size) {
return read(read_to, max_size, 0);
}
int PISharedMemory::read(void * read_to, int max_size, int offset) {
#ifdef WINDOWS
if (!PRIVATE->data) return -1;
CopyMemory(read_to, &(((char *)(PRIVATE->data))[offset]), max_size);
return max_size;
#endif
#ifdef SHM_POSIX
if (!PRIVATE->data) return -1;
memcpy(read_to, &(((char *)(PRIVATE->data))[offset]), max_size);
return max_size;
#endif
return -1;
}
int PISharedMemory::write(const void * data, int max_size) {
return write(data, max_size, 0);
}
int PISharedMemory::write(const void * data, int max_size, int offset) {
#ifdef WINDOWS
if (!PRIVATE->data) return -1;
CopyMemory(&(((char *)(PRIVATE->data))[offset]), data, max_size);
return max_size;
#endif
#ifdef SHM_POSIX
if (!PRIVATE->data) return -1;
memcpy(&(((char *)(PRIVATE->data))[offset]), data, max_size);
return max_size;
#endif
return -1;
}