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#ifdef Q_CLANG_QDOC
54# undef QT_BASIC_ATOMIC_HAS_CONSTRUCTORS
55#endif
56
57// High-level atomic integer operations
58template <typename T>
59class QAtomicInteger : public QBasicAtomicInteger<T>
60{
61public:
62 // Non-atomic API
63#ifdef QT_BASIC_ATOMIC_HAS_CONSTRUCTORS
64 constexpr QAtomicInteger(T value = 0) noexcept : QBasicAtomicInteger<T>(value) {}
65#else
66 inline QAtomicInteger(T value = 0) noexcept
67 {
68 this->_q_value = value;
69 }
70#endif
71
72 inline QAtomicInteger(const QAtomicInteger &other) noexcept
73#ifdef QT_BASIC_ATOMIC_HAS_CONSTRUCTORS
74 : QBasicAtomicInteger<T>()
75#endif
76 {
77 this->storeRelease(other.loadAcquire());
78 }
79
80 inline QAtomicInteger &operator=(const QAtomicInteger &other) noexcept
81 {
82 this->storeRelease(other.loadAcquire());
83 return *this;
84 }
85
86#ifdef Q_CLANG_QDOC
87 T load() const;
88 T loadRelaxed() const;
89 T loadAcquire() const;
90 void store(T newValue);
91 void storeRelaxed(T newValue);
92 void storeRelease(T newValue);
93
94 operator T() const;
95 QAtomicInteger &operator=(T);
96
97 static Q_DECL_CONSTEXPR bool isReferenceCountingNative();
98 static Q_DECL_CONSTEXPR bool isReferenceCountingWaitFree();
99
100 bool ref();
101 bool deref();
102
103 static Q_DECL_CONSTEXPR bool isTestAndSetNative();
104 static Q_DECL_CONSTEXPR bool isTestAndSetWaitFree();
105
106 bool testAndSetRelaxed(T expectedValue, T newValue);
107 bool testAndSetAcquire(T expectedValue, T newValue);
108 bool testAndSetRelease(T expectedValue, T newValue);
109 bool testAndSetOrdered(T expectedValue, T newValue);
110
111 static Q_DECL_CONSTEXPR bool isFetchAndStoreNative();
112 static Q_DECL_CONSTEXPR bool isFetchAndStoreWaitFree();
113
114 T fetchAndStoreRelaxed(T newValue);
115 T fetchAndStoreAcquire(T newValue);
116 T fetchAndStoreRelease(T newValue);
117 T fetchAndStoreOrdered(T newValue);
118
119 static Q_DECL_CONSTEXPR bool isFetchAndAddNative();
120 static Q_DECL_CONSTEXPR bool isFetchAndAddWaitFree();
121
122 T fetchAndAddRelaxed(T valueToAdd);
123 T fetchAndAddAcquire(T valueToAdd);
124 T fetchAndAddRelease(T valueToAdd);
125 T fetchAndAddOrdered(T valueToAdd);
126
127 T fetchAndSubRelaxed(T valueToSub);
128 T fetchAndSubAcquire(T valueToSub);
129 T fetchAndSubRelease(T valueToSub);
130 T fetchAndSubOrdered(T valueToSub);
131
132 T fetchAndOrRelaxed(T valueToOr);
133 T fetchAndOrAcquire(T valueToOr);
134 T fetchAndOrRelease(T valueToOr);
135 T fetchAndOrOrdered(T valueToOr);
136
137 T fetchAndAndRelaxed(T valueToAnd);
138 T fetchAndAndAcquire(T valueToAnd);
139 T fetchAndAndRelease(T valueToAnd);
140 T fetchAndAndOrdered(T valueToAnd);
141
142 T fetchAndXorRelaxed(T valueToXor);
143 T fetchAndXorAcquire(T valueToXor);
144 T fetchAndXorRelease(T valueToXor);
145 T fetchAndXorOrdered(T valueToXor);
146
147 T operator++();
148 T operator++(int);
149 T operator--();
150 T operator--(int);
151 T operator+=(T value);
152 T operator-=(T value);
153 T operator|=(T value);
154 T operator&=(T value);
155 T operator^=(T value);
156#endif
157};
158
159class QAtomicInt : public QAtomicInteger<int>
160{
161public:
162 // Non-atomic API
163 // We could use QT_COMPILER_INHERITING_CONSTRUCTORS, but we need only one;
164 // the implicit definition for all the others is fine.
165#ifdef QT_BASIC_ATOMIC_HAS_CONSTRUCTORS
166 constexpr
167#endif
168 QAtomicInt(int value = 0) noexcept : QAtomicInteger<int>(value) {}
169};
170
171// High-level atomic pointer operations
172template <typename T>
173class QAtomicPointer : public QBasicAtomicPointer<T>
174{
175public:
176#ifdef QT_BASIC_ATOMIC_HAS_CONSTRUCTORS
177 constexpr QAtomicPointer(T *value = nullptr) noexcept : QBasicAtomicPointer<T>(value) {}
178#else
179 inline QAtomicPointer(T *value = nullptr) noexcept
180 {
181 this->storeRelaxed(value);
182 }
183#endif
184 inline QAtomicPointer(const QAtomicPointer<T> &other) noexcept
185#ifdef QT_BASIC_ATOMIC_HAS_CONSTRUCTORS
186 : QBasicAtomicPointer<T>()
187#endif
188 {
189 this->storeRelease(other.loadAcquire());
190 }
191
192 inline QAtomicPointer<T> &operator=(const QAtomicPointer<T> &other) noexcept
193 {
194 this->storeRelease(other.loadAcquire());
195 return *this;
196 }
197
198#ifdef Q_QDOC
199 T *load() const;
200 T *loadAcquire() const;
201 T *loadRelaxed() const;
202 void store(T *newValue);
203 void storeRelaxed(T *newValue);
204 void storeRelease(T *newValue);
205
206 static Q_DECL_CONSTEXPR bool isTestAndSetNative();
207 static Q_DECL_CONSTEXPR bool isTestAndSetWaitFree();
208
209 bool testAndSetRelaxed(T *expectedValue, T *newValue);
210 bool testAndSetAcquire(T *expectedValue, T *newValue);
211 bool testAndSetRelease(T *expectedValue, T *newValue);
212 bool testAndSetOrdered(T *expectedValue, T *newValue);
213
214 static Q_DECL_CONSTEXPR bool isFetchAndStoreNative();
215 static Q_DECL_CONSTEXPR bool isFetchAndStoreWaitFree();
216
217 T *fetchAndStoreRelaxed(T *newValue);
218 T *fetchAndStoreAcquire(T *newValue);
219 T *fetchAndStoreRelease(T *newValue);
220 T *fetchAndStoreOrdered(T *newValue);
221
222 static Q_DECL_CONSTEXPR bool isFetchAndAddNative();
223 static Q_DECL_CONSTEXPR bool isFetchAndAddWaitFree();
224
225 T *fetchAndAddRelaxed(qptrdiff valueToAdd);
226 T *fetchAndAddAcquire(qptrdiff valueToAdd);
227 T *fetchAndAddRelease(qptrdiff valueToAdd);
228 T *fetchAndAddOrdered(qptrdiff valueToAdd);
229#endif
230};
231
232QT_WARNING_POP
233
234#ifdef QT_BASIC_ATOMIC_HAS_CONSTRUCTORS
235# undef QT_BASIC_ATOMIC_HAS_CONSTRUCTORS
236#endif
237
238/*!
239 This is a helper for the assignment operators of implicitly
240 shared classes. Your assignment operator should look like this:
241
242 \snippet code/src.corelib.thread.qatomic.h 0
243*/
244template <typename T>
245inline void qAtomicAssign(T *&d, T *x)
246{
247 if (d == x)
248 return;
249 x->ref.ref();
250 if (!d->ref.deref())
251 delete d;
252 d = x;
253}
254
255/*!
256 This is a helper for the detach method of implicitly shared
257 classes. Your private class needs a copy constructor which copies
258 the members and sets the refcount to 1. After that, your detach
259 function should look like this:
260
261 \snippet code/src.corelib.thread.qatomic.h 1
262*/
263template <typename T>
264inline void qAtomicDetach(T *&d)
265{
266 if (d->ref.loadRelaxed() == 1)
267 return;
268 T *x = d;
269 d = new T(*d);
270 if (!x->ref.deref())
271 delete x;
272}
273
274QT_END_NAMESPACE
275#endif // QATOMIC_H
276