In the paper "Non-blocking synchronization between real-time and non-real-time applications" the following pseudo code is listened in Listing 2. It suggests a non-blocking implementation for a single real-time writer and one or multiple non-real-time readers.
volatile counter : pointer to shared memory area of an integer
data_size : unsigned
pt_base : pointer to shared memory area of data_size bytes
initialization (d_size: unsigned)
counter := 0
data_size := d_size
pt_base := allocate data_size bytes in the shared memory
//Real-time operation
write (new_value: pointer)
local_counter := *counter
*counter := local_counter + 1
copy data_size bytes from *new_value
*pt_base*data_size
*counter := local_counter + 2
//Non-real-time operation
read (pt_data: pointer)
loop
counter_begin := *counter
copy data_size bytes from *pt_base to *pt_data *data_size
counter_end := *counter
if (counter_end == counter_begin and counter_begin is even)
break;
endif
endloop
How can this correctly be implemented in C with either C11 _Atomic, gcc/clang __atomic or just using volatile and memory barriers (if that is even possible)?
In his answer to another question Peter Cordes hinted that volatile and memory barriers could be enough or at least I understand it like that.
EDIT: So this is what I have now.
struct latency
{
uint64_t counter;
uint64_t active;
uint64_t minimal;
uint64_t maximal;
uint64_t sum;
};
struct timer
{
//timer related stuff
struct latency latency;
_Atomic uint32_t latency_seqcount;
};
static struct timer *timer;
//writer invoked by real-time thread
static void writer(void)
{
uint32_t seqcount;
struct latency *latency;
//setup timer / next period
//timer wait
//calculate latency
seqcount = atomic_load_explicit(&timer->latency_seqcount, memory_order_relaxed);
atomic_store_explicit(&timer->latency_seqcount, seqcount + 1, memory_order_relaxed);
atomic_thread_fence(memory_order_release);
latency = &timer->latency;
latency->active = latency_domain;
if (latency->counter == 0)
{
latency->maximal = latency->active;
latency->minimal = latency->active;
}
else if (latency->active > latency->maximal)
{
latency->maximal = latency->active;
}
else if (latency->active < latency->minimal)
{
latency->minimal = latency->active;
}
latency->counter++;
latency->sum += latency->active;
atomic_store_explicit(&timer->latency_seqcount, seqcount + 2, memory_order_release);
}
//reader invoked by non-real-time thread
static void reader(void)
{
struct latency latency;
uint32_t seqcount_begin;
uint32_t seqcount_end;
do
{
seqcount_begin = atomic_load_explicit(&timer->latency_seqcount, memory_order_acquire);
latency.counter = timer->latency.counter;
latency.active = timer->latency.active;
latency.minimal = timer->latency.minimal;
latency.maximal = timer->latency.maximal;
latency.sum = timer->latency.sum;
atomic_thread_fence(memory_order_acquire);
seqcount_end = atomic_load_explicit(&timer->latency_seqcount, memory_order_relaxed);
}
while (seqcount_begin != seqcount_end || seqcount_end & 0x01);
//print
}