What's the best way to fetch-or an atomic pointer?

I'm working on a lockless algorithm that requires me to manipulate the address of an atomic pointer. In particular, I have an AtomicPtr that can have a few values:

  • if the pointer is null, it's a sentinel value for the end of a list.
  • if the address segment of the pointer is odd, the pointer should be interpreted as an integer (i.e. never dereferenced).
  • if the address segment of the pointer is even, it's a valid pointer to another element in the list.

The pointee structure has alignment greater than 2, so I believe this is all valid. In order to make this all work, I need a method to perform an atomic fetch-or operation on an AtomicPtr (to mask in the lowest bit). There seem to be a few options:

AtomicPtr::fetch_or seems like the best bet, but the problem is that it's gated by strict_provenance_atomic_ptr, which is unlikely to be stabilized any time soon.

The other option would be to manipulate everything as an AtomicUsize and then use its implementation of fetch_or to make it all work, then cast the usize back as a pointer when I need it. I don't like this approach because it blows up when working with Miri or other strict-provenance tools.

Two questions:

  • Are these the only two options?
  • If so, is there something else I've missed that would make one better than the other?

I'm currently thinking that if I move forward with this, I'll make a custom wrapper for the two which compile-gates its underlying implementation based on whether strict provenance is enabled. Is there a better way to do that?

You can always use compare_exchange or compare_exchange_weak to implement an update operation, such as OR.

But you will need unsafe code to cast the current value to usize, OR in the mask, and cast back to ptr. Whether Miri will accept it, I don't know.

Edit: The casting itself is not unsafe, only the dereferencing of pointers created by casting.