diff --git a/m-genint.h b/m-genint.h index 22b34a78..c8d5b82c 100644 --- a/m-genint.h +++ b/m-genint.h @@ -57,8 +57,10 @@ typedef struct genint_s { atomic_ullong *data; // the bitfield which informs if an integer } genint_t[1]; -#define GENINT_MAX_ALLOC (GENINT_LIMBSIZE * GENINT_LIMBSIZE) +// Define the max supported value +#define GENINT_MAX_ALLOC (GENINT_LIMBSIZE * (GENINT_LIMBSIZE - GENINT_ABA_CPT)) +// Define the size of a limb in bits. #define GENINT_LIMBSIZE (sizeof(genint_limb_t) * CHAR_BIT) #define GENINT_CONTRACT(s) do { \ @@ -70,6 +72,10 @@ typedef struct genint_s { #define GENINT_ONE ((genint_limb_t)1) +// Value returned in case of error. +#define GENINT_ERROR (-1U) + +// 32 bits of master are kept for handling the ABA problems. #define GENINT_ABA_CPT 32 #define GENINT_ABA_CPT_T uint32_t @@ -81,11 +87,11 @@ typedef struct genint_s { (((master) & (~((GENINT_ONE<< GENINT_ABA_CPT)-1)) & ~(GENINT_ONE << (GENINT_LIMBSIZE - 1 - i))) \ |((GENINT_ABA_CPT_T)((master) + 1))) -static inline void genint_init(genint_t s, size_t n) +static inline void genint_init(genint_t s, unsigned int n) { - assert (s != NULL && n > 0 && n <= GENINT_LIMBSIZE * (GENINT_LIMBSIZE - GENINT_ABA_CPT)); + assert (s != NULL && n > 0 && n <= GENINT_MAX_ALLOC); const size_t alloc = (n + GENINT_LIMBSIZE - 1) / GENINT_LIMBSIZE; - const size_t index = n % GENINT_LIMBSIZE; + const unsigned int index = n % GENINT_LIMBSIZE; atomic_ullong *ptr = M_MEMORY_REALLOC (atomic_ullong, NULL, alloc); if (M_UNLIKELY (ptr == NULL)) { M_MEMORY_FULL(alloc); @@ -97,7 +103,7 @@ static inline void genint_init(genint_t s, size_t n) s->mask0 = (index == 0) ? -GENINT_ONE : ~((GENINT_ONE<<(GENINT_LIMBSIZE-index))-1); s->mask_master = (((GENINT_ONE << alloc) - 1) << (GENINT_LIMBSIZE-alloc)) >> GENINT_ABA_CPT; atomic_init (&s->master, (genint_limb_t)0); - for(size_t i = 0; i < alloc; i++) + for(unsigned int i = 0; i < alloc; i++) atomic_init(&s->data[i], (genint_limb_t)0); GENINT_CONTRACT(s); } @@ -116,7 +122,7 @@ static inline size_t genint_size(genint_t s) } // Typical case: one CAS per pop. -static inline size_t genint_pop(genint_t s) +static inline unsigned int genint_pop(genint_t s) { GENINT_CONTRACT(s); // First read master to see which limb is not full. @@ -170,16 +176,16 @@ static inline size_t genint_pop(genint_t s) master = atomic_load(&s->master); } GENINT_CONTRACT(s); - return -(size_t)1; // No more resource available + return GENINT_ERROR; // No more resource available } // Typical usage: one CAS per push -static inline void genint_push(genint_t s, size_t n) +static inline void genint_push(genint_t s, unsigned int n) { GENINT_CONTRACT(s); assert (n < s->n); - const size_t i = n / GENINT_LIMBSIZE; - const size_t bit = GENINT_LIMBSIZE - 1 - (n % GENINT_LIMBSIZE); + const unsigned int i = n / GENINT_LIMBSIZE; + const unsigned int bit = GENINT_LIMBSIZE - 1 - (n % GENINT_LIMBSIZE); genint_limb_t master = atomic_load(&s->master); // Load the limb genint_limb_t next, org = atomic_load(&s->data[i]); diff --git a/m-shared.h b/m-shared.h index 8cfe4e9e..dffc3374 100644 --- a/m-shared.h +++ b/m-shared.h @@ -355,7 +355,7 @@ static inline int sharedi_integer_cref(int *p) { return *p; } unsigned int idx = genint_pop(s->core); \ it->idx = idx; \ it->ref = s; \ - if (M_LIKELY (idx != -1U)) { \ + if (M_LIKELY (idx != GENINT_ERROR)) { \ assert(atomic_load(&s->buffer[idx].cpt) == 0); \ atomic_store(&s->buffer[idx].cpt, 1U); \ } \ @@ -365,13 +365,13 @@ static inline int sharedi_integer_cref(int *p) { return *p; } M_C(name, _end_p)(M_C(name, _it_t) it) \ { \ assert (it != NULL); \ - return it->idx == -1U; \ + return it->idx == GENINT_ERROR; \ } \ \ static inline type * \ M_C(name, _ref)(M_C(name, _it_t) it) \ { \ - assert (it != NULL && it->ref != NULL && it->idx != -1U); \ + assert (it != NULL && it->ref != NULL && it->idx != GENINT_ERROR); \ SHAREDI_RESOURCE_CONTRACT(it->ref); \ return &it->ref->buffer[it->idx].x; \ } \ @@ -379,7 +379,7 @@ static inline int sharedi_integer_cref(int *p) { return *p; } static inline const type * \ M_C(name, _cref)(M_C(name, _it_t) it) \ { \ - assert (it != NULL && it->ref != NULL && it->idx != -1U); \ + assert (it != NULL && it->ref != NULL && it->idx != GENINT_ERROR); \ SHAREDI_RESOURCE_CONTRACT(it->ref); \ return M_CONST_CAST (type, &it->ref->buffer[it->idx].x); \ } \ @@ -391,12 +391,12 @@ static inline int sharedi_integer_cref(int *p) { return *p; } assert (it != NULL); \ assert (it->ref == s); \ unsigned int idx = it->idx; \ - if (M_LIKELY (idx != -1U)) { \ + if (M_LIKELY (idx != GENINT_ERROR)) { \ unsigned int c = atomic_fetch_sub (&it->ref->buffer[idx].cpt, 1U); \ if (c == 1) { \ genint_push(it->ref->core, idx); \ } \ - it->idx = -1U; \ + it->idx = GENINT_ERROR; \ } \ } \ \ @@ -408,7 +408,7 @@ static inline int sharedi_integer_cref(int *p) { return *p; } itd->ref = its->ref; \ unsigned int idx = its->idx; \ itd->idx = idx; \ - if (M_LIKELY (idx != -1U)) { \ + if (M_LIKELY (idx != GENINT_ERROR)) { \ unsigned int c = atomic_fetch_add(&itd->ref->buffer[idx].cpt, 1U); \ assert (c >= 1); \ } \ diff --git a/m-snapshot.h b/m-snapshot.h index e0cd6ddf..5982a3b6 100644 --- a/m-snapshot.h +++ b/m-snapshot.h @@ -313,12 +313,12 @@ static inline void snapshot_mrsw_int_init(snapshot_mrsw_int_t s, size_t n) genint_init (s->freeList, n); // Get a free buffer and set it as available for readers unsigned int w = genint_pop(s->freeList); - assert (w != -1U); + assert (w != GENINT_ERROR); atomic_store(&s->cptTab[w], 1U); atomic_init(&s->lastNext, SNAPSHOTI_SPMC_INT_FLAG(w, true)); // Get working buffer s->currentWrite = genint_pop(s->freeList); - assert (s->currentWrite != -1U); + assert (s->currentWrite != GENINT_ERROR); atomic_store(&s->cptTab[s->currentWrite], 1U); SNAPSHOTI_SPMC_INT_CONTRACT(s); } @@ -367,7 +367,7 @@ static inline unsigned int snapshot_mrsw_int_write_idx(snapshot_mrsw_int_t s, un // If someone else keeps a ref on the buffer, we can't reuse it // get another free one. idx = genint_pop(s->freeList); - assert(idx != -1U); + assert(idx != GENINT_ERROR); } assert (idx < s->n + SNAPSHOTI_SPMC_EXTRA_BUFFER); assert (atomic_load(&s->cptTab[idx]) == 0); @@ -389,7 +389,7 @@ static inline unsigned int snapshot_mrsw_int_write_start(snapshot_mrsw_int_t s) SNAPSHOTI_SPMC_INT_CONTRACT(s); // Get a new buffer. unsigned int idx = genint_pop(s->freeList); - assert (idx != -1U); + assert (idx != GENINT_ERROR); assert (idx < s->n + SNAPSHOTI_SPMC_EXTRA_BUFFER); assert (atomic_load(&s->cptTab[idx]) == 0); atomic_store(&s->cptTab[idx], 1U); @@ -583,7 +583,7 @@ static inline void snapshot_mrsw_int_read_end(snapshot_mrsw_int_t s, unsigned in { \ M_C(name, _mrsw_init)(snap->core, nReader + nWriter -1 ); \ unsigned int idx = snap->core->core->currentWrite; \ - snap->core->core->currentWrite = -1; \ + snap->core->core->currentWrite = GENINT_ERROR; \ snapshot_mrsw_int_write_end(snap->core->core, idx); \ } \ \ diff --git a/tests/test-mgenint.c b/tests/test-mgenint.c index 43273983..20cbc112 100644 --- a/tests/test-mgenint.c +++ b/tests/test-mgenint.c @@ -40,8 +40,8 @@ static void test(size_t n) assert (i == j); } i = genint_pop(s); - assert (i == -1UL); - assert (genint_pop(s) == -1UL); + assert (i == GENINT_ERROR); + assert (genint_pop(s) == GENINT_ERROR); for(size_t j = 0; j< n ; j++) { genint_push(s, (j+k) % n ); @@ -63,14 +63,14 @@ static void conso(void *p) unsigned int tab[4]; for(int j= 0; j < 4; j++) { tab[j] = genint_pop(global); - if (tab[j] != -1U) { + if (tab[j] != GENINT_ERROR) { assert (tab[j] < n); assert (atomic_load(&tab_g[tab[j]]) == false); atomic_store(&tab_g[tab[j]], true); } } for(int j = 0; j < 4; j++) { - if (tab[j] != -1U) { + if (tab[j] != GENINT_ERROR) { assert (tab[j] < n); assert (atomic_load(&tab_g[tab[j]]) == true); atomic_store(&tab_g[tab[j]], false);