Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the C++11 atomic API equivalent to ```__asm__ volatile("" ::: "memory")```

A codebase has a COMPILER_BARRIER macro defined as __asm__ volatile("" ::: "memory"). The intent of the macro is to prevent the compiler from re-ordering reads and writes across the barrier. Note that this is explicitly a compiler barrier, and not a processor level memory barrier.

As is, this is fairly portable since there are no actual assembly instructions in the AssemblerTemplate, just the volatile and the memory clobber. So, as long as the compiler honors GCCs Extended Asm syntax, it should work fine. Still, I'm curious what the right way to express this would be in the C++11 atomics API, if possible.

The following seemed like it might be the right idea: atomic_signal_fence(memory_order_acq_rel);.

My reasoning being that:

  • Of the <atomic> APIs, only atomic_signal_fence and atomic_thread_fence do not need a memory address against which to operate.
  • atomic_thread_fence affects memory ordering, which we don't need for a compiler barrier.
  • The memory clobber in the Extended Asm version doesn't distinguish between reads and writes, so it would appear that we want both acquire and release semantics, so memory_order_acq_rel seems to be required, at minimum.
  • memory_order_seq_cst seems unnecessary, as we don't require a total order across threads - we are only interested in the instruction sequencing within the current thread.

Is it possible to express the equivalent to __asm__ volatile("" ::: "memory") entirely portably with the C++11 atomics API? If so, is atomic_signal_fence the correct API to use? If so, what memory order argument is appropriate/required here?

Or, am I off in the weeds here and there is a better way to approach this?

like image 618
acm Avatar asked Jul 26 '16 02:07

acm


1 Answers

__asm__ volatile("" ::: "memory") is not even a complete compiler barrier; it only forces ordering of loads/stores to objects whose addresses are potentially accessible to the asm block, which would not include local variables for which the compiler can track that the address does not leak. For example, memset(password, 0, len); followed by __asm__ volatile("" ::: "memory"); may fail to actually zero the memory used by password[].

This can be remedied by passing the addresses of such objects as inputs to the asm block, but I don't see any perfect equivalent with atomic_signal_fence. The closest you could probably do is storing the address of the object into an external-linkage volatile pointer object (be careful to make the pointer, not the pointed-to-type, volatile-qualified) and then atomic_signal_fence would have to assume it might be accessed from a signal handler.

like image 56
R.. GitHub STOP HELPING ICE Avatar answered Oct 16 '22 10:10

R.. GitHub STOP HELPING ICE