Add m_ prefix for GENINT module,

as it is purely internal (no need to prevent user space breakage).

It will put more stuff in the global m_ prefix
This commit is contained in:
Patrick Pelissier committed 2021-12-03 22:08:15 +01:00
1 parent d22c0b05ef
commit 50669a320c
5 files changed
+86 -88

No files matched your search

+6 -6
View File
@@ -574,9 +574,9 @@ typedef struct m_gc_lfmp_thread_s {
typedef struct m_gc_s {
m_gc_atomic_ticket_ct ticket;
m_gc_tid_t max_thread;
genint_t thread_alloc;
m_genint_t thread_alloc;
m_gc_lfmp_thread_ct *thread_data;
m_gM_CMEMP00L_list_ct *mempool_list;
m_gM_CMEMP00L_list_ct *mempool_list;
} m_gc_t[1];
static inline void
@@ -586,7 +586,7 @@ m_gc_init(m_gc_t gc_mem, size_t max_thread)
M_ASSERT(max_thread > 0 && max_thread < INT_MAX);
atomic_init(&gc_mem->ticket, 0UL);
genint_init(gc_mem->thread_alloc, (unsigned int) max_thread);
m_genint_init(gc_mem->thread_alloc, (unsigned int) max_thread);
gc_mem->thread_data = M_MEMORY_REALLOC(m_gc_lfmp_thread_ct, NULL, max_thread);
if (gc_mem->thread_data == NULL) {
M_MEMORY_FULL(max_thread * sizeof(m_gc_lfmp_thread_ct));
@@ -610,7 +610,7 @@ m_gc_clear(m_gc_t gc_mem)
}
M_MEMORY_FREE(gc_mem->thread_data);
gc_mem->thread_data = NULL;
genint_clear(gc_mem->thread_alloc);
m_genint_clear(gc_mem->thread_alloc);
}
static inline m_gc_tid_t
@@ -618,7 +618,7 @@ m_gc_attach_thread(m_gc_t gc_mem)
{
M_ASSERT(gc_mem != NULL && gc_mem->max_thread > 0);
unsigned id = genint_pop(gc_mem->thread_alloc);
unsigned id = m_genint_pop(gc_mem->thread_alloc);
return M_ASSIGN_CAST(m_gc_tid_t, id);
}
@@ -629,7 +629,7 @@ m_gc_detach_thread(m_gc_t gc_mem, m_gc_tid_t id)
M_ASSERT(id < gc_mem->max_thread);
M_ASSERT(atomic_load(&gc_mem->thread_data[id].ticket) == ULONG_MAX);
genint_push(gc_mem->thread_alloc, id);
m_genint_push(gc_mem->thread_alloc, id);
}
static inline void
+31 -33
View File
@@ -45,42 +45,40 @@ M_BEGIN_PROTECTED_CODE
enough.
*/
// TO DO: We may want a specialization with constant N value.
// Define the limb size used by genint
typedef unsigned long long genint_limb_ct;
typedef unsigned long long m_genint_limb_ct;
/* Define a generator of unique integer (Lock Free) */
typedef struct genint_s {
unsigned int n; // size of the container
unsigned int max; // number of allocated limb - 1
genint_limb_ct mask0; // mask of the last limb (constant)
genint_limb_ct mask_master; // mask of the master limb that controls others (constant)
atomic_ullong master; // master bitfield (which informs if a limb is full or not)
atomic_ullong *data; // the bitfield which informs if an integer is used or not
} genint_t[1];
typedef struct m_genint_s {
unsigned int n; // size of the container
unsigned int max; // number of allocated limb - 1
m_genint_limb_ct mask0; // mask of the last limb (constant)
m_genint_limb_ct mask_master; // mask of the master limb that controls others (constant)
atomic_ullong master; // master bitfield (which informs if a limb is full or not)
atomic_ullong *data; // the bitfield which informs if an integer is used or not
} m_genint_t[1];
// Define the max absolute supported value. It should be 2048 on most implementations.
#define GENINT_MAX_ALLOC (M_GEN1NT_LIMBSIZE * (M_GEN1NT_LIMBSIZE - M_GEN1NT_ABA_CPT))
#define M_GENINT_MAX_ALLOC (M_GEN1NT_LIMBSIZE * (M_GEN1NT_LIMBSIZE - M_GEN1NT_ABA_CPT))
// Define the size of a limb in bits.
#define M_GEN1NT_LIMBSIZE ((unsigned)(sizeof(genint_limb_ct) * CHAR_BIT))
#define M_GEN1NT_LIMBSIZE ((unsigned)(sizeof(m_genint_limb_ct) * CHAR_BIT))
// Define the contract of a genint
#define M_GEN1NT_CONTRACT(s) do { \
M_ASSERT (s != NULL); \
M_ASSERT (s->n > 0 && s->n <= GENINT_MAX_ALLOC); \
M_ASSERT (s->n > 0 && s->n <= M_GENINT_MAX_ALLOC); \
M_ASSERT ((s->max+1) * M_GEN1NT_LIMBSIZE >= s->n); \
M_ASSERT (s->data != NULL); \
} while (0)
// Define the limb one
#define M_GEN1NT_ONE ((genint_limb_ct)1)
#define M_GEN1NT_ONE ((m_genint_limb_ct)1)
#define M_GEN1NT_FULL_MASK ULLONG_MAX
// Value returned in case of error (not integer available).
#define GENINT_ERROR (UINT_MAX)
#define M_GENINT_ERROR (UINT_MAX)
/* 32 bits of the master mask are kept for handling the ABA problem.
* NOTE: May be too much. 16 bits should be more than enough. TBC
@@ -106,9 +104,9 @@ typedef struct genint_s {
* for all threads.
*/
static inline void
genint_init(genint_t s, unsigned int n)
m_genint_init(m_genint_t s, unsigned int n)
{
M_ASSERT (s != NULL && n > 0 && n <= GENINT_MAX_ALLOC);
M_ASSERT (s != NULL && n > 0 && n <= M_GENINT_MAX_ALLOC);
const size_t alloc = (n + M_GEN1NT_LIMBSIZE - 1) / M_GEN1NT_LIMBSIZE;
const unsigned int index = n % M_GEN1NT_LIMBSIZE;
atomic_ullong *ptr = M_MEMORY_REALLOC (atomic_ullong, NULL, alloc);
@@ -121,15 +119,15 @@ genint_init(genint_t s, unsigned int n)
s->max = (unsigned int) (alloc-1);
s->mask0 = (index == 0) ? M_GEN1NT_FULL_MASK : ~((M_GEN1NT_ONE<<(M_GEN1NT_LIMBSIZE-index))-1);
s->mask_master = (((M_GEN1NT_ONE << alloc) - 1) << (M_GEN1NT_LIMBSIZE-alloc)) >> M_GEN1NT_ABA_CPT;
atomic_init (&s->master, (genint_limb_ct)0);
atomic_init (&s->master, (m_genint_limb_ct)0);
for(unsigned int i = 0; i < alloc; i++)
atomic_init(&s->data[i], (genint_limb_ct)0);
atomic_init(&s->data[i], (m_genint_limb_ct)0);
M_GEN1NT_CONTRACT(s);
}
/* Clear an integer generator (Destructor) */
static inline void
genint_clear(genint_t s)
m_genint_clear(m_genint_t s)
{
M_GEN1NT_CONTRACT(s);
M_MEMORY_FREE(s->data);
@@ -138,7 +136,7 @@ genint_clear(genint_t s)
/* Return the maximum integer that the generator will provide */
static inline size_t
genint_size(genint_t s)
m_genint_size(m_genint_t s)
{
M_GEN1NT_CONTRACT(s);
return s->n;
@@ -147,22 +145,22 @@ genint_size(genint_t s)
/* Get an unique integer from the integer generator.
* NOTE: For a typical case, the amortized cost is one CAS per pop. */
static inline unsigned int
genint_pop(genint_t s)
m_genint_pop(m_genint_t s)
{
M_GEN1NT_CONTRACT(s);
// First read master to see which limb is not full.
genint_limb_ct master = atomic_load(&s->master);
m_genint_limb_ct master = atomic_load(&s->master);
// While master is not full
while ((master >> M_GEN1NT_ABA_CPT) != s->mask_master) {
// Let's get the index i of the first not full limb according to master.
unsigned int i = m_core_clz64(~master);
M_ASSERT (i < M_GEN1NT_LIMBSIZE);
// Let's compute the mask of this limb representing the limb as being full
genint_limb_ct mask = s->mask0;
m_genint_limb_ct mask = s->mask0;
mask = (i == s->max) ? mask : M_GEN1NT_FULL_MASK;
unsigned int bit;
// Let's load this limb,
genint_limb_ct next, org = atomic_load(&s->data[i]);
m_genint_limb_ct next, org = atomic_load(&s->data[i]);
do {
// If it is now full, we have been preempted by another.
if (M_UNLIKELY (org == mask))
@@ -181,7 +179,7 @@ genint_pop(genint_t s)
// If the limb is now full, try to update master
if (M_UNLIKELY(next == mask)) {
while (true) {
genint_limb_ct newMaster;
m_genint_limb_ct newMaster;
if (next == mask) {
newMaster = M_GEN1NT_MASTER_SET(master, i);
} else {
@@ -201,21 +199,21 @@ genint_pop(genint_t s)
master = atomic_load(&s->master);
}
M_GEN1NT_CONTRACT(s);
return GENINT_ERROR; // No more resource available
return M_GENINT_ERROR; // No more resource available
}
/* Restore a used integer in the integer generator.
* NOTE: For a typical case, the amortized cost is one CAS per pop */
static inline void
genint_push(genint_t s, unsigned int n)
m_genint_push(m_genint_t s, unsigned int n)
{
M_GEN1NT_CONTRACT(s);
M_ASSERT (n < s->n);
const unsigned int i = n / M_GEN1NT_LIMBSIZE;
const unsigned int bit = M_GEN1NT_LIMBSIZE - 1 - (n % M_GEN1NT_LIMBSIZE);
genint_limb_ct master = atomic_load(&s->master);
m_genint_limb_ct master = atomic_load(&s->master);
// Load the limb
genint_limb_ct next, org = atomic_load(&s->data[i]);
m_genint_limb_ct next, org = atomic_load(&s->data[i]);
do {
M_ASSERT ((org & (M_GEN1NT_ONE << bit)) != 0);
// Reset it
@@ -223,13 +221,13 @@ genint_push(genint_t s, unsigned int n)
// Try to unreserve it.
} while (!atomic_compare_exchange_weak (&s->data[i], &org, next));
// if the limb was marked as full by master
genint_limb_ct mask = s->mask0;
m_genint_limb_ct mask = s->mask0;
mask = (i == s->max) ? mask : M_GEN1NT_FULL_MASK;
if (M_UNLIKELY (next != mask)) {
// Let's compute the mask of this limb representing the limb as being full
// Let's try to update master to say that this limb is not full
while (true) {
genint_limb_ct newMaster;
m_genint_limb_ct newMaster;
if (next == mask) {
newMaster = M_GEN1NT_MASTER_SET(master, i);
} else {
+13 -13
View File
@@ -380,7 +380,7 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
} M_C(name, _atype_ct); \
\
typedef struct M_C(name, _s) { \
genint_t core; \
m_genint_t core; \
M_C(name, _atype_ct) *buffer; \
} shared_t[1]; \
\
@@ -406,7 +406,7 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
M_CALL_INIT(oplist, s->buffer[i].x); \
atomic_init (&s->buffer[i].cpt, 0U); \
} \
genint_init(s->core, (unsigned int) n); \
m_genint_init(s->core, (unsigned int) n); \
M_SHAR3D_RESOURCE_CONTRACT(s); \
} \
\
@@ -414,13 +414,13 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
M_C(name, _clear)(shared_t s) \
{ \
M_SHAR3D_RESOURCE_CONTRACT(s); \
size_t n = genint_size(s->core); \
size_t n = m_genint_size(s->core); \
for(size_t i = 0; i < n; i++) { \
M_CALL_CLEAR(oplist, s->buffer[i].x); \
} \
M_CALL_FREE(oplist, s->buffer); \
s->buffer = NULL; \
genint_clear(s->core); \
m_genint_clear(s->core); \
} \
\
static inline void \
@@ -428,10 +428,10 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
{ \
M_SHAR3D_RESOURCE_CONTRACT(s); \
M_ASSERT (it != NULL); \
unsigned int idx = genint_pop(s->core); \
unsigned int idx = m_genint_pop(s->core); \
it->idx = idx; \
it->ref = s; \
if (M_LIKELY (idx != GENINT_ERROR)) { \
if (M_LIKELY (idx != M_GENINT_ERROR)) { \
M_ASSERT(atomic_load(&s->buffer[idx].cpt) == 0); \
atomic_store(&s->buffer[idx].cpt, 1U); \
} \
@@ -441,13 +441,13 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
M_C(name, _end_p)(it_t it) \
{ \
M_ASSERT (it != NULL); \
return it->idx == GENINT_ERROR; \
return it->idx == M_GENINT_ERROR; \
} \
\
static inline type * \
M_C(name, _ref)(it_t it) \
{ \
M_ASSERT (it != NULL && it->ref != NULL && it->idx != GENINT_ERROR); \
M_ASSERT (it != NULL && it->ref != NULL && it->idx != M_GENINT_ERROR); \
M_SHAR3D_RESOURCE_CONTRACT(it->ref); \
return &it->ref->buffer[it->idx].x; \
} \
@@ -455,7 +455,7 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
static inline type const * \
M_C(name, _cref)(it_t it) \
{ \
M_ASSERT (it != NULL && it->ref != NULL && it->idx != GENINT_ERROR); \
M_ASSERT (it != NULL && it->ref != NULL && it->idx != M_GENINT_ERROR); \
M_SHAR3D_RESOURCE_CONTRACT(it->ref); \
return M_CONST_CAST (type, &it->ref->buffer[it->idx].x); \
} \
@@ -467,12 +467,12 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
M_ASSERT (it != NULL); \
M_ASSERT (it->ref == s); \
unsigned int idx = it->idx; \
if (M_LIKELY (idx != GENINT_ERROR)) { \
if (M_LIKELY (idx != M_GENINT_ERROR)) { \
unsigned int c = atomic_fetch_sub (&it->ref->buffer[idx].cpt, 1U); \
if (c == 1) { \
genint_push(it->ref->core, idx); \
m_genint_push(it->ref->core, idx); \
} \
it->idx = GENINT_ERROR; \
it->idx = M_GENINT_ERROR; \
} \
} \
\
@@ -484,7 +484,7 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
itd->ref = its->ref; \
unsigned int idx = its->idx; \
itd->idx = idx; \
if (M_LIKELY (idx != GENINT_ERROR)) { \
if (M_LIKELY (idx != M_GENINT_ERROR)) { \
unsigned int c = atomic_fetch_add(&itd->ref->buffer[idx].cpt, 1U); \
M_ASSERT (c >= 1); \
} \
+16 -16
View File
@@ -347,7 +347,7 @@ M_BEGIN_PROTECTED_CODE
// 2 more buffer than the number of readers are needed
#define M_SNAPSH0T_SPMC_EXTRA_BUFFER 2
#define M_SNAPSH0T_SPMC_MAX_READER (GENINT_MAX_ALLOC-M_SNAPSH0T_SPMC_EXTRA_BUFFER)
#define M_SNAPSH0T_SPMC_MAX_READER (M_GENINT_MAX_ALLOC-M_SNAPSH0T_SPMC_EXTRA_BUFFER)
/* Internal structure to handle SPMC snapshot but return an unique index in the buffer array.
- lastNext: last published written index + next flag (format M_SNAPSH0T_SPMC_INT_FLAG)
@@ -361,7 +361,7 @@ typedef struct m_snapshot_mrsw_s {
unsigned int currentWrite;
size_t n_reader;
atomic_uint *cptTab;
genint_t freeList;
m_genint_t freeList;
} m_snapshot_mrsw_ct[1];
// can't check currentWrite due to potential data race on it
@@ -391,17 +391,17 @@ m_snapsh0t_mrsw_init(m_snapshot_mrsw_ct s, size_t n)
s->cptTab = ptr;
for(size_t i = 0; i < n; i++)
atomic_init(&s->cptTab[i], 0U);
genint_init (s->freeList, (unsigned int) n);
m_genint_init (s->freeList, (unsigned int) n);
// Get a free buffer and set it as available for readers
unsigned int w = genint_pop(s->freeList);
M_ASSERT (w != GENINT_ERROR);
unsigned int w = m_genint_pop(s->freeList);
M_ASSERT (w != M_GENINT_ERROR);
atomic_store(&s->cptTab[w], 1U);
atomic_init(&s->lastNext, M_SNAPSH0T_SPMC_INT_FLAG(w, true));
// Get working buffer
s->currentWrite = genint_pop(s->freeList);
M_ASSERT (s->currentWrite != GENINT_ERROR);
s->currentWrite = m_genint_pop(s->freeList);
M_ASSERT (s->currentWrite != M_GENINT_ERROR);
atomic_store(&s->cptTab[s->currentWrite], 1U);
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
}
@@ -412,7 +412,7 @@ m_snapsh0t_mrsw_clear(m_snapshot_mrsw_ct s)
{
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
M_MEMORY_FREE (s->cptTab);
genint_clear(s->freeList);
m_genint_clear(s->freeList);
s->cptTab = NULL;
s->n_reader = 0;
}
@@ -462,8 +462,8 @@ m_snapsh0t_mrsw_write_idx(m_snapshot_mrsw_ct s, unsigned int idx)
if (c != 1) {
// If someone else keeps a ref on the buffer, we can't reuse it
// get another free one.
idx = genint_pop(s->freeList);
M_ASSERT(idx != GENINT_ERROR);
idx = m_genint_pop(s->freeList);
M_ASSERT(idx != M_GENINT_ERROR);
} else {
// No other thread keep track of this buffer.
// Reuse it.
@@ -491,8 +491,8 @@ m_snapsh0t_mrsw_write_start(m_snapshot_mrsw_ct s)
{
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
// Get a new buffer.
unsigned int idx = genint_pop(s->freeList);
M_ASSERT (idx != GENINT_ERROR);
unsigned int idx = m_genint_pop(s->freeList);
M_ASSERT (idx != M_GENINT_ERROR);
M_ASSERT (idx < s->n_reader + M_SNAPSH0T_SPMC_EXTRA_BUFFER);
M_ASSERT (atomic_load(&s->cptTab[idx]) == 0);
atomic_store(&s->cptTab[idx], 1U);
@@ -517,7 +517,7 @@ m_snapsh0t_mrsw_write_end(m_snapshot_mrsw_ct s, unsigned int idx)
unsigned int c = atomic_fetch_sub(&s->cptTab[idx], 1U);
M_ASSERT (c != 0 && c <= s->n_reader + 1);
if (c == 1) {
genint_push(s->freeList, idx);
m_genint_push(s->freeList, idx);
}
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
}
@@ -558,7 +558,7 @@ m_snapsh0t_mrsw_read_start(m_snapshot_mrsw_ct s)
c = atomic_fetch_sub(&s->cptTab[idx], 1U);
M_ASSERT (c != 0 && c <= s->n_reader + 1);
if (c == 1) {
genint_push(s->freeList, idx);
m_genint_push(s->freeList, idx);
}
}
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
@@ -577,7 +577,7 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
if (c == 1) {
// Buffer no longer used by any reader thread.
// Push back index in free list
genint_push(s->freeList, idx);
m_genint_push(s->freeList, idx);
}
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
}
@@ -730,7 +730,7 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
{ \
M_C(name, _mrsw_init)(snap->core, nReader + nWriter -1 ); \
unsigned int idx = snap->core->core->currentWrite; \
snap->core->core->currentWrite = GENINT_ERROR; \
snap->core->core->currentWrite = M_GENINT_ERROR; \
m_snapsh0t_mrsw_write_end(snap->core->core, idx); \
} \
\
+20 -20
View File
@@ -30,30 +30,30 @@
static void test(size_t n)
{
genint_t s;
m_genint_t s;
size_t i;
genint_init(s, (unsigned int) n);
m_genint_init(s, (unsigned int) n);
for(int k = 0; k < 3; k++) {
for(size_t j = 0; j< n ; j++) {
i = genint_pop(s);
i = m_genint_pop(s);
assert (i == j);
}
i = genint_pop(s);
assert (i == GENINT_ERROR);
assert (genint_pop(s) == GENINT_ERROR);
i = m_genint_pop(s);
assert (i == M_GENINT_ERROR);
assert (m_genint_pop(s) == M_GENINT_ERROR);
for(size_t j = 0; j< n ; j++) {
genint_push(s, (unsigned int) ((j + (size_t) k) % n ));
m_genint_push(s, (unsigned int) ((j + (size_t) k) % n ));
}
}
genint_clear(s);
m_genint_clear(s);
}
/*******************************************************/
genint_t global;
m_genint_t global;
atomic_bool tab_g[MAX_N];
static void conso(void *p)
@@ -62,19 +62,19 @@ static void conso(void *p)
for(int i = 0; i < 100000; i++) {
unsigned int tab[4];
for(int j= 0; j < 4; j++) {
tab[j] = genint_pop(global);
if (tab[j] != GENINT_ERROR) {
tab[j] = m_genint_pop(global);
if (tab[j] != M_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] != GENINT_ERROR) {
if (tab[j] != M_GENINT_ERROR) {
assert (tab[j] < n);
assert (atomic_load(&tab_g[tab[j]]) == true);
atomic_store(&tab_g[tab[j]], false);
genint_push(global, tab[j]);
m_genint_push(global, tab[j]);
}
}
}
@@ -84,7 +84,7 @@ static void test2(size_t n)
{
m_thread_t idx[4];
genint_init(global, (unsigned int) n);
m_genint_init(global, (unsigned int) n);
for(int i = 0; i < MAX_N; i++)
atomic_init(&tab_g[i], false);
@@ -95,7 +95,7 @@ static void test2(size_t n)
m_thread_join(idx[i]);
}
genint_clear(global);
m_genint_clear(global);
}
// In this test, the dimension of the global and the number of threads
@@ -104,10 +104,10 @@ static void conso2(void *p)
{
size_t n = *(size_t*)p;
for(int i = 0; i < 1000000; i++) {
unsigned int j = genint_pop(global);
assert (j != GENINT_ERROR);
unsigned int j = m_genint_pop(global);
assert (j != M_GENINT_ERROR);
assert (j < n);
genint_push(global, j);
m_genint_push(global, j);
}
}
@@ -116,14 +116,14 @@ static void test3(size_t n)
m_thread_t idx[MAX_N];
assert (n <= MAX_N);
genint_init(global, (unsigned int) n);
m_genint_init(global, (unsigned int) n);
for(size_t i = 0; i < n; i++) {
m_thread_create (idx[i], conso2, (void*)&n);
}
for(size_t i = 0; i < n;i++) {
m_thread_join(idx[i]);
}
genint_clear(global);
m_genint_clear(global);
}
int main(void)