summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThiago Macieira <thiago@kde.org>2011-07-31 17:40:40 -0300
committerQt by Nokia <qt-info@nokia.com>2012-01-20 12:26:26 +0100
commit1f843ca39ee59c5304009faf308ddce791614a02 (patch)
tree31e9e0bd87f30ecb26f93846a6380759b231013b
parentf188d8a005e7c06869aa96bddb82053178c554e9 (diff)
Add the new QBasicAtomicXXX implementation - no backends yet
The new implementation is API- and ABI-compatible with the old implementation, provided that QBasicAtomicInt isn't used as an argument in a function call or the return value: now, QBasicAtomicInt is a typedef to QBasicAtomicInteger<int>. The new design is based on CRTP: the QGenericAtomicOps template class takes as a template parameter the derived class itself. This way, we implement a "poor man's virtual" without a virtual table and everything is inline. QGenericAtomicOps implements most of the atomics code that is repeated in many classes all over: * Acquire semantics are obtained by placing an acquire barrier after the Relaxed operation * Release semantics are obtained by placing a release barrier before the Relaxed operation * Ordered semantics are obtained by placing an ordered barrier before the Relaxed operation (either way would be fine) * fetchAndStoreRelaxed and fetchAndAddRelaxed are implemented on top of testAndSetRelaxed * ref and deref are implemented on top of fetchAndAddRelaxed It also adds load, loadAcquire, store and storeRelease: the default implementations of loadAcquire and storeRelease operate on a volatile variable and add barriers. There are no direct operators for accessing the value. Each architecture-specific implementation can override any of the functions or the memory barrier functions. It must implement at least the testAndSetRelaxed function. In addition, by specialising one template class, the implementations can allow QBasicAtomicInteger for additional types (of different sizes). At the very least, int, unsigned and pointers must be supported. Change-Id: I6da647e225bb330d3cfc16f84d0e7849dff85ec7 Reviewed-by: Bradley T. Hughes <bradley.hughes@nokia.com>
-rw-r--r--src/corelib/thread/qatomic.h2
-rw-r--r--src/corelib/thread/qbasicatomic.h207
-rw-r--r--src/corelib/thread/qgenericatomic.h232
-rw-r--r--src/corelib/thread/qoldbasicatomic.h9
-rw-r--r--src/corelib/thread/thread.pri2
5 files changed, 449 insertions, 3 deletions
diff --git a/src/corelib/thread/qatomic.h b/src/corelib/thread/qatomic.h
index 07350ecfcd..46026f3000 100644
--- a/src/corelib/thread/qatomic.h
+++ b/src/corelib/thread/qatomic.h
@@ -44,7 +44,7 @@
#ifndef QATOMIC_H
#define QATOMIC_H
-#include <QtCore/qoldbasicatomic.h>
+#include <QtCore/qbasicatomic.h>
QT_BEGIN_HEADER
diff --git a/src/corelib/thread/qbasicatomic.h b/src/corelib/thread/qbasicatomic.h
new file mode 100644
index 0000000000..7a93a4b661
--- /dev/null
+++ b/src/corelib/thread/qbasicatomic.h
@@ -0,0 +1,207 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Thiago Macieira <thiago@kde.org>
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.1, 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBASICATOMIC_H
+#define QBASICATOMIC_H
+
+#include <QtCore/qglobal.h>
+
+# define QT_OLD_ATOMICS
+
+#ifdef QT_OLD_ATOMICS
+# include "qoldbasicatomic.h"
+# undef QT_OLD_ATOMICS
+#else
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#if 0
+#pragma qt_no_master_include
+#pragma qt_sync_stop_processing
+#endif
+
+// New atomics
+
+template <typename T>
+struct QBasicAtomicInteger
+{
+ typedef QAtomicOps<T> Ops;
+ // static check that this is a valid integer
+ typedef char PermittedIntegerType[QAtomicIntegerTraits<T>::IsInteger ? 1 : -1];
+
+ typename Ops::Type _q_value;
+
+ // Non-atomic API
+ T load() const { return Ops::load(_q_value); }
+ void store(T newValue) { Ops::store(_q_value, newValue); }
+
+ // Atomic API, implemented in qatomic_XXX.h
+
+ T loadAcquire() { return Ops::loadAcquire(_q_value); }
+ void storeRelease(T newValue) { Ops::storeRelease(_q_value, newValue); }
+
+ static bool isReferenceCountingNative() { return Ops::isReferenceCountingNative(); }
+ static bool isReferenceCountingWaitFree() { return Ops::isReferenceCountingWaitFree(); }
+
+ bool ref() { return Ops::ref(_q_value); }
+ bool deref() { return Ops::deref(_q_value); }
+
+ static bool isTestAndSetNative() { return Ops::isTestAndSetNative(); }
+ static bool isTestAndSetWaitFree() { return Ops::isTestAndSetWaitFree(); }
+
+ bool testAndSetRelaxed(T expectedValue, T newValue)
+ { return Ops::testAndSetRelaxed(_q_value, expectedValue, newValue); }
+ bool testAndSetAcquire(T expectedValue, T newValue)
+ { return Ops::testAndSetAcquire(_q_value, expectedValue, newValue); }
+ bool testAndSetRelease(T expectedValue, T newValue)
+ { return Ops::testAndSetRelease(_q_value, expectedValue, newValue); }
+ bool testAndSetOrdered(T expectedValue, T newValue)
+ { return Ops::testAndSetOrdered(_q_value, expectedValue, newValue); }
+
+ static bool isFetchAndStoreNative() { return Ops::isFetchAndStoreNative(); }
+ static bool isFetchAndStoreWaitFree() { return Ops::isFetchAndStoreWaitFree(); }
+
+ T fetchAndStoreRelaxed(T newValue)
+ { return Ops::fetchAndStoreRelaxed(_q_value, newValue); }
+ T fetchAndStoreAcquire(T newValue)
+ { return Ops::fetchAndStoreAcquire(_q_value, newValue); }
+ T fetchAndStoreRelease(T newValue)
+ { return Ops::fetchAndStoreRelease(_q_value, newValue); }
+ T fetchAndStoreOrdered(T newValue)
+ { return Ops::fetchAndStoreOrdered(_q_value, newValue); }
+
+ static bool isFetchAndAddNative() { return Ops::isFetchAndAddNative(); }
+ static bool isFetchAndAddWaitFree() { return Ops::isFetchAndAddWaitFree(); }
+
+ T fetchAndAddRelaxed(T valueToAdd)
+ { return Ops::fetchAndAddRelaxed(_q_value, valueToAdd); }
+ T fetchAndAddAcquire(T valueToAdd)
+ { return Ops::fetchAndAddAcquire(_q_value, valueToAdd); }
+ T fetchAndAddRelease(T valueToAdd)
+ { return Ops::fetchAndAddRelease(_q_value, valueToAdd); }
+ T fetchAndAddOrdered(T valueToAdd)
+ { return Ops::fetchAndAddOrdered(_q_value, valueToAdd); }
+
+#if defined(Q_COMPILER_CONSTEXPR) && defined(Q_COMPILER_DEFAULT_DELETE_MEMBERS)
+ QBasicAtomicInteger() = default;
+ constexpr QBasicAtomicInteger(T value) : _q_value(value) {}
+ QBasicAtomicInteger(const QBasicAtomicInteger &) = delete;
+ QBasicAtomicInteger &operator=(const QBasicAtomicInteger &) = delete;
+ QBasicAtomicInteger &operator=(const QBasicAtomicInteger &) volatile = delete;
+#endif
+};
+typedef QBasicAtomicInteger<int> QBasicAtomicInt;
+
+template <typename X>
+struct QBasicAtomicPointer
+{
+ typedef X *Type;
+ typedef QAtomicOps<Type> Ops;
+ typedef typename Ops::Type AtomicType;
+
+ AtomicType _q_value;
+
+ // Non-atomic API
+ Type load() const { return _q_value; }
+ void store(Type newValue) { _q_value = newValue; }
+
+ // Atomic API, implemented in qatomic_XXX.h
+ Type loadAcquire() { return Ops::loadAcquire(_q_value); }
+ void storeRelease(Type newValue) { Ops::storeRelease(_q_value, newValue); }
+
+ static bool isTestAndSetNative() { return Ops::isTestAndSetNative(); }
+ static bool isTestAndSetWaitFree() { return Ops::isTestAndSetWaitFree(); }
+
+ bool testAndSetRelaxed(Type expectedValue, Type newValue)
+ { return Ops::testAndSetRelaxed(_q_value, expectedValue, newValue); }
+ bool testAndSetAcquire(Type expectedValue, Type newValue)
+ { return Ops::testAndSetAcquire(_q_value, expectedValue, newValue); }
+ bool testAndSetRelease(Type expectedValue, Type newValue)
+ { return Ops::testAndSetRelease(_q_value, expectedValue, newValue); }
+ bool testAndSetOrdered(Type expectedValue, Type newValue)
+ { return Ops::testAndSetOrdered(_q_value, expectedValue, newValue); }
+
+ static bool isFetchAndStoreNative() { return Ops::isFetchAndStoreNative(); }
+ static bool isFetchAndStoreWaitFree() { return Ops::isFetchAndStoreWaitFree(); }
+
+ Type fetchAndStoreRelaxed(Type newValue)
+ { return Ops::fetchAndStoreRelaxed(_q_value, newValue); }
+ Type fetchAndStoreAcquire(Type newValue)
+ { return Ops::fetchAndStoreAcquire(_q_value, newValue); }
+ Type fetchAndStoreRelease(Type newValue)
+ { return Ops::fetchAndStoreRelease(_q_value, newValue); }
+ Type fetchAndStoreOrdered(Type newValue)
+ { return Ops::fetchAndStoreOrdered(_q_value, newValue); }
+
+ static bool isFetchAndAddNative() { return Ops::isFetchAndAddNative(); }
+ static bool isFetchAndAddWaitFree() { return Ops::isFetchAndAddWaitFree(); }
+
+ Type fetchAndAddRelaxed(qptrdiff valueToAdd)
+ { return Ops::fetchAndAddRelaxed(_q_value, valueToAdd); }
+ Type fetchAndAddAcquire(qptrdiff valueToAdd)
+ { return Ops::fetchAndAddAcquire(_q_value, valueToAdd); }
+ Type fetchAndAddRelease(qptrdiff valueToAdd)
+ { return Ops::fetchAndAddRelease(_q_value, valueToAdd); }
+ Type fetchAndAddOrdered(qptrdiff valueToAdd)
+ { return Ops::fetchAndAddOrdered(_q_value, valueToAdd); }
+
+#if defined(Q_COMPILER_CONSTEXPR) && defined(Q_COMPILER_DEFAULT_DELETE_MEMBERS)
+ QBasicAtomicPointer() = default;
+ constexpr QBasicAtomicPointer(Type value) : _q_value(value) {}
+ QBasicAtomicPointer(const QBasicAtomicPointer &) = delete;
+ QBasicAtomicPointer &operator=(const QBasicAtomicPointer &) = delete;
+ QBasicAtomicPointer &operator=(const QBasicAtomicPointer &) volatile = delete;
+#endif
+};
+
+#ifndef Q_BASIC_ATOMIC_INITIALIZER
+# define Q_BASIC_ATOMIC_INITIALIZER(a) { (a) }
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_OLD_ATOMICS
+
+#endif // QBASIC_ATOMIC
diff --git a/src/corelib/thread/qgenericatomic.h b/src/corelib/thread/qgenericatomic.h
new file mode 100644
index 0000000000..575589befc
--- /dev/null
+++ b/src/corelib/thread/qgenericatomic.h
@@ -0,0 +1,232 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Thiago Macieira <thiago@kde.org>
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.1, 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGENERICATOMIC_H
+#define QGENERICATOMIC_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+#if 0
+#pragma qt_sync_stop_processing
+#endif
+
+#ifdef Q_CC_GNU
+// lowercase is fine, we'll undef it below
+#define always_inline __attribute__((always_inline, gnu_inline))
+#else
+#define always_inline
+#endif
+
+template<typename T> struct QAtomicIntegerTraits { enum { IsInteger = 0 }; };
+
+template <typename T> struct QAtomicAdditiveType
+{
+ typedef T AdditiveT;
+ static const int AddScale = 1;
+};
+template <typename T> struct QAtomicAdditiveType<T *>
+{
+ typedef qptrdiff AdditiveT;
+ static const int AddScale = sizeof(T);
+};
+
+// not really atomic...
+template <typename BaseClass> struct QGenericAtomicOps
+{
+ template <typename T> struct AtomicType { typedef T Type; typedef T *PointerType; };
+
+ static void acquireMemoryFence() { BaseClass::orderedMemoryFence(); }
+ static void releaseMemoryFence() { BaseClass::orderedMemoryFence(); }
+ static void orderedMemoryFence() { }
+
+ template <typename T> static inline always_inline
+ T load(T &_q_value)
+ {
+ return _q_value;
+ }
+
+ template <typename T> static inline always_inline
+ void store(T &_q_value, T newValue)
+ {
+ _q_value = newValue;
+ }
+
+ template <typename T> static inline always_inline
+ T loadAcquire(T &_q_value)
+ {
+ T tmp = *static_cast<volatile T *>(&_q_value);
+ BaseClass::acquireMemoryFence();
+ return tmp;
+ }
+
+ template <typename T> static inline always_inline
+ void storeRelease(T &_q_value, T newValue)
+ {
+ BaseClass::releaseMemoryFence();
+ *static_cast<volatile T *>(&_q_value) = newValue;
+ }
+
+ static inline bool isReferenceCountingNative()
+ { return BaseClass::isFetchAndAddNative(); }
+ static inline bool isReferenceCountingWaitFree()
+ { return BaseClass::isFetchAndAddWaitFree(); }
+ template <typename T> static inline always_inline
+ bool ref(T &_q_value)
+ {
+ return BaseClass::fetchAndAddRelaxed(_q_value, 1) != T(-1);
+ }
+
+ template <typename T> static inline always_inline
+ bool deref(T &_q_value)
+ {
+ return BaseClass::fetchAndAddRelaxed(_q_value, -1) != 1;
+ }
+
+#if 0
+ // These functions have no default implementation
+ // Archictectures must implement them
+ static inline bool isTestAndSetNative();
+ static inline bool isTestAndSetWaitFree();
+ template <typename T> static inline
+ bool testAndSetRelaxed(T &_q_value, T expectedValue, T newValue);
+#endif
+
+ template <typename T> static inline always_inline
+ bool testAndSetAcquire(T &_q_value, T expectedValue, T newValue)
+ {
+ bool tmp = BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue);
+ BaseClass::acquireMemoryFence();
+ return tmp;
+ }
+
+ template <typename T> static inline always_inline
+ bool testAndSetRelease(T &_q_value, T expectedValue, T newValue)
+ {
+ BaseClass::releaseMemoryFence();
+ return BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue);
+ }
+
+ template <typename T> static inline always_inline
+ bool testAndSetOrdered(T &_q_value, T expectedValue, T newValue)
+ {
+ BaseClass::orderedMemoryFence();
+ return BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue);
+ }
+
+ static inline bool isFetchAndStoreNative() { return false; }
+ static inline bool isFetchAndStoreWaitFree() { return false; }
+
+ template <typename T> static inline always_inline
+ T fetchAndStoreRelaxed(T &_q_value, T newValue)
+ {
+ // implement fetchAndStore on top of testAndSet
+ forever {
+ register T tmp = load(_q_value);
+ if (BaseClass::testAndSetRelaxed(_q_value, tmp, newValue))
+ return tmp;
+ }
+ }
+
+ template <typename T> static inline always_inline
+ T fetchAndStoreAcquire(T &_q_value, T newValue)
+ {
+ T tmp = BaseClass::fetchAndStoreRelaxed(_q_value, newValue);
+ BaseClass::acquireMemoryFence();
+ return tmp;
+ }
+
+ template <typename T> static inline always_inline
+ T fetchAndStoreRelease(T &_q_value, T newValue)
+ {
+ BaseClass::releaseMemoryFence();
+ return BaseClass::fetchAndStoreRelaxed(_q_value, newValue);
+ }
+
+ template <typename T> static inline always_inline
+ T fetchAndStoreOrdered(T &_q_value, T newValue)
+ {
+ BaseClass::orderedMemoryFence();
+ return BaseClass::fetchAndStoreRelaxed(_q_value, newValue);
+ }
+
+ static inline bool isFetchAndAddNative() { return false; }
+ static inline bool isFetchAndAddWaitFree() { return false; }
+ template <typename T> static inline always_inline
+ T fetchAndAddRelaxed(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd)
+ {
+ // implement fetchAndAdd on top of testAndSet
+ forever {
+ register T tmp = BaseClass::load(_q_value);
+ if (BaseClass::testAndSetRelaxed(_q_value, tmp, T(tmp + valueToAdd)))
+ return tmp;
+ }
+ }
+
+ template <typename T> static inline always_inline
+ T fetchAndAddAcquire(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd)
+ {
+ T tmp = BaseClass::fetchAndAddRelaxed(_q_value, valueToAdd);
+ BaseClass::acquireMemoryFence();
+ return tmp;
+ }
+
+ template <typename T> static inline always_inline
+ T fetchAndAddRelease(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd)
+ {
+ BaseClass::releaseMemoryFence();
+ return BaseClass::fetchAndAddRelaxed(_q_value, valueToAdd);
+ }
+
+ template <typename T> static inline always_inline
+ T fetchAndAddOrdered(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd)
+ {
+ BaseClass::orderedMemoryFence();
+ return BaseClass::fetchAndAddRelaxed(_q_value, valueToAdd);
+ }
+};
+
+#undef always_inline
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // QGENERICATOMIC_H
diff --git a/src/corelib/thread/qoldbasicatomic.h b/src/corelib/thread/qoldbasicatomic.h
index 2f952c9e0a..114615d1d2 100644
--- a/src/corelib/thread/qoldbasicatomic.h
+++ b/src/corelib/thread/qoldbasicatomic.h
@@ -39,8 +39,8 @@
**
****************************************************************************/
-#ifndef QBASICATOMIC_H
-#define QBASICATOMIC_H
+#ifndef QOLDBASICATOMIC_H
+#define QOLDBASICATOMIC_H
#include <QtCore/qglobal.h>
@@ -50,6 +50,11 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Core)
+#if 0
+#pragma qt_no_master_include
+#pragma qt_sync_stop_processing
+#endif
+
class Q_CORE_EXPORT QBasicAtomicInt
{
public:
diff --git a/src/corelib/thread/thread.pri b/src/corelib/thread/thread.pri
index 974e086684..ea6f0eb91e 100644
--- a/src/corelib/thread/thread.pri
+++ b/src/corelib/thread/thread.pri
@@ -8,6 +8,8 @@ HEADERS += thread/qmutex.h \
thread/qthreadstorage.h \
thread/qwaitcondition.h \
thread/qatomic.h \
+ thread/qbasicatomic.h \
+ thread/qgenericatomic.h \
thread/qoldbasicatomic.h
# private headers