Kyle Lippincott has uploaded this change for review. (
https://review.gerrithub.io/c/ffilz/nfs-ganesha/+/1199063?usp=email )
Change subject: atomics: remove broken __sync-based implementations
......................................................................
atomics: remove broken __sync-based implementations
The "new" version of these functions, using functions with an `__atomic`
prefix have been available since gcc 4.7, released March 2012, which is
more than 12 years ago. We can just assume that the compilers in use
today support them; if this is incorrect, then we'll get an error
message during compilation.
This is not purely a code cleanup. Clang presents itself as gcc 4.2,
which means it's using the `__sync` versions of the functions per the
version checking being done at the top of the file, even though it
supports the `__atomic` versions. This is a missed performance
opportunity, even if the function implementations were correct, as the
`__atomic` versions may be faster. There's a reason we prefer them if
they're available, after all.
Furthermore, the versions of these functions that are based on the
`__sync` versions are broken. An example:
```
static inline int32_t atomic_inc_unless_0_int32_t(int32_t *var)
{
int32_t cur, newv;
bool changed;
cur = atomic_fetch_int32_t(var);
do {
if (cur == 0)
return 0;
newv = cur + 1;
changed = __sync_val_compare_and_swap(var, cur, newv) != cur;
} while (!changed);
return newv;
}
```
This has multiple issues:
- In the 99.99% case, we'll:
- fetch `*var` into `cur`,
- set `newv = cur + 1`,
- then atomically (possibly "transactionally") perform an operation
equivalent to:
```
old_value = *var;
if (*var == cur) *var = newv;
return old_value;
```
- This then does `changed = old_value != cur`, which is incorrect
since `__sync_val_compare_and_swap` returns the _original_ value
(whether it changed or not). This isn't correct; this should be
`changed = old_value == cur`, not `!=`.
- Basically: if nothing weird happens, we always go through the loop
_twice_.
- In the tragic 0.01% case, where some other thread modifies `var`
between the `atomic_fetch_int32_t` and `__sync_val_compare_and_swap`,
we'll get that other thread's value from `__sync_val_compare_and_swap`,
which won't be equal to `cur`, so we just skip incrementing at all.
- The implementation can't be fixed by just using the correct
comparison, because then you run into the possibility of an infinite
loop:
```
cur = 10; // atomic_fetch_int32_t(var)
do {
newv = 11; // cur + 1;
// !!!! Some other thread sets *var to 50 !!!!
changed = false; // 50 == 10, since sync_val... returns 50
} while (!changed); // loops until some other thread sets it to 10
```
- We could capture the value from `__sync_val_compare_and_swap`, and
update `cur`, or we could switch to `__sync_bool_compare_and_swap`
and move the `atomic_fetch_int32_t` into the `do {} while` loop to
resolve this other issue.
- It seems like there might have been some confusion about what the
`_and_swap` part of the function name meant (i.e. that it updated
`cur`), and also an assumption that the function would return the
_new_ value, like `__atomic_add_fetch` does.
Ultimately, however, these `__sync` functions are old, the replacements
(`__atomic`) are also old and broadly available, and maintaining two
implementations of these functions is a cost that we shouldn't have to
take.
Remove the broken, legacy versions of the atomic functions that use the
`__sync` compiler builtins.
Change-Id: I1851d4e37cb9ecfeb5959736f682a9625cc42be5
Signed-off-by: Kyle Lippincott <spectral(a)google.com>
---
M src/include/abstract_atomic.h
M src/include/atomic_utils.h
2 files changed, 0 insertions(+), 684 deletions(-)
git pull ssh://review.gerrithub.io:29418/ffilz/nfs-ganesha refs/changes/63/1199063/1
--
To view, visit
https://review.gerrithub.io/c/ffilz/nfs-ganesha/+/1199063?usp=email
To unsubscribe, or for help writing mail filters, visit
https://review.gerrithub.io/settings?usp=email
Gerrit-MessageType: newchange
Gerrit-Project: ffilz/nfs-ganesha
Gerrit-Branch: next
Gerrit-Change-Id: I1851d4e37cb9ecfeb5959736f682a9625cc42be5
Gerrit-Change-Number: 1199063
Gerrit-PatchSet: 1
Gerrit-Owner: Kyle Lippincott <spectral(a)google.com>