IPC: add support for multiple backends to QSystemSemaphore
Simultaneously. Change-Id: If4c23ea3719947d790d4fffd17152a29e6c217d3 Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
968d9584ff
commit
32a06e9830
@ -1139,7 +1139,13 @@ qt_internal_extend_target(Core CONDITION UNIX
|
|||||||
SOURCES
|
SOURCES
|
||||||
ipc/qsharedmemory_posix.cpp
|
ipc/qsharedmemory_posix.cpp
|
||||||
ipc/qsharedmemory_systemv.cpp
|
ipc/qsharedmemory_systemv.cpp
|
||||||
|
)
|
||||||
|
qt_internal_extend_target(Core CONDITION QT_FEATURE_posix_sem
|
||||||
|
SOURCES
|
||||||
ipc/qsystemsemaphore_posix.cpp
|
ipc/qsystemsemaphore_posix.cpp
|
||||||
|
)
|
||||||
|
qt_internal_extend_target(Core CONDITION QT_FEATURE_sysv_sem
|
||||||
|
SOURCES
|
||||||
ipc/qsystemsemaphore_systemv.cpp
|
ipc/qsystemsemaphore_systemv.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -3,14 +3,33 @@
|
|||||||
|
|
||||||
#include "qsystemsemaphore.h"
|
#include "qsystemsemaphore.h"
|
||||||
#include "qsystemsemaphore_p.h"
|
#include "qsystemsemaphore_p.h"
|
||||||
#include <qglobal.h>
|
|
||||||
|
#if QT_CONFIG(systemsemaphore)
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
using namespace QtIpcCommon;
|
using namespace QtIpcCommon;
|
||||||
using namespace Qt::StringLiterals;
|
using namespace Qt::StringLiterals;
|
||||||
|
|
||||||
#if QT_CONFIG(systemsemaphore)
|
#if __cplusplus >= 202002L
|
||||||
|
using std::construct_at;
|
||||||
|
#else
|
||||||
|
template <typename T> static void construct_at(T *ptr)
|
||||||
|
{
|
||||||
|
new (ptr) T;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inline void QSystemSemaphorePrivate::constructBackend()
|
||||||
|
{
|
||||||
|
visit([](auto p) { construct_at(p); });
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void QSystemSemaphorePrivate::destructBackend()
|
||||||
|
{
|
||||||
|
visit([](auto p) { std::destroy_at(p); });
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\class QSystemSemaphore
|
\class QSystemSemaphore
|
||||||
@ -113,7 +132,7 @@ QSystemSemaphore::QSystemSemaphore(const QString &key, int initialValue, AccessM
|
|||||||
\sa acquire(), key()
|
\sa acquire(), key()
|
||||||
*/
|
*/
|
||||||
QSystemSemaphore::QSystemSemaphore(const QNativeIpcKey &key, int initialValue, AccessMode mode)
|
QSystemSemaphore::QSystemSemaphore(const QNativeIpcKey &key, int initialValue, AccessMode mode)
|
||||||
: d(new QSystemSemaphorePrivate)
|
: d(new QSystemSemaphorePrivate(key.type()))
|
||||||
{
|
{
|
||||||
setNativeKey(key, initialValue, mode);
|
setNativeKey(key, initialValue, mode);
|
||||||
}
|
}
|
||||||
@ -187,7 +206,15 @@ void QSystemSemaphore::setNativeKey(const QNativeIpcKey &key, int initialValue,
|
|||||||
|
|
||||||
d->clearError();
|
d->clearError();
|
||||||
d->cleanHandle();
|
d->cleanHandle();
|
||||||
|
if (key.type() == d->nativeKey.type()) {
|
||||||
|
// we can reuse the backend
|
||||||
d->nativeKey = key;
|
d->nativeKey = key;
|
||||||
|
} else {
|
||||||
|
// we must recreate the backend
|
||||||
|
d->destructBackend();
|
||||||
|
d->nativeKey = key;
|
||||||
|
d->constructBackend();
|
||||||
|
}
|
||||||
d->initialValue = initialValue;
|
d->initialValue = initialValue;
|
||||||
d->handle(mode);
|
d->handle(mode);
|
||||||
|
|
||||||
@ -373,7 +400,13 @@ void QSystemSemaphorePrivate::setUnixErrorString(QLatin1StringView function)
|
|||||||
|
|
||||||
bool QSystemSemaphore::isKeyTypeSupported(QNativeIpcKey::Type type)
|
bool QSystemSemaphore::isKeyTypeSupported(QNativeIpcKey::Type type)
|
||||||
{
|
{
|
||||||
return QSystemSemaphorePrivate::DefaultBackend::supports(type);
|
if (!isIpcSupported(IpcType::SystemSemaphore, type))
|
||||||
|
return false;
|
||||||
|
using Variant = decltype(QSystemSemaphorePrivate::backend);
|
||||||
|
return Variant::staticVisit(type, [](auto ptr) {
|
||||||
|
using Impl = std::decay_t<decltype(*ptr)>;
|
||||||
|
return Impl::runtimeSupportCheck();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QNativeIpcKey QSystemSemaphore::platformSafeKey(const QString &key, QNativeIpcKey::Type type)
|
QNativeIpcKey QSystemSemaphore::platformSafeKey(const QString &key, QNativeIpcKey::Type type)
|
||||||
@ -386,8 +419,8 @@ QNativeIpcKey QSystemSemaphore::legacyNativeKey(const QString &key, QNativeIpcKe
|
|||||||
return { legacyPlatformSafeKey(key, IpcType::SystemSemaphore, type), type };
|
return { legacyPlatformSafeKey(key, IpcType::SystemSemaphore, type), type };
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // QT_CONFIG(systemsemaphore)
|
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
#include "moc_qsystemsemaphore.cpp"
|
#include "moc_qsystemsemaphore.cpp"
|
||||||
|
|
||||||
|
#endif // QT_CONFIG(systemsemaphore)
|
||||||
|
@ -42,8 +42,10 @@ class QSystemSemaphorePrivate;
|
|||||||
|
|
||||||
struct QSystemSemaphorePosix
|
struct QSystemSemaphorePosix
|
||||||
{
|
{
|
||||||
|
static constexpr bool Enabled = QT_CONFIG(posix_sem);
|
||||||
static bool supports(QNativeIpcKey::Type type)
|
static bool supports(QNativeIpcKey::Type type)
|
||||||
{ return type == QNativeIpcKey::Type::PosixRealtime; }
|
{ return type == QNativeIpcKey::Type::PosixRealtime; }
|
||||||
|
static bool runtimeSupportCheck();
|
||||||
|
|
||||||
bool handle(QSystemSemaphorePrivate *self, QSystemSemaphore::AccessMode mode);
|
bool handle(QSystemSemaphorePrivate *self, QSystemSemaphore::AccessMode mode);
|
||||||
void cleanHandle(QSystemSemaphorePrivate *self);
|
void cleanHandle(QSystemSemaphorePrivate *self);
|
||||||
@ -55,8 +57,10 @@ struct QSystemSemaphorePosix
|
|||||||
|
|
||||||
struct QSystemSemaphoreSystemV
|
struct QSystemSemaphoreSystemV
|
||||||
{
|
{
|
||||||
|
static constexpr bool Enabled = QT_CONFIG(sysv_sem);
|
||||||
static bool supports(QNativeIpcKey::Type type)
|
static bool supports(QNativeIpcKey::Type type)
|
||||||
{ return quint16(type) <= 0xff; }
|
{ return quint16(type) <= 0xff; }
|
||||||
|
static bool runtimeSupportCheck();
|
||||||
|
|
||||||
#if QT_CONFIG(sysv_sem)
|
#if QT_CONFIG(sysv_sem)
|
||||||
key_t handle(QSystemSemaphorePrivate *self, QSystemSemaphore::AccessMode mode);
|
key_t handle(QSystemSemaphorePrivate *self, QSystemSemaphore::AccessMode mode);
|
||||||
@ -73,10 +77,16 @@ struct QSystemSemaphoreSystemV
|
|||||||
|
|
||||||
struct QSystemSemaphoreWin32
|
struct QSystemSemaphoreWin32
|
||||||
{
|
{
|
||||||
|
#ifdef Q_OS_WIN32
|
||||||
|
static constexpr bool Enabled = true;
|
||||||
|
#else
|
||||||
|
static constexpr bool Enabled = false;
|
||||||
|
#endif
|
||||||
static bool supports(QNativeIpcKey::Type type)
|
static bool supports(QNativeIpcKey::Type type)
|
||||||
{ return type == QNativeIpcKey::Type::Windows; }
|
{ return type == QNativeIpcKey::Type::Windows; }
|
||||||
|
static bool runtimeSupportCheck() { return Enabled; }
|
||||||
|
|
||||||
//#ifdef Q_OS_WIN32 but there's nothing Windows-specific in the header
|
// we can declare the members without the #if
|
||||||
Qt::HANDLE handle(QSystemSemaphorePrivate *self, QSystemSemaphore::AccessMode mode);
|
Qt::HANDLE handle(QSystemSemaphorePrivate *self, QSystemSemaphore::AccessMode mode);
|
||||||
void cleanHandle(QSystemSemaphorePrivate *self);
|
void cleanHandle(QSystemSemaphorePrivate *self);
|
||||||
bool modifySemaphore(QSystemSemaphorePrivate *self, int count);
|
bool modifySemaphore(QSystemSemaphorePrivate *self, int count);
|
||||||
@ -87,6 +97,10 @@ struct QSystemSemaphoreWin32
|
|||||||
class QSystemSemaphorePrivate
|
class QSystemSemaphorePrivate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
QSystemSemaphorePrivate(QNativeIpcKey::Type type) : nativeKey(type)
|
||||||
|
{ constructBackend(); }
|
||||||
|
~QSystemSemaphorePrivate() { destructBackend(); }
|
||||||
|
|
||||||
void setWindowsErrorString(QLatin1StringView function); // Windows only
|
void setWindowsErrorString(QLatin1StringView function); // Windows only
|
||||||
void setUnixErrorString(QLatin1StringView function);
|
void setUnixErrorString(QLatin1StringView function);
|
||||||
inline void setError(QSystemSemaphore::SystemSemaphoreError e, const QString &message)
|
inline void setError(QSystemSemaphore::SystemSemaphoreError e, const QString &message)
|
||||||
@ -99,26 +113,34 @@ public:
|
|||||||
int initialValue;
|
int initialValue;
|
||||||
QSystemSemaphore::SystemSemaphoreError error = QSystemSemaphore::NoError;
|
QSystemSemaphore::SystemSemaphoreError error = QSystemSemaphore::NoError;
|
||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
union Backend {
|
||||||
using DefaultBackend = QSystemSemaphoreWin32;
|
Backend() {}
|
||||||
#elif defined(QT_POSIX_IPC)
|
~Backend() {}
|
||||||
using DefaultBackend = QSystemSemaphorePosix;
|
QSystemSemaphorePosix posix;
|
||||||
#else
|
QSystemSemaphoreSystemV sysv;
|
||||||
using DefaultBackend = QSystemSemaphoreSystemV;
|
QSystemSemaphoreWin32 win32;
|
||||||
#endif
|
};
|
||||||
DefaultBackend backend;
|
QtIpcCommon::IpcStorageVariant<&Backend::posix, &Backend::sysv, &Backend::win32> backend;
|
||||||
|
|
||||||
|
void constructBackend();
|
||||||
|
void destructBackend();
|
||||||
|
|
||||||
|
template <typename Lambda> auto visit(const Lambda &lambda)
|
||||||
|
{
|
||||||
|
return backend.visit(nativeKey.type(), lambda);
|
||||||
|
}
|
||||||
|
|
||||||
void handle(QSystemSemaphore::AccessMode mode)
|
void handle(QSystemSemaphore::AccessMode mode)
|
||||||
{
|
{
|
||||||
backend.handle(this, mode);
|
visit([=](auto p) { p->handle(this, mode); });
|
||||||
}
|
}
|
||||||
void cleanHandle()
|
void cleanHandle()
|
||||||
{
|
{
|
||||||
backend.cleanHandle(this);
|
visit([=](auto p) { p->cleanHandle(this); });
|
||||||
}
|
}
|
||||||
bool modifySemaphore(int count)
|
bool modifySemaphore(int count)
|
||||||
{
|
{
|
||||||
return backend.modifySemaphore(this, count);
|
return visit([=](auto p) { return p->modifySemaphore(this, count); });
|
||||||
}
|
}
|
||||||
|
|
||||||
QString legacyKey; // deprecated
|
QString legacyKey; // deprecated
|
||||||
|
@ -35,6 +35,15 @@ QT_BEGIN_NAMESPACE
|
|||||||
|
|
||||||
using namespace Qt::StringLiterals;
|
using namespace Qt::StringLiterals;
|
||||||
|
|
||||||
|
bool QSystemSemaphorePosix::runtimeSupportCheck()
|
||||||
|
{
|
||||||
|
static const bool result = []() {
|
||||||
|
sem_open("/", 0, 0, 0); // this WILL fail
|
||||||
|
return errno != ENOSYS;
|
||||||
|
}();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
bool QSystemSemaphorePosix::handle(QSystemSemaphorePrivate *self, QSystemSemaphore::AccessMode mode)
|
bool QSystemSemaphorePosix::handle(QSystemSemaphorePrivate *self, QSystemSemaphore::AccessMode mode)
|
||||||
{
|
{
|
||||||
if (semaphore != SEM_FAILED)
|
if (semaphore != SEM_FAILED)
|
||||||
|
@ -33,6 +33,19 @@ QT_BEGIN_NAMESPACE
|
|||||||
|
|
||||||
using namespace Qt::StringLiterals;
|
using namespace Qt::StringLiterals;
|
||||||
|
|
||||||
|
bool QSystemSemaphoreSystemV::runtimeSupportCheck()
|
||||||
|
{
|
||||||
|
#if defined(Q_OS_DARWIN)
|
||||||
|
if (qt_apple_isSandboxed())
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
static const bool result = []() {
|
||||||
|
semget(IPC_PRIVATE, -1, 0); // this will fail
|
||||||
|
return errno != ENOSYS;
|
||||||
|
}();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
|
|
||||||
|
@ -63,6 +63,61 @@ bool isIpcSupportedAtRuntime(IpcType type, QNativeIpcKey::Type);
|
|||||||
static constexpr auto isIpcSupportedAtRuntime = isIpcSupported;
|
static constexpr auto isIpcSupportedAtRuntime = isIpcSupported;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
template <auto Member1, auto... Members> class IpcStorageVariant
|
||||||
|
{
|
||||||
|
template <typename T, typename C> static C extractClass(T C::*);
|
||||||
|
template <typename T, typename C> static T extractObject(T C::*);
|
||||||
|
|
||||||
|
template <auto M>
|
||||||
|
static constexpr bool IsEnabled = decltype(extractObject(M))::Enabled;
|
||||||
|
|
||||||
|
static_assert(std::is_member_object_pointer_v<decltype(Member1)>);
|
||||||
|
using StorageType = decltype(extractClass(Member1));
|
||||||
|
StorageType d;
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <typename Lambda> static auto
|
||||||
|
visit_internal(StorageType &storage, QNativeIpcKey::Type keyType, const Lambda &lambda)
|
||||||
|
{
|
||||||
|
if constexpr ((IsEnabled<Member1> || ... || IsEnabled<Members>)) {
|
||||||
|
if constexpr (IsEnabled<Member1>) {
|
||||||
|
using MemberType1 = decltype(extractObject(Member1));
|
||||||
|
if (MemberType1::supports(keyType))
|
||||||
|
return lambda(&(storage.*Member1));
|
||||||
|
}
|
||||||
|
if constexpr ((... || IsEnabled<Members>))
|
||||||
|
return IpcStorageVariant<Members...>::visit_internal(storage, keyType, lambda);
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
} else {
|
||||||
|
// no backends enabled, but we can't return void
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Lambda> auto visit(QNativeIpcKey::Type keyType, const Lambda &lambda)
|
||||||
|
{
|
||||||
|
return visit_internal(d, keyType, lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Lambda> static auto
|
||||||
|
staticVisit(QNativeIpcKey::Type keyType, const Lambda &lambda)
|
||||||
|
{
|
||||||
|
if constexpr ((IsEnabled<Member1> || ... || IsEnabled<Members>)) {
|
||||||
|
if constexpr (IsEnabled<Member1>) {
|
||||||
|
using MemberType1 = decltype(extractObject(Member1));
|
||||||
|
if (MemberType1::supports(keyType))
|
||||||
|
return lambda(static_cast<MemberType1 *>(nullptr));
|
||||||
|
}
|
||||||
|
if constexpr ((... || IsEnabled<Members>))
|
||||||
|
return IpcStorageVariant<Members...>::staticVisit(keyType, lambda);
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
} else {
|
||||||
|
// no backends enabled, but we can't return void
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Q_AUTOTEST_EXPORT QString
|
Q_AUTOTEST_EXPORT QString
|
||||||
legacyPlatformSafeKey(const QString &key, IpcType ipcType,
|
legacyPlatformSafeKey(const QString &key, IpcType ipcType,
|
||||||
QNativeIpcKey::Type type = QNativeIpcKey::legacyDefaultTypeForOs());
|
QNativeIpcKey::Type type = QNativeIpcKey::legacyDefaultTypeForOs());
|
||||||
|
83
tests/auto/corelib/ipc/ipctestcommon.h
Normal file
83
tests/auto/corelib/ipc/ipctestcommon.h
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
// Copyright (C) 2022 Intel Corporation.
|
||||||
|
|
||||||
|
#include <QtTest/QTest>
|
||||||
|
#include <QtCore/QNativeIpcKey>
|
||||||
|
|
||||||
|
namespace IpcTestCommon {
|
||||||
|
static QList<QNativeIpcKey::Type> supportedKeyTypes;
|
||||||
|
|
||||||
|
template <typename IpcClass> void addGlobalTestRows()
|
||||||
|
{
|
||||||
|
qDebug() << "Default key type is" << QNativeIpcKey::DefaultTypeForOs
|
||||||
|
<< "and legacy key type is" << QNativeIpcKey::legacyDefaultTypeForOs();
|
||||||
|
|
||||||
|
#if defined(Q_OS_FREEBSD) || defined(Q_OS_DARWIN) || defined(Q_OS_WIN) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
|
||||||
|
// only enforce that IPC works on the platforms above; other platforms may
|
||||||
|
// have no working backends (notably, Android)
|
||||||
|
QVERIFY(IpcClass::isKeyTypeSupported(QNativeIpcKey::DefaultTypeForOs));
|
||||||
|
QVERIFY(IpcClass::isKeyTypeSupported(QNativeIpcKey::legacyDefaultTypeForOs()));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
auto addRowIfSupported = [](const char *name, QNativeIpcKey::Type type) {
|
||||||
|
if (IpcClass::isKeyTypeSupported(type)) {
|
||||||
|
supportedKeyTypes << type;
|
||||||
|
QTest::newRow(name) << type;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QTest::addColumn<QNativeIpcKey::Type>("keyType");
|
||||||
|
|
||||||
|
addRowIfSupported("Windows", QNativeIpcKey::Type::Windows);
|
||||||
|
addRowIfSupported("POSIX", QNativeIpcKey::Type::PosixRealtime);
|
||||||
|
addRowIfSupported("SystemV-Q", QNativeIpcKey::Type::SystemV);
|
||||||
|
addRowIfSupported("SystemV-T", QNativeIpcKey::Type('T'));
|
||||||
|
|
||||||
|
if (supportedKeyTypes.isEmpty())
|
||||||
|
QSKIP("System reports no supported IPC types.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// rotate through the supported types and find another
|
||||||
|
inline QNativeIpcKey::Type nextKeyType(QNativeIpcKey::Type type)
|
||||||
|
{
|
||||||
|
qsizetype idx = supportedKeyTypes.indexOf(type);
|
||||||
|
Q_ASSERT(idx >= 0);
|
||||||
|
|
||||||
|
++idx;
|
||||||
|
if (idx == supportedKeyTypes.size())
|
||||||
|
idx = 0;
|
||||||
|
return supportedKeyTypes.at(idx);
|
||||||
|
}
|
||||||
|
} // namespace IpcTestCommon
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
namespace QTest {
|
||||||
|
template<> inline char *toString(const QNativeIpcKey::Type &type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case QNativeIpcKey::Type::SystemV: return qstrdup("SystemV");
|
||||||
|
case QNativeIpcKey::Type::PosixRealtime: return qstrdup("PosixRealTime");
|
||||||
|
case QNativeIpcKey::Type::Windows: return qstrdup("Windows");
|
||||||
|
}
|
||||||
|
if (type == QNativeIpcKey::Type{})
|
||||||
|
return qstrdup("Invalid");
|
||||||
|
|
||||||
|
char buf[32];
|
||||||
|
qsnprintf(buf, sizeof(buf), "%u", unsigned(type));
|
||||||
|
return qstrdup(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> inline char *toString(const QNativeIpcKey &key)
|
||||||
|
{
|
||||||
|
if (!key.isValid())
|
||||||
|
return qstrdup("<invalid>");
|
||||||
|
|
||||||
|
const char *type = toString(key.type());
|
||||||
|
const char *text = toString(key.nativeKey());
|
||||||
|
char buf[256];
|
||||||
|
qsnprintf(buf, sizeof(buf), "QNativeIpcKey(%s, %s)", text, type);
|
||||||
|
delete[] type;
|
||||||
|
delete[] text;
|
||||||
|
return qstrdup(buf);
|
||||||
|
}
|
||||||
|
} // namespace QTest
|
||||||
|
QT_END_NAMESPACE
|
@ -4,39 +4,10 @@
|
|||||||
#include <QtCore/QNativeIpcKey>
|
#include <QtCore/QNativeIpcKey>
|
||||||
#include <QtTest/QTest>
|
#include <QtTest/QTest>
|
||||||
|
|
||||||
|
#include "../ipctestcommon.h"
|
||||||
|
|
||||||
using namespace Qt::StringLiterals;
|
using namespace Qt::StringLiterals;
|
||||||
|
|
||||||
namespace QTest {
|
|
||||||
template<> inline char *toString(const QNativeIpcKey::Type &type)
|
|
||||||
{
|
|
||||||
switch (type) {
|
|
||||||
case QNativeIpcKey::Type::SystemV: return qstrdup("SystemV");
|
|
||||||
case QNativeIpcKey::Type::PosixRealtime: return qstrdup("PosixRealTime");
|
|
||||||
case QNativeIpcKey::Type::Windows: return qstrdup("Windows");
|
|
||||||
}
|
|
||||||
if (type == QNativeIpcKey::Type{})
|
|
||||||
return qstrdup("Invalid");
|
|
||||||
|
|
||||||
char buf[32];
|
|
||||||
qsnprintf(buf, sizeof(buf), "%u", unsigned(type));
|
|
||||||
return qstrdup(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<> inline char *toString(const QNativeIpcKey &key)
|
|
||||||
{
|
|
||||||
if (!key.isValid())
|
|
||||||
return qstrdup("<invalid>");
|
|
||||||
|
|
||||||
const char *type = toString(key.type());
|
|
||||||
const char *text = toString(key.nativeKey());
|
|
||||||
char buf[256];
|
|
||||||
qsnprintf(buf, sizeof(buf), "QNativeIpcKey(%s, %s)", text, type);
|
|
||||||
delete[] type;
|
|
||||||
delete[] text;
|
|
||||||
return qstrdup(buf);
|
|
||||||
}
|
|
||||||
} // namespace QTest
|
|
||||||
|
|
||||||
class tst_QNativeIpcKey : public QObject
|
class tst_QNativeIpcKey : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
#include <QtCore/QSystemSemaphore>
|
#include <QtCore/QSystemSemaphore>
|
||||||
#include <QtCore/QTemporaryDir>
|
#include <QtCore/QTemporaryDir>
|
||||||
|
|
||||||
|
#include "../ipctestcommon.h"
|
||||||
|
|
||||||
#define HELPERWAITTIME 10000
|
#define HELPERWAITTIME 10000
|
||||||
|
|
||||||
using namespace Qt::StringLiterals;
|
using namespace Qt::StringLiterals;
|
||||||
@ -32,11 +34,12 @@ public:
|
|||||||
|
|
||||||
QNativeIpcKey platformSafeKey(const QString &key)
|
QNativeIpcKey platformSafeKey(const QString &key)
|
||||||
{
|
{
|
||||||
QNativeIpcKey::Type keyType = QNativeIpcKey::DefaultTypeForOs;
|
QFETCH_GLOBAL(QNativeIpcKey::Type, keyType);
|
||||||
return QSystemSemaphore::platformSafeKey(mangleKey(key), keyType);
|
return QSystemSemaphore::platformSafeKey(mangleKey(key), keyType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
|
void initTestCase();
|
||||||
void init();
|
void init();
|
||||||
void cleanup();
|
void cleanup();
|
||||||
|
|
||||||
@ -46,9 +49,11 @@ private slots:
|
|||||||
void legacyKey_data() { nativeKey_data(); }
|
void legacyKey_data() { nativeKey_data(); }
|
||||||
void legacyKey();
|
void legacyKey();
|
||||||
|
|
||||||
|
void changeKeyType();
|
||||||
void basicacquire();
|
void basicacquire();
|
||||||
void complexacquire();
|
void complexacquire();
|
||||||
void release();
|
void release();
|
||||||
|
void twoSemaphores();
|
||||||
|
|
||||||
void basicProcesses();
|
void basicProcesses();
|
||||||
|
|
||||||
@ -70,6 +75,11 @@ tst_QSystemSemaphore::tst_QSystemSemaphore()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QSystemSemaphore::initTestCase()
|
||||||
|
{
|
||||||
|
IpcTestCommon::addGlobalTestRows<QSystemSemaphore>();
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QSystemSemaphore::init()
|
void tst_QSystemSemaphore::init()
|
||||||
{
|
{
|
||||||
QNativeIpcKey key = platformSafeKey("existing");
|
QNativeIpcKey key = platformSafeKey("existing");
|
||||||
@ -111,6 +121,14 @@ void tst_QSystemSemaphore::nativeKey()
|
|||||||
QCOMPARE(sem.nativeIpcKey(), setIpcKey);
|
QCOMPARE(sem.nativeIpcKey(), setIpcKey);
|
||||||
QCOMPARE(sem.error(), QSystemSemaphore::NoError);
|
QCOMPARE(sem.error(), QSystemSemaphore::NoError);
|
||||||
QCOMPARE(sem.errorString(), QString());
|
QCOMPARE(sem.errorString(), QString());
|
||||||
|
|
||||||
|
// change the key type
|
||||||
|
QNativeIpcKey::Type nextKeyType = IpcTestCommon::nextKeyType(setIpcKey.type());
|
||||||
|
if (nextKeyType != setIpcKey.type()) {
|
||||||
|
QNativeIpcKey setIpcKey2 = QSystemSemaphore::platformSafeKey(setKey, nextKeyType);
|
||||||
|
sem.setNativeKey(setIpcKey2);
|
||||||
|
QCOMPARE(sem.nativeIpcKey(), setIpcKey2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QT_WARNING_PUSH
|
QT_WARNING_PUSH
|
||||||
@ -132,6 +150,21 @@ void tst_QSystemSemaphore::legacyKey()
|
|||||||
}
|
}
|
||||||
QT_WARNING_POP
|
QT_WARNING_POP
|
||||||
|
|
||||||
|
void tst_QSystemSemaphore::changeKeyType()
|
||||||
|
{
|
||||||
|
QString keyName = "changeKeyType";
|
||||||
|
QNativeIpcKey key = platformSafeKey(keyName);
|
||||||
|
QNativeIpcKey otherKey =
|
||||||
|
QSystemSemaphore::platformSafeKey(mangleKey(keyName), IpcTestCommon::nextKeyType(key.type()));
|
||||||
|
if (key == otherKey)
|
||||||
|
QSKIP("System only supports one key type");
|
||||||
|
|
||||||
|
QSystemSemaphore sem1(key, 1, QSystemSemaphore::Create);
|
||||||
|
QSystemSemaphore sem2(otherKey);
|
||||||
|
sem1.setNativeKey(otherKey);
|
||||||
|
sem2.setNativeKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QSystemSemaphore::basicacquire()
|
void tst_QSystemSemaphore::basicacquire()
|
||||||
{
|
{
|
||||||
QNativeIpcKey key = platformSafeKey("basicacquire");
|
QNativeIpcKey key = platformSafeKey("basicacquire");
|
||||||
@ -185,6 +218,17 @@ void tst_QSystemSemaphore::release()
|
|||||||
QCOMPARE(sem.errorString(), QString());
|
QCOMPARE(sem.errorString(), QString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QSystemSemaphore::twoSemaphores()
|
||||||
|
{
|
||||||
|
QNativeIpcKey key = platformSafeKey("twoSemaphores");
|
||||||
|
QSystemSemaphore sem1(key, 1, QSystemSemaphore::Create);
|
||||||
|
QSystemSemaphore sem2(key);
|
||||||
|
QVERIFY(sem1.acquire());
|
||||||
|
QVERIFY(sem2.release());
|
||||||
|
QVERIFY(sem1.acquire());
|
||||||
|
QVERIFY(sem2.release());
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QSystemSemaphore::basicProcesses()
|
void tst_QSystemSemaphore::basicProcesses()
|
||||||
{
|
{
|
||||||
#if !QT_CONFIG(process)
|
#if !QT_CONFIG(process)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user