1/****************************************************************************
2**
3** Copyright (C) 2017 The Qt Company Ltd.
4** Copyright (C) 2016 Intel Corporation.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the QtCore module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or (at your option) the GNU General
29** Public license version 3 or any later version approved by the KDE Free
30** Qt Foundation. The licenses are as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32** included in the packaging of this file. Please review the following
33** information to ensure the GNU General Public License requirements will
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35** https://www.gnu.org/licenses/gpl-3.0.html.
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#include <QtCore/qglobal.h>
42
43#ifndef QATOMIC_H
44#define QATOMIC_H
45
46#include <QtCore/qbasicatomic.h>
47
48QT_BEGIN_NAMESPACE
49
50QT_WARNING_PUSH
51QT_WARNING_DISABLE_GCC("-Wextra")
52
53// High-level atomic integer operations
54template <typename T>
55class QAtomicInteger : public QBasicAtomicInteger<T>
56{
57public:
58 // Non-atomic API
59#ifdef QT_BASIC_ATOMIC_HAS_CONSTRUCTORS
60 constexpr QAtomicInteger(T value = 0) noexcept : QBasicAtomicInteger<T>(value) {}
61#else
62 inline QAtomicInteger(T value = 0) noexcept
63 {
64 this->_q_value = value;
65 }
66#endif
67
68 inline QAtomicInteger(const QAtomicInteger &other) noexcept
69#ifdef QT_BASIC_ATOMIC_HAS_CONSTRUCTORS
70 : QBasicAtomicInteger<T>()
71#endif
72 {
73 this->storeRelease(other.loadAcquire());
74 }
75
76 inline QAtomicInteger &operator=(const QAtomicInteger &other) noexcept
77 {
78 this->storeRelease(other.loadAcquire());
79 return *this;
80 }
81
82#ifdef Q_CLANG_QDOC
83 T load() const;
84 T loadRelaxed() const;
85 T loadAcquire() const;
86 void store(T newValue);
87 void storeRelaxed(T newValue);
88 void storeRelease(T newValue);
89
90 operator T() const;
91 QAtomicInteger &operator=(T);
92
93 static Q_DECL_CONSTEXPR bool isReferenceCountingNative();
94 static Q_DECL_CONSTEXPR bool isReferenceCountingWaitFree();
95
96 bool ref();
97 bool deref();
98
99 static Q_DECL_CONSTEXPR bool isTestAndSetNative();
100 static Q_DECL_CONSTEXPR bool isTestAndSetWaitFree();
101
102 bool testAndSetRelaxed(T expectedValue, T newValue);
103 bool testAndSetAcquire(T expectedValue, T newValue);
104 bool testAndSetRelease(T expectedValue, T newValue);
105 bool testAndSetOrdered(T expectedValue, T newValue);
106
107 static Q_DECL_CONSTEXPR bool isFetchAndStoreNative();
108 static Q_DECL_CONSTEXPR bool isFetchAndStoreWaitFree();
109
110 T fetchAndStoreRelaxed(T newValue);
111 T fetchAndStoreAcquire(T newValue);
112 T fetchAndStoreRelease(T newValue);
113 T fetchAndStoreOrdered(T newValue);
114
115 static Q_DECL_CONSTEXPR bool isFetchAndAddNative();
116 static Q_DECL_CONSTEXPR bool isFetchAndAddWaitFree();
117
118 T fetchAndAddRelaxed(T valueToAdd);
119 T fetchAndAddAcquire(T valueToAdd);
120 T fetchAndAddRelease(T valueToAdd);
121 T fetchAndAddOrdered(T valueToAdd);
122
123 T fetchAndSubRelaxed(T valueToSub);
124 T fetchAndSubAcquire(T valueToSub);
125 T fetchAndSubRelease(T valueToSub);
126 T fetchAndSubOrdered(T valueToSub);
127
128 T fetchAndOrRelaxed(T valueToOr);
129 T fetchAndOrAcquire(T valueToOr);
130 T fetchAndOrRelease(T valueToOr);
131 T fetchAndOrOrdered(T valueToOr);
132
133 T fetchAndAndRelaxed(T valueToAnd);
134 T fetchAndAndAcquire(T valueToAnd);
135 T fetchAndAndRelease(T valueToAnd);
136 T fetchAndAndOrdered(T valueToAnd);
137
138 T fetchAndXorRelaxed(T valueToXor);
139 T fetchAndXorAcquire(T valueToXor);
140 T fetchAndXorRelease(T valueToXor);
141 T fetchAndXorOrdered(T valueToXor);
142
143 T operator++();
144 T operator++(int);
145 T operator--();
146 T operator--(int);
147 T operator+=(T value);
148 T operator-=(T value);
149 T operator|=(T value);
150 T operator&=(T value);
151 T operator^=(T value);
152#endif
153};
154
155class QAtomicInt : public QAtomicInteger<int>
156{
157public:
158 // Non-atomic API
159 // We could use QT_COMPILER_INHERITING_CONSTRUCTORS, but we need only one;
160 // the implicit definition for all the others is fine.
161#ifdef QT_BASIC_ATOMIC_HAS_CONSTRUCTORS
162 constexpr
163#endif
164 QAtomicInt(int value = 0) noexcept : QAtomicInteger<int>(value) {}
165};
166
167// High-level atomic pointer operations
168template <typename T>
169class QAtomicPointer : public QBasicAtomicPointer<T>
170{
171public:
172#ifdef QT_BASIC_ATOMIC_HAS_CONSTRUCTORS
173 constexpr QAtomicPointer(T *value = nullptr) noexcept : QBasicAtomicPointer<T>(value) {}
174#else
175 inline QAtomicPointer(T *value = nullptr) noexcept
176 {
177 this->storeRelaxed(value);
178 }
179#endif
180 inline QAtomicPointer(const QAtomicPointer<T> &other) noexcept
181#ifdef QT_BASIC_ATOMIC_HAS_CONSTRUCTORS
182 : QBasicAtomicPointer<T>()
183#endif
184 {
185 this->storeRelease(other.loadAcquire());
186 }
187
188 inline QAtomicPointer<T> &operator=(const QAtomicPointer<T> &other) noexcept
189 {
190 this->storeRelease(other.loadAcquire());
191 return *this;
192 }
193
194#ifdef Q_QDOC
195 T *load() const;
196 T *loadAcquire() const;
197 void store(T *newValue);
198 void storeRelease(T *newValue);
199
200 static Q_DECL_CONSTEXPR bool isTestAndSetNative();
201 static Q_DECL_CONSTEXPR bool isTestAndSetWaitFree();
202
203 bool testAndSetRelaxed(T *expectedValue, T *newValue);
204 bool testAndSetAcquire(T *expectedValue, T *newValue);
205 bool testAndSetRelease(T *expectedValue, T *newValue);
206 bool testAndSetOrdered(T *expectedValue, T *newValue);
207
208 static Q_DECL_CONSTEXPR bool isFetchAndStoreNative();
209 static Q_DECL_CONSTEXPR bool isFetchAndStoreWaitFree();
210
211 T *fetchAndStoreRelaxed(T *newValue);
212 T *fetchAndStoreAcquire(T *newValue);
213 T *fetchAndStoreRelease(T *newValue);
214 T *fetchAndStoreOrdered(T *newValue);
215
216 static Q_DECL_CONSTEXPR bool isFetchAndAddNative();
217 static Q_DECL_CONSTEXPR bool isFetchAndAddWaitFree();
218
219 T *fetchAndAddRelaxed(qptrdiff valueToAdd);
220 T *fetchAndAddAcquire(qptrdiff valueToAdd);
221 T *fetchAndAddRelease(qptrdiff valueToAdd);
222 T *fetchAndAddOrdered(qptrdiff valueToAdd);
223#endif
224};
225
226QT_WARNING_POP
227
228#ifdef QT_BASIC_ATOMIC_HAS_CONSTRUCTORS
229# undef QT_BASIC_ATOMIC_HAS_CONSTRUCTORS
230#endif
231
232/*!
233 This is a helper for the assignment operators of implicitly
234 shared classes. Your assignment operator should look like this:
235
236 \snippet code/src.corelib.thread.qatomic.h 0
237*/
238template <typename T>
239inline void qAtomicAssign(T *&d, T *x)
240{
241 if (d == x)
242 return;
243 x->ref.ref();
244 if (!d->ref.deref())
245 delete d;
246 d = x;
247}
248
249/*!
250 This is a helper for the detach method of implicitly shared
251 classes. Your private class needs a copy constructor which copies
252 the members and sets the refcount to 1. After that, your detach
253 function should look like this:
254
255 \snippet code/src.corelib.thread.qatomic.h 1
256*/
257template <typename T>
258inline void qAtomicDetach(T *&d)
259{
260 if (d->ref.loadRelaxed() == 1)
261 return;
262 T *x = d;
263 d = new T(*d);
264 if (!x->ref.deref())
265 delete x;
266}
267
268QT_END_NAMESPACE
269#endif // QATOMIC_H
270