summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qsystemsemaphore.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/kernel/qsystemsemaphore.cpp')
-rw-r--r--src/corelib/kernel/qsystemsemaphore.cpp360
1 files changed, 360 insertions, 0 deletions
diff --git a/src/corelib/kernel/qsystemsemaphore.cpp b/src/corelib/kernel/qsystemsemaphore.cpp
new file mode 100644
index 0000000..e8426b3
--- /dev/null
+++ b/src/corelib/kernel/qsystemsemaphore.cpp
@@ -0,0 +1,360 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsystemsemaphore.h"
+#include "qsystemsemaphore_p.h"
+#include <qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_SYSTEMSEMAPHORE
+
+/*!
+ \class QSystemSemaphore
+ \ingroup ipc
+ \since 4.4
+
+ \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.
+
+ Like its lighter counterpart QSemaphore, 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
+ if your application doesn't need to access your semaphores across
+ multiple processes, you will probably want to use QSemaphore.
+
+ Semaphores support two fundamental operations, acquire() and release():
+
+ acquire() tries to acquire one resource. If there isn't a resource
+ available, the call blocks until a resource becomes available. Then
+ the resource is acquired and the call returns.
+
+ release() releases one resource so it can be acquired by another
+ 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.
+
+ Example: Create a system semaphore
+ \snippet doc/src/snippets/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.
+
+ \section1 Platform-Specific Behavior
+
+ When using this class, be aware of the following platform
+ differences:
+
+ \bold{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.
+
+ \bold{Unix:}
+
+ \list
+ \o 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.
+
+ \o 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
+
+ \sa QSharedMemory, QSemaphore
+ */
+
+/*!
+ Requests a system semaphore for the specified \a key. The parameters
+ \a initialValue and \a mode are used according to the following
+ rules, which are system dependent.
+
+ In Unix, if the \a mode is \l {QSystemSemaphore::} {Open} and the
+ system already has a semaphore identified by \a key, that semaphore
+ is used, and the semaphore's resource count is not changed, i.e., \a
+ initialValue is ignored. But if the system does not already have a
+ semaphore identified by \a key, it creates a new semaphore for that
+ key and sets its resource count to \a initialValue.
+
+ In Unix, if the \a mode is \l {QSystemSemaphore::} {Create} and the
+ system already has a semaphore identified by \a key, that semaphore
+ is used, and its resource count is set to \a initialValue. If the
+ system does not already have a semaphore identified by \a key, it
+ creates a new semaphore for that key and sets its resource count to
+ \a initialValue.
+
+ In Windows, \a mode is ignored, and the system always tries to
+ create a semaphore for the specified \a key. If the system does not
+ already have a semaphore identified as \a key, it creates the
+ semaphore and sets its resource count to \a initialValue. But if the
+ system already has a semaphore identified as \a key it uses that
+ semaphore and ignores \a initialValue.
+
+ The \l {QSystemSemaphore::AccessMode} {mode} parameter is only used
+ in Unix systems to handle the case where a semaphore survives a
+ process crash. In that case, the next process to allocate a
+ semaphore with the same \a key will get the semaphore that survived
+ the crash, and unless \a mode is \l {QSystemSemaphore::} {Create},
+ the resource count will not be reset to \a initialValue but will
+ retain the initial value it had been given by the crashed process.
+
+ \sa acquire(), key()
+ */
+QSystemSemaphore::QSystemSemaphore(const QString &key, int initialValue, AccessMode mode)
+{
+ d = new QSystemSemaphorePrivate;
+ setKey(key, initialValue, mode);
+}
+
+/*!
+ The destructor destroys the QSystemSemaphore object, but the
+ underlying system semaphore is not removed from the system unless
+ this instance of QSystemSemaphore is the last one existing for that
+ system semaphore.
+
+ Two important side effects of the destructor depend on the system.
+ In Windows, if acquire() has been called for this semaphore but not
+ release(), release() will not be called by the destructor, nor will
+ the resource be released when the process exits normally. This would
+ be a program bug which could be the cause of a deadlock in another
+ process trying to acquire the same resource. In Unix, acquired
+ resources that are not released before the destructor is called are
+ automatically released when the process exits.
+*/
+QSystemSemaphore::~QSystemSemaphore()
+{
+ d->cleanHandle();
+ delete d;
+}
+
+/*!
+ \enum QSystemSemaphore::AccessMode
+
+ This enum is used by the constructor and setKey(). Its purpose is to
+ enable handling the problem in Unix implementations of semaphores
+ that survive a crash. In Unix, when a semaphore survives a crash, we
+ need a way to force it to reset its resource count, when the system
+ reuses the semaphore. In Windows, where semaphores can't survive a
+ crash, this enum has no effect.
+
+ \value Open If the semaphore already exists, its initial resource
+ count is not reset. If the semaphore does not already exist, it is
+ created and its initial resource count set.
+
+ \value Create QSystemSemaphore takes ownership of the semaphore and
+ sets its resource count to the requested value, regardless of
+ whether the semaphore already exists by having survived a crash.
+ This value should be passed to the constructor, when the first
+ semaphore for a particular key is constructed and you know that if
+ the semaphore already exists it could only be because of a crash. In
+ Windows, where a semaphore can't survive a crash, Create and Open
+ have the same behavior.
+*/
+
+/*!
+ 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)
+{
+ if (key == d->key && mode == Open)
+ return;
+ d->error = NoError;
+ d->errorString = QString();
+#ifndef Q_OS_WIN
+ // optimization to not destroy/create the file & semaphore
+ if (key == d->key && mode == Create && d->createdSemaphore && d->createdFile) {
+ d->initialValue = initialValue;
+ d->unix_key = -1;
+ d->handle(mode);
+ return;
+ }
+#endif
+ d->cleanHandle();
+ d->key = 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);
+}
+
+/*!
+ Returns the 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;
+}
+
+/*!
+ Acquires one of the resources guarded by this semaphore, if there is
+ one available, and returns true. If all the resources guarded by this
+ semaphore have already been acquired, the call blocks until one of
+ them is released by another process or thread having a semaphore
+ with the same key.
+
+ If false is returned, a system error has occurred. Call error()
+ to get a value of QSystemSemaphore::SystemSemaphoreError that
+ indicates which error occurred.
+
+ \sa release()
+ */
+bool QSystemSemaphore::acquire()
+{
+ return d->modifySemaphore(-1);
+}
+
+/*!
+ Releases \a n resources guarded by the semaphore. Returns true
+ unless there is a system error.
+
+ Example: Create a system semaphore having five resources; acquire
+ them all and then release them all.
+
+ \snippet doc/src/snippets/code/src_corelib_kernel_qsystemsemaphore.cpp 1
+
+ This function can also "create" resources. For example, immediately
+ following the sequence of statements above, suppose we add the
+ statement:
+
+ \snippet doc/src/snippets/code/src_corelib_kernel_qsystemsemaphore.cpp 2
+
+ Ten new resources are now guarded by the semaphore, in addition to
+ the five that already existed. You would not normally use this
+ function to create more resources.
+
+ \sa acquire()
+ */
+bool QSystemSemaphore::release(int n)
+{
+ if (n == 0)
+ return true;
+ if (n < 0) {
+ qWarning("QSystemSemaphore::release: n is negative.");
+ return false;
+ }
+ return d->modifySemaphore(n);
+}
+
+/*!
+ Returns a value indicating whether an error occurred, and, if so,
+ which error it was.
+
+ \sa errorString()
+ */
+QSystemSemaphore::SystemSemaphoreError QSystemSemaphore::error() const
+{
+ return d->error;
+}
+
+/*!
+ \enum QSystemSemaphore::SystemSemaphoreError
+
+ \value NoError No error occurred.
+
+ \value PermissionDenied The operation failed because the caller
+ didn't have the required permissions.
+
+ \value KeyError The operation failed because of an invalid key.
+
+ \value AlreadyExists The operation failed because a system
+ semaphore with the specified key already existed.
+
+ \value NotFound The operation failed because a system semaphore
+ with the specified key could not be found.
+
+ \value OutOfResources The operation failed because there was
+ not enough memory available to fill the request.
+
+ \value UnknownError Something else happened and it was bad.
+*/
+
+/*!
+ Returns a text description of the last error that occurred. If
+ error() returns an \l {QSystemSemaphore::SystemSemaphoreError} {error
+ value}, call this function to get a text string that describes the
+ error.
+
+ \sa error()
+ */
+QString QSystemSemaphore::errorString() const
+{
+ return d->errorString;
+}
+
+#endif // QT_NO_SYSTEMSEMAPHORE
+
+QT_END_NAMESPACE