[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:
Patrick Pelissier committed 2017-10-11 22:16:39 +02:00
1 parent 49624eee15
commit 2700ccba1a
3 files changed
+51 -18

No files matched your search

+12 -3
View File
@@ -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
View File
@@ -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); \
+4 -2
View File
@@ -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;