diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qsystemsemaphore.cpp b/src/corelib/doc/snippets/code/src_corelib_kernel_qsystemsemaphore.cpp index d1afba270e..45da88c75d 100644 --- a/src/corelib/doc/snippets/code/src_corelib_kernel_qsystemsemaphore.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qsystemsemaphore.cpp @@ -2,7 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause //! [0] -QSystemSemaphore sem("market", 3, QSystemSemaphore::Create); +QSystemSemaphore sem(QSystemSemaphore::platformSafeKey("market"), 3, QSystemSemaphore::Create); // resources available == 3 sem.acquire(); // resources available == 2 sem.acquire(); // resources available == 1 @@ -13,7 +13,7 @@ sem.release(2); // resources available == 3 //! [1] -QSystemSemaphore sem("market", 5, QSystemSemaphore::Create); +QSystemSemaphore sem(QSystemSemaphore::platformSafeKey("market"), 5, QSystemSemaphore::Create); for (int i = 0; i < 5; ++i) // acquire all 5 resources sem.acquire(); sem.release(5); // release the 5 resources diff --git a/src/corelib/ipc/qsharedmemory.cpp b/src/corelib/ipc/qsharedmemory.cpp index dea41c798e..a877545e6f 100644 --- a/src/corelib/ipc/qsharedmemory.cpp +++ b/src/corelib/ipc/qsharedmemory.cpp @@ -12,11 +12,35 @@ # include #endif +#ifndef MAX_PATH +# define MAX_PATH PATH_MAX +#endif + QT_BEGIN_NAMESPACE +#if QT_CONFIG(sharedmemory) + +using namespace QtIpcCommon; using namespace Qt::StringLiterals; -#if QT_CONFIG(sharedmemory) +#if QT_CONFIG(systemsemaphore) +inline QNativeIpcKey QSharedMemoryPrivate::semaphoreNativeKey() const +{ + if (isIpcSupported(IpcType::SharedMemory, QNativeIpcKey::Type::Windows) + && nativeKey.type() == QNativeIpcKey::Type::Windows) { + // native keys are plain kernel object names, limited to MAX_PATH + auto suffix = "_sem"_L1; + QString semkey = nativeKey.nativeKey(); + semkey.truncate(MAX_PATH - suffix.size() - 1); + semkey += suffix; + return { semkey, QNativeIpcKey::Type::Windows }; + } + + // System V and POSIX keys appear to operate in different namespaces, so we + // can just use the same native key + return nativeKey; +} +#endif /*! \class QSharedMemory @@ -293,8 +317,8 @@ bool QSharedMemoryPrivate::initKey() if (!cleanHandle()) return false; #if QT_CONFIG(systemsemaphore) - systemSemaphore.setKey(QString(), 1); - systemSemaphore.setKey(key, 1); + systemSemaphore.setNativeKey(QNativeIpcKey(), 1); + systemSemaphore.setNativeKey(semaphoreNativeKey(), 1); if (systemSemaphore.error() != QSystemSemaphore::NoError) { QString function = "QSharedMemoryPrivate::initKey"_L1; errorString = QSharedMemory::tr("%1: unable to set key on lock").arg(function); diff --git a/src/corelib/ipc/qsharedmemory_p.h b/src/corelib/ipc/qsharedmemory_p.h index 7db4afa21f..f61065713f 100644 --- a/src/corelib/ipc/qsharedmemory_p.h +++ b/src/corelib/ipc/qsharedmemory_p.h @@ -115,7 +115,7 @@ public: QString nativeKey; QString errorString; #if QT_CONFIG(systemsemaphore) - QSystemSemaphore systemSemaphore{QString()}; + QSystemSemaphore systemSemaphore{ QNativeIpcKey() }; bool lockedByMe = false; #endif QSharedMemory::SharedMemoryError error = QSharedMemory::NoError; @@ -166,6 +166,7 @@ public: } return true; } + QNativeIpcKey semaphoreNativeKey() const; #endif // QT_CONFIG(systemsemaphore) }; diff --git a/src/corelib/ipc/qsystemsemaphore.cpp b/src/corelib/ipc/qsystemsemaphore.cpp index 9b42b93995..a5c236824f 100644 --- a/src/corelib/ipc/qsystemsemaphore.cpp +++ b/src/corelib/ipc/qsystemsemaphore.cpp @@ -7,6 +7,9 @@ QT_BEGIN_NAMESPACE +using namespace QtIpcCommon; +using namespace Qt::StringLiterals; + #if QT_CONFIG(systemsemaphore) /*! @@ -16,12 +19,10 @@ QT_BEGIN_NAMESPACE \brief The QSystemSemaphore class provides a general counting system semaphore. - A semaphore is a generalization of a mutex. While a mutex can be - locked only once, a semaphore can be acquired multiple times. - Typically, a semaphore is used to protect a certain number of - identical resources. + A system semaphore is a generalization of \l QSemaphore. Typically, a + semaphore is used to protect a certain number of identical resources. - Like its lighter counterpart QSemaphore, a QSystemSemaphore can be + Like its lighter counterpart, a QSystemSemaphore can be accessed from multiple \l {QThread} {threads}. Unlike QSemaphore, a QSystemSemaphore can also be accessed from multiple \l {QProcess} {processes}. This means QSystemSemaphore is a much heavier class, so @@ -38,66 +39,43 @@ QT_BEGIN_NAMESPACE process. The function can also be called with a parameter n > 1, which releases n resources. - A system semaphore is created with a string key that other processes - can use to use the same semaphore. + System semaphores are identified by a key, represented by \l QNativeIpcKey. A + key can be created in a cross-platform manner by using platformSafeKey(). A + system semaphore is created by the QSystemSemaphore constructor when passed + an access mode parameter of AccessMode::Create. Once it is created, other + processes may attach to the same semaphore using the same key and an access + mode parameter of AccessMode::Open. Example: Create a system semaphore \snippet code/src_corelib_kernel_qsystemsemaphore.cpp 0 - A typical application of system semaphores is for controlling access - to a circular buffer shared by a producer process and a consumer - processes. + For details on the key types, platform-specific limitations, and + interoperability with older or non-Qt applications, see the \l{Native IPC + Key} documentation. That includes important information for sandboxed + applications on Apple platforms, including all apps obtained via the Apple + App Store. - \section1 Platform-Specific Behavior - - When using this class, be aware of the following platform - differences: - - \b{Windows:} QSystemSemaphore does not own its underlying system - semaphore. Windows owns it. This means that when all instances of - QSystemSemaphore for a particular key have been destroyed, either by - having their destructors called, or because one or more processes - crash, Windows removes the underlying system semaphore. - - \b{Unix:} - - \list - \li QSystemSemaphore owns the underlying system semaphore - in Unix systems. This means that the last process having an instance of - QSystemSemaphore for a particular key must remove the underlying - system semaphore in its destructor. If the last process crashes - without running the QSystemSemaphore destructor, Unix does not - automatically remove the underlying system semaphore, and the - semaphore survives the crash. A subsequent process that constructs a - QSystemSemaphore with the same key will then be given the existing - system semaphore. In that case, if the QSystemSemaphore constructor - has specified its \l {QSystemSemaphore::AccessMode} {access mode} as - \l {QSystemSemaphore::} {Open}, its initial resource count will not - be reset to the one provided but remain set to the value it received - in the crashed process. To protect against this, the first process - to create a semaphore for a particular key (usually a server), must - pass its \l {QSystemSemaphore::AccessMode} {access mode} as \l - {QSystemSemaphore::} {Create}, which will force Unix to reset the - resource count in the underlying system semaphore. - - \li When a process using QSystemSemaphore terminates for - any reason, Unix automatically reverses the effect of all acquire - operations that were not released. Thus if the process acquires a - resource and then exits without releasing it, Unix will release that - resource. - - \endlist - - \b{Apple platforms:} Sandboxed applications (including apps - shipped through the Apple App Store) require the key to - be in the form \c {/}, - as documented \l {https://developer.apple.com/library/archive/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW24} - {here} and \l {https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_application-groups} - {here}, and the key length is limited to 30 characters. - - \sa QSharedMemory, QSemaphore + \sa Inter-Process Communication, QSharedMemory, QSemaphore */ +/*! + \deprecated + + Requests a system semaphore identified by the legacy key \a key. This + constructor does the same as: + + \code + QSystemSemaphore(QSystemSemaphore::legacyNativeKey(key), initialValue, mode) + \endcode + + except that it stores the legacy native key to retrieve using key(). + */ +QSystemSemaphore::QSystemSemaphore(const QString &key, int initialValue, AccessMode mode) + : QSystemSemaphore(legacyNativeKey(key), initialValue, mode) +{ + d->legacyKey = key; +} + /*! Requests a system semaphore for the specified \a key. The parameters \a initialValue and \a mode are used according to the following @@ -134,10 +112,10 @@ QT_BEGIN_NAMESPACE \sa acquire(), key() */ -QSystemSemaphore::QSystemSemaphore(const QString &key, int initialValue, AccessMode mode) +QSystemSemaphore::QSystemSemaphore(const QNativeIpcKey &key, int initialValue, AccessMode mode) : d(new QSystemSemaphorePrivate) { - setKey(key, initialValue, mode); + setNativeKey(key, initialValue, mode); } /*! @@ -192,16 +170,25 @@ QSystemSemaphore::~QSystemSemaphore() create a new semaphore with the new \a key. The \a initialValue and \a mode parameters are as defined for the constructor. - \sa QSystemSemaphore(), key() + This function is useful if the native key was shared from another process. + See \l{Native IPC Keys} for more information. + + \sa QSystemSemaphore(), nativeKey() */ -void QSystemSemaphore::setKey(const QString &key, int initialValue, AccessMode mode) +void QSystemSemaphore::setNativeKey(const QNativeIpcKey &key, int initialValue, AccessMode mode) { - if (key == d->key && mode == Open) + if (key == d->nativeKey && mode == Open) return; + if (!isKeyTypeSupported(key.type())) { + d->setError(KeyError, tr("%1: unsupported key type") + .arg("QSystemSemaphore::setNativeKey"_L1)); + return; + } + d->clearError(); #if !defined(Q_OS_WIN) && !defined(QT_POSIX_IPC) // optimization to not destroy/create the file & semaphore - if (key == d->key && mode == Create && d->backend.createdSemaphore && d->backend.createdFile) { + if (key == d->nativeKey && mode == Create && d->backend.createdSemaphore && d->backend.createdFile) { d->initialValue = initialValue; d->backend.unix_key = -1; d->handle(mode); @@ -209,22 +196,55 @@ void QSystemSemaphore::setKey(const QString &key, int initialValue, AccessMode m } #endif d->cleanHandle(); - d->key = key; + d->nativeKey = key; d->initialValue = initialValue; - // cache the file name so it doesn't have to be generated all the time. - d->fileName = d->makeKeyFileName(); d->handle(mode); + + d->legacyKey.clear(); } /*! Returns the key assigned to this system semaphore. The key is the name by which the semaphore can be accessed from other processes. + You can use the native key to access system semaphores that have not been + created by Qt, or to grant access to non-Qt applications. See \l{Native IPC + Keys} for more information. + + \sa setNativeKey() + */ +QNativeIpcKey QSystemSemaphore::nativeIpcKey() const +{ + return d->nativeKey; +} + +/*! + \deprecated + This function works the same as the constructor. It reconstructs + this QSystemSemaphore object. If the new \a key is different from + the old key, calling this function is like calling the destructor of + the semaphore with the old key, then calling the constructor to + create a new semaphore with the new \a key. The \a initialValue and + \a mode parameters are as defined for the constructor. + + \sa QSystemSemaphore(), key() + */ +void QSystemSemaphore::setKey(const QString &key, int initialValue, AccessMode mode) +{ + setNativeKey(legacyNativeKey(key), initialValue, mode); + d->legacyKey = key; +} + +/*! + \deprecated + Returns the legacy key assigned to this system semaphore. The key is the + name by which the semaphore can be accessed from other processes. + \sa setKey() */ QString QSystemSemaphore::key() const { - return d->key; + return d->legacyKey; } /*! @@ -360,6 +380,21 @@ void QSystemSemaphorePrivate::setUnixErrorString(QLatin1StringView function) } } +bool QSystemSemaphore::isKeyTypeSupported(QNativeIpcKey::Type type) +{ + return QSystemSemaphorePrivate::DefaultBackend::supports(type); +} + +QNativeIpcKey QSystemSemaphore::platformSafeKey(const QString &key, QNativeIpcKey::Type type) +{ + return { QtIpcCommon::platformSafeKey(key, IpcType::SystemSemaphore, type), type }; +} + +QNativeIpcKey QSystemSemaphore::legacyNativeKey(const QString &key, QNativeIpcKey::Type type) +{ + return { legacyPlatformSafeKey(key, IpcType::SystemSemaphore, type), type }; +} + #endif // QT_CONFIG(systemsemaphore) QT_END_NAMESPACE diff --git a/src/corelib/ipc/qsystemsemaphore.h b/src/corelib/ipc/qsystemsemaphore.h index 7843ec8f04..2eec661ab3 100644 --- a/src/corelib/ipc/qsystemsemaphore.h +++ b/src/corelib/ipc/qsystemsemaphore.h @@ -5,12 +5,12 @@ #define QSYSTEMSEMAPHORE_H #include +#include #include #include QT_BEGIN_NAMESPACE - #if QT_CONFIG(systemsemaphore) class QSystemSemaphorePrivate; @@ -38,11 +38,23 @@ public: UnknownError }; - QSystemSemaphore(const QString &key, int initialValue = 0, AccessMode mode = Open); + QSystemSemaphore(const QNativeIpcKey &key, int initialValue = 0, AccessMode = Open); ~QSystemSemaphore(); + void setNativeKey(const QNativeIpcKey &key, int initialValue = 0, AccessMode = Open); + void setNativeKey(const QString &key, int initialValue = 0, AccessMode mode = Open, + QNativeIpcKey::Type type = QNativeIpcKey::legacyDefaultTypeForOs()) + { setNativeKey({ key, type }, initialValue, mode); } + QNativeIpcKey nativeIpcKey() const; + +#if QT_DEPRECATED_SINCE(6, 9) + QT_DEPRECATED_VERSION_X_6_9("Please refer to 'Native IPC Key' documentation") + QSystemSemaphore(const QString &key, int initialValue = 0, AccessMode mode = Open); + QT_DEPRECATED_VERSION_X_6_9("Please refer to 'Native IPC Key' documentation") void setKey(const QString &key, int initialValue = 0, AccessMode mode = Open); + QT_DEPRECATED_VERSION_X_6_9("Please refer to 'Native IPC Key' documentation") QString key() const; +#endif bool acquire(); bool release(int n = 1); @@ -50,6 +62,12 @@ public: SystemSemaphoreError error() const; QString errorString() const; + static bool isKeyTypeSupported(QNativeIpcKey::Type type) Q_DECL_CONST_FUNCTION; + static QNativeIpcKey platformSafeKey(const QString &key, + QNativeIpcKey::Type type = QNativeIpcKey::DefaultTypeForOs); + static QNativeIpcKey legacyNativeKey(const QString &key, + QNativeIpcKey::Type type = QNativeIpcKey::legacyDefaultTypeForOs()); + private: Q_DISABLE_COPY(QSystemSemaphore) QScopedPointer d; diff --git a/src/corelib/ipc/qsystemsemaphore_p.h b/src/corelib/ipc/qsystemsemaphore_p.h index 92aa0e3354..45d27f1f51 100644 --- a/src/corelib/ipc/qsystemsemaphore_p.h +++ b/src/corelib/ipc/qsystemsemaphore_p.h @@ -42,6 +42,9 @@ class QSystemSemaphorePrivate; struct QSystemSemaphorePosix { + static bool supports(QNativeIpcKey::Type type) + { return type == QNativeIpcKey::Type::PosixRealtime; } + bool handle(QSystemSemaphorePrivate *self, QSystemSemaphore::AccessMode mode); void cleanHandle(QSystemSemaphorePrivate *self); bool modifySemaphore(QSystemSemaphorePrivate *self, int count); @@ -52,11 +55,15 @@ struct QSystemSemaphorePosix struct QSystemSemaphoreSystemV { + static bool supports(QNativeIpcKey::Type type) + { return quint16(type) <= 0xff; } + #if QT_CONFIG(sysv_sem) key_t handle(QSystemSemaphorePrivate *self, QSystemSemaphore::AccessMode mode); void cleanHandle(QSystemSemaphorePrivate *self); bool modifySemaphore(QSystemSemaphorePrivate *self, int count); + QByteArray nativeKeyFile; key_t unix_key = -1; int semaphore = -1; bool createdFile = false; @@ -66,6 +73,9 @@ struct QSystemSemaphoreSystemV struct QSystemSemaphoreWin32 { + static bool supports(QNativeIpcKey::Type type) + { return type == QNativeIpcKey::Type::Windows; } + //#ifdef Q_OS_WIN32 but there's nothing Windows-specific in the header Qt::HANDLE handle(QSystemSemaphorePrivate *self, QSystemSemaphore::AccessMode mode); void cleanHandle(QSystemSemaphorePrivate *self); @@ -77,11 +87,6 @@ struct QSystemSemaphoreWin32 class QSystemSemaphorePrivate { public: - QString makeKeyFileName() - { - return QtIpcCommon::legacyPlatformSafeKey(key, QtIpcCommon::IpcType::SystemSemaphore); - } - void setWindowsErrorString(QLatin1StringView function); // Windows only void setUnixErrorString(QLatin1StringView function); inline void setError(QSystemSemaphore::SystemSemaphoreError e, const QString &message) @@ -89,8 +94,7 @@ public: inline void clearError() { setError(QSystemSemaphore::NoError, QString()); } - QString key; - QString fileName; + QNativeIpcKey nativeKey; QString errorString; int initialValue; QSystemSemaphore::SystemSemaphoreError error = QSystemSemaphore::NoError; @@ -116,6 +120,8 @@ public: { return backend.modifySemaphore(this, count); } + + QString legacyKey; // deprecated }; QT_END_NAMESPACE diff --git a/src/corelib/ipc/qsystemsemaphore_posix.cpp b/src/corelib/ipc/qsystemsemaphore_posix.cpp index 3a26ccf7e3..257a571d51 100644 --- a/src/corelib/ipc/qsystemsemaphore_posix.cpp +++ b/src/corelib/ipc/qsystemsemaphore_posix.cpp @@ -34,15 +34,14 @@ bool QSystemSemaphorePosix::handle(QSystemSemaphorePrivate *self, QSystemSemapho if (semaphore != SEM_FAILED) return true; // we already have a semaphore - if (self->fileName.isEmpty()) { + const QByteArray semName = QFile::encodeName(self->nativeKey.nativeKey()); + if (semName.isEmpty()) { self->setError(QSystemSemaphore::KeyError, QSystemSemaphore::tr("%1: key is empty") .arg("QSystemSemaphore::handle"_L1)); return false; } - const QByteArray semName = QFile::encodeName(self->fileName); - // Always try with O_EXCL so we know whether we created the semaphore. int oflag = O_CREAT | O_EXCL; for (int tryNum = 0, maxTries = 1; tryNum < maxTries; ++tryNum) { @@ -92,8 +91,8 @@ void QSystemSemaphorePosix::cleanHandle(QSystemSemaphorePrivate *self) } if (createdSemaphore) { - if (::sem_unlink(QFile::encodeName(self->fileName).constData()) == -1 - && errno != ENOENT) { + const QByteArray semName = QFile::encodeName(self->nativeKey.nativeKey()); + if (::sem_unlink(semName) == -1 && errno != ENOENT) { self->setUnixErrorString("QSystemSemaphore::cleanHandle (sem_unlink)"_L1); #if defined QSYSTEMSEMAPHORE_DEBUG qDebug("QSystemSemaphorePosix::cleanHandle sem_unlink failed."); diff --git a/src/corelib/ipc/qsystemsemaphore_systemv.cpp b/src/corelib/ipc/qsystemsemaphore_systemv.cpp index 08181f903a..2078caea9a 100644 --- a/src/corelib/ipc/qsystemsemaphore_systemv.cpp +++ b/src/corelib/ipc/qsystemsemaphore_systemv.cpp @@ -52,19 +52,19 @@ key_t QSystemSemaphoreSystemV::handle(QSystemSemaphorePrivate *self, QSystemSema } #endif - if (self->key.isEmpty()) { + nativeKeyFile = QFile::encodeName(self->nativeKey.nativeKey()); + if (nativeKeyFile.isEmpty()) { self->setError(QSystemSemaphore::KeyError, QSystemSemaphore::tr("%1: key is empty") .arg("QSystemSemaphore::handle:"_L1)); return -1; } - // ftok requires that an actual file exists somewhere if (-1 != unix_key) return unix_key; - // Create the file needed for ftok - int built = QtIpcCommon::createUnixKeyFile(QFile::encodeName(self->fileName)); + // ftok requires that an actual file exists somewhere + int built = QtIpcCommon::createUnixKeyFile(nativeKeyFile); if (-1 == built) { self->setError(QSystemSemaphore::KeyError, QSystemSemaphore::tr("%1: unable to make key") @@ -75,7 +75,7 @@ key_t QSystemSemaphoreSystemV::handle(QSystemSemaphorePrivate *self, QSystemSema createdFile = (1 == built); // Get the unix key for the created file - unix_key = ftok(QFile::encodeName(self->fileName).constData(), 'Q'); + unix_key = ftok(nativeKeyFile, int(self->nativeKey.type())); if (-1 == unix_key) { self->setError(QSystemSemaphore::KeyError, QSystemSemaphore::tr("%1: ftok failed") @@ -129,7 +129,7 @@ void QSystemSemaphoreSystemV::cleanHandle(QSystemSemaphorePrivate *self) // remove the file if we made it if (createdFile) { - QFile::remove(self->fileName); + unlink(nativeKeyFile.constData()); createdFile = false; } diff --git a/src/corelib/ipc/qsystemsemaphore_win.cpp b/src/corelib/ipc/qsystemsemaphore_win.cpp index 13da3f301c..f42fecf71f 100644 --- a/src/corelib/ipc/qsystemsemaphore_win.cpp +++ b/src/corelib/ipc/qsystemsemaphore_win.cpp @@ -42,13 +42,13 @@ void QSystemSemaphorePrivate::setWindowsErrorString(QLatin1StringView function) HANDLE QSystemSemaphoreWin32::handle(QSystemSemaphorePrivate *self, QSystemSemaphore::AccessMode) { // don't allow making handles on empty keys - if (self->key.isEmpty()) + if (self->nativeKey.isEmpty()) return 0; // Create it if it doesn't already exists. if (semaphore == 0) { semaphore = CreateSemaphore(0, self->initialValue, MAXLONG, - reinterpret_cast(self->fileName.utf16())); + reinterpret_cast(self->nativeKey.nativeKey().utf16())); if (semaphore == NULL) self->setWindowsErrorString("QSystemSemaphore::handle"_L1); } diff --git a/src/tools/androidtestrunner/main.cpp b/src/tools/androidtestrunner/main.cpp index 60dfc84ab3..0a2c8e63b8 100644 --- a/src/tools/androidtestrunner/main.cpp +++ b/src/tools/androidtestrunner/main.cpp @@ -478,7 +478,8 @@ struct RunnerLocker { runner.release(); } - QSystemSemaphore runner{QStringLiteral("androidtestrunner"), 1, QSystemSemaphore::Open}; + QSystemSemaphore runner{ QSystemSemaphore::platformSafeKey(u"androidtestrunner"_s), + 1, QSystemSemaphore::Open }; }; int main(int argc, char *argv[]) diff --git a/tests/auto/corelib/ipc/qsystemsemaphore/acquirerelease/main.cpp b/tests/auto/corelib/ipc/qsystemsemaphore/acquirerelease/main.cpp index b2de1d764c..e170789f75 100644 --- a/tests/auto/corelib/ipc/qsystemsemaphore/acquirerelease/main.cpp +++ b/tests/auto/corelib/ipc/qsystemsemaphore/acquirerelease/main.cpp @@ -6,9 +6,9 @@ #include #include -int acquire(int count = 1) +int acquire(const QNativeIpcKey &key, int count = 1) { - QSystemSemaphore sem("store"); + QSystemSemaphore sem(key); for (int i = 0; i < count; ++i) { if (!sem.acquire()) { @@ -20,9 +20,9 @@ int acquire(int count = 1) return EXIT_SUCCESS; } -int release() +int release(const QNativeIpcKey &key) { - QSystemSemaphore sem("store"); + QSystemSemaphore sem(key); if (!sem.release()) { qWarning() << "Could not release" << sem.key(); return EXIT_FAILURE; @@ -31,9 +31,9 @@ int release() return EXIT_SUCCESS; } -int acquirerelease() +int acquirerelease(const QNativeIpcKey &key) { - QSystemSemaphore sem("store"); + QSystemSemaphore sem(key); if (!sem.acquire()) { qWarning() << "Could not acquire" << sem.key(); return EXIT_FAILURE; @@ -52,11 +52,15 @@ int main(int argc, char *argv[]) QStringList arguments = app.arguments(); // binary name is not used here arguments.takeFirst(); - if (arguments.size() < 1) { - qWarning("Please call the helper with the function to call as argument"); + if (arguments.size() < 2) { + fprintf(stderr, + "Usage: %s [other args...]\n", + argv[0]); return EXIT_FAILURE; } + QString function = arguments.takeFirst(); + QNativeIpcKey key = QNativeIpcKey::fromString(arguments.takeFirst()); if (function == QLatin1String("acquire")) { int count = 1; bool ok = true; @@ -64,11 +68,11 @@ int main(int argc, char *argv[]) count = arguments.takeFirst().toInt(&ok); if (!ok) count = 1; - return acquire(count); + return acquire(key, count); } else if (function == QLatin1String("release")) { - return release(); + return release(key); } else if (function == QLatin1String("acquirerelease")) { - return acquirerelease(); + return acquirerelease(key); } else { qWarning() << "Unknown function" << function; } diff --git a/tests/auto/corelib/ipc/qsystemsemaphore/tst_qsystemsemaphore.cpp b/tests/auto/corelib/ipc/qsystemsemaphore/tst_qsystemsemaphore.cpp index 1ba789e12d..7e5ba91cba 100644 --- a/tests/auto/corelib/ipc/qsystemsemaphore/tst_qsystemsemaphore.cpp +++ b/tests/auto/corelib/ipc/qsystemsemaphore/tst_qsystemsemaphore.cpp @@ -1,4 +1,5 @@ // Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2022 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include @@ -20,13 +21,21 @@ class tst_QSystemSemaphore : public QObject public: tst_QSystemSemaphore(); + QNativeIpcKey platformSafeKey(const QString &key) + { + QNativeIpcKey::Type keyType = QNativeIpcKey::DefaultTypeForOs; + return QSystemSemaphore::platformSafeKey(key, keyType); + } + public Q_SLOTS: void init(); void cleanup(); private slots: - void key_data(); - void key(); + void nativeKey_data(); + void nativeKey(); + void legacyKey_data() { nativeKey_data(); } + void legacyKey(); void basicacquire(); void complexacquire(); @@ -37,9 +46,7 @@ private slots: void processes_data(); void processes(); -#if !defined(Q_OS_WIN) && !defined(QT_POSIX_IPC) void undo(); -#endif void initialValue(); private: @@ -55,7 +62,8 @@ tst_QSystemSemaphore::tst_QSystemSemaphore() void tst_QSystemSemaphore::init() { - existingLock = new QSystemSemaphore(EXISTING_SHARE, 1, QSystemSemaphore::Create); + QNativeIpcKey key = platformSafeKey(EXISTING_SHARE); + existingLock = new QSystemSemaphore(key, 1, QSystemSemaphore::Create); } void tst_QSystemSemaphore::cleanup() @@ -63,7 +71,7 @@ void tst_QSystemSemaphore::cleanup() delete existingLock; } -void tst_QSystemSemaphore::key_data() +void tst_QSystemSemaphore::nativeKey_data() { QTest::addColumn("constructorKey"); QTest::addColumn("setKey"); @@ -76,7 +84,27 @@ void tst_QSystemSemaphore::key_data() /*! Basic key testing */ -void tst_QSystemSemaphore::key() +void tst_QSystemSemaphore::nativeKey() +{ + QFETCH(QString, constructorKey); + QFETCH(QString, setKey); + QNativeIpcKey constructorIpcKey = platformSafeKey(constructorKey); + QNativeIpcKey setIpcKey = platformSafeKey(setKey); + + QSystemSemaphore sem(constructorIpcKey); + QCOMPARE(sem.nativeIpcKey(), constructorIpcKey); + QCOMPARE(sem.error(), QSystemSemaphore::NoError); + QCOMPARE(sem.errorString(), QString()); + + sem.setNativeKey(setIpcKey); + QCOMPARE(sem.nativeIpcKey(), setIpcKey); + QCOMPARE(sem.error(), QSystemSemaphore::NoError); + QCOMPARE(sem.errorString(), QString()); +} + +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED +void tst_QSystemSemaphore::legacyKey() { QFETCH(QString, constructorKey); QFETCH(QString, setKey); @@ -91,10 +119,12 @@ void tst_QSystemSemaphore::key() QCOMPARE(sem.error(), QSystemSemaphore::NoError); QCOMPARE(sem.errorString(), QString()); } +QT_WARNING_POP void tst_QSystemSemaphore::basicacquire() { - QSystemSemaphore sem("QSystemSemaphore_basicacquire", 1, QSystemSemaphore::Create); + QNativeIpcKey key = platformSafeKey("QSystemSemaphore_basicacquire"); + QSystemSemaphore sem(key, 1, QSystemSemaphore::Create); QVERIFY(sem.acquire()); QCOMPARE(sem.error(), QSystemSemaphore::NoError); QVERIFY(sem.release()); @@ -104,7 +134,8 @@ void tst_QSystemSemaphore::basicacquire() void tst_QSystemSemaphore::complexacquire() { - QSystemSemaphore sem("QSystemSemaphore_complexacquire", 2, QSystemSemaphore::Create); + QNativeIpcKey key = platformSafeKey("QSystemSemaphore_complexacquire"); + QSystemSemaphore sem(key, 2, QSystemSemaphore::Create); QVERIFY(sem.acquire()); QCOMPARE(sem.error(), QSystemSemaphore::NoError); QVERIFY(sem.release()); @@ -126,7 +157,8 @@ void tst_QSystemSemaphore::complexacquire() void tst_QSystemSemaphore::release() { - QSystemSemaphore sem("QSystemSemaphore_release", 0, QSystemSemaphore::Create); + QNativeIpcKey key = platformSafeKey("QSystemSemaphore_release"); + QSystemSemaphore sem(key, 0, QSystemSemaphore::Create); QVERIFY(sem.release()); QCOMPARE(sem.error(), QSystemSemaphore::NoError); QVERIFY(sem.release()); @@ -147,7 +179,8 @@ void tst_QSystemSemaphore::basicProcesses() #if !QT_CONFIG(process) QSKIP("No qprocess support", SkipAll); #else - QSystemSemaphore sem("store", 0, QSystemSemaphore::Create); + QNativeIpcKey key = platformSafeKey("store"); + QSystemSemaphore sem(key, 0, QSystemSemaphore::Create); QProcess acquire; acquire.setProcessChannelMode(QProcess::ForwardedChannels); @@ -155,12 +188,12 @@ void tst_QSystemSemaphore::basicProcesses() QProcess release; release.setProcessChannelMode(QProcess::ForwardedChannels); - acquire.start(m_helperBinary, QStringList("acquire")); + acquire.start(m_helperBinary, { "acquire", key.toString() }); QVERIFY2(acquire.waitForStarted(), "Could not start helper binary"); acquire.waitForFinished(HELPERWAITTIME); QCOMPARE(acquire.state(), QProcess::Running); acquire.kill(); - release.start(m_helperBinary, QStringList("release")); + release.start(m_helperBinary, { "release", key.toString() }); QVERIFY2(release.waitForStarted(), "Could not start helper binary"); acquire.waitForFinished(HELPERWAITTIME); release.waitForFinished(HELPERWAITTIME); @@ -183,7 +216,8 @@ void tst_QSystemSemaphore::processes() #if !QT_CONFIG(process) QSKIP("No qprocess support", SkipAll); #else - QSystemSemaphore sem("store", 1, QSystemSemaphore::Create); + QNativeIpcKey key = platformSafeKey("store"); + QSystemSemaphore sem(key, 1, QSystemSemaphore::Create); QFETCH(int, processes); QList scripts(processes, "acquirerelease"); @@ -193,7 +227,7 @@ void tst_QSystemSemaphore::processes() QProcess *p = new QProcess; p->setProcessChannelMode(QProcess::ForwardedChannels); consumers.append(p); - p->start(m_helperBinary, QStringList(scripts.at(i))); + p->start(m_helperBinary, { scripts.at(i), key.toString() }); } while (!consumers.isEmpty()) { @@ -205,16 +239,24 @@ void tst_QSystemSemaphore::processes() #endif } -// This test only checks a system v unix behavior. -#if !defined(Q_OS_WIN) && !defined(QT_POSIX_IPC) void tst_QSystemSemaphore::undo() { #if !QT_CONFIG(process) QSKIP("No qprocess support", SkipAll); #else - QSystemSemaphore sem("store", 1, QSystemSemaphore::Create); + QNativeIpcKey key = platformSafeKey("store"); + switch (key.type()) { + case QNativeIpcKey::Type::PosixRealtime: + case QNativeIpcKey::Type::Windows: + QSKIP("This test only checks a System V behavior."); - QStringList acquireArguments = QStringList("acquire"); + case QNativeIpcKey::Type::SystemV: + break; + } + + QSystemSemaphore sem(key, 1, QSystemSemaphore::Create); + + QStringList acquireArguments = { "acquire", key.toString() }; QProcess acquire; acquire.setProcessChannelMode(QProcess::ForwardedChannels); acquire.start(m_helperBinary, acquireArguments); @@ -230,17 +272,17 @@ void tst_QSystemSemaphore::undo() QVERIFY(acquire.state()== QProcess::NotRunning); #endif } -#endif void tst_QSystemSemaphore::initialValue() { #if !QT_CONFIG(process) QSKIP("No qprocess support", SkipAll); #else - QSystemSemaphore sem("store", 1, QSystemSemaphore::Create); + QNativeIpcKey key = platformSafeKey("store"); + QSystemSemaphore sem(key, 1, QSystemSemaphore::Create); - QStringList acquireArguments = QStringList("acquire"); - QStringList releaseArguments = QStringList("release"); + QStringList acquireArguments = { "acquire", key.toString() }; + QStringList releaseArguments = { "release", key.toString() }; QProcess acquire; acquire.setProcessChannelMode(QProcess::ForwardedChannels);