1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#ifndef QATOMIC_X86_64_H
43#define QATOMIC_X86_64_H
44
45QT_BEGIN_HEADER
46
47QT_BEGIN_NAMESPACE
48
49#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE
50#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_WAIT_FREE
51
52inline bool QBasicAtomicInt::isReferenceCountingNative()
53{ return true; }
54inline bool QBasicAtomicInt::isReferenceCountingWaitFree()
55{ return true; }
56
57#define Q_ATOMIC_INT_TEST_AND_SET_IS_ALWAYS_NATIVE
58#define Q_ATOMIC_INT_TEST_AND_SET_IS_WAIT_FREE
59
60inline bool QBasicAtomicInt::isTestAndSetNative()
61{ return true; }
62inline bool QBasicAtomicInt::isTestAndSetWaitFree()
63{ return true; }
64
65#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE
66#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_WAIT_FREE
67
68inline bool QBasicAtomicInt::isFetchAndStoreNative()
69{ return true; }
70inline bool QBasicAtomicInt::isFetchAndStoreWaitFree()
71{ return true; }
72
73#define Q_ATOMIC_INT_FETCH_AND_ADD_IS_ALWAYS_NATIVE
74#define Q_ATOMIC_INT_FETCH_AND_ADD_IS_WAIT_FREE
75
76inline bool QBasicAtomicInt::isFetchAndAddNative()
77{ return true; }
78inline bool QBasicAtomicInt::isFetchAndAddWaitFree()
79{ return true; }
80
81#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE
82#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_WAIT_FREE
83
84template <typename T>
85Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isTestAndSetNative()
86{ return true; }
87template <typename T>
88Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isTestAndSetWaitFree()
89{ return true; }
90
91#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE
92#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_WAIT_FREE
93
94template <typename T>
95Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndStoreNative()
96{ return true; }
97template <typename T>
98Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndStoreWaitFree()
99{ return true; }
100
101#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_ALWAYS_NATIVE
102#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_WAIT_FREE
103
104template <typename T>
105Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndAddNative()
106{ return true; }
107template <typename T>
108Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndAddWaitFree()
109{ return true; }
110
111#if defined(Q_CC_GNU) || defined(Q_CC_INTEL)
112
113inline bool QBasicAtomicInt::ref()
114{
115 unsigned char ret;
116 asm volatile("lock\n"
117 "incl %0\n"
118 "setne %1"
119 : "=m" (_q_value), "=qm" (ret)
120 : "m" (_q_value)
121 : "memory");
122 return ret != 0;
123}
124
125inline bool QBasicAtomicInt::deref()
126{
127 unsigned char ret;
128 asm volatile("lock\n"
129 "decl %0\n"
130 "setne %1"
131 : "=m" (_q_value), "=qm" (ret)
132 : "m" (_q_value)
133 : "memory");
134 return ret != 0;
135}
136
137inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue)
138{
139 unsigned char ret;
140 asm volatile("lock\n"
141 "cmpxchgl %3,%2\n"
142 "sete %1\n"
143 : "=a" (newValue), "=qm" (ret), "+m" (_q_value)
144 : "r" (newValue), "0" (expectedValue)
145 : "memory");
146 return ret != 0;
147}
148
149inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue)
150{
151 asm volatile("xchgl %0,%1"
152 : "=r" (newValue), "+m" (_q_value)
153 : "0" (newValue)
154 : "memory");
155 return newValue;
156}
157
158inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd)
159{
160 asm volatile("lock\n"
161 "xaddl %0,%1"
162 : "=r" (valueToAdd), "+m" (_q_value)
163 : "0" (valueToAdd)
164 : "memory");
165 return valueToAdd;
166}
167
168template <typename T>
169Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetOrdered(T *expectedValue, T *newValue)
170{
171 unsigned char ret;
172 asm volatile("lock\n"
173 "cmpxchg %3,%2\n"
174 "sete %1\n"
175 : "=a" (newValue), "=qm" (ret), "+m" (_q_value)
176 : "r" (newValue), "0" (expectedValue)
177 : "memory");
178 return ret != 0;
179}
180
181template <typename T>
182Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreOrdered(T *newValue)
183{
184 asm volatile("xchg %0,%1"
185 : "=r" (newValue), "+m" (_q_value)
186 : "0" (newValue)
187 : "memory");
188 return newValue;
189}
190
191template <typename T>
192Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddOrdered(qptrdiff valueToAdd)
193{
194 asm volatile("lock\n"
195 "xadd %0,%1"
196 : "=r" (valueToAdd), "+m" (_q_value)
197 : "0" (valueToAdd * sizeof(T))
198 : "memory");
199 return reinterpret_cast<T *>(valueToAdd);
200}
201
202#else // !Q_CC_INTEL && !Q_CC_GNU
203
204extern "C" {
205 Q_CORE_EXPORT int q_atomic_test_and_set_int(volatile int *ptr, int expected, int newval);
206 Q_CORE_EXPORT int q_atomic_test_and_set_ptr(volatile void *ptr, void *expected, void *newval);
207 Q_CORE_EXPORT int q_atomic_increment(volatile int *ptr);
208 Q_CORE_EXPORT int q_atomic_decrement(volatile int *ptr);
209 Q_CORE_EXPORT int q_atomic_set_int(volatile int *ptr, int newval);
210 Q_CORE_EXPORT void *q_atomic_set_ptr(volatile void *ptr, void *newval);
211 Q_CORE_EXPORT int q_atomic_fetch_and_add_int(volatile int *ptr, int value);
212 Q_CORE_EXPORT void *q_atomic_fetch_and_add_ptr(volatile void *ptr, qptrdiff value);
213} // extern "C"
214
215inline bool QBasicAtomicInt::ref()
216{
217 return q_atomic_increment(&_q_value) != 0;
218}
219
220inline bool QBasicAtomicInt::deref()
221{
222 return q_atomic_decrement(&_q_value) != 0;
223}
224
225inline bool QBasicAtomicInt::testAndSetOrdered(int expected, int newval)
226{
227 return q_atomic_test_and_set_int(&_q_value, expected, newval) != 0;
228}
229
230inline int QBasicAtomicInt::fetchAndStoreOrdered(int newval)
231{
232 return q_atomic_set_int(&_q_value, newval);
233}
234
235inline int QBasicAtomicInt::fetchAndAddOrdered(int aValue)
236{
237 return q_atomic_fetch_and_add_int(&_q_value, aValue);
238}
239
240template <typename T>
241Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetOrdered(T *expectedValue, T *newValue)
242{
243 return q_atomic_test_and_set_ptr(&_q_value, expectedValue, newValue);
244}
245
246template <typename T>
247Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreOrdered(T *newValue)
248{
249 return reinterpret_cast<T *>(q_atomic_set_ptr(&_q_value, newValue));
250}
251
252template <typename T>
253Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddOrdered(qptrdiff valueToAdd)
254{
255 return reinterpret_cast<T *>(q_atomic_fetch_and_add_ptr(&_q_value, valueToAdd * sizeof(T)));
256}
257
258#endif // Q_CC_GNU || Q_CC_INTEL
259
260inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue)
261{
262 return testAndSetOrdered(expectedValue, newValue);
263}
264
265inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue)
266{
267 return testAndSetOrdered(expectedValue, newValue);
268}
269
270inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue)
271{
272 return testAndSetOrdered(expectedValue, newValue);
273}
274
275inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue)
276{
277 return fetchAndStoreOrdered(newValue);
278}
279
280inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue)
281{
282 return fetchAndStoreOrdered(newValue);
283}
284
285inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue)
286{
287 return fetchAndStoreOrdered(newValue);
288}
289
290inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd)
291{
292 return fetchAndAddOrdered(valueToAdd);
293}
294
295inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd)
296{
297 return fetchAndAddOrdered(valueToAdd);
298}
299
300inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd)
301{
302 return fetchAndAddOrdered(valueToAdd);
303}
304
305template <typename T>
306Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetRelaxed(T *expectedValue, T *newValue)
307{
308 return testAndSetOrdered(expectedValue, newValue);
309}
310
311template <typename T>
312Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetAcquire(T *expectedValue, T *newValue)
313{
314 return testAndSetOrdered(expectedValue, newValue);
315}
316
317template <typename T>
318Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetRelease(T *expectedValue, T *newValue)
319{
320 return testAndSetOrdered(expectedValue, newValue);
321}
322
323template <typename T>
324Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreRelaxed(T *newValue)
325{
326 return fetchAndStoreOrdered(newValue);
327}
328
329template <typename T>
330Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreAcquire(T *newValue)
331{
332 return fetchAndStoreOrdered(newValue);
333}
334
335template <typename T>
336Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreRelease(T *newValue)
337{
338 return fetchAndStoreOrdered(newValue);
339}
340
341template <typename T>
342Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddRelaxed(qptrdiff valueToAdd)
343{
344 return fetchAndAddOrdered(valueToAdd);
345}
346
347template <typename T>
348Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddAcquire(qptrdiff valueToAdd)
349{
350 return fetchAndAddOrdered(valueToAdd);
351}
352
353template <typename T>
354Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddRelease(qptrdiff valueToAdd)
355{
356 return fetchAndAddOrdered(valueToAdd);
357}
358
359QT_END_NAMESPACE
360
361QT_END_HEADER
362
363#endif // QATOMIC_X86_64_H
364