Ensure that the data in ringbuff is accessed in the right order
This commit is contained in:
parent
552408b241
commit
d68cbb2980
|
@ -38,6 +38,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lib/ringbuf.h"
|
#include "lib/ringbuf.h"
|
||||||
|
#include <sys/cc.h>
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
void
|
void
|
||||||
ringbuf_init(struct ringbuf *r, uint8_t *dataptr, uint8_t size)
|
ringbuf_init(struct ringbuf *r, uint8_t *dataptr, uint8_t size)
|
||||||
|
@ -63,8 +64,15 @@ ringbuf_put(struct ringbuf *r, uint8_t c)
|
||||||
if(((r->put_ptr - r->get_ptr) & r->mask) == r->mask) {
|
if(((r->put_ptr - r->get_ptr) & r->mask) == r->mask) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
r->data[r->put_ptr] = c;
|
/*
|
||||||
r->put_ptr = (r->put_ptr + 1) & r->mask;
|
* CC_ACCESS_NOW is used because the compiler is allowed to reorder
|
||||||
|
* the access to non-volatile variables.
|
||||||
|
* In this case a reader might read from the moved index/ptr before
|
||||||
|
* its value (c) is written. Reordering makes little sense, but
|
||||||
|
* better safe than sorry.
|
||||||
|
*/
|
||||||
|
CC_ACCESS_NOW(uint8_t, r->data[r->put_ptr]) = c;
|
||||||
|
CC_ACCESS_NOW(uint8_t, r->put_ptr) = (r->put_ptr + 1) & r->mask;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
@ -84,8 +92,17 @@ ringbuf_get(struct ringbuf *r)
|
||||||
most platforms, but C does not guarantee this.
|
most platforms, but C does not guarantee this.
|
||||||
*/
|
*/
|
||||||
if(((r->put_ptr - r->get_ptr) & r->mask) > 0) {
|
if(((r->put_ptr - r->get_ptr) & r->mask) > 0) {
|
||||||
c = r->data[r->get_ptr];
|
/*
|
||||||
r->get_ptr = (r->get_ptr + 1) & r->mask;
|
* CC_ACCESS_NOW is used because the compiler is allowed to reorder
|
||||||
|
* the access to non-volatile variables.
|
||||||
|
* In this case the memory might be freed and overwritten by
|
||||||
|
* increasing get_ptr before the value was copied to c.
|
||||||
|
* Opposed to the put-operation this would even make sense,
|
||||||
|
* because the register used for mask can be reused to save c
|
||||||
|
* (on some architectures).
|
||||||
|
*/
|
||||||
|
c = CC_ACCESS_NOW(uint8_t, r->data[r->get_ptr]);
|
||||||
|
CC_ACCESS_NOW(uint8_t, r->get_ptr) = (r->get_ptr + 1) & r->mask;
|
||||||
return c;
|
return c;
|
||||||
} else {
|
} else {
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -123,6 +123,17 @@
|
||||||
#define CC_NO_VA_ARGS CC_CONF_VA_ARGS
|
#define CC_NO_VA_ARGS CC_CONF_VA_ARGS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** \def CC_ACCESS_NOW(x)
|
||||||
|
* This macro ensures that the access to a non-volatile variable can
|
||||||
|
* not be reordered or optimized by the compiler.
|
||||||
|
* See also https://lwn.net/Articles/508991/ - In Linux the macro is
|
||||||
|
* called ACCESS_ONCE
|
||||||
|
* The type must be passed, because the typeof-operator is a gcc
|
||||||
|
* extension
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CC_ACCESS_NOW(type, variable) (*(volatile type *)&(variable))
|
||||||
|
|
||||||
#ifndef NULL
|
#ifndef NULL
|
||||||
#define NULL 0
|
#define NULL 0
|
||||||
#endif /* NULL */
|
#endif /* NULL */
|
||||||
|
|
Loading…
Reference in a new issue