atomic_design_a.html
10.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title><atomic> design</title>
<link type="text/css" rel="stylesheet" href="menu.css">
<link type="text/css" rel="stylesheet" href="content.css">
</head>
<body>
<div id="menu">
<div>
<a href="https://llvm.org/">LLVM Home</a>
</div>
<div class="submenu">
<label>libc++ Info</label>
<a href="/index.html">About</a>
</div>
<div class="submenu">
<label>Quick Links</label>
<a href="https://lists.llvm.org/mailman/listinfo/cfe-dev">cfe-dev</a>
<a href="https://lists.llvm.org/mailman/listinfo/cfe-commits">cfe-commits</a>
<a href="https://bugs.llvm.org/">Bug Reports</a>
<a href="https://github.com/llvm/llvm-project/tree/master/libcxx/">Browse Sources</a>
</div>
</div>
<div id="content">
<!--*********************************************************************-->
<h1><atomic> design</h1>
<!--*********************************************************************-->
<p>
The compiler supplies all of the intrinsics as described below. This list of
intrinsics roughly parallels the requirements of the C and C++ atomics
proposals. The C and C++ library implementations simply drop through to these
intrinsics. Anything the platform does not support in hardware, the compiler
arranges for a (compiler-rt) library call to be made which will do the job with
a mutex, and in this case ignoring the memory ordering parameter (effectively
implementing <tt>memory_order_seq_cst</tt>).
</p>
<p>
Ultimate efficiency is preferred over run time error checking. Undefined
behavior is acceptable when the inputs do not conform as defined below.
</p>
<blockquote><pre>
<font color="#C80000">// In every intrinsic signature below, type* atomic_obj may be a pointer to a</font>
<font color="#C80000">// volatile-qualified type.</font>
<font color="#C80000">// Memory ordering values map to the following meanings:</font>
<font color="#C80000">// memory_order_relaxed == 0</font>
<font color="#C80000">// memory_order_consume == 1</font>
<font color="#C80000">// memory_order_acquire == 2</font>
<font color="#C80000">// memory_order_release == 3</font>
<font color="#C80000">// memory_order_acq_rel == 4</font>
<font color="#C80000">// memory_order_seq_cst == 5</font>
<font color="#C80000">// type must be trivially copyable</font>
<font color="#C80000">// type represents a "type argument"</font>
bool __atomic_is_lock_free(type);
<font color="#C80000">// type must be trivially copyable</font>
<font color="#C80000">// Behavior is defined for mem_ord = 0, 1, 2, 5</font>
type __atomic_load(const type* atomic_obj, int mem_ord);
<font color="#C80000">// type must be trivially copyable</font>
<font color="#C80000">// Behavior is defined for mem_ord = 0, 3, 5</font>
void __atomic_store(type* atomic_obj, type desired, int mem_ord);
<font color="#C80000">// type must be trivially copyable</font>
<font color="#C80000">// Behavior is defined for mem_ord = [0 ... 5]</font>
type __atomic_exchange(type* atomic_obj, type desired, int mem_ord);
<font color="#C80000">// type must be trivially copyable</font>
<font color="#C80000">// Behavior is defined for mem_success = [0 ... 5],</font>
<font color="#C80000">// mem_failure <= mem_success</font>
<font color="#C80000">// mem_failure != 3</font>
<font color="#C80000">// mem_failure != 4</font>
bool __atomic_compare_exchange_strong(type* atomic_obj,
type* expected, type desired,
int mem_success, int mem_failure);
<font color="#C80000">// type must be trivially copyable</font>
<font color="#C80000">// Behavior is defined for mem_success = [0 ... 5],</font>
<font color="#C80000">// mem_failure <= mem_success</font>
<font color="#C80000">// mem_failure != 3</font>
<font color="#C80000">// mem_failure != 4</font>
bool __atomic_compare_exchange_weak(type* atomic_obj,
type* expected, type desired,
int mem_success, int mem_failure);
<font color="#C80000">// type is one of: char, signed char, unsigned char, short, unsigned short, int,</font>
<font color="#C80000">// unsigned int, long, unsigned long, long long, unsigned long long,</font>
<font color="#C80000">// char16_t, char32_t, wchar_t</font>
<font color="#C80000">// Behavior is defined for mem_ord = [0 ... 5]</font>
type __atomic_fetch_add(type* atomic_obj, type operand, int mem_ord);
<font color="#C80000">// type is one of: char, signed char, unsigned char, short, unsigned short, int,</font>
<font color="#C80000">// unsigned int, long, unsigned long, long long, unsigned long long,</font>
<font color="#C80000">// char16_t, char32_t, wchar_t</font>
<font color="#C80000">// Behavior is defined for mem_ord = [0 ... 5]</font>
type __atomic_fetch_sub(type* atomic_obj, type operand, int mem_ord);
<font color="#C80000">// type is one of: char, signed char, unsigned char, short, unsigned short, int,</font>
<font color="#C80000">// unsigned int, long, unsigned long, long long, unsigned long long,</font>
<font color="#C80000">// char16_t, char32_t, wchar_t</font>
<font color="#C80000">// Behavior is defined for mem_ord = [0 ... 5]</font>
type __atomic_fetch_and(type* atomic_obj, type operand, int mem_ord);
<font color="#C80000">// type is one of: char, signed char, unsigned char, short, unsigned short, int,</font>
<font color="#C80000">// unsigned int, long, unsigned long, long long, unsigned long long,</font>
<font color="#C80000">// char16_t, char32_t, wchar_t</font>
<font color="#C80000">// Behavior is defined for mem_ord = [0 ... 5]</font>
type __atomic_fetch_or(type* atomic_obj, type operand, int mem_ord);
<font color="#C80000">// type is one of: char, signed char, unsigned char, short, unsigned short, int,</font>
<font color="#C80000">// unsigned int, long, unsigned long, long long, unsigned long long,</font>
<font color="#C80000">// char16_t, char32_t, wchar_t</font>
<font color="#C80000">// Behavior is defined for mem_ord = [0 ... 5]</font>
type __atomic_fetch_xor(type* atomic_obj, type operand, int mem_ord);
<font color="#C80000">// Behavior is defined for mem_ord = [0 ... 5]</font>
void* __atomic_fetch_add(void** atomic_obj, ptrdiff_t operand, int mem_ord);
void* __atomic_fetch_sub(void** atomic_obj, ptrdiff_t operand, int mem_ord);
<font color="#C80000">// Behavior is defined for mem_ord = [0 ... 5]</font>
void __atomic_thread_fence(int mem_ord);
void __atomic_signal_fence(int mem_ord);
</pre></blockquote>
<p>
If desired the intrinsics taking a single <tt>mem_ord</tt> parameter can default
this argument to 5.
</p>
<p>
If desired the intrinsics taking two ordering parameters can default
<tt>mem_success</tt> to 5, and <tt>mem_failure</tt> to
<tt>translate_memory_order(mem_success)</tt> where
<tt>translate_memory_order(mem_success)</tt> is defined as:
</p>
<blockquote><pre>
int
translate_memory_order(int o)
{
switch (o)
{
case 4:
return 2;
case 3:
return 0;
}
return o;
}
</pre></blockquote>
<p>
Below are representative C++ implementations of all of the operations. Their
purpose is to document the desired semantics of each operation, assuming
<tt>memory_order_seq_cst</tt>. This is essentially the code that will be called
if the front end calls out to compiler-rt.
</p>
<blockquote><pre>
template <class T>
T
__atomic_load(T const volatile* obj)
{
unique_lock<mutex> _(some_mutex);
return *obj;
}
template <class T>
void
__atomic_store(T volatile* obj, T desr)
{
unique_lock<mutex> _(some_mutex);
*obj = desr;
}
template <class T>
T
__atomic_exchange(T volatile* obj, T desr)
{
unique_lock<mutex> _(some_mutex);
T r = *obj;
*obj = desr;
return r;
}
template <class T>
bool
__atomic_compare_exchange_strong(T volatile* obj, T* exp, T desr)
{
unique_lock<mutex> _(some_mutex);
if (std::memcmp(const_cast<T*>(obj), exp, sizeof(T)) == 0) <font color="#C80000">// if (*obj == *exp)</font>
{
std::memcpy(const_cast<T*>(obj), &desr, sizeof(T)); <font color="#C80000">// *obj = desr;</font>
return true;
}
std::memcpy(exp, const_cast<T*>(obj), sizeof(T)); <font color="#C80000">// *exp = *obj;</font>
return false;
}
<font color="#C80000">// May spuriously return false (even if *obj == *exp)</font>
template <class T>
bool
__atomic_compare_exchange_weak(T volatile* obj, T* exp, T desr)
{
unique_lock<mutex> _(some_mutex);
if (std::memcmp(const_cast<T*>(obj), exp, sizeof(T)) == 0) <font color="#C80000">// if (*obj == *exp)</font>
{
std::memcpy(const_cast<T*>(obj), &desr, sizeof(T)); <font color="#C80000">// *obj = desr;</font>
return true;
}
std::memcpy(exp, const_cast<T*>(obj), sizeof(T)); <font color="#C80000">// *exp = *obj;</font>
return false;
}
template <class T>
T
__atomic_fetch_add(T volatile* obj, T operand)
{
unique_lock<mutex> _(some_mutex);
T r = *obj;
*obj += operand;
return r;
}
template <class T>
T
__atomic_fetch_sub(T volatile* obj, T operand)
{
unique_lock<mutex> _(some_mutex);
T r = *obj;
*obj -= operand;
return r;
}
template <class T>
T
__atomic_fetch_and(T volatile* obj, T operand)
{
unique_lock<mutex> _(some_mutex);
T r = *obj;
*obj &= operand;
return r;
}
template <class T>
T
__atomic_fetch_or(T volatile* obj, T operand)
{
unique_lock<mutex> _(some_mutex);
T r = *obj;
*obj |= operand;
return r;
}
template <class T>
T
__atomic_fetch_xor(T volatile* obj, T operand)
{
unique_lock<mutex> _(some_mutex);
T r = *obj;
*obj ^= operand;
return r;
}
void*
__atomic_fetch_add(void* volatile* obj, ptrdiff_t operand)
{
unique_lock<mutex> _(some_mutex);
void* r = *obj;
(char*&)(*obj) += operand;
return r;
}
void*
__atomic_fetch_sub(void* volatile* obj, ptrdiff_t operand)
{
unique_lock<mutex> _(some_mutex);
void* r = *obj;
(char*&)(*obj) -= operand;
return r;
}
void __atomic_thread_fence()
{
unique_lock<mutex> _(some_mutex);
}
void __atomic_signal_fence()
{
unique_lock<mutex> _(some_mutex);
}
</pre></blockquote>
</div>
</body>
</html>