IPC: add support for multiple backends to QSharedMemory
Simultaneously. Change-Id: If4c23ea3719947d790d4fffd17152760989b9bc6 Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
32a06e9830
commit
0740ab56d7
@ -1135,9 +1135,12 @@ qt_internal_extend_target(Core CONDITION QT_FEATURE_clock_gettime AND UNIX
|
||||
WrapRt::WrapRt
|
||||
)
|
||||
|
||||
qt_internal_extend_target(Core CONDITION UNIX
|
||||
qt_internal_extend_target(Core CONDITION QT_FEATURE_posix_shm
|
||||
SOURCES
|
||||
ipc/qsharedmemory_posix.cpp
|
||||
)
|
||||
qt_internal_extend_target(Core CONDITION QT_FEATURE_sysv_shm
|
||||
SOURCES
|
||||
ipc/qsharedmemory_systemv.cpp
|
||||
)
|
||||
qt_internal_extend_target(Core CONDITION QT_FEATURE_posix_sem
|
||||
|
@ -23,6 +23,30 @@ QT_BEGIN_NAMESPACE
|
||||
using namespace QtIpcCommon;
|
||||
using namespace Qt::StringLiterals;
|
||||
|
||||
#if __cplusplus >= 202002L
|
||||
using std::construct_at;
|
||||
#else
|
||||
template <typename T> static void construct_at(T *ptr)
|
||||
{
|
||||
new (ptr) T;
|
||||
}
|
||||
#endif
|
||||
|
||||
QSharedMemoryPrivate::~QSharedMemoryPrivate()
|
||||
{
|
||||
destructBackend();
|
||||
}
|
||||
|
||||
inline void QSharedMemoryPrivate::constructBackend()
|
||||
{
|
||||
visit([](auto p) { construct_at(p); });
|
||||
}
|
||||
|
||||
inline void QSharedMemoryPrivate::destructBackend()
|
||||
{
|
||||
visit([](auto p) { std::destroy_at(p); });
|
||||
}
|
||||
|
||||
#if QT_CONFIG(systemsemaphore)
|
||||
inline QNativeIpcKey QSharedMemoryPrivate::semaphoreNativeKey() const
|
||||
{
|
||||
@ -103,7 +127,7 @@ QSharedMemory::QSharedMemory(QObject *parent)
|
||||
\sa setNativeKey(), create(), attach()
|
||||
*/
|
||||
QSharedMemory::QSharedMemory(const QNativeIpcKey &key, QObject *parent)
|
||||
: QObject(*new QSharedMemoryPrivate, parent)
|
||||
: QObject(*new QSharedMemoryPrivate(key.type()), parent)
|
||||
{
|
||||
setNativeKey(key);
|
||||
}
|
||||
@ -120,12 +144,9 @@ QSharedMemory::QSharedMemory(const QNativeIpcKey &key, QObject *parent)
|
||||
\sa setKey(), create(), attach()
|
||||
*/
|
||||
QSharedMemory::QSharedMemory(const QString &key, QObject *parent)
|
||||
: QObject(*new QSharedMemoryPrivate, parent)
|
||||
: QSharedMemory(legacyNativeKey(key), parent)
|
||||
{
|
||||
QT_WARNING_PUSH
|
||||
QT_WARNING_DISABLE_DEPRECATED
|
||||
setKey(key);
|
||||
QT_WARNING_POP
|
||||
d_func()->legacyKey = key;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -139,7 +160,10 @@ QSharedMemory::QSharedMemory(const QString &key, QObject *parent)
|
||||
*/
|
||||
QSharedMemory::~QSharedMemory()
|
||||
{
|
||||
setNativeKey(QNativeIpcKey());
|
||||
Q_D(QSharedMemory);
|
||||
if (isAttached())
|
||||
detach();
|
||||
d->cleanHandle();
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -224,7 +248,15 @@ void QSharedMemory::setNativeKey(const QNativeIpcKey &key)
|
||||
detach();
|
||||
d->cleanHandle();
|
||||
d->legacyKey = QString();
|
||||
d->nativeKey = key;
|
||||
if (key.type() == d->nativeKey.type()) {
|
||||
// we can reuse the backend
|
||||
d->nativeKey = key;
|
||||
} else {
|
||||
// we must recreate the backend
|
||||
d->destructBackend();
|
||||
d->nativeKey = key;
|
||||
d->constructBackend();
|
||||
}
|
||||
}
|
||||
|
||||
bool QSharedMemoryPrivate::initKey(SemaphoreAccessMode mode)
|
||||
@ -642,7 +674,13 @@ void QSharedMemoryPrivate::setUnixErrorString(QLatin1StringView function)
|
||||
|
||||
bool QSharedMemory::isKeyTypeSupported(QNativeIpcKey::Type type)
|
||||
{
|
||||
return QSharedMemoryPrivate::DefaultBackend::supports(type);
|
||||
if (!isIpcSupported(IpcType::SharedMemory, type))
|
||||
return false;
|
||||
using Variant = decltype(QSharedMemoryPrivate::backend);
|
||||
return Variant::staticVisit(type, [](auto ptr) {
|
||||
using Impl = std::decay_t<decltype(*ptr)>;
|
||||
return Impl::runtimeSupportCheck();
|
||||
});
|
||||
}
|
||||
|
||||
QNativeIpcKey QSharedMemory::platformSafeKey(const QString &key, QNativeIpcKey::Type type)
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#if QT_CONFIG(sharedmemory)
|
||||
#include "qsystemsemaphore.h"
|
||||
#include "qtipccommon_p.h"
|
||||
#include "private/qobject_p.h"
|
||||
|
||||
#if QT_CONFIG(posix_shm)
|
||||
@ -69,8 +70,10 @@ private:
|
||||
class QSharedMemoryPosix
|
||||
{
|
||||
public:
|
||||
static constexpr bool Enabled = QT_CONFIG(posix_shm);
|
||||
static bool supports(QNativeIpcKey::Type type)
|
||||
{ return type == QNativeIpcKey::Type::PosixRealtime; }
|
||||
static bool runtimeSupportCheck();
|
||||
|
||||
bool handle(QSharedMemoryPrivate *self);
|
||||
bool cleanHandle(QSharedMemoryPrivate *self);
|
||||
@ -84,8 +87,10 @@ public:
|
||||
class QSharedMemorySystemV
|
||||
{
|
||||
public:
|
||||
static constexpr bool Enabled = QT_CONFIG(sysv_shm);
|
||||
static bool supports(QNativeIpcKey::Type type)
|
||||
{ return quint16(type) <= 0xff; }
|
||||
static bool runtimeSupportCheck();
|
||||
|
||||
#if QT_CONFIG(sysv_sem)
|
||||
key_t handle(QSharedMemoryPrivate *self);
|
||||
@ -105,6 +110,12 @@ private:
|
||||
class QSharedMemoryWin32
|
||||
{
|
||||
public:
|
||||
#ifdef Q_OS_WIN32
|
||||
static constexpr bool Enabled = true;
|
||||
#else
|
||||
static constexpr bool Enabled = false;
|
||||
#endif
|
||||
static bool runtimeSupportCheck() { return Enabled; }
|
||||
static bool supports(QNativeIpcKey::Type type)
|
||||
{ return type == QNativeIpcKey::Type::Windows; }
|
||||
|
||||
@ -122,6 +133,10 @@ class Q_AUTOTEST_EXPORT QSharedMemoryPrivate : public QObjectPrivate
|
||||
Q_DECLARE_PUBLIC(QSharedMemory)
|
||||
|
||||
public:
|
||||
QSharedMemoryPrivate(QNativeIpcKey::Type type) : nativeKey(type)
|
||||
{ constructBackend(); }
|
||||
~QSharedMemoryPrivate();
|
||||
|
||||
void *memory = nullptr;
|
||||
qsizetype size = 0;
|
||||
QNativeIpcKey nativeKey;
|
||||
@ -135,36 +150,43 @@ public:
|
||||
#endif
|
||||
QSharedMemory::SharedMemoryError error = QSharedMemory::NoError;
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
using DefaultBackend = QSharedMemoryWin32;
|
||||
#elif defined(QT_POSIX_IPC)
|
||||
using DefaultBackend = QSharedMemoryPosix;
|
||||
#else
|
||||
using DefaultBackend = QSharedMemorySystemV;
|
||||
#endif
|
||||
DefaultBackend backend;
|
||||
union Backend {
|
||||
Backend() {}
|
||||
~Backend() {}
|
||||
QSharedMemoryPosix posix;
|
||||
QSharedMemorySystemV sysv;
|
||||
QSharedMemoryWin32 win32;
|
||||
};
|
||||
QtIpcCommon::IpcStorageVariant<&Backend::posix, &Backend::sysv, &Backend::win32> backend;
|
||||
|
||||
void constructBackend();
|
||||
void destructBackend();
|
||||
bool initKey(SemaphoreAccessMode mode);
|
||||
|
||||
template <typename Lambda> auto visit(const Lambda &lambda)
|
||||
{
|
||||
return backend.visit(nativeKey.type(), lambda);
|
||||
}
|
||||
|
||||
bool handle()
|
||||
{
|
||||
return backend.handle(this);
|
||||
return visit([=](auto p) { return !!p->handle(this); });
|
||||
}
|
||||
bool cleanHandle()
|
||||
{
|
||||
return backend.cleanHandle(this);
|
||||
return visit([=](auto p) { return p->cleanHandle(this); });
|
||||
}
|
||||
bool create(qsizetype size)
|
||||
{
|
||||
return backend.create(this, size);
|
||||
return visit([=](auto p) { return p->create(this, size); });
|
||||
}
|
||||
bool attach(QSharedMemory::AccessMode mode)
|
||||
{
|
||||
return backend.attach(this, mode);
|
||||
return visit([=](auto p) { return p->attach(this, mode); });
|
||||
}
|
||||
bool detach()
|
||||
{
|
||||
return backend.detach(this);
|
||||
return visit([=](auto p) { return p->detach(this); });
|
||||
}
|
||||
|
||||
inline void setError(QSharedMemory::SharedMemoryError e, const QString &message)
|
||||
|
@ -24,6 +24,15 @@ QT_BEGIN_NAMESPACE
|
||||
using namespace Qt::StringLiterals;
|
||||
using namespace QtIpcCommon;
|
||||
|
||||
bool QSharedMemoryPosix::runtimeSupportCheck()
|
||||
{
|
||||
static const bool result = []() {
|
||||
shm_open("", 0, 0); // this WILL fail
|
||||
return errno != ENOSYS;
|
||||
}();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool QSharedMemoryPosix::handle(QSharedMemoryPrivate *self)
|
||||
{
|
||||
// don't allow making handles on empty keys
|
||||
|
@ -20,12 +20,29 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "private/qcore_unix_p.h"
|
||||
#if defined(Q_OS_DARWIN)
|
||||
#include "private/qcore_mac_p.h"
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
using namespace Qt::StringLiterals;
|
||||
using namespace QtIpcCommon;
|
||||
|
||||
bool QSharedMemorySystemV::runtimeSupportCheck()
|
||||
{
|
||||
#if defined(Q_OS_DARWIN)
|
||||
if (qt_apple_isSandboxed())
|
||||
return false;
|
||||
#endif
|
||||
static const bool result = []() {
|
||||
shmget(IPC_PRIVATE, ~size_t(0), 0); // this will fail
|
||||
return errno != ENOSYS;
|
||||
}();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
inline void QSharedMemorySystemV::updateNativeKeyFile(const QNativeIpcKey &nativeKey)
|
||||
{
|
||||
Q_ASSERT(nativeKeyFile.isEmpty() );
|
||||
|
@ -85,33 +85,6 @@ static QNativeIpcKey::Type stringToType(QStringView typeString)
|
||||
return QNativeIpcKey::Type{};
|
||||
}
|
||||
|
||||
#if defined(Q_OS_DARWIN) || defined(QT_BUILD_INTERNAL)
|
||||
/*!
|
||||
\internal
|
||||
|
||||
Returns whether this IPC type \a ipcType and key type \a keyType is
|
||||
supported on the current machine, with a runtime check.
|
||||
*/
|
||||
bool QtIpcCommon::isIpcSupportedAtRuntime(IpcType ipcType, QNativeIpcKey::Type keyType)
|
||||
{
|
||||
switch (keyType) {
|
||||
case QNativeIpcKey::Type::SystemV:
|
||||
break;
|
||||
|
||||
case QNativeIpcKey::Type::PosixRealtime:
|
||||
case QNativeIpcKey::Type::Windows:
|
||||
return isIpcSupported(ipcType, keyType);
|
||||
}
|
||||
|
||||
# if defined(Q_OS_DARWIN)
|
||||
// System V IPC is not supported on Apple platforms if the application is
|
||||
// currently running in a sandbox.
|
||||
return !qt_apple_isSandboxed();
|
||||
# endif
|
||||
return isIpcSupported(ipcType, keyType);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
\internal
|
||||
|
||||
|
@ -57,11 +57,6 @@ static constexpr bool isIpcSupported(IpcType ipcType, QNativeIpcKey::Type type)
|
||||
return QT_CONFIG(sysv_shm);
|
||||
return QT_CONFIG(sysv_sem);
|
||||
}
|
||||
#if defined(Q_OS_DARWIN) || defined(QT_BUILD_INTERNAL)
|
||||
bool isIpcSupportedAtRuntime(IpcType type, QNativeIpcKey::Type);
|
||||
#else
|
||||
static constexpr auto isIpcSupportedAtRuntime = isIpcSupported;
|
||||
#endif
|
||||
|
||||
template <auto Member1, auto... Members> class IpcStorageVariant
|
||||
{
|
||||
|
@ -19,6 +19,7 @@
|
||||
#endif
|
||||
|
||||
#include "private/qtcore-config_p.h"
|
||||
#include "../ipctestcommon.h"
|
||||
|
||||
#define EXISTING_SIZE 1024
|
||||
|
||||
@ -31,15 +32,11 @@ class tst_QSharedMemory : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
tst_QSharedMemory();
|
||||
virtual ~tst_QSharedMemory();
|
||||
|
||||
public Q_SLOTS:
|
||||
void initTestCase();
|
||||
void init();
|
||||
void cleanup();
|
||||
|
||||
|
||||
private slots:
|
||||
// basics
|
||||
void constructor();
|
||||
@ -51,6 +48,8 @@ private slots:
|
||||
void create();
|
||||
void attach_data();
|
||||
void attach();
|
||||
void changeKeyType_data() { attach_data(); }
|
||||
void changeKeyType();
|
||||
void lock();
|
||||
|
||||
// custom edge cases
|
||||
@ -92,7 +91,7 @@ protected:
|
||||
|
||||
QNativeIpcKey platformSafeKey(const QString &key)
|
||||
{
|
||||
QNativeIpcKey::Type keyType = QNativeIpcKey::DefaultTypeForOs;
|
||||
QFETCH_GLOBAL(QNativeIpcKey::Type, keyType);
|
||||
return QSharedMemory::platformSafeKey(mangleKey(key), keyType);
|
||||
}
|
||||
|
||||
@ -108,21 +107,16 @@ protected:
|
||||
|
||||
QList<QNativeIpcKey> keys;
|
||||
QList<QSharedMemory*> jail;
|
||||
QSharedMemory *existingSharedMemory;
|
||||
QSharedMemory *existingSharedMemory = nullptr;
|
||||
int seq = 0;
|
||||
|
||||
private:
|
||||
const QString m_helperBinary;
|
||||
const QString m_helperBinary = "./producerconsumer_helper";
|
||||
};
|
||||
|
||||
tst_QSharedMemory::tst_QSharedMemory()
|
||||
: existingSharedMemory(0)
|
||||
, m_helperBinary("./producerconsumer_helper")
|
||||
{
|
||||
}
|
||||
|
||||
tst_QSharedMemory::~tst_QSharedMemory()
|
||||
void tst_QSharedMemory::initTestCase()
|
||||
{
|
||||
IpcTestCommon::addGlobalTestRows<QSharedMemory>();
|
||||
}
|
||||
|
||||
void tst_QSharedMemory::init()
|
||||
@ -285,6 +279,25 @@ void tst_QSharedMemory::nativeKey()
|
||||
QCOMPARE(sm.size(), 0);
|
||||
|
||||
QCOMPARE(sm.detach(), false);
|
||||
|
||||
// change the key type
|
||||
QNativeIpcKey::Type nextKeyType = IpcTestCommon::nextKeyType(setIpcKey.type());
|
||||
if (nextKeyType != setIpcKey.type()) {
|
||||
QNativeIpcKey setIpcKey2 = QSharedMemory::platformSafeKey(setKey, nextKeyType);
|
||||
sm.setNativeKey(setIpcKey2);
|
||||
|
||||
QCOMPARE(sm.nativeIpcKey(), setIpcKey2);
|
||||
QCOMPARE(sm.nativeKey(), setIpcKey2.nativeKey());
|
||||
|
||||
QCOMPARE(sm.isAttached(), false);
|
||||
|
||||
QCOMPARE(sm.error(), QSharedMemory::NoError);
|
||||
QCOMPARE(sm.errorString(), QString());
|
||||
QVERIFY(!sm.data());
|
||||
QCOMPARE(sm.size(), 0);
|
||||
|
||||
QCOMPARE(sm.detach(), false);
|
||||
}
|
||||
}
|
||||
|
||||
QT_WARNING_PUSH
|
||||
@ -408,6 +421,34 @@ void tst_QSharedMemory::attach()
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QSharedMemory::changeKeyType()
|
||||
{
|
||||
QFETCH(QString, key);
|
||||
QFETCH(bool, exists);
|
||||
QFETCH(QSharedMemory::SharedMemoryError, error);
|
||||
|
||||
QNativeIpcKey nativeKey = platformSafeKey(key);
|
||||
QNativeIpcKey::Type nextKeyType = IpcTestCommon::nextKeyType(nativeKey.type());
|
||||
if (nextKeyType == nativeKey.type())
|
||||
QSKIP("System only supports one key type");
|
||||
// qDebug() << "Changing from" << nativeKey.type() << "to" << nextKeyType;
|
||||
|
||||
QSharedMemory sm(nativeKey);
|
||||
QCOMPARE(sm.attach(), exists);
|
||||
QCOMPARE(sm.error(), error);
|
||||
|
||||
QNativeIpcKey nextKey =
|
||||
QSharedMemory::platformSafeKey(mangleKey(key), nextKeyType);
|
||||
sm.setNativeKey(nextKey);
|
||||
QCOMPARE(sm.isAttached(), false);
|
||||
QVERIFY(!sm.attach());
|
||||
|
||||
if (exists)
|
||||
QCOMPARE(sm.error(), QSharedMemory::NotFound);
|
||||
else
|
||||
QCOMPARE(sm.error(), error);
|
||||
}
|
||||
|
||||
void tst_QSharedMemory::lock()
|
||||
{
|
||||
QSharedMemory shm;
|
||||
|
Loading…
x
Reference in New Issue
Block a user