diff options
author | Matias Elo <matias.elo@nokia.com> | 2023-08-23 13:54:07 +0300 |
---|---|---|
committer | Matias Elo <matias.elo@nokia.com> | 2023-08-24 12:05:49 +0300 |
commit | ee1e983c0004f1d1d2b3bf15236a8a539f056cd0 (patch) | |
tree | d6a3db4d461daab34469306ec6d24faeb4144236 /platform/linux-generic/include | |
parent | 3acb2035e9e7bc70b44eaaf8e442d35907eacb18 (diff) |
linux-gen: ring: fix ring size detection
Previously, _RING_MPMC_ENQ_MULTI() and _RING_MPMC_ENQ_BATCH() could return
zero even though the ring was not actually full. Read w_head before r_tail,
which guarantees that w_head - r_tail <= size. Any additional delay in
reading r_tail makes the subtraction result only smaller. This avoids
returning zero when the ring is not actually full.
Signed-off-by: Matias Elo <matias.elo@nokia.com>
Reviewed-by: Petri Savolainen <petri.savolainen@nokia.com>
Reported-by: Fan Hong <fan.hong@arm.com>
Diffstat (limited to 'platform/linux-generic/include')
-rw-r--r-- | platform/linux-generic/include/odp_ring_mpmc_internal.h | 28 |
1 files changed, 18 insertions, 10 deletions
diff --git a/platform/linux-generic/include/odp_ring_mpmc_internal.h b/platform/linux-generic/include/odp_ring_mpmc_internal.h index e35179267..c03a8e9a0 100644 --- a/platform/linux-generic/include/odp_ring_mpmc_internal.h +++ b/platform/linux-generic/include/odp_ring_mpmc_internal.h @@ -212,13 +212,17 @@ static inline uint32_t _RING_MPMC_ENQ_MULTI(_ring_mpmc_gen_t *ring, uint32_t old_head, new_head, r_tail, num_free, i; uint32_t size = ring_mask + 1; - /* Load acquires ensure that w_head load happens after r_tail load, - * and thus r_tail value is always behind or equal to w_head value. - * When CAS operation succeeds, this thread owns data between old - * and new w_head. */ + /* The CAS operation guarantees that w_head value is up to date. Load + * acquire is used to ensure that r_tail is read after w_head. This + * guarantees that w_head - r_tail <= size. Any additional delay in + * reading r_tail makes the subtraction result only smaller. This + * avoids returning zero when the ring is not actually full. + * + * When CAS operation succeeds, this thread owns data between old and + * new w_head. */ do { - r_tail = odp_atomic_load_acq_u32(&ring->r.r_tail); old_head = odp_atomic_load_acq_u32(&ring->r.w_head); + r_tail = odp_atomic_load_acq_u32(&ring->r.r_tail); num_free = size - (old_head - r_tail); @@ -259,13 +263,17 @@ static inline uint32_t _RING_MPMC_ENQ_BATCH(_ring_mpmc_gen_t *ring, uint32_t old_head, new_head, r_tail, num_free, i; uint32_t size = ring_mask + 1; - /* Load acquires ensure that w_head load happens after r_tail load, - * and thus r_tail value is always behind or equal to w_head value. - * When CAS operation succeeds, this thread owns data between old - * and new w_head. */ + /* The CAS operation guarantees that w_head value is up to date. Load + * acquire is used to ensure that r_tail is read after w_head. This + * guarantees that w_head - r_tail <= size. Any additional delay in + * reading r_tail makes the subtraction result only smaller. This + * avoids returning zero when the ring is not actually full. + * + * When CAS operation succeeds, this thread owns data between old and + * new w_head. */ do { - r_tail = odp_atomic_load_acq_u32(&ring->r.r_tail); old_head = odp_atomic_load_acq_u32(&ring->r.w_head); + r_tail = odp_atomic_load_acq_u32(&ring->r.r_tail); num_free = size - (old_head - r_tail); |