/* 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 . */ #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 #endif #ifdef SHM_POSIX # include # include # include #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; }