286 lines
7.3 KiB
C++
286 lines
7.3 KiB
C++
/*
|
||
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;
|
||
}
|