IPC: add native key support to QSystemSemaphore
And deprecate the non-native key support API. Qt 7 may not even store the old, non-native Qt. Documentation in a new commit, when the dust settles. Change-Id: I12a088d1ae424825abd3fffd171d2b549eeed040 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
parent
510e0914c0
commit
3ae052d3bb
@ -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
|
||||
|
@ -12,11 +12,35 @@
|
||||
# include <qt_windows.h>
|
||||
#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);
|
||||
|
@ -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)
|
||||
};
|
||||
|
||||
|
@ -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 {<application group identifier>/<custom identifier>},
|
||||
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
|
||||
|
@ -5,12 +5,12 @@
|
||||
#define QSYSTEMSEMAPHORE_H
|
||||
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#include <QtCore/qtipccommon.h>
|
||||
#include <QtCore/qstring.h>
|
||||
#include <QtCore/qscopedpointer.h>
|
||||
|
||||
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<QSystemSemaphorePrivate> d;
|
||||
|
@ -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
|
||||
|
@ -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.");
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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<const wchar_t*>(self->fileName.utf16()));
|
||||
reinterpret_cast<const wchar_t*>(self->nativeKey.nativeKey().utf16()));
|
||||
if (semaphore == NULL)
|
||||
self->setWindowsErrorString("QSystemSemaphore::handle"_L1);
|
||||
}
|
||||
|
@ -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[])
|
||||
|
@ -6,9 +6,9 @@
|
||||
#include <QStringList>
|
||||
#include <QSystemSemaphore>
|
||||
|
||||
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 <acquire|release|acquirerelease> <key> [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;
|
||||
}
|
||||
|
@ -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 <QTest>
|
||||
@ -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<QString>("constructorKey");
|
||||
QTest::addColumn<QString>("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<QString> 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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user