On Thu, Mar 24, 2022 at 11:01:30AM +0100, Tom de Vries wrote:
> > Shouldn't that be instead
> > return (woldval & ((UWORD) -1 << shift)) != 0;
> > or
> > return (woldval & ((UWORD) ~(UWORD) 0 << shift)) != 0;
> > ?
>
> Well, I used '(woldval & wval) == wval' based on the fact that the set
> operation uses a bitor:
> ...
> wval = (UWORD)__GCC_ATOMIC_TEST_AND_SET_TRUEVAL << shift;
> woldval = __atomic_load_n (wptr, __ATOMIC_RELAXED);
> do
> {
> t = woldval | wval;
> ...
> so apparently we do not care here about bits not in
> __GCC_ATOMIC_TEST_AND_SET_TRUEVAL (or alternatively, we care but assume that
> they're 0).
>
> AFAIU, it would have been more precise to compare the entire byte with
> __GCC_ATOMIC_TEST_AND_SET_TRUEVAL, but then it would have made sense to set
> the entire byte in the set part as well.
>
> Anyway, that doesn't seem to be what you're proposing. During investigation
> of the failure I found that the address used is word-aligned, so shift
> becomes 0 in that case. AFAICT, the fix you're proposing is a nop for shift
> == 0, and indeed, it doesn't fix the failure I'm observing.
Ah, sorry, I certainly meant
return (woldval & ((UTYPE) -1 << shift)) != 0;
or
return (woldval & ((UTYPE) ~(UTYPE) 0 << shift)) != 0;
i.e. more portable ways of
return (woldval & (0xff << shift)) != 0;
which don't hardcode that UTYPE is 8-bit unsigned char.
If one uses just __atomic_test_and_set and __atomic_clear, then I think
it makes no difference.
But testing whether the old byte was non-zero more matches the previous
intent in case the previous value is neither 0 nor
__GCC_ATOMIC_TEST_AND_SET_TRUEVAL
and treats it as "set" as well.
I think we don't need to change the loop, woldval | wval even for woldval
byte containing say 42 the or will make it still non-zero.
The documentation argues against using those atomics on types other than
bool and {,{un,}signed }char but libatomic still supports those, I believe
when one doesn't have hw specific support for these, __atomic_clear will
clear the entire UTYPE.
Jakub