summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib')
-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