There seems to be a significant amount of confusion around the new try_cmpxchg(), despite this being more like the C11 atomic_compare_exchange_*() family. Add a few words of clarification on how cmpxchg() and try_cmpxchg() relate to one another.
Unified · Split
| @@ -271,3 +271,44 @@ WRITE_ONCE. Thus: · 270 unmodified lines | ||
| 271 | 271 | SC *y, t; |
| 272 | 272 | |
| 273 | 273 | is allowed. |
| 274 | + | |
| 275 | + | |
| 276 | +CMPXCHG vs TRY_CMPXCHG | |
| 277 | +---------------------- | |
| 278 | + | |
| 279 | + int atomic_cmpxchg(atomic_t *ptr, int old, int new); | |
| 280 | + bool atomic_try_cmpxchg(atomic_t *ptr, int *oldp, int new); | |
| 281 | + | |
| 282 | +Both provide the same functionality, but try_cmpxchg() can lead to more | |
| 283 | +compact code. The functions relate like: | |
| 284 | + | |
| 285 | + bool atomic_try_cmpxchg(atomic_t *ptr, int *oldp, int new) | |
| 286 | + { | |
| 287 | + int ret, old = *oldp; | |
| 288 | + ret = atomic_cmpxchg(ptr, old, new); | |
| 289 | + if (ret != old) | |
| 290 | + *oldp = ret; | |
| 291 | + return ret == old; | |
| 292 | + } | |
| 293 | + | |
| 294 | +and: | |
| 295 | + | |
| 296 | + int atomic_cmpxchg(atomic_t *ptr, int old, int new) | |
| 297 | + { | |
| 298 | + (void)atomic_try_cmpxchg(ptr, &old, new); | |
| 299 | + return old; | |
| 300 | + } | |
| 301 | + | |
| 302 | +Usage: | |
| 303 | + | |
| 304 | + old = atomic_read(&v); old = atomic_read(&v); | |
| 305 | + for (;;) { do { | |
| 306 | + new = func(old); new = func(old); | |
| 307 | + tmp = atomic_cmpxchg(&v, old, new); } while (!atomic_try_cmpxchg(&v, &old, new)); | |
| 308 | + if (tmp == old) | |
| 309 | + break; | |
| 310 | + old = tmp; | |
| 311 | + } | |
| 312 | + | |
| 313 | +NB. try_cmpxchg() also generates better code on some platforms (notably x86) | |
| 314 | +where the function more closely matches the hardware instruction. | |