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:
Thiago Macieira 2022-11-05 12:27:24 -07:00
parent 75e73ea7fc
commit eaa7528baa
8 changed files with 198 additions and 226 deletions

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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) {

View File

@ -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)