[SNAPSHOT]:
* Rename functions get_produced / get_consummed into get_write_buffer and get_read_buffer * Add function _updated_p * Add comments.
This commit is contained in:
1 parent
49624eee15
commit
2700ccba1a
3 files changed
+51
-18
No files matched your search
@@ -2021,7 +2021,9 @@ This header is for created snapshots.
|
|||||||
#### SNAPSHOT\_DEF(name, type[, oplist])
|
#### SNAPSHOT\_DEF(name, type[, oplist])
|
||||||
|
|
||||||
Define the snapshot 'name##\_t' and its associated methods as "static inline" functions.
|
Define the snapshot 'name##\_t' and its associated methods as "static inline" functions.
|
||||||
A snapshot is a mechanism to allows a consumer thread and a produce thread, **working at different speeds**, to exchange messages in a reliable and thread safe way (the message is passed atomatically).
|
A snapshot is a mechanism to allows a single consumer thread and a single produce thread,
|
||||||
|
**working at different speeds**, to exchange messages in a reliable and thread safe way
|
||||||
|
(the message is passed atomatically).
|
||||||
In practice, it is implemented using a triple buffer.
|
In practice, it is implemented using a triple buffer.
|
||||||
|
|
||||||
This container is designed to be used for easy synchronization inter-threads (and the variable shall be a global one).
|
This container is designed to be used for easy synchronization inter-threads (and the variable shall be a global one).
|
||||||
@@ -2096,16 +2098,23 @@ Look at the last atomic snap of the active contain of the snapshot 'snap'.
|
|||||||
It returns the pointer to the data.
|
It returns the pointer to the data.
|
||||||
This functions is thread-safe and performs atomic operation on the snapshot.
|
This functions is thread-safe and performs atomic operation on the snapshot.
|
||||||
|
|
||||||
##### type *name\_get\_produced(snapshot\_t snap)
|
##### bool name\_updated\_p(snapshot\_t snap)
|
||||||
|
|
||||||
|
Return true if the buffer has updated data compared to the last time
|
||||||
|
it was read.
|
||||||
|
This functions is thread-safe and performs atomic operation on the snapshot.
|
||||||
|
|
||||||
|
##### type *name\_get\_write\_buffer(snapshot\_t snap)
|
||||||
|
|
||||||
Return a pointer to the active 'in-progress' contain of the snapshot 'snap'.
|
Return a pointer to the active 'in-progress' contain of the snapshot 'snap'.
|
||||||
It is the same as the last return from name\_take.
|
It is the same as the last return from name\_take.
|
||||||
This functions is thread-safe and performs atomic operation on the snapshot.
|
This functions is thread-safe and performs atomic operation on the snapshot.
|
||||||
|
|
||||||
##### type *name\_get\_consummed(snapshot\_t snap)
|
##### type *name\_get\_read\_buffer(snapshot\_t snap)
|
||||||
|
|
||||||
Return a pointer to the active 'freezed' contain of the snapshot 'snap'.
|
Return a pointer to the active 'freezed' contain of the snapshot 'snap'.
|
||||||
It is the same as the last return from name\_look.
|
It is the same as the last return from name\_look.
|
||||||
|
It doesn't perform any switch of the data which has to be read.
|
||||||
This functions is thread-safe and performs atomic operation on the snapshot.
|
This functions is thread-safe and performs atomic operation on the snapshot.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+35
-13
@@ -93,18 +93,24 @@
|
|||||||
//defered
|
//defered
|
||||||
#define SNAPSHOTI_DEF(arg) SNAPSHOTI_DEF2 arg
|
#define SNAPSHOTI_DEF(arg) SNAPSHOTI_DEF2 arg
|
||||||
|
|
||||||
|
// This is basically an atomic triple buffer between a produced thread
|
||||||
|
// and a consummer thread.
|
||||||
|
// TODO: Analyse generalisation to N produced threads and M consummer threads
|
||||||
|
#define SNAPSHOTI_MAX_BUFFER 3
|
||||||
|
|
||||||
#define SNAPSHOTI_DEF2(name, type, oplist) \
|
#define SNAPSHOTI_DEF2(name, type, oplist) \
|
||||||
\
|
\
|
||||||
typedef struct M_C(name, _s) { \
|
typedef struct M_C(name, _s) { \
|
||||||
type data[3]; \
|
type data[SNAPSHOTI_MAX_BUFFER]; \
|
||||||
atomic_uchar flags; \
|
atomic_uchar flags; \
|
||||||
} M_C(name, _t)[1]; \
|
} M_C(name, _t)[1]; \
|
||||||
|
\
|
||||||
typedef type M_C(name, _type_t); \
|
typedef type M_C(name, _type_t); \
|
||||||
\
|
\
|
||||||
static inline void M_C(name, _init)(M_C(name, _t) snap) \
|
static inline void M_C(name, _init)(M_C(name, _t) snap) \
|
||||||
{ \
|
{ \
|
||||||
assert(snap != NULL); \
|
assert(snap != NULL); \
|
||||||
for(int i = 0; i < 3; i++) { \
|
for(int i = 0; i < SNAPSHOTI_MAX_BUFFER; i++) { \
|
||||||
M_GET_INIT oplist(snap->data[i]); \
|
M_GET_INIT oplist(snap->data[i]); \
|
||||||
} \
|
} \
|
||||||
atomic_init (&snap->flags, SNAPSHOTI_FLAG(0, 1, 2, 0)); \
|
atomic_init (&snap->flags, SNAPSHOTI_FLAG(0, 1, 2, 0)); \
|
||||||
@@ -114,7 +120,7 @@
|
|||||||
static inline void M_C(name, _clear)(M_C(name, _t) snap) \
|
static inline void M_C(name, _clear)(M_C(name, _t) snap) \
|
||||||
{ \
|
{ \
|
||||||
SNAPSHOTI_CONTRACT(snap); \
|
SNAPSHOTI_CONTRACT(snap); \
|
||||||
for(int i = 0; i < 3; i++) { \
|
for(int i = 0; i < SNAPSHOTI_MAX_BUFFER; i++) { \
|
||||||
M_GET_CLEAR oplist(snap->data[i]); \
|
M_GET_CLEAR oplist(snap->data[i]); \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
@@ -124,7 +130,7 @@
|
|||||||
{ \
|
{ \
|
||||||
SNAPSHOTI_CONTRACT(org); \
|
SNAPSHOTI_CONTRACT(org); \
|
||||||
assert(snap != NULL && snap != org); \
|
assert(snap != NULL && snap != org); \
|
||||||
for(int i = 0; i < 3; i++) { \
|
for(int i = 0; i < SNAPSHOTI_MAX_BUFFER; i++) { \
|
||||||
M_GET_INIT_SET oplist(snap->data[i], org->data[i]); \
|
M_GET_INIT_SET oplist(snap->data[i], org->data[i]); \
|
||||||
} \
|
} \
|
||||||
atomic_init (&snap->flags, atomic_load(&org->flags)); \
|
atomic_init (&snap->flags, atomic_load(&org->flags)); \
|
||||||
@@ -136,7 +142,7 @@
|
|||||||
{ \
|
{ \
|
||||||
SNAPSHOTI_CONTRACT(snap); \
|
SNAPSHOTI_CONTRACT(snap); \
|
||||||
SNAPSHOTI_CONTRACT(org); \
|
SNAPSHOTI_CONTRACT(org); \
|
||||||
for(int i = 0; i < 3; i++) { \
|
for(int i = 0; i < SNAPSHOTI_MAX_BUFFER; i++) { \
|
||||||
M_GET_SET oplist(snap->data[i], org->data[i]); \
|
M_GET_SET oplist(snap->data[i], org->data[i]); \
|
||||||
} \
|
} \
|
||||||
atomic_init (&snap->flags, atomic_load(&org->flags)); \
|
atomic_init (&snap->flags, atomic_load(&org->flags)); \
|
||||||
@@ -149,7 +155,7 @@
|
|||||||
{ \
|
{ \
|
||||||
SNAPSHOTI_CONTRACT(org); \
|
SNAPSHOTI_CONTRACT(org); \
|
||||||
assert(snap != NULL && snap != org); \
|
assert(snap != NULL && snap != org); \
|
||||||
for(int i = 0; i < 3; i++) { \
|
for(int i = 0; i < SNAPSHOTI_MAX_BUFFER; i++) { \
|
||||||
M_GET_INIT_MOVE oplist(snap->data[i], org->data[i]); \
|
M_GET_INIT_MOVE oplist(snap->data[i], org->data[i]); \
|
||||||
} \
|
} \
|
||||||
snap->flags = org->flags; \
|
snap->flags = org->flags; \
|
||||||
@@ -165,7 +171,7 @@
|
|||||||
SNAPSHOTI_CONTRACT(snap); \
|
SNAPSHOTI_CONTRACT(snap); \
|
||||||
SNAPSHOTI_CONTRACT(org); \
|
SNAPSHOTI_CONTRACT(org); \
|
||||||
assert(snap != org); \
|
assert(snap != org); \
|
||||||
for(int i = 0; i < 3; i++) { \
|
for(int i = 0; i < SNAPSHOTI_MAX_BUFFER; i++) { \
|
||||||
M_GET_MOVE oplist(snap->data[i], org->data[i]); \
|
M_GET_MOVE oplist(snap->data[i], org->data[i]); \
|
||||||
} \
|
} \
|
||||||
snap->flags = org->flags; \
|
snap->flags = org->flags; \
|
||||||
@@ -174,17 +180,21 @@
|
|||||||
} \
|
} \
|
||||||
,) /* IF_METHOD (MOVE) */ \
|
,) /* IF_METHOD (MOVE) */ \
|
||||||
\
|
\
|
||||||
|
\
|
||||||
static inline type *M_C(name, _take)(M_C(name, _t) snap) \
|
static inline type *M_C(name, _take)(M_C(name, _t) snap) \
|
||||||
{ \
|
{ \
|
||||||
SNAPSHOTI_CONTRACT(snap); \
|
SNAPSHOTI_CONTRACT(snap); \
|
||||||
unsigned char nextFlags, origFlags = atomic_load (&snap->flags); \
|
unsigned char nextFlags, origFlags = atomic_load (&snap->flags); \
|
||||||
|
/* Atomic CAS operation */ \
|
||||||
do { \
|
do { \
|
||||||
|
/* Swap F and W buffer, setting exchange flag */ \
|
||||||
nextFlags = SNAPSHOTI_FLAG(SNAPSHOTI_R(origFlags), \
|
nextFlags = SNAPSHOTI_FLAG(SNAPSHOTI_R(origFlags), \
|
||||||
SNAPSHOTI_F(origFlags), \
|
SNAPSHOTI_F(origFlags), \
|
||||||
SNAPSHOTI_W(origFlags), 1); \
|
SNAPSHOTI_W(origFlags), 1); \
|
||||||
/* TODO: exponential backoff */ \
|
/* FIXME: Is exponential backoff really needed ? */ \
|
||||||
} while (!atomic_compare_exchange_weak (&snap->flags, &origFlags, \
|
} while (!atomic_compare_exchange_weak (&snap->flags, &origFlags, \
|
||||||
nextFlags)); \
|
nextFlags)); \
|
||||||
|
/* Return new write buffer for new updating */ \
|
||||||
return &snap->data[SNAPSHOTI_W(nextFlags)]; \
|
return &snap->data[SNAPSHOTI_W(nextFlags)]; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
@@ -192,27 +202,39 @@
|
|||||||
{ \
|
{ \
|
||||||
SNAPSHOTI_CONTRACT(snap); \
|
SNAPSHOTI_CONTRACT(snap); \
|
||||||
unsigned char nextFlags, origFlags = atomic_load (&snap->flags); \
|
unsigned char nextFlags, origFlags = atomic_load (&snap->flags); \
|
||||||
|
/* Atomic CAS operation */ \
|
||||||
do { \
|
do { \
|
||||||
if (!SNAPSHOTI_B(origFlags)) \
|
/* If no exchange registered, do nothing and keep the same */ \
|
||||||
|
if (!SNAPSHOTI_B(origFlags)) { \
|
||||||
|
nextFlags = origFlags; \
|
||||||
break; \
|
break; \
|
||||||
|
} \
|
||||||
|
/* Swap R and F buffer, clearing exchange flag */ \
|
||||||
nextFlags = SNAPSHOTI_FLAG(SNAPSHOTI_F(origFlags), \
|
nextFlags = SNAPSHOTI_FLAG(SNAPSHOTI_F(origFlags), \
|
||||||
SNAPSHOTI_W(origFlags), \
|
SNAPSHOTI_W(origFlags), \
|
||||||
SNAPSHOTI_R(origFlags), 0); \
|
SNAPSHOTI_R(origFlags), 0); \
|
||||||
/* TODO: exponential backoff */ \
|
/* FIXME: Is exponential backoff really needed ? */ \
|
||||||
} while (!atomic_compare_exchange_weak (&snap->flags, &origFlags, \
|
} while (!atomic_compare_exchange_weak (&snap->flags, &origFlags, \
|
||||||
nextFlags)); \
|
nextFlags)); \
|
||||||
nextFlags = atomic_load(&snap->flags); \
|
/* Return current read buffer */ \
|
||||||
return M_CONST_CAST(type, &snap->data[SNAPSHOTI_R(nextFlags)]); \
|
return M_CONST_CAST(type, &snap->data[SNAPSHOTI_R(nextFlags)]); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
static inline type *M_C(name, _get_produced)(M_C(name, _t) snap) \
|
static inline bool M_C(name, _updated_p)(M_C(name, _t) snap) \
|
||||||
|
{ \
|
||||||
|
SNAPSHOTI_CONTRACT(snap); \
|
||||||
|
unsigned char flags = atomic_load (&snap->flags); \
|
||||||
|
return SNAPSHOTI_B(flags); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline type *M_C(name, _get_write_buffer)(M_C(name, _t) snap) \
|
||||||
{ \
|
{ \
|
||||||
SNAPSHOTI_CONTRACT(snap); \
|
SNAPSHOTI_CONTRACT(snap); \
|
||||||
unsigned char flags = atomic_load(&snap->flags); \
|
unsigned char flags = atomic_load(&snap->flags); \
|
||||||
return &snap->data[SNAPSHOTI_W(flags)]; \
|
return &snap->data[SNAPSHOTI_W(flags)]; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
static inline const type *M_C(name, _get_consummed)(M_C(name, _t) snap) \
|
static inline const type *M_C(name, _get_read_buffer)(M_C(name, _t) snap) \
|
||||||
{ \
|
{ \
|
||||||
SNAPSHOTI_CONTRACT(snap); \
|
SNAPSHOTI_CONTRACT(snap); \
|
||||||
unsigned char flags = atomic_load(&snap->flags); \
|
unsigned char flags = atomic_load(&snap->flags); \
|
||||||
|
|||||||
@@ -39,15 +39,17 @@ static void test_uint(void)
|
|||||||
snapshot_uint_init(t);
|
snapshot_uint_init(t);
|
||||||
|
|
||||||
p_r = snapshot_uint_look(t);
|
p_r = snapshot_uint_look(t);
|
||||||
assert (p_r == snapshot_uint_get_consummed(t));
|
assert (p_r == snapshot_uint_get_read_buffer(t));
|
||||||
assert(*p_r == 0);
|
assert(*p_r == 0);
|
||||||
assert(snapshot_uint_look(t) == p_r);
|
assert(snapshot_uint_look(t) == p_r);
|
||||||
|
|
||||||
p_w = snapshot_uint_take(t);
|
p_w = snapshot_uint_take(t);
|
||||||
|
assert (snapshot_uint_updated_p (t) == true);
|
||||||
assert (p_w != p_r);
|
assert (p_w != p_r);
|
||||||
*p_w = 1;
|
*p_w = 1;
|
||||||
assert (*p_r == 0);
|
assert (*p_r == 0);
|
||||||
assert (snapshot_uint_look(t) != p_r);
|
assert (snapshot_uint_look(t) != p_r);
|
||||||
|
assert (snapshot_uint_updated_p (t) == false);
|
||||||
assert (*snapshot_uint_look(t) == 0);
|
assert (*snapshot_uint_look(t) == 0);
|
||||||
p_r = snapshot_uint_look(t);
|
p_r = snapshot_uint_look(t);
|
||||||
assert (*p_r == 0);
|
assert (*p_r == 0);
|
||||||
@@ -57,7 +59,7 @@ static void test_uint(void)
|
|||||||
assert (*snapshot_uint_look(t) == 1);
|
assert (*snapshot_uint_look(t) == 1);
|
||||||
|
|
||||||
p_w = snapshot_uint_take(t);
|
p_w = snapshot_uint_take(t);
|
||||||
assert (p_w == snapshot_uint_get_produced(t));
|
assert (p_w == snapshot_uint_get_write_buffer(t));
|
||||||
*p_w = 3;
|
*p_w = 3;
|
||||||
p_w = snapshot_uint_take(t);
|
p_w = snapshot_uint_take(t);
|
||||||
*p_w = 4;
|
*p_w = 4;
|
||||||
|
|||||||
Reference in new issue
Block a user