BUG/MAJOR: threads/freq_ctr: use a memory barrier to detect changes

commit 6e01286 (BUG/MAJOR: threads/freq_ctr: fix lock on freq counters)
attempted to fix the loop using volatile but that doesn't work depending
on the level of optimization, resulting in situations where the threads
could remain looping forever. Here we use memory barriers between reads
to enforce a strict ordering and the asm code produced does exactly what
the C code does and works perfectly, with a 3-digit measurement accuracy
observed during a test.
This commit is contained in:
Willy Tarreau 2017-10-31 17:54:15 +01:00
parent b29dc95a97
commit a06a580941

View File

@ -33,15 +33,21 @@ unsigned int read_freq_ctr(struct freq_ctr *ctr)
unsigned int curr, past, _curr, _past;
unsigned int age, curr_sec, _curr_sec;
while(1) {
_curr = (volatile unsigned int)ctr->curr_ctr;
_past = (volatile unsigned int)ctr->prev_ctr;
_curr_sec = (volatile unsigned int)ctr->curr_sec;
while (1) {
_curr = ctr->curr_ctr;
HA_BARRIER();
_past = ctr->prev_ctr;
HA_BARRIER();
_curr_sec = ctr->curr_sec;
HA_BARRIER();
if (_curr_sec & 0x80000000)
continue;
curr = (volatile unsigned int)ctr->curr_ctr;
past = (volatile unsigned int)ctr->prev_ctr;
curr_sec = (volatile unsigned int)ctr->curr_sec;
curr = ctr->curr_ctr;
HA_BARRIER();
past = ctr->prev_ctr;
HA_BARRIER();
curr_sec = ctr->curr_sec;
HA_BARRIER();
if (_curr == curr && _past == past && _curr_sec == curr_sec)
break;
}
@ -70,15 +76,21 @@ unsigned int freq_ctr_remain(struct freq_ctr *ctr, unsigned int freq, unsigned i
unsigned int curr, past, _curr, _past;
unsigned int age, curr_sec, _curr_sec;
while(1) {
_curr = (volatile unsigned int)ctr->curr_ctr;
_past = (volatile unsigned int)ctr->prev_ctr;
_curr_sec = (volatile unsigned int)ctr->curr_sec;
while (1) {
_curr = ctr->curr_ctr;
HA_BARRIER();
_past = ctr->prev_ctr;
HA_BARRIER();
_curr_sec = ctr->curr_sec;
HA_BARRIER();
if (_curr_sec & 0x80000000)
continue;
curr = (volatile unsigned int)ctr->curr_ctr;
past = (volatile unsigned int)ctr->prev_ctr;
curr_sec = (volatile unsigned int)ctr->curr_sec;
curr = ctr->curr_ctr;
HA_BARRIER();
past = ctr->prev_ctr;
HA_BARRIER();
curr_sec = ctr->curr_sec;
HA_BARRIER();
if (_curr == curr && _past == past && _curr_sec == curr_sec)
break;
}
@ -111,15 +123,21 @@ unsigned int next_event_delay(struct freq_ctr *ctr, unsigned int freq, unsigned
unsigned int curr, past, _curr, _past;
unsigned int wait, age, curr_sec, _curr_sec;
while(1) {
_curr = (volatile unsigned int)ctr->curr_ctr;
_past = (volatile unsigned int)ctr->prev_ctr;
_curr_sec = (volatile unsigned int)ctr->curr_sec;
while (1) {
_curr = ctr->curr_ctr;
HA_BARRIER();
_past = ctr->prev_ctr;
HA_BARRIER();
_curr_sec = ctr->curr_sec;
HA_BARRIER();
if (_curr_sec & 0x80000000)
continue;
curr = (volatile unsigned int)ctr->curr_ctr;
past = (volatile unsigned int)ctr->prev_ctr;
curr_sec = (volatile unsigned int)ctr->curr_sec;
curr = ctr->curr_ctr;
HA_BARRIER();
past = ctr->prev_ctr;
HA_BARRIER();
curr_sec = ctr->curr_sec;
HA_BARRIER();
if (_curr == curr && _past == past && _curr_sec == curr_sec)
break;
}
@ -164,15 +182,21 @@ unsigned int read_freq_ctr_period(struct freq_ctr_period *ctr, unsigned int peri
unsigned int _curr, _past, curr, past;
unsigned int remain, _curr_tick, curr_tick;
while(1) {
while (1) {
_curr = ctr->curr_ctr;
HA_BARRIER();
_past = ctr->prev_ctr;
HA_BARRIER();
_curr_tick = ctr->curr_tick;
HA_BARRIER();
if (_curr_tick & 0x1)
continue;
curr = ctr->curr_ctr;
HA_BARRIER();
past = ctr->prev_ctr;
HA_BARRIER();
curr_tick = ctr->curr_tick;
HA_BARRIER();
if (_curr == curr && _past == past && _curr_tick == curr_tick)
break;
};
@ -205,15 +229,21 @@ unsigned int freq_ctr_remain_period(struct freq_ctr_period *ctr, unsigned int pe
unsigned int _curr, _past, curr, past;
unsigned int remain, _curr_tick, curr_tick;
while(1) {
while (1) {
_curr = ctr->curr_ctr;
HA_BARRIER();
_past = ctr->prev_ctr;
HA_BARRIER();
_curr_tick = ctr->curr_tick;
HA_BARRIER();
if (_curr_tick & 0x1)
continue;
curr = ctr->curr_ctr;
HA_BARRIER();
past = ctr->prev_ctr;
HA_BARRIER();
curr_tick = ctr->curr_tick;
HA_BARRIER();
if (_curr == curr && _past == past && _curr_tick == curr_tick)
break;
};