diff options
Diffstat (limited to 'src/corelib/kernel/qsharedmemory.cpp')
-rw-r--r-- | src/corelib/kernel/qsharedmemory.cpp | 681 |
1 files changed, 0 insertions, 681 deletions
diff --git a/src/corelib/kernel/qsharedmemory.cpp b/src/corelib/kernel/qsharedmemory.cpp deleted file mode 100644 index 3dbbe75fc4..0000000000 --- a/src/corelib/kernel/qsharedmemory.cpp +++ /dev/null @@ -1,681 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qsharedmemory.h" -#include "qsharedmemory_p.h" -#include "qsystemsemaphore.h" -#include <qdir.h> -#include <qcryptographichash.h> -#include <qdebug.h> -#ifdef Q_OS_WIN -# include <qt_windows.h> -#endif - -#if defined(Q_OS_DARWIN) -# include "qcore_mac_p.h" -# if !defined(SHM_NAME_MAX) - // Based on PSEMNAMLEN in XNU's posix_sem.c, which would - // indicate the max length is 31, _excluding_ the zero - // terminator. But in practice (possibly due to an off- - // by-one bug in the kernel) the usable bytes are only 30. -# define SHM_NAME_MAX 30 -# endif -#endif - -QT_BEGIN_NAMESPACE - -#if !(defined(QT_NO_SHAREDMEMORY) && defined(QT_NO_SYSTEMSEMAPHORE)) -/*! - \internal - - Generate a string from the key which can be any unicode string into - the subset that the win/unix kernel allows. - - On Unix this will be a file name - */ -QString -QSharedMemoryPrivate::makePlatformSafeKey(const QString &key, - const QString &prefix) -{ - if (key.isEmpty()) - return QString(); - - QByteArray hex = QCryptographicHash::hash(key.toUtf8(), QCryptographicHash::Sha1).toHex(); - -#if defined(Q_OS_DARWIN) && defined(QT_POSIX_IPC) - if (qt_apple_isSandboxed()) { - // Sandboxed applications on Apple platforms require the shared memory name - // to be in the form <application group identifier>/<custom identifier>. - // Since we don't know which application group identifier the user wants - // to apply, we instead document that requirement, and use the key directly. - return key; - } else { - // The shared memory name limit on Apple platforms is very low (30 characters), - // so we can't use the logic below of combining the prefix, key, and a hash, - // to ensure a unique and valid name. Instead we use the first part of the - // hash, which should still long enough to avoid collisions in practice. - return QLatin1Char('/') + hex.left(SHM_NAME_MAX - 1); - } -#endif - - QString result = prefix; - for (QChar ch : key) { - if ((ch >= QLatin1Char('a') && ch <= QLatin1Char('z')) || - (ch >= QLatin1Char('A') && ch <= QLatin1Char('Z'))) - result += ch; - } - result.append(QLatin1String(hex)); - -#ifdef Q_OS_WIN - return result; -#elif defined(QT_POSIX_IPC) - return QLatin1Char('/') + result; -#else - return QDir::tempPath() + QLatin1Char('/') + result; -#endif -} -#endif // QT_NO_SHAREDMEMORY && QT_NO_SHAREDMEMORY - -#ifndef QT_NO_SHAREDMEMORY - -/*! - \class QSharedMemory - \inmodule QtCore - \since 4.4 - - \brief The QSharedMemory class provides access to a shared memory segment. - - QSharedMemory provides access to a shared memory segment by multiple - threads and processes. It also provides a way for a single thread or - process to lock the memory for exclusive access. - - When using this class, be aware of the following platform - differences: - - \list - - \li Windows: QSharedMemory does not "own" the shared memory segment. - When all threads or processes that have an instance of QSharedMemory - attached to a particular shared memory segment have either destroyed - their instance of QSharedMemory or exited, the Windows kernel - releases the shared memory segment automatically. - - \li Unix: QSharedMemory "owns" the shared memory segment. When the - last thread or process that has an instance of QSharedMemory - attached to a particular shared memory segment detaches from the - segment by destroying its instance of QSharedMemory, the Unix kernel - release the shared memory segment. But if that last thread or - process crashes without running the QSharedMemory destructor, the - shared memory segment survives the crash. - - \li HP-UX: Only one attach to a shared memory segment is allowed per - process. This means that QSharedMemory should not be used across - multiple threads in the same process in HP-UX. - - \li Apple platforms: Sandboxed applications (including apps - shipped through the Apple App Store) require the use of POSIX - shared memory (instead of System V shared memory), which adds - a number of limitations, including: - - \list - - \li The key must 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}. - - \li The key length is limited to 30 characters. - - \li On process exit, the named shared memory entries are not - cleaned up, so restarting the application and re-creating the - shared memory under the same name will fail. To work around this, - fall back to attaching to the existing shared memory entry: - - \code - - QSharedMemory shm("DEVTEAMID.app-group/shared"); - if (!shm.create(42) && shm.error() == QSharedMemory::AlreadyExists) - shm.attach(); - - \endcode - - - \endlist - - \endlist - - Remember to lock the shared memory with lock() before reading from - or writing to the shared memory, and remember to release the lock - with unlock() after you are done. - - QSharedMemory automatically destroys the shared memory segment when - the last instance of QSharedMemory is detached from the segment, and - no references to the segment remain. - - \warning QSharedMemory changes the key in a Qt-specific way, unless otherwise - specified. Interoperation with non-Qt applications is achieved by first creating - a default shared memory with QSharedMemory() and then setting a native key with - setNativeKey(). When using native keys, shared memory is not protected against - multiple accesses on it (for example, unable to lock()) and a user-defined mechanism - should be used to achieve such protection. - */ - -/*! - \overload QSharedMemory() - - Constructs a shared memory object with the given \a parent. The - shared memory object's key is not set by the constructor, so the - shared memory object does not have an underlying shared memory - segment attached. The key must be set with setKey() or setNativeKey() - before create() or attach() can be used. - - \sa setKey() - */ - -#ifndef QT_NO_QOBJECT -QSharedMemory::QSharedMemory(QObject *parent) - : QObject(*new QSharedMemoryPrivate, parent) -{ -} -#else -QSharedMemory::QSharedMemory() - : d_ptr(new QSharedMemoryPrivate) -{ -} -#endif -/*! - Constructs a shared memory object with the given \a parent and with - its key set to \a key. Because its key is set, its create() and - attach() functions can be called. - - \sa setKey(), create(), attach() - */ -#ifndef QT_NO_QOBJECT -QSharedMemory::QSharedMemory(const QString &key, QObject *parent) - : QObject(*new QSharedMemoryPrivate, parent) -{ - setKey(key); -} -#else -QSharedMemory::QSharedMemory(const QString &key) - : d_ptr(new QSharedMemoryPrivate) -{ - setKey(key); -} -#endif - -/*! - The destructor clears the key, which forces the shared memory object - to \l {detach()} {detach} from its underlying shared memory - segment. If this shared memory object is the last one connected to - the shared memory segment, the detach() operation destroys the - shared memory segment. - - \sa detach(), isAttached() - */ -QSharedMemory::~QSharedMemory() -{ - setKey(QString()); -} - -/*! - Sets the platform independent \a key for this shared memory object. If \a key - is the same as the current key, the function returns without doing anything. - - You can call key() to retrieve the platform independent key. Internally, - QSharedMemory converts this key into a platform specific key. If you instead - call nativeKey(), you will get the platform specific, converted key. - - If the shared memory object is attached to an underlying shared memory - segment, it will \l {detach()} {detach} from it before setting the new key. - This function does not do an attach(). - - \sa key(), nativeKey(), isAttached() -*/ -void QSharedMemory::setKey(const QString &key) -{ - Q_D(QSharedMemory); - if (key == d->key && d->makePlatformSafeKey(key) == d->nativeKey) - return; - - if (isAttached()) - detach(); - d->cleanHandle(); - d->key = key; - d->nativeKey = d->makePlatformSafeKey(key); -} - -/*! - \since 4.8 - - Sets the native, platform specific, \a key for this shared memory object. If - \a key is the same as the current native key, the function returns without - doing anything. If all you want is to assign a key to a segment, you should - call setKey() instead. - - You can call nativeKey() to retrieve the native key. If a native key has been - assigned, calling key() will return a null string. - - If the shared memory object is attached to an underlying shared memory - segment, it will \l {detach()} {detach} from it before setting the new key. - This function does not do an attach(). - - The application will not be portable if you set a native key. - - \sa nativeKey(), key(), isAttached() -*/ -void QSharedMemory::setNativeKey(const QString &key) -{ - Q_D(QSharedMemory); - if (key == d->nativeKey && d->key.isNull()) - return; - - if (isAttached()) - detach(); - d->cleanHandle(); - d->key = QString(); - d->nativeKey = key; -} - -bool QSharedMemoryPrivate::initKey() -{ - if (!cleanHandle()) - return false; -#ifndef QT_NO_SYSTEMSEMAPHORE - systemSemaphore.setKey(QString(), 1); - systemSemaphore.setKey(key, 1); - if (systemSemaphore.error() != QSystemSemaphore::NoError) { - QString function = QLatin1String("QSharedMemoryPrivate::initKey"); - errorString = QSharedMemory::tr("%1: unable to set key on lock").arg(function); - switch(systemSemaphore.error()) { - case QSystemSemaphore::PermissionDenied: - error = QSharedMemory::PermissionDenied; - break; - case QSystemSemaphore::KeyError: - error = QSharedMemory::KeyError; - break; - case QSystemSemaphore::AlreadyExists: - error = QSharedMemory::AlreadyExists; - break; - case QSystemSemaphore::NotFound: - error = QSharedMemory::NotFound; - break; - case QSystemSemaphore::OutOfResources: - error = QSharedMemory::OutOfResources; - break; - case QSystemSemaphore::UnknownError: - default: - error = QSharedMemory::UnknownError; - break; - } - return false; - } -#endif - errorString = QString(); - error = QSharedMemory::NoError; - return true; -} - -/*! - Returns the key assigned with setKey() to this shared memory, or a null key - if no key has been assigned, or if the segment is using a nativeKey(). The - key is the identifier used by Qt applications to identify the shared memory - segment. - - You can find the native, platform specific, key used by the operating system - by calling nativeKey(). - - \sa setKey(), setNativeKey() - */ -QString QSharedMemory::key() const -{ - Q_D(const QSharedMemory); - return d->key; -} - -/*! - \since 4.8 - - Returns the native, platform specific, key for this shared memory object. The - native key is the identifier used by the operating system to identify the - shared memory segment. - - You can use the native key to access shared memory segments that have not - been created by Qt, or to grant shared memory access to non-Qt applications. - - \sa setKey(), setNativeKey() -*/ -QString QSharedMemory::nativeKey() const -{ - Q_D(const QSharedMemory); - return d->nativeKey; -} - -/*! - Creates a shared memory segment of \a size bytes with the key passed to the - constructor, set with setKey() or set with setNativeKey(), then attaches to - the new shared memory segment with the given access \a mode and returns - \tt true. If a shared memory segment identified by the key already exists, - the attach operation is not performed and \tt false is returned. When the - return value is \tt false, call error() to determine which error occurred. - - \sa error() - */ -bool QSharedMemory::create(qsizetype size, AccessMode mode) -{ - Q_D(QSharedMemory); - - if (!d->initKey()) - return false; - -#ifndef QT_NO_SYSTEMSEMAPHORE -#ifndef Q_OS_WIN - // Take ownership and force set initialValue because the semaphore - // might have already existed from a previous crash. - d->systemSemaphore.setKey(d->key, 1, QSystemSemaphore::Create); -#endif -#endif - - QString function = QLatin1String("QSharedMemory::create"); -#ifndef QT_NO_SYSTEMSEMAPHORE - QSharedMemoryLocker lock(this); - if (!d->key.isNull() && !d->tryLocker(&lock, function)) - return false; -#endif - - if (size <= 0) { - d->error = QSharedMemory::InvalidSize; - d->errorString = - QSharedMemory::tr("%1: create size is less then 0").arg(function); - return false; - } - - if (!d->create(size)) - return false; - - return d->attach(mode); -} - -/*! - Returns the size of the attached shared memory segment. If no shared - memory segment is attached, 0 is returned. - - \note The size of the segment may be larger than the requested size that was - passed to create(). - - \sa create(), attach() - */ -qsizetype QSharedMemory::size() const -{ - Q_D(const QSharedMemory); - return d->size; -} - -/*! - \enum QSharedMemory::AccessMode - - \value ReadOnly The shared memory segment is read-only. Writing to - the shared memory segment is not allowed. An attempt to write to a - shared memory segment created with ReadOnly causes the program to - abort. - - \value ReadWrite Reading and writing the shared memory segment are - both allowed. -*/ - -/*! - Attempts to attach the process to the shared memory segment - identified by the key that was passed to the constructor or to a - call to setKey() or setNativeKey(). The access \a mode is \l {QSharedMemory::} - {ReadWrite} by default. It can also be \l {QSharedMemory::} - {ReadOnly}. Returns \c true if the attach operation is successful. If - false is returned, call error() to determine which error occurred. - After attaching the shared memory segment, a pointer to the shared - memory can be obtained by calling data(). - - \sa isAttached(), detach(), create() - */ -bool QSharedMemory::attach(AccessMode mode) -{ - Q_D(QSharedMemory); - - if (isAttached() || !d->initKey()) - return false; -#ifndef QT_NO_SYSTEMSEMAPHORE - QSharedMemoryLocker lock(this); - if (!d->key.isNull() && !d->tryLocker(&lock, QLatin1String("QSharedMemory::attach"))) - return false; -#endif - - if (isAttached() || !d->handle()) - return false; - - return d->attach(mode); -} - -/*! - Returns \c true if this process is attached to the shared memory - segment. - - \sa attach(), detach() - */ -bool QSharedMemory::isAttached() const -{ - Q_D(const QSharedMemory); - return (nullptr != d->memory); -} - -/*! - Detaches the process from the shared memory segment. If this was the - last process attached to the shared memory segment, then the shared - memory segment is released by the system, i.e., the contents are - destroyed. The function returns \c true if it detaches the shared - memory segment. If it returns \c false, it usually means the segment - either isn't attached, or it is locked by another process. - - \sa attach(), isAttached() - */ -bool QSharedMemory::detach() -{ - Q_D(QSharedMemory); - if (!isAttached()) - return false; - -#ifndef QT_NO_SYSTEMSEMAPHORE - QSharedMemoryLocker lock(this); - if (!d->key.isNull() && !d->tryLocker(&lock, QLatin1String("QSharedMemory::detach"))) - return false; -#endif - - return d->detach(); -} - -/*! - Returns a pointer to the contents of the shared memory segment, if - one is attached. Otherwise it returns null. Remember to lock the - shared memory with lock() before reading from or writing to the - shared memory, and remember to release the lock with unlock() after - you are done. - - \sa attach() - */ -void *QSharedMemory::data() -{ - Q_D(QSharedMemory); - return d->memory; -} - -/*! - Returns a const pointer to the contents of the shared memory - segment, if one is attached. Otherwise it returns null. Remember to - lock the shared memory with lock() before reading from or writing to - the shared memory, and remember to release the lock with unlock() - after you are done. - - \sa attach(), create() - */ -const void *QSharedMemory::constData() const -{ - Q_D(const QSharedMemory); - return d->memory; -} - -/*! - \overload data() - */ -const void *QSharedMemory::data() const -{ - Q_D(const QSharedMemory); - return d->memory; -} - -#ifndef QT_NO_SYSTEMSEMAPHORE -/*! - This is a semaphore that locks the shared memory segment for access - by this process and returns \c true. If another process has locked the - segment, this function blocks until the lock is released. Then it - acquires the lock and returns \c true. If this function returns \c false, - it means that you have ignored a false return from create() or attach(), - that you have set the key with setNativeKey() or that - QSystemSemaphore::acquire() failed due to an unknown system error. - - \sa unlock(), data(), QSystemSemaphore::acquire() - */ -bool QSharedMemory::lock() -{ - Q_D(QSharedMemory); - if (d->lockedByMe) { - qWarning("QSharedMemory::lock: already locked"); - return true; - } - if (d->systemSemaphore.acquire()) { - d->lockedByMe = true; - return true; - } - QString function = QLatin1String("QSharedMemory::lock"); - d->errorString = QSharedMemory::tr("%1: unable to lock").arg(function); - d->error = QSharedMemory::LockError; - return false; -} - -/*! - Releases the lock on the shared memory segment and returns \c true, if - the lock is currently held by this process. If the segment is not - locked, or if the lock is held by another process, nothing happens - and false is returned. - - \sa lock() - */ -bool QSharedMemory::unlock() -{ - Q_D(QSharedMemory); - if (!d->lockedByMe) - return false; - d->lockedByMe = false; - if (d->systemSemaphore.release()) - return true; - QString function = QLatin1String("QSharedMemory::unlock"); - d->errorString = QSharedMemory::tr("%1: unable to unlock").arg(function); - d->error = QSharedMemory::LockError; - return false; -} -#endif // QT_NO_SYSTEMSEMAPHORE - -/*! - \enum QSharedMemory::SharedMemoryError - - \value NoError No error occurred. - - \value PermissionDenied The operation failed because the caller - didn't have the required permissions. - - \value InvalidSize A create operation failed because the requested - size was invalid. - - \value KeyError The operation failed because of an invalid key. - - \value AlreadyExists A create() operation failed because a shared - memory segment with the specified key already existed. - - \value NotFound An attach() failed because a shared memory segment - with the specified key could not be found. - - \value LockError The attempt to lock() the shared memory segment - failed because create() or attach() failed and returned false, or - because a system error occurred in QSystemSemaphore::acquire(). - - \value OutOfResources A create() operation failed because there was - not enough memory available to fill the request. - - \value UnknownError Something else happened and it was bad. -*/ - -/*! - Returns a value indicating whether an error occurred, and, if so, - which error it was. - - \sa errorString() - */ -QSharedMemory::SharedMemoryError QSharedMemory::error() const -{ - Q_D(const QSharedMemory); - return d->error; -} - -/*! - Returns a text description of the last error that occurred. If - error() returns an \l {QSharedMemory::SharedMemoryError} {error - value}, call this function to get a text string that describes the - error. - - \sa error() - */ -QString QSharedMemory::errorString() const -{ - Q_D(const QSharedMemory); - return d->errorString; -} - -#endif // QT_NO_SHAREDMEMORY - -QT_END_NAMESPACE - -#ifndef QT_NO_QOBJECT -#include "moc_qsharedmemory.cpp" -#endif |