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><atomic> 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><atomic> 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 <= 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 <= 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 <class T> 172T 173__atomic_load(T const volatile* obj) 174{ 175 unique_lock<mutex> _(some_mutex); 176 return *obj; 177} 178 179template <class T> 180void 181__atomic_store(T volatile* obj, T desr) 182{ 183 unique_lock<mutex> _(some_mutex); 184 *obj = desr; 185} 186 187template <class T> 188T 189__atomic_exchange(T volatile* obj, T desr) 190{ 191 unique_lock<mutex> _(some_mutex); 192 T r = *obj; 193 *obj = desr; 194 return r; 195} 196 197template <class T> 198bool 199__atomic_compare_exchange_strong(T volatile* obj, T* exp, T desr) 200{ 201 unique_lock<mutex> _(some_mutex); 202 if (std::memcmp(const_cast<T*>(obj), exp, sizeof(T)) == 0) <font color="#C80000">// if (*obj == *exp)</font> 203 { 204 std::memcpy(const_cast<T*>(obj), &desr, sizeof(T)); <font color="#C80000">// *obj = desr;</font> 205 return true; 206 } 207 std::memcpy(exp, const_cast<T*>(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 <class T> 213bool 214__atomic_compare_exchange_weak(T volatile* obj, T* exp, T desr) 215{ 216 unique_lock<mutex> _(some_mutex); 217 if (std::memcmp(const_cast<T*>(obj), exp, sizeof(T)) == 0) <font color="#C80000">// if (*obj == *exp)</font> 218 { 219 std::memcpy(const_cast<T*>(obj), &desr, sizeof(T)); <font color="#C80000">// *obj = desr;</font> 220 return true; 221 } 222 std::memcpy(exp, const_cast<T*>(obj), sizeof(T)); <font color="#C80000">// *exp = *obj;</font> 223 return false; 224} 225 226template <class T> 227T 228__atomic_fetch_add(T volatile* obj, T operand) 229{ 230 unique_lock<mutex> _(some_mutex); 231 T r = *obj; 232 *obj += operand; 233 return r; 234} 235 236template <class T> 237T 238__atomic_fetch_sub(T volatile* obj, T operand) 239{ 240 unique_lock<mutex> _(some_mutex); 241 T r = *obj; 242 *obj -= operand; 243 return r; 244} 245 246template <class T> 247T 248__atomic_fetch_and(T volatile* obj, T operand) 249{ 250 unique_lock<mutex> _(some_mutex); 251 T r = *obj; 252 *obj &= operand; 253 return r; 254} 255 256template <class T> 257T 258__atomic_fetch_or(T volatile* obj, T operand) 259{ 260 unique_lock<mutex> _(some_mutex); 261 T r = *obj; 262 *obj |= operand; 263 return r; 264} 265 266template <class T> 267T 268__atomic_fetch_xor(T volatile* obj, T operand) 269{ 270 unique_lock<mutex> _(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<mutex> _(some_mutex); 280 void* r = *obj; 281 (char*&)(*obj) += operand; 282 return r; 283} 284 285void* 286__atomic_fetch_sub(void* volatile* obj, ptrdiff_t operand) 287{ 288 unique_lock<mutex> _(some_mutex); 289 void* r = *obj; 290 (char*&)(*obj) -= operand; 291 return r; 292} 293 294void __atomic_thread_fence() 295{ 296 unique_lock<mutex> _(some_mutex); 297} 298 299void __atomic_signal_fence() 300{ 301 unique_lock<mutex> _(some_mutex); 302} 303</pre></blockquote> 304 305 306</div> 307</body> 308</html> 309