aboutsummaryrefslogtreecommitdiff
path: root/platform/linux-generic/include
diff options
context:
space:
mode:
authorMatias Elo <matias.elo@nokia.com>2023-08-23 13:54:07 +0300
committerMatias Elo <matias.elo@nokia.com>2023-08-24 12:05:49 +0300
commitee1e983c0004f1d1d2b3bf15236a8a539f056cd0 (patch)
treed6a3db4d461daab34469306ec6d24faeb4144236 /platform/linux-generic/include
parent3acb2035e9e7bc70b44eaaf8e442d35907eacb18 (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.h28
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);