On Wed, Dec 8, 2021 at 9:07 AM Peter Zijlstra <peterz@xxxxxxxxxxxxx> wrote: > > IOW, the effective range becomes: [1..INT_MIN], which is a bit > counter-intuitive, but then so is most of this stuff. I'd suggest not codifying it too strictly, because the exact range at the upper end might depend on what is convenient for an architecture to do. For x86, 'xadd' has odd semantics in that the flags register is about the *new* state, but the returned value is about the *old* state. That means that on x86, some things are cheaper to test based on the pre-inc/dec values, and other things are cheaper to test based on the post-inc/dec ones. It's also why for "page->_mapcount" we have the "free" value being -1, not 0, and the refcount is "off by one". It makes the special cases of "increment from zero" and "decrement to zero" be very easy and straightforward to test for. That might be an option for an "atomic_ref" type - with our existing "page_mapcount()" code being the thing we'd convert first, and make be the example for it. I think it should also make the error cases be very easy to check for without extra tests. If you make "decrement from zero" be the "ok, now it's free", then that shows in the carry flag. But otherwise, if SF or OF is set, it's an error. That means we can use the regular atomics and flags (although not "dec" and "inc", since we'd care about CF). So on x86, I think "atomic_dec_ref()" could be lock subl $1,ptr jc now_its_free jl this_is_an_error if we end up having that "off by one" model. And importantly, "atomic_inc_ref()" would be just lock incl ptr jle this_is_an_error and this avoids us having to have the value in a register and test it separately. So your suggestion is _close_, but note how you can't do the "inc_ofl" without that "off-by-one" model. And again - I might have gotten the exact flag test instructions wrong. That's what you get for not actually doing serious assembly language for a couple of decades. Linus