On Fri, Mar 4, 2016 at 11:21 PM, Fons Adriaensen <fons(a)linuxaudio.org> wrote:
On Fri, Mar 04, 2016 at 10:16:02AM +0100, Sebastian
Gesemann wrote:
As I said, I consider JACK's ringbuffer
implementation to be broken.
According to the C11/C++11 memory model there is nothing in the code
that prevents reordering the update to write_ptr and the update to
*buf in jack_ringbuffer_write. The use of volatile only makes sure
that read/write accesses to the volatile variables are not reordered
or "optimized out" by caching. Specificaly, a volatile write is not a
release barrier. It does not constrain reordering with respect to
other memory locations (*buf). This makes the access to the buffer's
content unordered and invokes undefined behaviour.
What if writing to the buffer and updating the write pointer is
done by two separate function calls (and in that order of course) ?
The second could be inlined, but even then it's still a function call.
You're right. Calling functions the compiler does not know anything
about will constrain reordering because the compiler has to assume the
worst about what happens in this function. But once you give it the
chance of inlining or enable link-time optimization, this could break
again. In general, you would want to avoid relying on compilers being
"stupid enough". Better not violate the contract in the first place.
Control of memory ordering and atomics are officially part of the C
and C++ languages since 2011. GCC already supported this when the ISO
standards was finalized. Microsoft and Clang started supporting it in
2012. So, it's been pretty much portable since 2012. This is 2016.
IMHO, it's time to make use of it. :)
Cheers!
sg