fix ringbuffer thread safety on ARM. fix #715 #388
commit165f5fdd92617562eaed576c6c703002186fdd0a
authorkrasjet <nil@krj.st>
Thu, 21 Jul 2022 03:27:10 +0000 (21 03:27 +0000)
committerNedko Arnaudov <nedko@nedk.org>
Sat, 27 Aug 2022 15:07:35 +0000 (27 18:07 +0300)
tree5e75bbf852f90102f512daf21b525a8b8bc5f4bc
parent0fbb9c161ac5beaf4f29aaa1e5e2450fda5d3a98
fix ringbuffer thread safety on ARM. fix #715 #388

This patch addresses the thread safety problem of `jack_ringbuffer_t`
mentioned in #715 and #388. The overbound read bug caused by this problem
is impossible to reproduce on x86 due to its strong memory ordering, but
it is a problem on ARM and other weakly ordered architectures.

Basically, the main problem is that, on a weakly ordered architecture,
it is possible that the pointer increment after `memcpy` becomes visible
to the other thread before `memcpy` finishes:

memcpy (&(rb->buf[rb->write_ptr]), src, n1);
// vvv can be visible to reading thread before memcpy finishes
rb->write_ptr = (rb->write_ptr + n1) & rb->size_mask;

If this happens, the other thread can read the remaining garbage values
in `rb->buf` due to be overwritten by the unfinished `memcpy`.

To fix this, an explicit pair of release/acquire memory fences [1] is
used to ensure the copy on the other thread *happens after* the `memcpy`
finishes so no garbage values can be read.

[1]: https://preshing.com/20130922/acquire-and-release-fences/
common/ringbuffer.c