IPC: split the backend implementations of QSharedMemory...
Into separate classes. This temporarily compiles QSharedMemoryPosix on most Unix systems despite defaulting to SystemV. Change-Id: I12a088d1ae424825abd3fffd171d25efdee8d2de Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
75e73ea7fc
commit
eaa7528baa
@ -508,8 +508,6 @@ qt_internal_extend_target(Core
|
||||
)
|
||||
|
||||
qt_internal_extend_target(Core CONDITION ANDROID
|
||||
SOURCES
|
||||
ipc/qsharedmemory_android.cpp
|
||||
DEFINES
|
||||
LIBS_SUFFIX="_${ANDROID_ABI}.so" # special case
|
||||
)
|
||||
@ -1137,14 +1135,11 @@ qt_internal_extend_target(Core CONDITION QT_FEATURE_clock_gettime AND UNIX
|
||||
WrapRt::WrapRt
|
||||
)
|
||||
|
||||
qt_internal_extend_target(Core CONDITION UNIX AND NOT ANDROID
|
||||
qt_internal_extend_target(Core CONDITION UNIX
|
||||
SOURCES
|
||||
ipc/qsharedmemory_posix.cpp
|
||||
ipc/qsharedmemory_systemv.cpp
|
||||
ipc/qsharedmemory_unix.cpp
|
||||
)
|
||||
qt_internal_extend_target(Core CONDITION UNIX
|
||||
SOURCES
|
||||
ipc/qsystemsemaphore_posix.cpp
|
||||
ipc/qsystemsemaphore_systemv.cpp
|
||||
ipc/qsystemsemaphore_unix.cpp
|
||||
|
@ -745,7 +745,7 @@ qt_feature("sharedmemory" PUBLIC
|
||||
SECTION "Kernel"
|
||||
LABEL "QSharedMemory"
|
||||
PURPOSE "Provides access to a shared memory segment."
|
||||
CONDITION ( ANDROID OR WIN32 OR ( NOT VXWORKS AND ( TEST_sysv_shm OR TEST_posix_shm ) ) )
|
||||
CONDITION WIN32 OR TEST_sysv_shm OR TEST_posix_shm
|
||||
)
|
||||
qt_feature_definition("sharedmemory" "QT_NO_SHAREDMEMORY" NEGATE VALUE "1")
|
||||
qt_feature("shortcut" PUBLIC
|
||||
|
@ -1,52 +0,0 @@
|
||||
// Copyright (C) 2012 Collabora Ltd, author <robin.burchell@collabora.co.uk>
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
#include "qsharedmemory.h"
|
||||
#include "qsharedmemory_p.h"
|
||||
#include <qdebug.h>
|
||||
|
||||
#if QT_CONFIG(sharedmemory)
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
void QSharedMemoryPrivate::setErrorString(QLatin1StringView function)
|
||||
{
|
||||
Q_UNUSED(function);
|
||||
Q_UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
key_t QSharedMemoryPrivate::handle()
|
||||
{
|
||||
Q_UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool QSharedMemoryPrivate::cleanHandle()
|
||||
{
|
||||
Q_UNIMPLEMENTED();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QSharedMemoryPrivate::create(qsizetype size)
|
||||
{
|
||||
Q_UNUSED(size);
|
||||
Q_UNIMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QSharedMemoryPrivate::attach(QSharedMemory::AccessMode mode)
|
||||
{
|
||||
Q_UNUSED(mode);
|
||||
Q_UNIMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QSharedMemoryPrivate::detach()
|
||||
{
|
||||
Q_UNIMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QT_CONFIG(sharedmemory)
|
@ -23,12 +23,17 @@
|
||||
#include "qsystemsemaphore.h"
|
||||
#include "private/qobject_p.h"
|
||||
|
||||
#if !defined(Q_OS_WIN) && !defined(Q_OS_ANDROID) && !defined(Q_OS_INTEGRITY) && !defined(Q_OS_RTEMS)
|
||||
# include <sys/sem.h>
|
||||
#if QT_CONFIG(posix_shm)
|
||||
# include <sys/mman.h>
|
||||
#endif
|
||||
#if QT_CONFIG(sysv_shm)
|
||||
# include <sys/shm.h>
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QSharedMemoryPrivate;
|
||||
|
||||
#if QT_CONFIG(systemsemaphore)
|
||||
/*!
|
||||
Helper class
|
||||
@ -61,6 +66,44 @@ private:
|
||||
};
|
||||
#endif // QT_CONFIG(systemsemaphore)
|
||||
|
||||
class QSharedMemoryPosix
|
||||
{
|
||||
public:
|
||||
bool handle(QSharedMemoryPrivate *self);
|
||||
bool cleanHandle(QSharedMemoryPrivate *self);
|
||||
bool create(QSharedMemoryPrivate *self, qsizetype size);
|
||||
bool attach(QSharedMemoryPrivate *self, QSharedMemory::AccessMode mode);
|
||||
bool detach(QSharedMemoryPrivate *self);
|
||||
|
||||
int hand = -1;
|
||||
};
|
||||
|
||||
class QSharedMemorySystemV
|
||||
{
|
||||
public:
|
||||
#if QT_CONFIG(sysv_sem)
|
||||
key_t handle(QSharedMemoryPrivate *self);
|
||||
bool cleanHandle(QSharedMemoryPrivate *self);
|
||||
bool create(QSharedMemoryPrivate *self, qsizetype size);
|
||||
bool attach(QSharedMemoryPrivate *self, QSharedMemory::AccessMode mode);
|
||||
bool detach(QSharedMemoryPrivate *self);
|
||||
|
||||
key_t unix_key = 0;
|
||||
#endif
|
||||
};
|
||||
|
||||
class QSharedMemoryWin32
|
||||
{
|
||||
public:
|
||||
Qt::HANDLE handle(QSharedMemoryPrivate *self);
|
||||
bool cleanHandle(QSharedMemoryPrivate *self);
|
||||
bool create(QSharedMemoryPrivate *self, qsizetype size);
|
||||
bool attach(QSharedMemoryPrivate *self, QSharedMemory::AccessMode mode);
|
||||
bool detach(QSharedMemoryPrivate *self);
|
||||
|
||||
Qt::HANDLE hand = nullptr;
|
||||
};
|
||||
|
||||
class Q_AUTOTEST_EXPORT QSharedMemoryPrivate : public QObjectPrivate
|
||||
{
|
||||
Q_DECLARE_PUBLIC(QSharedMemory)
|
||||
@ -70,27 +113,49 @@ public:
|
||||
qsizetype size = 0;
|
||||
QString key;
|
||||
QString nativeKey;
|
||||
QSharedMemory::SharedMemoryError error = QSharedMemory::NoError;
|
||||
QString errorString;
|
||||
#if QT_CONFIG(systemsemaphore)
|
||||
QSystemSemaphore systemSemaphore{QString()};
|
||||
bool lockedByMe = false;
|
||||
#endif
|
||||
QSharedMemory::SharedMemoryError error = QSharedMemory::NoError;
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
Qt::HANDLE handle();
|
||||
#if defined(Q_OS_WIN)
|
||||
using DefaultBackend = QSharedMemoryWin32;
|
||||
#elif defined(QT_POSIX_IPC)
|
||||
int handle();
|
||||
using DefaultBackend = QSharedMemoryPosix;
|
||||
#else
|
||||
key_t handle();
|
||||
using DefaultBackend = QSharedMemorySystemV;
|
||||
#endif
|
||||
bool initKey();
|
||||
bool cleanHandle();
|
||||
bool create(qsizetype size);
|
||||
bool attach(QSharedMemory::AccessMode mode);
|
||||
bool detach();
|
||||
DefaultBackend backend;
|
||||
|
||||
void setErrorString(QLatin1StringView function);
|
||||
bool initKey();
|
||||
|
||||
bool handle()
|
||||
{
|
||||
return backend.handle(this);
|
||||
}
|
||||
bool cleanHandle()
|
||||
{
|
||||
return backend.cleanHandle(this);
|
||||
}
|
||||
bool create(qsizetype size)
|
||||
{
|
||||
return backend.create(this, size);
|
||||
}
|
||||
bool attach(QSharedMemory::AccessMode mode)
|
||||
{
|
||||
return backend.attach(this, mode);
|
||||
}
|
||||
bool detach()
|
||||
{
|
||||
return backend.detach(this);
|
||||
}
|
||||
|
||||
inline void setError(QSharedMemory::SharedMemoryError e, const QString &message)
|
||||
{ error = e; errorString = message; }
|
||||
void setUnixErrorString(QLatin1StringView function);
|
||||
void setWindowsErrorString(QLatin1StringView function);
|
||||
|
||||
#if QT_CONFIG(systemsemaphore)
|
||||
bool tryLocker(QSharedMemoryLocker *locker, const QString &function) {
|
||||
@ -102,15 +167,6 @@ public:
|
||||
return true;
|
||||
}
|
||||
#endif // QT_CONFIG(systemsemaphore)
|
||||
|
||||
private:
|
||||
#ifdef Q_OS_WIN
|
||||
Qt::HANDLE hand = nullptr;
|
||||
#elif defined(QT_POSIX_IPC)
|
||||
int hand = -1;
|
||||
#else
|
||||
key_t unix_key = 0;
|
||||
#endif
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -3,8 +3,6 @@
|
||||
// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
#include "qplatformdefs.h"
|
||||
|
||||
#include "qsharedmemory.h"
|
||||
#include "qsharedmemory_p.h"
|
||||
#include "qtipccommon_p.h"
|
||||
@ -12,9 +10,7 @@
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef QT_POSIX_IPC
|
||||
|
||||
#if QT_CONFIG(sharedmemory)
|
||||
#if QT_CONFIG(posix_shm)
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
@ -28,20 +24,20 @@ QT_BEGIN_NAMESPACE
|
||||
using namespace Qt::StringLiterals;
|
||||
using namespace QtIpcCommon;
|
||||
|
||||
int QSharedMemoryPrivate::handle()
|
||||
bool QSharedMemoryPosix::handle(QSharedMemoryPrivate *self)
|
||||
{
|
||||
// don't allow making handles on empty keys
|
||||
const QString safeKey = legacyPlatformSafeKey(key, QtIpcCommon::IpcType::SharedMemory);
|
||||
const QString safeKey = legacyPlatformSafeKey(self->key, IpcType::SharedMemory);
|
||||
if (safeKey.isEmpty()) {
|
||||
errorString = QSharedMemory::tr("%1: key is empty").arg("QSharedMemory::handle"_L1);
|
||||
error = QSharedMemory::KeyError;
|
||||
return 0;
|
||||
self->setError(QSharedMemory::KeyError,
|
||||
QSharedMemory::tr("%1: key is empty").arg("QSharedMemory::handle"_L1));
|
||||
return false;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QSharedMemoryPrivate::cleanHandle()
|
||||
bool QSharedMemoryPosix::cleanHandle(QSharedMemoryPrivate *)
|
||||
{
|
||||
qt_safe_close(hand);
|
||||
hand = -1;
|
||||
@ -49,12 +45,12 @@ bool QSharedMemoryPrivate::cleanHandle()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QSharedMemoryPrivate::create(qsizetype size)
|
||||
bool QSharedMemoryPosix::create(QSharedMemoryPrivate *self, qsizetype size)
|
||||
{
|
||||
if (!handle())
|
||||
if (!handle(self))
|
||||
return false;
|
||||
|
||||
const QByteArray shmName = QFile::encodeName(legacyPlatformSafeKey(key, IpcType::SharedMemory));
|
||||
const QByteArray shmName = QFile::encodeName(legacyPlatformSafeKey(self->key, IpcType::SharedMemory));
|
||||
|
||||
int fd;
|
||||
#ifdef O_CLOEXEC
|
||||
@ -70,11 +66,11 @@ bool QSharedMemoryPrivate::create(qsizetype size)
|
||||
const auto function = "QSharedMemory::attach (shm_open)"_L1;
|
||||
switch (errorNumber) {
|
||||
case EINVAL:
|
||||
errorString = QSharedMemory::tr("%1: bad name").arg(function);
|
||||
error = QSharedMemory::KeyError;
|
||||
self->setError(QSharedMemory::KeyError,
|
||||
QSharedMemory::tr("%1: bad name").arg(function));
|
||||
break;
|
||||
default:
|
||||
setErrorString(function);
|
||||
self->setUnixErrorString(function);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -83,7 +79,7 @@ bool QSharedMemoryPrivate::create(qsizetype size)
|
||||
int ret;
|
||||
EINTR_LOOP(ret, QT_FTRUNCATE(fd, size));
|
||||
if (ret == -1) {
|
||||
setErrorString("QSharedMemory::create (ftruncate)"_L1);
|
||||
self->setUnixErrorString("QSharedMemory::create (ftruncate)"_L1);
|
||||
qt_safe_close(fd);
|
||||
return false;
|
||||
}
|
||||
@ -93,9 +89,9 @@ bool QSharedMemoryPrivate::create(qsizetype size)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QSharedMemoryPrivate::attach(QSharedMemory::AccessMode mode)
|
||||
bool QSharedMemoryPosix::attach(QSharedMemoryPrivate *self, QSharedMemory::AccessMode mode)
|
||||
{
|
||||
const QByteArray shmName = QFile::encodeName(legacyPlatformSafeKey(key, IpcType::SharedMemory));
|
||||
const QByteArray shmName = QFile::encodeName(legacyPlatformSafeKey(self->key, IpcType::SharedMemory));
|
||||
|
||||
const int oflag = (mode == QSharedMemory::ReadOnly ? O_RDONLY : O_RDWR);
|
||||
const mode_t omode = (mode == QSharedMemory::ReadOnly ? 0400 : 0600);
|
||||
@ -113,11 +109,11 @@ bool QSharedMemoryPrivate::attach(QSharedMemory::AccessMode mode)
|
||||
const auto function = "QSharedMemory::attach (shm_open)"_L1;
|
||||
switch (errorNumber) {
|
||||
case EINVAL:
|
||||
errorString = QSharedMemory::tr("%1: bad name").arg(function);
|
||||
error = QSharedMemory::KeyError;
|
||||
self->setError(QSharedMemory::KeyError,
|
||||
QSharedMemory::tr("%1: bad name").arg(function));
|
||||
break;
|
||||
default:
|
||||
setErrorString(function);
|
||||
self->setUnixErrorString(function);
|
||||
}
|
||||
hand = -1;
|
||||
return false;
|
||||
@ -126,20 +122,20 @@ bool QSharedMemoryPrivate::attach(QSharedMemory::AccessMode mode)
|
||||
// grab the size
|
||||
QT_STATBUF st;
|
||||
if (QT_FSTAT(hand, &st) == -1) {
|
||||
setErrorString("QSharedMemory::attach (fstat)"_L1);
|
||||
cleanHandle();
|
||||
self->setUnixErrorString("QSharedMemory::attach (fstat)"_L1);
|
||||
cleanHandle(self);
|
||||
return false;
|
||||
}
|
||||
size = qsizetype(st.st_size);
|
||||
self->size = qsizetype(st.st_size);
|
||||
|
||||
// grab the memory
|
||||
const int mprot = (mode == QSharedMemory::ReadOnly ? PROT_READ : PROT_READ | PROT_WRITE);
|
||||
memory = QT_MMAP(0, size_t(size), mprot, MAP_SHARED, hand, 0);
|
||||
if (memory == MAP_FAILED || !memory) {
|
||||
setErrorString("QSharedMemory::attach (mmap)"_L1);
|
||||
cleanHandle();
|
||||
memory = 0;
|
||||
size = 0;
|
||||
self->memory = QT_MMAP(0, size_t(self->size), mprot, MAP_SHARED, hand, 0);
|
||||
if (self->memory == MAP_FAILED || !self->memory) {
|
||||
self->setUnixErrorString("QSharedMemory::attach (mmap)"_L1);
|
||||
cleanHandle(self);
|
||||
self->memory = 0;
|
||||
self->size = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -153,15 +149,15 @@ bool QSharedMemoryPrivate::attach(QSharedMemory::AccessMode mode)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QSharedMemoryPrivate::detach()
|
||||
bool QSharedMemoryPosix::detach(QSharedMemoryPrivate *self)
|
||||
{
|
||||
// detach from the memory segment
|
||||
if (::munmap(memory, size_t(size)) == -1) {
|
||||
setErrorString("QSharedMemory::detach (munmap)"_L1);
|
||||
if (::munmap(self->memory, size_t(self->size)) == -1) {
|
||||
self->setUnixErrorString("QSharedMemory::detach (munmap)"_L1);
|
||||
return false;
|
||||
}
|
||||
memory = 0;
|
||||
size = 0;
|
||||
self->memory = 0;
|
||||
self->size = 0;
|
||||
|
||||
#ifdef Q_OS_QNX
|
||||
// On QNX the st_nlink field of struct stat contains the number of
|
||||
@ -177,18 +173,18 @@ bool QSharedMemoryPrivate::detach()
|
||||
shm_nattch = st.st_nlink - 2;
|
||||
}
|
||||
|
||||
cleanHandle();
|
||||
cleanHandle(self);
|
||||
|
||||
// if there are no attachments then unlink the shared memory
|
||||
if (shm_nattch == 0) {
|
||||
const QByteArray shmName = QFile::encodeName(legacyPlatformSafeKey(key, IpcType::SharedMemory));
|
||||
const QByteArray shmName = QFile::encodeName(legacyPlatformSafeKey(self->key, IpcType::SharedMemory));
|
||||
if (::shm_unlink(shmName.constData()) == -1 && errno != ENOENT)
|
||||
setErrorString("QSharedMemory::detach (shm_unlink)"_L1);
|
||||
self->setUnixErrorString("QSharedMemory::detach (shm_unlink)"_L1);
|
||||
}
|
||||
#else
|
||||
// On non-QNX systems (tested Linux and Haiku), the st_nlink field is always 1,
|
||||
// so we'll simply leak the shared memory files.
|
||||
cleanHandle();
|
||||
cleanHandle(self);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
@ -196,6 +192,4 @@ bool QSharedMemoryPrivate::detach()
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QT_CONFIG(sharedmemory)
|
||||
|
||||
#endif // QT_POSIX_IPC
|
||||
#endif // QT_CONFIG(posix_shm)
|
||||
|
@ -11,20 +11,16 @@
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#ifndef QT_POSIX_IPC
|
||||
|
||||
#if QT_CONFIG(sharedmemory)
|
||||
#if QT_CONFIG(sysv_shm)
|
||||
#include <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#endif // QT_CONFIG(sharedmemory)
|
||||
|
||||
#include "private/qcore_unix_p.h"
|
||||
|
||||
#if QT_CONFIG(sharedmemory)
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
using namespace Qt::StringLiterals;
|
||||
@ -35,50 +31,54 @@ using namespace QtIpcCommon;
|
||||
|
||||
If not already made create the handle used for accessing the shared memory.
|
||||
*/
|
||||
key_t QSharedMemoryPrivate::handle()
|
||||
key_t QSharedMemorySystemV::handle(QSharedMemoryPrivate *self)
|
||||
{
|
||||
// already made
|
||||
if (unix_key)
|
||||
return unix_key;
|
||||
|
||||
// don't allow making handles on empty keys
|
||||
if (nativeKey.isEmpty()) {
|
||||
errorString = QSharedMemory::tr("%1: key is empty").arg("QSharedMemory::handle:"_L1);
|
||||
error = QSharedMemory::KeyError;
|
||||
if (self->nativeKey.isEmpty()) {
|
||||
self->setError(QSharedMemory::KeyError,
|
||||
QSharedMemory::tr("%1: key is empty")
|
||||
.arg("QSharedMemory::handle:"_L1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ftok requires that an actual file exists somewhere
|
||||
if (!QFile::exists(nativeKey)) {
|
||||
errorString = QSharedMemory::tr("%1: UNIX key file doesn't exist").arg("QSharedMemory::handle:"_L1);
|
||||
error = QSharedMemory::NotFound;
|
||||
if (!QFile::exists(self->nativeKey)) {
|
||||
self->setError(QSharedMemory::NotFound,
|
||||
QSharedMemory::tr("%1: UNIX key file doesn't exist")
|
||||
.arg("QSharedMemory::handle:"_L1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
unix_key = ftok(QFile::encodeName(nativeKey).constData(), 'Q');
|
||||
unix_key = ftok(QFile::encodeName(self->nativeKey).constData(), 'Q');
|
||||
if (-1 == unix_key) {
|
||||
errorString = QSharedMemory::tr("%1: ftok failed").arg("QSharedMemory::handle:"_L1);
|
||||
error = QSharedMemory::KeyError;
|
||||
self->setError(QSharedMemory::KeyError,
|
||||
QSharedMemory::tr("%1: ftok failed")
|
||||
.arg("QSharedMemory::handle:"_L1));
|
||||
unix_key = 0;
|
||||
}
|
||||
return unix_key;
|
||||
}
|
||||
|
||||
bool QSharedMemoryPrivate::cleanHandle()
|
||||
bool QSharedMemorySystemV::cleanHandle(QSharedMemoryPrivate *)
|
||||
{
|
||||
unix_key = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QSharedMemoryPrivate::create(qsizetype size)
|
||||
bool QSharedMemorySystemV::create(QSharedMemoryPrivate *self, qsizetype size)
|
||||
{
|
||||
// build file if needed
|
||||
bool createdFile = false;
|
||||
QByteArray nativeKeyFile = QFile::encodeName(nativeKey);
|
||||
QByteArray nativeKeyFile = QFile::encodeName(self->nativeKey);
|
||||
int built = createUnixKeyFile(nativeKeyFile);
|
||||
if (built == -1) {
|
||||
errorString = QSharedMemory::tr("%1: unable to make key").arg("QSharedMemory::handle:"_L1);
|
||||
error = QSharedMemory::KeyError;
|
||||
self->setError(QSharedMemory::KeyError,
|
||||
QSharedMemory::tr("%1: unable to make key")
|
||||
.arg("QSharedMemory::handle:"_L1));
|
||||
return false;
|
||||
}
|
||||
if (built == 1) {
|
||||
@ -86,7 +86,7 @@ bool QSharedMemoryPrivate::create(qsizetype size)
|
||||
}
|
||||
|
||||
// get handle
|
||||
if (!handle()) {
|
||||
if (!handle(self)) {
|
||||
if (createdFile)
|
||||
unlink(nativeKeyFile);
|
||||
return false;
|
||||
@ -97,13 +97,14 @@ bool QSharedMemoryPrivate::create(qsizetype size)
|
||||
const auto function = "QSharedMemory::create"_L1;
|
||||
switch (errno) {
|
||||
case EINVAL:
|
||||
errorString = QSharedMemory::tr("%1: system-imposed size restrictions").arg("QSharedMemory::handle"_L1);
|
||||
error = QSharedMemory::InvalidSize;
|
||||
self->setError(QSharedMemory::InvalidSize,
|
||||
QSharedMemory::tr("%1: system-imposed size restrictions")
|
||||
.arg("QSharedMemory::handle"_L1));
|
||||
break;
|
||||
default:
|
||||
setErrorString(function);
|
||||
self->setUnixErrorString(function);
|
||||
}
|
||||
if (createdFile && error != QSharedMemory::AlreadyExists)
|
||||
if (createdFile && self->error != QSharedMemory::AlreadyExists)
|
||||
unlink(nativeKeyFile);
|
||||
return false;
|
||||
}
|
||||
@ -111,56 +112,56 @@ bool QSharedMemoryPrivate::create(qsizetype size)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QSharedMemoryPrivate::attach(QSharedMemory::AccessMode mode)
|
||||
bool QSharedMemorySystemV::attach(QSharedMemoryPrivate *self, QSharedMemory::AccessMode mode)
|
||||
{
|
||||
// grab the shared memory segment id
|
||||
int id = shmget(unix_key, 0, (mode == QSharedMemory::ReadOnly ? 0400 : 0600));
|
||||
if (-1 == id) {
|
||||
setErrorString("QSharedMemory::attach (shmget)"_L1);
|
||||
self->setUnixErrorString("QSharedMemory::attach (shmget)"_L1);
|
||||
return false;
|
||||
}
|
||||
|
||||
// grab the memory
|
||||
memory = shmat(id, nullptr, (mode == QSharedMemory::ReadOnly ? SHM_RDONLY : 0));
|
||||
if ((void *)-1 == memory) {
|
||||
memory = nullptr;
|
||||
setErrorString("QSharedMemory::attach (shmat)"_L1);
|
||||
self->memory = shmat(id, nullptr, (mode == QSharedMemory::ReadOnly ? SHM_RDONLY : 0));
|
||||
if (self->memory == MAP_FAILED) {
|
||||
self->memory = nullptr;
|
||||
self->setUnixErrorString("QSharedMemory::attach (shmat)"_L1);
|
||||
return false;
|
||||
}
|
||||
|
||||
// grab the size
|
||||
shmid_ds shmid_ds;
|
||||
if (!shmctl(id, IPC_STAT, &shmid_ds)) {
|
||||
size = (qsizetype)shmid_ds.shm_segsz;
|
||||
self->size = (qsizetype)shmid_ds.shm_segsz;
|
||||
} else {
|
||||
setErrorString("QSharedMemory::attach (shmctl)"_L1);
|
||||
self->setUnixErrorString("QSharedMemory::attach (shmctl)"_L1);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QSharedMemoryPrivate::detach()
|
||||
bool QSharedMemorySystemV::detach(QSharedMemoryPrivate *self)
|
||||
{
|
||||
// detach from the memory segment
|
||||
if (-1 == shmdt(memory)) {
|
||||
if (shmdt(self->memory) < 0) {
|
||||
const auto function = "QSharedMemory::detach"_L1;
|
||||
switch (errno) {
|
||||
case EINVAL:
|
||||
errorString = QSharedMemory::tr("%1: not attached").arg(function);
|
||||
error = QSharedMemory::NotFound;
|
||||
self->setError(QSharedMemory::NotFound,
|
||||
QSharedMemory::tr("%1: not attached").arg(function));
|
||||
break;
|
||||
default:
|
||||
setErrorString(function);
|
||||
self->setUnixErrorString(function);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
memory = nullptr;
|
||||
size = 0;
|
||||
self->memory = nullptr;
|
||||
self->size = 0;
|
||||
|
||||
// Get the number of current attachments
|
||||
int id = shmget(unix_key, 0, 0400);
|
||||
cleanHandle();
|
||||
cleanHandle(self);
|
||||
|
||||
struct shmid_ds shmid_ds;
|
||||
if (0 != shmctl(id, IPC_STAT, &shmid_ds)) {
|
||||
@ -175,7 +176,7 @@ bool QSharedMemoryPrivate::detach()
|
||||
if (shmid_ds.shm_nattch == 0) {
|
||||
// mark for removal
|
||||
if (-1 == shmctl(id, IPC_RMID, &shmid_ds)) {
|
||||
setErrorString("QSharedMemory::remove"_L1);
|
||||
self->setUnixErrorString("QSharedMemory::remove"_L1);
|
||||
switch (errno) {
|
||||
case EINVAL:
|
||||
return true;
|
||||
@ -185,15 +186,12 @@ bool QSharedMemoryPrivate::detach()
|
||||
}
|
||||
|
||||
// remove file
|
||||
if (!unlink(QFile::encodeName(nativeKey)))
|
||||
if (!unlink(QFile::encodeName(self->nativeKey)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QT_CONFIG(sharedmemory)
|
||||
|
||||
#endif // QT_POSIX_IPC
|
||||
#endif // QT_CONFIG(sysv_shm)
|
||||
|
@ -1,34 +1,15 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
#include "qplatformdefs.h"
|
||||
|
||||
#include "qsharedmemory.h"
|
||||
#include "qsharedmemory_p.h"
|
||||
#include "qsystemsemaphore.h"
|
||||
#include <qdebug.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#if QT_CONFIG(sharedmemory)
|
||||
#include <sys/types.h>
|
||||
#ifndef QT_POSIX_IPC
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#else
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#endif // QT_CONFIG(sharedmemory)
|
||||
# include "qsharedmemory_p.h"
|
||||
# include <errno.h>
|
||||
|
||||
#include "private/qcore_unix_p.h"
|
||||
|
||||
#if QT_CONFIG(sharedmemory)
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
void QSharedMemoryPrivate::setErrorString(QLatin1StringView function)
|
||||
void QSharedMemoryPrivate::setUnixErrorString(QLatin1StringView function)
|
||||
{
|
||||
// EINVAL is handled in functions so they can give better error strings
|
||||
switch (errno) {
|
||||
|
@ -13,7 +13,7 @@ using namespace Qt::StringLiterals;
|
||||
|
||||
#if QT_CONFIG(sharedmemory)
|
||||
|
||||
void QSharedMemoryPrivate::setErrorString(QLatin1StringView function)
|
||||
void QSharedMemoryPrivate::setWindowsErrorString(QLatin1StringView function)
|
||||
{
|
||||
DWORD windowsError = GetLastError();
|
||||
if (windowsError == 0)
|
||||
@ -49,42 +49,41 @@ void QSharedMemoryPrivate::setErrorString(QLatin1StringView function)
|
||||
}
|
||||
}
|
||||
|
||||
HANDLE QSharedMemoryPrivate::handle()
|
||||
HANDLE QSharedMemoryWin32::handle(QSharedMemoryPrivate *self)
|
||||
{
|
||||
if (!hand) {
|
||||
const auto function = "QSharedMemory::handle"_L1;
|
||||
if (nativeKey.isEmpty()) {
|
||||
error = QSharedMemory::KeyError;
|
||||
errorString = QSharedMemory::tr("%1: unable to make key").arg(function);
|
||||
if (self->nativeKey.isEmpty()) {
|
||||
self->setError(QSharedMemory::KeyError,
|
||||
QSharedMemory::tr("%1: unable to make key").arg(function));
|
||||
return 0;
|
||||
}
|
||||
hand = OpenFileMapping(FILE_MAP_ALL_ACCESS, false,
|
||||
reinterpret_cast<const wchar_t *>(nativeKey.utf16()));
|
||||
reinterpret_cast<const wchar_t *>(self->nativeKey.utf16()));
|
||||
if (!hand) {
|
||||
setErrorString(function);
|
||||
self->setWindowsErrorString(function);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return hand;
|
||||
}
|
||||
|
||||
bool QSharedMemoryPrivate::cleanHandle()
|
||||
bool QSharedMemoryWin32::cleanHandle(QSharedMemoryPrivate *)
|
||||
{
|
||||
if (hand != 0 && !CloseHandle(hand)) {
|
||||
hand = 0;
|
||||
setErrorString("QSharedMemory::cleanHandle"_L1);
|
||||
return false;
|
||||
}
|
||||
hand = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QSharedMemoryPrivate::create(qsizetype size)
|
||||
bool QSharedMemoryWin32::create(QSharedMemoryPrivate *self, qsizetype size)
|
||||
{
|
||||
const auto function = "QSharedMemory::create"_L1;
|
||||
if (nativeKey.isEmpty()) {
|
||||
error = QSharedMemory::KeyError;
|
||||
errorString = QSharedMemory::tr("%1: key error").arg(function);
|
||||
if (self->nativeKey.isEmpty()) {
|
||||
self->setError(QSharedMemory::KeyError,
|
||||
QSharedMemory::tr("%1: key error").arg(function));
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -96,50 +95,51 @@ bool QSharedMemoryPrivate::create(qsizetype size)
|
||||
high = 0;
|
||||
low = DWORD(size_t(size) & 0xffffffff);
|
||||
hand = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, high, low,
|
||||
reinterpret_cast<const wchar_t *>(nativeKey.utf16()));
|
||||
setErrorString(function);
|
||||
reinterpret_cast<const wchar_t *>(self->nativeKey.utf16()));
|
||||
self->setWindowsErrorString(function);
|
||||
|
||||
// hand is valid when it already exists unlike unix so explicitly check
|
||||
return error != QSharedMemory::AlreadyExists && hand;
|
||||
return self->error != QSharedMemory::AlreadyExists && hand;
|
||||
}
|
||||
|
||||
bool QSharedMemoryPrivate::attach(QSharedMemory::AccessMode mode)
|
||||
bool QSharedMemoryWin32::attach(QSharedMemoryPrivate *self, QSharedMemory::AccessMode mode)
|
||||
{
|
||||
// Grab a pointer to the memory block
|
||||
int permissions = (mode == QSharedMemory::ReadOnly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS);
|
||||
memory = (void *)MapViewOfFile(handle(), permissions, 0, 0, 0);
|
||||
if (0 == memory) {
|
||||
setErrorString("QSharedMemory::attach"_L1);
|
||||
cleanHandle();
|
||||
self->memory = (void *)MapViewOfFile(handle(self), permissions, 0, 0, 0);
|
||||
if (!self->memory) {
|
||||
self->setWindowsErrorString("QSharedMemory::attach"_L1);
|
||||
cleanHandle(self);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Grab the size of the memory we have been given (a multiple of 4K on windows)
|
||||
MEMORY_BASIC_INFORMATION info;
|
||||
if (!VirtualQuery(memory, &info, sizeof(info))) {
|
||||
if (!VirtualQuery(self->memory, &info, sizeof(info))) {
|
||||
// Windows doesn't set an error code on this one,
|
||||
// it should only be a kernel memory error.
|
||||
error = QSharedMemory::UnknownError;
|
||||
errorString = QSharedMemory::tr("%1: size query failed").arg("QSharedMemory::attach: "_L1);
|
||||
self->setError(QSharedMemory::UnknownError,
|
||||
QSharedMemory::tr("%1: size query failed")
|
||||
.arg("QSharedMemory::attach: "_L1));
|
||||
return false;
|
||||
}
|
||||
size = qsizetype(info.RegionSize);
|
||||
self->size = qsizetype(info.RegionSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QSharedMemoryPrivate::detach()
|
||||
bool QSharedMemoryWin32::detach(QSharedMemoryPrivate *self)
|
||||
{
|
||||
// umap memory
|
||||
if (!UnmapViewOfFile(memory)) {
|
||||
setErrorString("QSharedMemory::detach"_L1);
|
||||
if (!UnmapViewOfFile(self->memory)) {
|
||||
self->setWindowsErrorString("QSharedMemory::detach"_L1);
|
||||
return false;
|
||||
}
|
||||
memory = 0;
|
||||
size = 0;
|
||||
self->memory = 0;
|
||||
self->size = 0;
|
||||
|
||||
// close handle
|
||||
return cleanHandle();
|
||||
return cleanHandle(self);
|
||||
}
|
||||
|
||||
#endif // QT_CONFIG(sharedmemory)
|
||||
|
Loading…
Reference in New Issue
Block a user