From 50669a320ccc3e4876160870a4f2a769a8f55e85 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Fri, 3 Dec 2021 22:08:15 +0100 Subject: [PATCH] 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 --- m-c-mempool.h | 12 ++++----- m-genint.h | 64 +++++++++++++++++++++----------------------- m-shared.h | 26 +++++++++--------- m-snapshot.h | 32 +++++++++++----------- tests/test-mgenint.c | 40 +++++++++++++-------------- 5 files changed, 86 insertions(+), 88 deletions(-) diff --git a/m-c-mempool.h b/m-c-mempool.h index 0094f238..3b0c15ff 100644 --- a/m-c-mempool.h +++ b/m-c-mempool.h @@ -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 diff --git a/m-genint.h b/m-genint.h index bf1be0b3..82278888 100644 --- a/m-genint.h +++ b/m-genint.h @@ -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 { diff --git a/m-shared.h b/m-shared.h index 6cd09587..99761a2d 100644 --- a/m-shared.h +++ b/m-shared.h @@ -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); \ } \ diff --git a/m-snapshot.h b/m-snapshot.h index 250eff27..2aa4d5ae 100644 --- a/m-snapshot.h +++ b/m-snapshot.h @@ -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); \ } \ \ diff --git a/tests/test-mgenint.c b/tests/test-mgenint.c index f5be7864..f66bb1ce 100644 --- a/tests/test-mgenint.c +++ b/tests/test-mgenint.c @@ -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)