Files
pip/src_main/io/pisharedmemory.cpp

252 lines
6.2 KiB
C++

/*
PIP - Platform Independent Primitives
File
Copyright (C) 2017 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "piincludes_p.h"
#include "pisharedmemory.h"
#ifdef WINDOWS
#endif
#if defined(QNX) || defined(ANDROID)
#endif
#ifdef MAC_OS
#endif
#ifdef LINUX
# include <fcntl.h>
# include <sys/stat.h>
# include <sys/mman.h>
#endif
/*! \class PISharedMemory
* \brief Shared memory
*
* \section PISharedMemory_sec0 Synopsis
* This class provide access to local file. You can manipulate
* binary content or use this class as text stream. To binary
* access there are function \a read(), \a write(), and many
* \a writeBinary() functions. For write variables to file in
* their text representation threr are many "<<" operators.
*
* \section PISharedMemory_sec1 Position
* Each opened file has a read/write position - logical position
* in the file content you read from or you write to. You can
* find out current position with function \a pos(). Function
* \a seek(llong position) move position to position "position",
* \a seekToBegin() move position to the begin of file,
* \a seekToEnd() move position to the end of file.
*
*/
//REGISTER_DEVICE(PISharedMemory);
PRIVATE_DEFINITION_START(PISharedMemory)
PIByteArray name;
#ifdef WINDOWS
HANDLE map;
void * data;
#endif
#ifdef LINUX
void * data;
bool owner;
#endif
PRIVATE_DEFINITION_END(PISharedMemory)
PISharedMemory::PISharedMemory(): PIIODevice() {
initPrivate();
dsize = -1;
}
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(const PISharedMemory & other) {
initPrivate();
dsize = other.dsize;
setPath(other.path());
mode_ = other.mode_;
}
bool PISharedMemory::openDevice() {
close();
#ifdef WINDOWS
DWORD m = PAGE_READWRITE;
if (!isWriteable()) m = PAGE_READONLY;
PRIVATE->name = ("PIP_SHM_" + path()).toByteArray();
PRIVATE->name.push_back(0);
PRIVATE->map = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, m, 0, (DWORD)dsize, (const char *)PRIVATE->name.data());
if (!PRIVATE->map) {
piCoutObj << "CreateFileMapping error," << errorString();
return false;
}
if (!isWriteable()) m = FILE_MAP_READ;
else m = FILE_MAP_ALL_ACCESS;
PRIVATE->data = MapViewOfFile(PRIVATE->map, m, 0, 0, dsize);
if (!PRIVATE->data) {
piCoutObj << "MapViewOfFile error," << errorString();
CloseHandle(PRIVATE->map);
return false;
}
//piCout << PRIVATE->map << PRIVATE->data;
#endif
#ifdef LINUX
int m = O_RDWR;
if (!isWriteable()) m = O_RDONLY;
PRIVATE->name = ("/pip_shm_" + path()).toByteArray();
PRIVATE->name.push_back(0);
int fd = shm_open((const char *)PRIVATE->name.data(), m, 0777);
//piCoutObj << "try open" << PICoutManipulators::Hex << fd;
if (fd < 0) {
//piCoutObj << "shm_open error," << errorString();
fd = shm_open((const char *)PRIVATE->name.data(), m | 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;
ftruncate(fd, dsize);
//piCoutObj << "created" << fd;
}
m = PROT_WRITE;
if (!isWriteable()) m = PROT_READ;
PRIVATE->data = mmap(0, dsize, m, MAP_SHARED, fd, 0);
::close(fd);
if (!PRIVATE->data) {
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 LINUX
//piCoutObj << "close" << PIString(PRIVATE->name) << PRIVATE->data;
if (PRIVATE->data) munmap(PRIVATE->data, dsize);
if (PRIVATE->owner) {
//if (!PRIVATE->name.isEmpty()) {
//piCout << "unlink" << PIString(PRIVATE->name);
shm_unlink((const char *)PRIVATE->name.data());
}
//if (fd > 0)
#endif
initPrivate();
return true;
}
void PISharedMemory::initPrivate() {
#ifdef WINDOWS
PRIVATE->map = 0;
PRIVATE->data = 0;
#endif
#ifdef LINUX
PRIVATE->data = 0;
PRIVATE->owner = false;
#endif
}
PIByteArray PISharedMemory::readAll() {
if (dsize <= 0) return PIByteArray();
#ifdef WINDOWS
if (!PRIVATE->data) return PIByteArray();
#endif
#ifdef LINUX
if (!PRIVATE->data) return PIByteArray();
#endif
PIByteArray a(dsize);
read(a.data(), a.size_s());
/*llong cp = pos();
if (forceRead) {
seekToBegin();
while (!isEnd())
a.push_back(readChar());
seek(cp);
return a;
}
llong s = size();
if (s < 0) return a;
a.resize(s);
s = readAll(a.data());
seek(cp);
if (s >= 0) a.resize(s);*/
return a;
}
llong PISharedMemory::size() const {
if (isClosed()) return -1;
return dsize;
}
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 LINUX
if (!PRIVATE->data) return -1;
memcpy(read_to, &(((char*)(PRIVATE->data))[offset]), max_size);
return max_size;
#endif
}
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 LINUX
if (!PRIVATE->data) return -1;
memcpy(&(((char*)(PRIVATE->data))[offset]), data, max_size);
return max_size;
#endif
}