diff options
author | Oswald Buddenhagen <oswald.buddenhagen@digia.com> | 2013-04-19 18:11:05 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-08-12 18:58:01 +0200 |
commit | 9c2c12b3ef1a17d54559d229bd788bcf1b731d55 (patch) | |
tree | 13c6e9dd34ea78930402c5acf67b9dbb3fc24edf /src/corelib/io/qprocess_p.h | |
parent | e9ff4a5d3f01ce0e107a1f797446b92a6e52fc0e (diff) |
restore QProcessEnvironment shared data thread safety on unix
implicit sharing together with 'mutable' is a time bomb.
we need to protect the nameMap, because concurrent "reads" may try to
insert into the hash, which would go boom.
we need to protect the key/value of Hash objects, because while the
refcounting is atomic, the d pointer assignments are not, which would
also go boom.
we can simply use a QMutex to protect the whole environment, because it
is very cheap in the uncontended case.
Task-number: QTBUG-30779
Change-Id: Iaad5720041ca06691d75eb9c6c0e1c120d4a7b46
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
(cherry picked from qtbase/85e61297f7b02297641826332dbdbc845a88c34b)
Diffstat (limited to 'src/corelib/io/qprocess_p.h')
-rw-r--r-- | src/corelib/io/qprocess_p.h | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/src/corelib/io/qprocess_p.h b/src/corelib/io/qprocess_p.h index c6e6f3dc2f..a36b0ac2cc 100644 --- a/src/corelib/io/qprocess_p.h +++ b/src/corelib/io/qprocess_p.h @@ -59,6 +59,9 @@ #include "QtCore/qshareddata.h" #include "private/qringbuffer_p.h" #include "private/qiodevice_p.h" +#ifdef Q_OS_UNIX +#include <QtCore/private/qorderedmutexlocker_p.h> +#endif #ifdef Q_OS_WIN #include "QtCore/qt_windows.h" @@ -150,6 +153,13 @@ public: inline QString nameToString(const Key &name) const { return name; } inline Value prepareValue(const QString &value) const { return value; } inline QString valueToString(const Value &value) const { return value; } + struct MutexLocker { + MutexLocker(const QProcessEnvironmentPrivate *) {} + }; + struct OrderedMutexLocker { + OrderedMutexLocker(const QProcessEnvironmentPrivate *, + const QProcessEnvironmentPrivate *) {} + }; #else inline Key prepareName(const QString &name) const { @@ -166,6 +176,37 @@ public: } inline Value prepareValue(const QString &value) const { return Value(value); } inline QString valueToString(const Value &value) const { return value.string(); } + + struct MutexLocker : public QMutexLocker + { + MutexLocker(const QProcessEnvironmentPrivate *d) : QMutexLocker(&d->mutex) {} + }; + struct OrderedMutexLocker : public QOrderedMutexLocker + { + OrderedMutexLocker(const QProcessEnvironmentPrivate *d1, + const QProcessEnvironmentPrivate *d2) : + QOrderedMutexLocker(&d1->mutex, &d2->mutex) + {} + }; + + QProcessEnvironmentPrivate() : QSharedData() {} + QProcessEnvironmentPrivate(const QProcessEnvironmentPrivate &other) : + QSharedData() + { + // This being locked ensures that the functions that only assign + // d pointers don't need explicit locking. + // We don't need to lock our own mutex, as this object is new and + // consequently not shared. For the same reason, non-const methods + // do not need a lock, as they detach objects (however, we need to + // ensure that they really detach before using prepareName()). + MutexLocker locker(&other); + hash = other.hash; + nameMap = other.nameMap; + // We need to detach our members, so that our mutex can protect them. + // As we are being detached, they likely would be detached a moment later anyway. + hash.detach(); + nameMap.detach(); + } #endif typedef QHash<Key, Value> Hash; @@ -174,6 +215,8 @@ public: #ifdef Q_OS_UNIX typedef QHash<QString, Key> NameHash; mutable NameHash nameMap; + + mutable QMutex mutex; #endif static QProcessEnvironment fromList(const QStringList &list); |