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